Opened 11 months ago

Closed 9 months ago

#9175 defect closed fixed (fixed)

inlineCallback missing one stack level on py3 when using trial

Reported by: Pierre Tardy Owned by: Craig Rodrigues <rodrigc@…>
Priority: normal Milestone: Python-3.x
Component: core Keywords:
Cc: Branch:
Author:

Description

Run this testcase on py2 and py3:

from twisted.internet import defer
from twisted.trial.unittest import SynchronousTestCase


@defer.inlineCallbacks
def test_gene():
    raise Exception('boo')
    yield


class Test(SynchronousTestCase):

    @defer.inlineCallbacks
    def test_foo(self):
        yield test_gene()

on py2, trial correctly shows where the error is raised:

0 % trial  test_traceback
test_traceback
  Test
    test_foo ...                                                        [ERROR]

===============================================================================
[ERROR]
Traceback (most recent call last):
  File "[..]twisted/twisted/internet/defer.py", line 1128, in _inlineCallbacks
    result = g.send(result)
  File "[..]twisted/test_traceback.py", line 7, in test_gene
    raise Exception('boo')
exceptions.Exception: boo

test_traceback.Test.test_foo
-------------------------------------------------------------------------------
Ran 1 tests in 0.034s

on py3 only show the traceback from the first generator:

 trial  test_traceback
test_traceback
  Test
    test_foo ...                                                        [ERROR]

===============================================================================
[ERROR]
Traceback (most recent call last):
  File "[..]twisted/twisted/internet/defer.py", line 1126, in _inlineCallbacks
    result = result.throwExceptionIntoGenerator(g)
  File "[..]twisted/twisted/python/failure.py", line 389, in throwExceptionIntoGenerator
    return g.throw(self.type, self.value, self.tb)
  File "[..]twisted/test_traceback.py", line 15, in test_foo
    yield test_gene()
builtins.Exception: boo

test_traceback.Test.test_foo
-------------------------------------------------------------------------------
Ran 1 tests in 0.065s

This problem makes it very annoying to debug buildbot py3 issues.

e.g: https://nine.buildbot.net/#/builders/51/builds/212

Change History (5)

comment:1 Changed 11 months ago by Pierre Tardy

After more investigation, it looks like throwExceptionIntoGenerator do not preserve traceback information as expected on py3

    def throwExceptionIntoGenerator(self, g):
        """
        Throw the original exception into the given generator,
        preserving traceback information if available.

        @return: The next value yielded from the generator.
        @raise StopIteration: If there are no more values in the generator.
        @raise anything else: Anything that the generator raises.
        """
        return g.throw(self.type, self.value, self.tb)

self.tb is always None, whatever the python version. This is because it is cleaned up by self.cleanFailure() in _runCallbacks()

The result is a new failure is generated by: https://github.com/twisted/twisted/blob/trunk/src/twisted/internet/defer.py#L1432

but in py2 case the next call to Failure get the right traceback in sys.exc_info() while in py3 the call to sys.exc_info() return the stack of the caller. (the parent inline callback)

comment:2 Changed 9 months ago by Craig Rodrigues

Keywords: py3 removed
Milestone: Python-3.x

comment:3 Changed 9 months ago by Craig Rodrigues

Keywords: review added

comment:5 Changed 9 months ago by Craig Rodrigues <rodrigc@…>

Owner: set to Craig Rodrigues <rodrigc@…>
Resolution: fixed
Status: newclosed

In 7ae6fa69:

Merge pull request #813 from tardyp/9175-py3tracebacks

Author: tardyp, jafd
Reviewer: rodrigc
Fixes: ticket:9175

Fix traceback forwarding with inlineCallbacks on python 3

Note: See TracTickets for help on using tickets.