[issue26407] csv.writer.writerows masks exceptions from __iter__

2016-02-22 Thread Ilja Everilä

New submission from Ilja Everilä:

When passing a class implementing the dunder __iter__ that raises to 
csv.writer.writerows it hides the original exception and raises a TypeError 
instead.

In the raised TypeError the __context__ and __cause__ both are None.

For example:

>>> class X:
...  def __iter__(self):
...   raise RuntimeError("I'm hidden")
... 
>>> x = X()
>>> list(x)
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 3, in __iter__
RuntimeError: I'm hidden
>>> import csv
>>> csv.writer(open('foo.csv', 'w', newline='')).writerows(x)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: writerows() argument must be iterable
>>> try:
...  csv.writer(open('foo.csv', 'w', newline='')).writerows(x)
... except TypeError as e:
...  e_ = e
>>> e_.__context__ is None
True
>>> e_.__cause__ is None
True

It would seem that for reasons unknown to me either PyObject_GetIter loses the 
exception context or the call to PyErr_SetString in csv_writerows hides it.

--
messages: 260673
nosy: Ilja Everilä
priority: normal
severity: normal
status: open
title: csv.writer.writerows masks exceptions from __iter__
type: behavior

___
Python tracker 
<http://bugs.python.org/issue26407>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26407] csv.writer.writerows masks exceptions from __iter__

2016-02-23 Thread Ilja Everilä

Ilja Everilä added the comment:

After doing some reading on https://docs.python.org/dev/c-api/exceptions.html 
it seems that this is possibly "as designed" or such, since csv_writerows 
explicitly calls PyErr_SetString on receiving NULL from PyObject_GetIter.

Still, it feels like this could either let the original exception fall through 
(since it has nothing in the way of handling it) or form the chain in PY3 for 
easier debugging of the real cause.

To give this thing some context we ran in to this while passing SQLAlchemy 
Query objects to csv_writerows. The Query object is compiled during call to 
__iter__ and the current behaviour masks possible SQL errors etc.

--

___
Python tracker 
<http://bugs.python.org/issue26407>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26407] csv.writer.writerows masks exceptions from __iter__

2016-02-29 Thread Ilja Everilä

Ilja Everilä added the comment:

I have 0 beef with it being the TypeError as long as the exception chain is 
kept intact, especially since PY3 makes it possible. With current behaviour 
heisenbugs would produce some serious hair pulling, until one figures out that 
it is actually the __iter__ raising an exception.

With that in mind, take an object implementing the __iter__ dunder correctly 
999,999 times out of a million. Is it not iterable?

Unfortunately I lack the experience with CPython C API to do something about 
this. Tests on the other hand I suppose I could manage, if a consensus on the 
behaviour can be reached.

--

___
Python tracker 
<http://bugs.python.org/issue26407>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26407] csv.writer.writerows masks exceptions from __iter__

2016-02-29 Thread Ilja Everilä

Ilja Everilä added the comment:

As a side note PyObject_GetIter actually raises a TypeError already for 
non-iterables (classes without __iter__ etc.), so csv_writerows duplicates the 
effort at the moment.

--

___
Python tracker 
<http://bugs.python.org/issue26407>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue26407] csv.writer.writerows masks exceptions from __iter__

2016-02-29 Thread Ilja Everilä

Ilja Everilä added the comment:

I'm starting to think my initial example code was too simplified and misled 
from the issue at hand. It very explicitly showed what happens when some class 
with __iter__ raises and is passed to csv_writerows. Even then:

>>> from collections.abc import Iterable
>>> class X:
...  def __iter__(self):
...   raise RuntimeError
... 
>>> x = X()
>>> issubclass(X, Iterable)
True
>>> isinstance(x, Iterable)
True

The glossary entry for iterable has nothing to say about exceptions. It only 
requires that they are able to return their members "one at a time". In a 
moderately complicated class this might be true most of the time, but that's 
not interesting; that 1 time when it can't is.

Now imagine you have a class with __iter__ using 1..N foreign libraries that 
all may blow up at the wrong phase of the moon (humor me). With the current 
implementation you get "TypeError: writerows() argument must be iterable", 
which goes out of its way to actually mislead you. Just letting the original 
exception through would be the obviously helpful thing to do. Which is what 
PyObject_GetIter does, before csv_writerows overwrites it.

--

___
Python tracker 
<http://bugs.python.org/issue26407>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com