classification
Title: Exception context set to string by BufferedWriter.close()
Type: behavior Stage: resolved
Components: IO Versions: Python 3.5, Python 3.4
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: serhiy.storchaka Nosy List: benjamin.peterson, martin.panter, ned.deily, pitrou, python-dev, serhiy.storchaka, stutzbach
Priority: normal Keywords: patch

Created on 2014-06-06 06:49 by martin.panter, last changed 2014-06-11 05:32 by serhiy.storchaka. This issue is now closed.

Files
File name Uploaded Description Edit
io_nonnormalized_error_on_close.patch serhiy.storchaka, 2014-06-07 12:33 review
Messages (8)
msg219864 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2014-06-06 06:49
I made a writer class whose write() and flush() methods (unintentionally) triggered exceptions. I wrapped this in a BufferedWriter. When close() is called, the resulting exception has a string object in its __context__ attribute. Although the original error was my fault, it created a confusing chain reaction of exception reports.

>>> from io import BufferedWriter, RawIOBase
>>> import sys
>>> 
>>> class BuggyWriter(RawIOBase):
...     def writable(self): return True
...     def write(self, b): in_write  # Initial exception
...     def flush(self): raise Exception("In flush()")
... 
>>> output = BufferedWriter(BuggyWriter())
>>> output.write(b"data")
4
>>> output.close()  # Note the TypeError printed at the top
TypeError: print_exception(): Exception expected for value, str found

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in flush
Exception: In flush()
>>> 
>>> sys.last_value
Exception('In flush()',)
>>> sys.last_value.__context__  # Should be exception, not string object
"name 'in_write' is not defined"
>>> 
>>> import traceback
>>> traceback.print_exception(sys.last_type, sys.last_value, sys.last_traceback)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.4/traceback.py", line 169, in print_exception
    for line in _format_exception_iter(etype, value, tb, limit, chain):
  File "/usr/lib/python3.4/traceback.py", line 146, in _format_exception_iter
    for value, tb in values:
  File "/usr/lib/python3.4/traceback.py", line 138, in _iter_chain
    yield from it
  File "/usr/lib/python3.4/traceback.py", line 125, in _iter_chain
    context = exc.__context__
AttributeError: 'str' object has no attribute '__context__'
msg219931 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2014-06-07 12:33
Here is a patch. It fixes also the same error in TextIOWrapper.
msg220083 - (view) Author: Roundup Robot (python-dev) Date: 2014-06-09 06:34
New changeset a3b7b89da34f by Serhiy Storchaka in branch '3.4':
Issue #21677: Fixed chaining nonnormalized exceptions in io close() methods.
http://hg.python.org/cpython/rev/a3b7b89da34f

New changeset d6ac4b6020b9 by Serhiy Storchaka in branch 'default':
Issue #21677: Fixed chaining nonnormalized exceptions in io close() methods.
http://hg.python.org/cpython/rev/d6ac4b6020b9
msg220103 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2014-06-09 17:40
Thank you Martin for your report.
msg220213 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2014-06-10 23:37
This changeset crashes test_io here:

test_close_error_on_close (test.test_io.CBufferedReaderTest) ... python: Objects/abstract.c:2091: PyObject_Call: Assertion `(result != ((void *)0) && !PyErr_Occurred()) || (result == ((void *)0) && PyErr_Occurred())' failed.
Fatal Python error: Aborted

Current thread 0x00007ff1b3264740 (most recent call first):
  File "/home/antoine/cpython/default/Lib/test/test_io.py", line 793 in test_close_error_on_close
  File "/home/antoine/cpython/default/Lib/unittest/case.py", line 577 in run
  File "/home/antoine/cpython/default/Lib/unittest/case.py", line 625 in __call__
  File "/home/antoine/cpython/default/Lib/unittest/suite.py", line 125 in run
  File "/home/antoine/cpython/default/Lib/unittest/suite.py", line 87 in __call__
  File "/home/antoine/cpython/default/Lib/unittest/suite.py", line 125 in run
  File "/home/antoine/cpython/default/Lib/unittest/suite.py", line 87 in __call__
  File "/home/antoine/cpython/default/Lib/unittest/suite.py", line 125 in run
  File "/home/antoine/cpython/default/Lib/unittest/suite.py", line 87 in __call__
  File "/home/antoine/cpython/default/Lib/unittest/runner.py", line 168 in run
  File "/home/antoine/cpython/default/Lib/test/support/__init__.py", line 1724 in _run_suite
  File "/home/antoine/cpython/default/Lib/test/support/__init__.py", line 1758 in run_unittest
  File "/home/antoine/cpython/default/Lib/test/regrtest.py", line 1277 in <lambda>
  File "/home/antoine/cpython/default/Lib/test/regrtest.py", line 1278 in runtest_inner
  File "/home/antoine/cpython/default/Lib/test/regrtest.py", line 978 in runtest
  File "/home/antoine/cpython/default/Lib/test/regrtest.py", line 763 in main
  File "/home/antoine/cpython/default/Lib/test/regrtest.py", line 1562 in main_in_temp_cwd
  File "/home/antoine/cpython/default/Lib/test/__main__.py", line 3 in <module>
  File "/home/antoine/cpython/default/Lib/runpy.py", line 85 in _run_code
  File "/home/antoine/cpython/default/Lib/runpy.py", line 170 in _run_module_as_main
Abandon
msg220216 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2014-06-10 23:52
gdb backtrace:

#0  0x00007ffff711ff79 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007ffff7123388 in __GI_abort () at abort.c:89
#2  0x00007ffff7118e36 in __assert_fail_base (fmt=0x7ffff726a718 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", 
    assertion=assertion@entry=0x670d48 "(result != ((void *)0) && !PyErr_Occurred()) || (result == ((void *)0) && PyErr_Occurred())", file=file@entry=0x670332 "Objects/abstract.c", line=line@entry=2077, 
    function=function@entry=0x670ff6 <__PRETTY_FUNCTION__.10598> "PyObject_Call") at assert.c:92
#3  0x00007ffff7118ee2 in __GI___assert_fail (
    assertion=0x670d48 "(result != ((void *)0) && !PyErr_Occurred()) || (result == ((void *)0) && PyErr_Occurred())", 
    file=0x670332 "Objects/abstract.c", line=2077, function=0x670ff6 <__PRETTY_FUNCTION__.10598> "PyObject_Call") at assert.c:101
#4  0x0000000000461e89 in PyObject_Call (func=0x7ffff27013d8, arg=0x7ffff6638ef8, kw=0x0) at Objects/abstract.c:2076
#5  0x0000000000462f62 in PyObject_CallFunctionObjArgs 
(callable=0x7ffff27013d8) at Objects/abstract.c:2362
#6  0x0000000000463c46 in PyObject_IsSubclass (derived=0x911140 <_PyExc_OSError>, cls=0x911140 <_PyExc_OSError>)
    at Objects/abstract.c:2617
#7  0x00000000005cc591 in PyErr_NormalizeException (exc=0x7ffffffdc578, val=0x7ffffffdc580, tb=0x7ffffffdc588)
    at Python/errors.c:254
#8  0x0000000000639bc6 in buffered_close (self=0x7ffff7e6ad78, args=0x0) at ./Modules/_io/bufferedio.c:552


It seems PyErr_NormalizeException doesn't like being called with an exception set.
msg220232 - (view) Author: Roundup Robot (python-dev) Date: 2014-06-11 04:20
New changeset a98fd4eeed40 by Serhiy Storchaka in branch '3.4':
PyErr_NormalizeException doesn't like being called with an exception set
http://hg.python.org/cpython/rev/a98fd4eeed40

New changeset 55c50c570098 by Serhiy Storchaka in branch 'default':
PyErr_NormalizeException doesn't like being called with an exception set
http://hg.python.org/cpython/rev/55c50c570098
msg220234 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2014-06-11 05:32
Thank you Antoine. Perhaps this non-trivial code for chaining exceptions (repeated at least three times) should be extracted to separate function.
History
Date User Action Args
2014-06-11 05:32:09serhiy.storchakasetstatus: open -> closed

messages: + msg220234
2014-06-11 04:20:05python-devsetmessages: + msg220232
2014-06-10 23:52:08pitrousetmessages: + msg220216
2014-06-10 23:37:51pitrousetstatus: closed -> open
nosy: + ned.deily
messages: + msg220213

2014-06-09 17:40:37serhiy.storchakasetstatus: open -> closed
versions: - Python 2.7
messages: + msg220103

resolution: fixed
stage: patch review -> resolved
2014-06-09 06:34:18python-devsetnosy: + python-dev
messages: + msg220083
2014-06-07 12:33:20serhiy.storchakasetfiles: + io_nonnormalized_error_on_close.patch
versions: + Python 2.7, Python 3.5
messages: + msg219931

assignee: serhiy.storchaka
keywords: + patch
stage: patch review
2014-06-06 17:43:26serhiy.storchakasetnosy: + pitrou, benjamin.peterson, stutzbach, serhiy.storchaka
2014-06-06 06:49:21martin.pantercreate