New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test hangs forever with a specific exception chain #3804

Closed
jcugat opened this Issue Aug 11, 2018 · 3 comments

Comments

Projects
None yet
2 participants
@jcugat

jcugat commented Aug 11, 2018

When running a test that raises an Exception with a loop in the __causes__ variable (by using raise A from B), pytest hangs forever but a normal execution succeeds.

This is a minimal example I have created to reproduce this issue:

class SomethingWentWrong(Exception):
    pass


def run_safely(callable):
    """
    Runs the callable and returns it,
    or raises SomethingWentWrong if there is any exception
    """
    try:
        return callable()
    except Exception as e:
        raise SomethingWentWrong() from e


def do_error():
    return 0 / 0


def do_something():
    try:
        return run_safely(lambda: do_error())
    except SomethingWentWrong as exc:
        raise exc.__cause__


if __name__ == "__main__":
    do_something()


def test_bug():
    do_something()

Note inside the except clause in do_something() it is reraising the original clause of the exception, and my guess is that implicitly it is creating a loop there.

A normal execution runs fine and shows the chained exception:

$ python test_bug.py
Traceback (most recent call last):
  File "test_bug.py", line 22, in do_something
    return run_safely(lambda: do_error())
  File "test_bug.py", line 13, in run_safely
    raise SomethingWentWrong() from e
__main__.SomethingWentWrong

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "test_bug.py", line 30, in <module>
    do_something()
  File "test_bug.py", line 26, in do_something
    raise exc.__cause__
  File "test_bug.py", line 11, in run_safely
    return callable()
  File "test_bug.py", line 22, in <lambda>
    return run_safely(lambda: do_error())
  File "test_bug.py", line 17, in do_error
    return 0 / 0
ZeroDivisionError: division by zero

But when running with pytest it just hangs forever:

$ pytest test_bug.py
=============================================================================== test session starts ===============================================================================
platform darwin -- Python 3.6.6, pytest-3.7.1, py-1.5.4, pluggy-0.7.1
rootdir: /Users/nova/workspace/sherlock, inifile:
collected 1 item

test_bug.py

Version information:

$ python -V
Python 3.6.6
$ pip list
Package        Version
-------------- -------
atomicwrites   1.1.5
attrs          18.1.0
more-itertools 4.3.0
pip            18.0
pluggy         0.7.1
py             1.5.4
pytest         3.7.1
setuptools     40.0.0
six            1.11.0
$ uname -a
Darwin 10.0.0.10 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT 2018; root:xnu-4570.71.2~1/RELEASE_X86_64 x86_64
@asottile

This comment has been minimized.

Show comment
Hide comment
@asottile

asottile Aug 11, 2018

Member

confirmed, goes away with --tb=native

Here's an interrupted run with --fulltrace:

$ pytest t.py --tb=short --fulltrace
============================= test session starts ==============================
platform linux -- Python 3.6.5, pytest-3.7.1, py-1.5.4, pluggy-0.7.1
rootdir: /tmp/t, inifile:
collected 1 item                                                               

t.py ^C

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

config = <_pytest.config.Config object at 0x7f3f977266a0>
doit = <function _main at 0x7f3f97bb5400>

    def wrap_session(config, doit):
        """Skeleton command line program"""
        session = Session(config)
        session.exitstatus = EXIT_OK
        initstate = 0
        try:
            try:
                config._do_configure()
                initstate = 1
                config.hook.pytest_sessionstart(session=session)
                initstate = 2
>               session.exitstatus = doit(config, session) or 0

venv/lib/python3.6/site-packages/_pytest/main.py:178: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

config = <_pytest.config.Config object at 0x7f3f977266a0>
session = <Session 't'>

    def _main(config, session):
        """ default command line protocol for initialization, session,
        running tests and reporting. """
        config.hook.pytest_collection(session=session)
>       config.hook.pytest_runtestloop(session=session)

venv/lib/python3.6/site-packages/_pytest/main.py:215: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_HookCaller 'pytest_runtestloop'>, args = ()
kwargs = {'session': <Session 't'>}, notincall = set()

    def __call__(self, *args, **kwargs):
        if args:
            raise TypeError("hook calling supports only keyword arguments")
        assert not self.is_historic()
        if self.argnames:
            notincall = set(self.argnames) - set(['__multicall__']) - set(
                kwargs.keys())
            if notincall:
                warnings.warn(
                    "Argument(s) {} which are declared in the hookspec "
                    "can not be found in this hook call"
                    .format(tuple(notincall)),
                    stacklevel=2,
                )
>       return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)

venv/lib/python3.6/site-packages/pluggy/hooks.py:258: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_pytest.config.PytestPluginManager object at 0x7f3f9b53f358>
hook = <_HookCaller 'pytest_runtestloop'>
methods = [<HookImpl plugin_name='main', plugin=<module '_pytest.main' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/main.py'>>, <HookImpl plugin_name='logging-plugin', plugin=<_pytest.logging.LoggingPlugin object at 0x7f3f97163f60>>]
kwargs = {'session': <Session 't'>}

    def _hookexec(self, hook, methods, kwargs):
        # called from all hookcaller instances.
        # enable_tracing will set its own wrapping function at self._inner_hookexec
>       return self._inner_hookexec(hook, methods, kwargs)

venv/lib/python3.6/site-packages/pluggy/manager.py:67: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

hook = <_HookCaller 'pytest_runtestloop'>
methods = [<HookImpl plugin_name='main', plugin=<module '_pytest.main' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/main.py'>>, <HookImpl plugin_name='logging-plugin', plugin=<_pytest.logging.LoggingPlugin object at 0x7f3f97163f60>>]
kwargs = {'session': <Session 't'>}

    self._inner_hookexec = lambda hook, methods, kwargs: \
        hook.multicall(
            methods, kwargs,
>           firstresult=hook.spec_opts.get('firstresult'),
        )

venv/lib/python3.6/site-packages/pluggy/manager.py:61: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

session = <Session 't'>

    def pytest_runtestloop(session):
        if session.testsfailed and not session.config.option.continue_on_collection_errors:
            raise session.Interrupted("%d errors during collection" % session.testsfailed)
    
        if session.config.option.collectonly:
            return True
    
        for i, item in enumerate(session.items):
            nextitem = session.items[i + 1] if i + 1 < len(session.items) else None
>           item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)

venv/lib/python3.6/site-packages/_pytest/main.py:236: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_HookCaller 'pytest_runtest_protocol'>, args = ()
kwargs = {'item': <Function 'test_bug'>, 'nextitem': None}, notincall = set()

    def __call__(self, *args, **kwargs):
        if args:
            raise TypeError("hook calling supports only keyword arguments")
        assert not self.is_historic()
        if self.argnames:
            notincall = set(self.argnames) - set(['__multicall__']) - set(
                kwargs.keys())
            if notincall:
                warnings.warn(
                    "Argument(s) {} which are declared in the hookspec "
                    "can not be found in this hook call"
                    .format(tuple(notincall)),
                    stacklevel=2,
                )
>       return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)

venv/lib/python3.6/site-packages/pluggy/hooks.py:258: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_pytest.config.PytestPluginManager object at 0x7f3f9b53f358>
hook = <_HookCaller 'pytest_runtest_protocol'>
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest...ame='warnings', plugin=<module '_pytest.warnings' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/warnings.py'>>]
kwargs = {'item': <Function 'test_bug'>, 'nextitem': None}

    def _hookexec(self, hook, methods, kwargs):
        # called from all hookcaller instances.
        # enable_tracing will set its own wrapping function at self._inner_hookexec
>       return self._inner_hookexec(hook, methods, kwargs)

venv/lib/python3.6/site-packages/pluggy/manager.py:67: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

hook = <_HookCaller 'pytest_runtest_protocol'>
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest...ame='warnings', plugin=<module '_pytest.warnings' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/warnings.py'>>]
kwargs = {'item': <Function 'test_bug'>, 'nextitem': None}

    self._inner_hookexec = lambda hook, methods, kwargs: \
        hook.multicall(
            methods, kwargs,
>           firstresult=hook.spec_opts.get('firstresult'),
        )

venv/lib/python3.6/site-packages/pluggy/manager.py:61: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

item = <Function 'test_bug'>, nextitem = None

    def pytest_runtest_protocol(item, nextitem):
        item.ihook.pytest_runtest_logstart(nodeid=item.nodeid, location=item.location)
>       runtestprotocol(item, nextitem=nextitem)

venv/lib/python3.6/site-packages/_pytest/runner.py:66: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

item = <Function 'test_bug'>, log = True, nextitem = None

    def runtestprotocol(item, log=True, nextitem=None):
        hasrequest = hasattr(item, "_request")
        if hasrequest and not item._request:
            item._initrequest()
        rep = call_and_report(item, "setup", log)
        reports = [rep]
        if rep.passed:
            if item.config.option.setupshow:
                show_test_item(item)
            if not item.config.option.setuponly:
>               reports.append(call_and_report(item, "call", log))

venv/lib/python3.6/site-packages/_pytest/runner.py:81: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

item = <Function 'test_bug'>, when = 'call', log = True, kwds = {}
call = <CallInfo when='call' exception: division by zero>
hook = <pluggy.hooks._HookRelay object at 0x7f3f9b5363c8>

    def call_and_report(item, when, log=True, **kwds):
        call = call_runtest_hook(item, when, **kwds)
        hook = item.ihook
>       report = hook.pytest_runtest_makereport(item=item, call=call)

venv/lib/python3.6/site-packages/_pytest/runner.py:163: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_HookCaller 'pytest_runtest_makereport'>, args = ()
kwargs = {'call': <CallInfo when='call' exception: division by zero>, 'item': <Function 'test_bug'>}
notincall = set()

    def __call__(self, *args, **kwargs):
        if args:
            raise TypeError("hook calling supports only keyword arguments")
        assert not self.is_historic()
        if self.argnames:
            notincall = set(self.argnames) - set(['__multicall__']) - set(
                kwargs.keys())
            if notincall:
                warnings.warn(
                    "Argument(s) {} which are declared in the hookspec "
                    "can not be found in this hook call"
                    .format(tuple(notincall)),
                    stacklevel=2,
                )
>       return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)

venv/lib/python3.6/site-packages/pluggy/hooks.py:258: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_pytest.config.PytestPluginManager object at 0x7f3f9b53f358>
hook = <_HookCaller 'pytest_runtest_makereport'>
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest...ame='skipping', plugin=<module '_pytest.skipping' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/skipping.py'>>]
kwargs = {'call': <CallInfo when='call' exception: division by zero>, 'item': <Function 'test_bug'>}

    def _hookexec(self, hook, methods, kwargs):
        # called from all hookcaller instances.
        # enable_tracing will set its own wrapping function at self._inner_hookexec
>       return self._inner_hookexec(hook, methods, kwargs)

venv/lib/python3.6/site-packages/pluggy/manager.py:67: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

hook = <_HookCaller 'pytest_runtest_makereport'>
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest...ame='skipping', plugin=<module '_pytest.skipping' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/skipping.py'>>]
kwargs = {'call': <CallInfo when='call' exception: division by zero>, 'item': <Function 'test_bug'>}

    self._inner_hookexec = lambda hook, methods, kwargs: \
        hook.multicall(
            methods, kwargs,
>           firstresult=hook.spec_opts.get('firstresult'),
        )

venv/lib/python3.6/site-packages/pluggy/manager.py:61: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

item = <Function 'test_bug'>
call = <CallInfo when='call' exception: division by zero>

    @hookimpl(hookwrapper=True)
    def pytest_runtest_makereport(item, call):
        outcome = yield
>       rep = outcome.get_result()

venv/lib/python3.6/site-packages/_pytest/skipping.py:123: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

item = <Function 'test_bug'>
call = <CallInfo when='call' exception: division by zero>

    def pytest_runtest_makereport(item, call):
        when = call.when
        duration = call.stop - call.start
        keywords = {x: 1 for x in item.keywords}
        excinfo = call.excinfo
        sections = []
        if not call.excinfo:
            outcome = "passed"
            longrepr = None
        else:
            if not isinstance(excinfo, ExceptionInfo):
                outcome = "failed"
                longrepr = excinfo
            elif excinfo.errisinstance(skip.Exception):
                outcome = "skipped"
                r = excinfo._getreprcrash()
                longrepr = (str(r.path), r.lineno, r.message)
            else:
                outcome = "failed"
                if call.when == "call":
>                   longrepr = item.repr_failure(excinfo)

venv/lib/python3.6/site-packages/_pytest/runner.py:240: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Function 'test_bug'>
excinfo = <ExceptionInfo ZeroDivisionError tblen=22>, outerr = None

    def repr_failure(self, excinfo, outerr=None):
        assert outerr is None, "XXX outerr usage is deprecated"
        style = self.config.option.tbstyle
        if style == "auto":
            style = "long"
>       return self._repr_failure_py(excinfo, style=style)

venv/lib/python3.6/site-packages/_pytest/python.py:754: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Function 'test_bug'>
excinfo = <ExceptionInfo ZeroDivisionError tblen=22>, style = 'short'

    def _repr_failure_py(self, excinfo, style="long"):
        if excinfo.errisinstance(fail.Exception):
            if not excinfo.value.pytrace:
                return py._builtin._totext(excinfo.value)
>       return super(FunctionMixin, self)._repr_failure_py(excinfo, style=style)

venv/lib/python3.6/site-packages/_pytest/python.py:747: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Function 'test_bug'>
excinfo = <ExceptionInfo ZeroDivisionError tblen=22>, style = 'long'

    def _repr_failure_py(self, excinfo, style=None):
        fm = self.session._fixturemanager
        if excinfo.errisinstance(fm.FixtureLookupError):
            return excinfo.value.formatrepr()
        tbfilter = True
        if self.config.option.fulltrace:
            style = "long"
        else:
            tb = _pytest._code.Traceback([excinfo.traceback[-1]])
            self._prunetraceback(excinfo)
            if len(excinfo.traceback) == 0:
                excinfo.traceback = tb
            tbfilter = False  # prunetraceback already does it
            if style == "auto":
                style = "long"
        # XXX should excinfo.getrepr record all data and toterminal() process it?
        if style is None:
            if self.config.option.tbstyle == "short":
                style = "short"
            else:
                style = "long"
    
        if self.config.option.verbose > 1:
            truncate_locals = False
        else:
            truncate_locals = True
    
        try:
            os.getcwd()
            abspath = False
        except OSError:
            abspath = True
    
        return excinfo.getrepr(
            funcargs=True,
            abspath=abspath,
            showlocals=self.config.option.showlocals,
            style=style,
            tbfilter=tbfilter,
>           truncate_locals=truncate_locals,
        )

venv/lib/python3.6/site-packages/_pytest/nodes.py:307: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ExceptionInfo ZeroDivisionError tblen=22>, showlocals = False
style = 'long', abspath = False, tbfilter = True, funcargs = True
truncate_locals = True

    def getrepr(
        self,
        showlocals=False,
        style="long",
        abspath=False,
        tbfilter=True,
        funcargs=False,
        truncate_locals=True,
    ):
        """ return str()able representation of this exception info.
                showlocals: show locals per traceback entry
                style: long|short|no|native traceback style
                tbfilter: hide entries (where __tracebackhide__ is true)
    
                in case of style==native, tbfilter and showlocals is ignored.
            """
        if style == "native":
            return ReprExceptionInfo(
                ReprTracebackNative(
                    traceback.format_exception(
                        self.type, self.value, self.traceback[0]._rawentry
                    )
                ),
                self._getreprcrash(),
            )
    
        fmt = FormattedExcinfo(
            showlocals=showlocals,
            style=style,
            abspath=abspath,
            tbfilter=tbfilter,
            funcargs=funcargs,
            truncate_locals=truncate_locals,
        )
>       return fmt.repr_excinfo(self)

venv/lib/python3.6/site-packages/_pytest/_code/code.py:479: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = FormattedExcinfo(showlocals=False, style='long', abspath=False, tbfilter=True, funcargs=True, truncate_locals=True)
excinfo = <ExceptionInfo ZeroDivisionError tblen=22>

    def repr_excinfo(self, excinfo):
        if _PY2:
            reprtraceback = self.repr_traceback(excinfo)
            reprcrash = excinfo._getreprcrash()
    
            return ReprExceptionInfo(reprtraceback, reprcrash)
        else:
            repr_chain = []
            e = excinfo.value
            descr = None
            while e is not None:
                if excinfo:
>                   reprtraceback = self.repr_traceback(excinfo)

venv/lib/python3.6/site-packages/_pytest/_code/code.py:724: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = FormattedExcinfo(showlocals=False, style='long', abspath=False, tbfilter=True, funcargs=True, truncate_locals=True)
excinfo = <ExceptionInfo ZeroDivisionError tblen=22>

    def repr_traceback(self, excinfo):
        traceback = excinfo.traceback
        if self.tbfilter:
            traceback = traceback.filter()
    
        if is_recursion_error(excinfo):
            traceback, extraline = self._truncate_recursive_traceback(traceback)
        else:
            extraline = None
    
        last = traceback[-1]
        entries = []
        for index, entry in enumerate(traceback):
            einfo = (last == entry) and excinfo or None
>           reprentry = self.repr_traceback_entry(entry, einfo)

venv/lib/python3.6/site-packages/_pytest/_code/code.py:671: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = FormattedExcinfo(showlocals=False, style='long', abspath=False, tbfilter=True, funcargs=True, truncate_locals=True)
entry = <TracebackEntry /tmp/t/venv/lib/python3.6/site-packages/_pytest/python.py:196>
excinfo = None

    def repr_traceback_entry(self, entry, excinfo=None):
        import _pytest._code
    
>       source = self._getentrysource(entry)

venv/lib/python3.6/site-packages/_pytest/_code/code.py:616: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = FormattedExcinfo(showlocals=False, style='long', abspath=False, tbfilter=True, funcargs=True, truncate_locals=True)
entry = <TracebackEntry /tmp/t/venv/lib/python3.6/site-packages/_pytest/python.py:196>

    def _getentrysource(self, entry):
>       source = entry.getsource(self.astcache)

venv/lib/python3.6/site-packages/_pytest/_code/code.py:536: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <TracebackEntry /tmp/t/venv/lib/python3.6/site-packages/_pytest/python.py:196>
astcache = {local('/tmp/t/t.py'): <_ast.Module object at 0x7f3f96e08908>, local('/tmp/t/venv/lib/python3.6/site-packages/_pytest/...f0df28>, local('/tmp/t/venv/lib/python3.6/site-packages/pluggy/hooks.py'): <_ast.Module object at 0x7f3f96e77ba8>, ...}

    def getsource(self, astcache=None):
        """ return failing source code. """
        # we use the passed in astcache to not reparse asttrees
        # within exception info printing
        from _pytest._code.source import getstatementrange_ast
    
        source = self.frame.code.fullsource
        if source is None:
            return None
        key = astnode = None
        if astcache is not None:
            key = self.frame.code.path
            if key is not None:
                astnode = astcache.get(key, None)
        start = self.getfirstlinesource()
        try:
            astnode, _, end = getstatementrange_ast(
>               self.lineno, source, astnode=astnode
            )

venv/lib/python3.6/site-packages/_pytest/_code/code.py:221: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

lineno = 195, source = <_pytest._code.source.Source object at 0x7f3f96d5ada0>
assertion = False, astnode = <_ast.Module object at 0x7f3f96e08c18>

    def getstatementrange_ast(lineno, source, assertion=False, astnode=None):
        if astnode is None:
            content = str(source)
            astnode = compile(content, "source", "exec", 1024)  # 1024 for AST
    
>       start, end = get_statement_startend2(lineno, astnode)

venv/lib/python3.6/site-packages/_pytest/_code/source.py:343: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

lineno = 195, node = <_ast.Module object at 0x7f3f96e08c18>

    def get_statement_startend2(lineno, node):
        import ast
    
        # flatten all statements and except handlers into one lineno-list
        # AST's line numbers start indexing at 1
        values = []
        for x in ast.walk(node):
>           if isinstance(x, (ast.stmt, ast.ExceptHandler)):
E           KeyboardInterrupt

venv/lib/python3.6/site-packages/_pytest/_code/source.py:321: KeyboardInterrupt
========================= no tests ran in 1.56 seconds =========================
Member

asottile commented Aug 11, 2018

confirmed, goes away with --tb=native

Here's an interrupted run with --fulltrace:

$ pytest t.py --tb=short --fulltrace
============================= test session starts ==============================
platform linux -- Python 3.6.5, pytest-3.7.1, py-1.5.4, pluggy-0.7.1
rootdir: /tmp/t, inifile:
collected 1 item                                                               

t.py ^C

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

config = <_pytest.config.Config object at 0x7f3f977266a0>
doit = <function _main at 0x7f3f97bb5400>

    def wrap_session(config, doit):
        """Skeleton command line program"""
        session = Session(config)
        session.exitstatus = EXIT_OK
        initstate = 0
        try:
            try:
                config._do_configure()
                initstate = 1
                config.hook.pytest_sessionstart(session=session)
                initstate = 2
>               session.exitstatus = doit(config, session) or 0

venv/lib/python3.6/site-packages/_pytest/main.py:178: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

config = <_pytest.config.Config object at 0x7f3f977266a0>
session = <Session 't'>

    def _main(config, session):
        """ default command line protocol for initialization, session,
        running tests and reporting. """
        config.hook.pytest_collection(session=session)
>       config.hook.pytest_runtestloop(session=session)

venv/lib/python3.6/site-packages/_pytest/main.py:215: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_HookCaller 'pytest_runtestloop'>, args = ()
kwargs = {'session': <Session 't'>}, notincall = set()

    def __call__(self, *args, **kwargs):
        if args:
            raise TypeError("hook calling supports only keyword arguments")
        assert not self.is_historic()
        if self.argnames:
            notincall = set(self.argnames) - set(['__multicall__']) - set(
                kwargs.keys())
            if notincall:
                warnings.warn(
                    "Argument(s) {} which are declared in the hookspec "
                    "can not be found in this hook call"
                    .format(tuple(notincall)),
                    stacklevel=2,
                )
>       return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)

venv/lib/python3.6/site-packages/pluggy/hooks.py:258: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_pytest.config.PytestPluginManager object at 0x7f3f9b53f358>
hook = <_HookCaller 'pytest_runtestloop'>
methods = [<HookImpl plugin_name='main', plugin=<module '_pytest.main' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/main.py'>>, <HookImpl plugin_name='logging-plugin', plugin=<_pytest.logging.LoggingPlugin object at 0x7f3f97163f60>>]
kwargs = {'session': <Session 't'>}

    def _hookexec(self, hook, methods, kwargs):
        # called from all hookcaller instances.
        # enable_tracing will set its own wrapping function at self._inner_hookexec
>       return self._inner_hookexec(hook, methods, kwargs)

venv/lib/python3.6/site-packages/pluggy/manager.py:67: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

hook = <_HookCaller 'pytest_runtestloop'>
methods = [<HookImpl plugin_name='main', plugin=<module '_pytest.main' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/main.py'>>, <HookImpl plugin_name='logging-plugin', plugin=<_pytest.logging.LoggingPlugin object at 0x7f3f97163f60>>]
kwargs = {'session': <Session 't'>}

    self._inner_hookexec = lambda hook, methods, kwargs: \
        hook.multicall(
            methods, kwargs,
>           firstresult=hook.spec_opts.get('firstresult'),
        )

venv/lib/python3.6/site-packages/pluggy/manager.py:61: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

session = <Session 't'>

    def pytest_runtestloop(session):
        if session.testsfailed and not session.config.option.continue_on_collection_errors:
            raise session.Interrupted("%d errors during collection" % session.testsfailed)
    
        if session.config.option.collectonly:
            return True
    
        for i, item in enumerate(session.items):
            nextitem = session.items[i + 1] if i + 1 < len(session.items) else None
>           item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)

venv/lib/python3.6/site-packages/_pytest/main.py:236: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_HookCaller 'pytest_runtest_protocol'>, args = ()
kwargs = {'item': <Function 'test_bug'>, 'nextitem': None}, notincall = set()

    def __call__(self, *args, **kwargs):
        if args:
            raise TypeError("hook calling supports only keyword arguments")
        assert not self.is_historic()
        if self.argnames:
            notincall = set(self.argnames) - set(['__multicall__']) - set(
                kwargs.keys())
            if notincall:
                warnings.warn(
                    "Argument(s) {} which are declared in the hookspec "
                    "can not be found in this hook call"
                    .format(tuple(notincall)),
                    stacklevel=2,
                )
>       return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)

venv/lib/python3.6/site-packages/pluggy/hooks.py:258: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_pytest.config.PytestPluginManager object at 0x7f3f9b53f358>
hook = <_HookCaller 'pytest_runtest_protocol'>
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest...ame='warnings', plugin=<module '_pytest.warnings' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/warnings.py'>>]
kwargs = {'item': <Function 'test_bug'>, 'nextitem': None}

    def _hookexec(self, hook, methods, kwargs):
        # called from all hookcaller instances.
        # enable_tracing will set its own wrapping function at self._inner_hookexec
>       return self._inner_hookexec(hook, methods, kwargs)

venv/lib/python3.6/site-packages/pluggy/manager.py:67: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

hook = <_HookCaller 'pytest_runtest_protocol'>
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest...ame='warnings', plugin=<module '_pytest.warnings' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/warnings.py'>>]
kwargs = {'item': <Function 'test_bug'>, 'nextitem': None}

    self._inner_hookexec = lambda hook, methods, kwargs: \
        hook.multicall(
            methods, kwargs,
>           firstresult=hook.spec_opts.get('firstresult'),
        )

venv/lib/python3.6/site-packages/pluggy/manager.py:61: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

item = <Function 'test_bug'>, nextitem = None

    def pytest_runtest_protocol(item, nextitem):
        item.ihook.pytest_runtest_logstart(nodeid=item.nodeid, location=item.location)
>       runtestprotocol(item, nextitem=nextitem)

venv/lib/python3.6/site-packages/_pytest/runner.py:66: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

item = <Function 'test_bug'>, log = True, nextitem = None

    def runtestprotocol(item, log=True, nextitem=None):
        hasrequest = hasattr(item, "_request")
        if hasrequest and not item._request:
            item._initrequest()
        rep = call_and_report(item, "setup", log)
        reports = [rep]
        if rep.passed:
            if item.config.option.setupshow:
                show_test_item(item)
            if not item.config.option.setuponly:
>               reports.append(call_and_report(item, "call", log))

venv/lib/python3.6/site-packages/_pytest/runner.py:81: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

item = <Function 'test_bug'>, when = 'call', log = True, kwds = {}
call = <CallInfo when='call' exception: division by zero>
hook = <pluggy.hooks._HookRelay object at 0x7f3f9b5363c8>

    def call_and_report(item, when, log=True, **kwds):
        call = call_runtest_hook(item, when, **kwds)
        hook = item.ihook
>       report = hook.pytest_runtest_makereport(item=item, call=call)

venv/lib/python3.6/site-packages/_pytest/runner.py:163: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_HookCaller 'pytest_runtest_makereport'>, args = ()
kwargs = {'call': <CallInfo when='call' exception: division by zero>, 'item': <Function 'test_bug'>}
notincall = set()

    def __call__(self, *args, **kwargs):
        if args:
            raise TypeError("hook calling supports only keyword arguments")
        assert not self.is_historic()
        if self.argnames:
            notincall = set(self.argnames) - set(['__multicall__']) - set(
                kwargs.keys())
            if notincall:
                warnings.warn(
                    "Argument(s) {} which are declared in the hookspec "
                    "can not be found in this hook call"
                    .format(tuple(notincall)),
                    stacklevel=2,
                )
>       return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)

venv/lib/python3.6/site-packages/pluggy/hooks.py:258: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <_pytest.config.PytestPluginManager object at 0x7f3f9b53f358>
hook = <_HookCaller 'pytest_runtest_makereport'>
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest...ame='skipping', plugin=<module '_pytest.skipping' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/skipping.py'>>]
kwargs = {'call': <CallInfo when='call' exception: division by zero>, 'item': <Function 'test_bug'>}

    def _hookexec(self, hook, methods, kwargs):
        # called from all hookcaller instances.
        # enable_tracing will set its own wrapping function at self._inner_hookexec
>       return self._inner_hookexec(hook, methods, kwargs)

venv/lib/python3.6/site-packages/pluggy/manager.py:67: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

hook = <_HookCaller 'pytest_runtest_makereport'>
methods = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest...ame='skipping', plugin=<module '_pytest.skipping' from '/tmp/t/venv/lib/python3.6/site-packages/_pytest/skipping.py'>>]
kwargs = {'call': <CallInfo when='call' exception: division by zero>, 'item': <Function 'test_bug'>}

    self._inner_hookexec = lambda hook, methods, kwargs: \
        hook.multicall(
            methods, kwargs,
>           firstresult=hook.spec_opts.get('firstresult'),
        )

venv/lib/python3.6/site-packages/pluggy/manager.py:61: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

item = <Function 'test_bug'>
call = <CallInfo when='call' exception: division by zero>

    @hookimpl(hookwrapper=True)
    def pytest_runtest_makereport(item, call):
        outcome = yield
>       rep = outcome.get_result()

venv/lib/python3.6/site-packages/_pytest/skipping.py:123: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

item = <Function 'test_bug'>
call = <CallInfo when='call' exception: division by zero>

    def pytest_runtest_makereport(item, call):
        when = call.when
        duration = call.stop - call.start
        keywords = {x: 1 for x in item.keywords}
        excinfo = call.excinfo
        sections = []
        if not call.excinfo:
            outcome = "passed"
            longrepr = None
        else:
            if not isinstance(excinfo, ExceptionInfo):
                outcome = "failed"
                longrepr = excinfo
            elif excinfo.errisinstance(skip.Exception):
                outcome = "skipped"
                r = excinfo._getreprcrash()
                longrepr = (str(r.path), r.lineno, r.message)
            else:
                outcome = "failed"
                if call.when == "call":
>                   longrepr = item.repr_failure(excinfo)

venv/lib/python3.6/site-packages/_pytest/runner.py:240: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Function 'test_bug'>
excinfo = <ExceptionInfo ZeroDivisionError tblen=22>, outerr = None

    def repr_failure(self, excinfo, outerr=None):
        assert outerr is None, "XXX outerr usage is deprecated"
        style = self.config.option.tbstyle
        if style == "auto":
            style = "long"
>       return self._repr_failure_py(excinfo, style=style)

venv/lib/python3.6/site-packages/_pytest/python.py:754: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Function 'test_bug'>
excinfo = <ExceptionInfo ZeroDivisionError tblen=22>, style = 'short'

    def _repr_failure_py(self, excinfo, style="long"):
        if excinfo.errisinstance(fail.Exception):
            if not excinfo.value.pytrace:
                return py._builtin._totext(excinfo.value)
>       return super(FunctionMixin, self)._repr_failure_py(excinfo, style=style)

venv/lib/python3.6/site-packages/_pytest/python.py:747: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Function 'test_bug'>
excinfo = <ExceptionInfo ZeroDivisionError tblen=22>, style = 'long'

    def _repr_failure_py(self, excinfo, style=None):
        fm = self.session._fixturemanager
        if excinfo.errisinstance(fm.FixtureLookupError):
            return excinfo.value.formatrepr()
        tbfilter = True
        if self.config.option.fulltrace:
            style = "long"
        else:
            tb = _pytest._code.Traceback([excinfo.traceback[-1]])
            self._prunetraceback(excinfo)
            if len(excinfo.traceback) == 0:
                excinfo.traceback = tb
            tbfilter = False  # prunetraceback already does it
            if style == "auto":
                style = "long"
        # XXX should excinfo.getrepr record all data and toterminal() process it?
        if style is None:
            if self.config.option.tbstyle == "short":
                style = "short"
            else:
                style = "long"
    
        if self.config.option.verbose > 1:
            truncate_locals = False
        else:
            truncate_locals = True
    
        try:
            os.getcwd()
            abspath = False
        except OSError:
            abspath = True
    
        return excinfo.getrepr(
            funcargs=True,
            abspath=abspath,
            showlocals=self.config.option.showlocals,
            style=style,
            tbfilter=tbfilter,
>           truncate_locals=truncate_locals,
        )

venv/lib/python3.6/site-packages/_pytest/nodes.py:307: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ExceptionInfo ZeroDivisionError tblen=22>, showlocals = False
style = 'long', abspath = False, tbfilter = True, funcargs = True
truncate_locals = True

    def getrepr(
        self,
        showlocals=False,
        style="long",
        abspath=False,
        tbfilter=True,
        funcargs=False,
        truncate_locals=True,
    ):
        """ return str()able representation of this exception info.
                showlocals: show locals per traceback entry
                style: long|short|no|native traceback style
                tbfilter: hide entries (where __tracebackhide__ is true)
    
                in case of style==native, tbfilter and showlocals is ignored.
            """
        if style == "native":
            return ReprExceptionInfo(
                ReprTracebackNative(
                    traceback.format_exception(
                        self.type, self.value, self.traceback[0]._rawentry
                    )
                ),
                self._getreprcrash(),
            )
    
        fmt = FormattedExcinfo(
            showlocals=showlocals,
            style=style,
            abspath=abspath,
            tbfilter=tbfilter,
            funcargs=funcargs,
            truncate_locals=truncate_locals,
        )
>       return fmt.repr_excinfo(self)

venv/lib/python3.6/site-packages/_pytest/_code/code.py:479: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = FormattedExcinfo(showlocals=False, style='long', abspath=False, tbfilter=True, funcargs=True, truncate_locals=True)
excinfo = <ExceptionInfo ZeroDivisionError tblen=22>

    def repr_excinfo(self, excinfo):
        if _PY2:
            reprtraceback = self.repr_traceback(excinfo)
            reprcrash = excinfo._getreprcrash()
    
            return ReprExceptionInfo(reprtraceback, reprcrash)
        else:
            repr_chain = []
            e = excinfo.value
            descr = None
            while e is not None:
                if excinfo:
>                   reprtraceback = self.repr_traceback(excinfo)

venv/lib/python3.6/site-packages/_pytest/_code/code.py:724: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = FormattedExcinfo(showlocals=False, style='long', abspath=False, tbfilter=True, funcargs=True, truncate_locals=True)
excinfo = <ExceptionInfo ZeroDivisionError tblen=22>

    def repr_traceback(self, excinfo):
        traceback = excinfo.traceback
        if self.tbfilter:
            traceback = traceback.filter()
    
        if is_recursion_error(excinfo):
            traceback, extraline = self._truncate_recursive_traceback(traceback)
        else:
            extraline = None
    
        last = traceback[-1]
        entries = []
        for index, entry in enumerate(traceback):
            einfo = (last == entry) and excinfo or None
>           reprentry = self.repr_traceback_entry(entry, einfo)

venv/lib/python3.6/site-packages/_pytest/_code/code.py:671: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = FormattedExcinfo(showlocals=False, style='long', abspath=False, tbfilter=True, funcargs=True, truncate_locals=True)
entry = <TracebackEntry /tmp/t/venv/lib/python3.6/site-packages/_pytest/python.py:196>
excinfo = None

    def repr_traceback_entry(self, entry, excinfo=None):
        import _pytest._code
    
>       source = self._getentrysource(entry)

venv/lib/python3.6/site-packages/_pytest/_code/code.py:616: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = FormattedExcinfo(showlocals=False, style='long', abspath=False, tbfilter=True, funcargs=True, truncate_locals=True)
entry = <TracebackEntry /tmp/t/venv/lib/python3.6/site-packages/_pytest/python.py:196>

    def _getentrysource(self, entry):
>       source = entry.getsource(self.astcache)

venv/lib/python3.6/site-packages/_pytest/_code/code.py:536: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <TracebackEntry /tmp/t/venv/lib/python3.6/site-packages/_pytest/python.py:196>
astcache = {local('/tmp/t/t.py'): <_ast.Module object at 0x7f3f96e08908>, local('/tmp/t/venv/lib/python3.6/site-packages/_pytest/...f0df28>, local('/tmp/t/venv/lib/python3.6/site-packages/pluggy/hooks.py'): <_ast.Module object at 0x7f3f96e77ba8>, ...}

    def getsource(self, astcache=None):
        """ return failing source code. """
        # we use the passed in astcache to not reparse asttrees
        # within exception info printing
        from _pytest._code.source import getstatementrange_ast
    
        source = self.frame.code.fullsource
        if source is None:
            return None
        key = astnode = None
        if astcache is not None:
            key = self.frame.code.path
            if key is not None:
                astnode = astcache.get(key, None)
        start = self.getfirstlinesource()
        try:
            astnode, _, end = getstatementrange_ast(
>               self.lineno, source, astnode=astnode
            )

venv/lib/python3.6/site-packages/_pytest/_code/code.py:221: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

lineno = 195, source = <_pytest._code.source.Source object at 0x7f3f96d5ada0>
assertion = False, astnode = <_ast.Module object at 0x7f3f96e08c18>

    def getstatementrange_ast(lineno, source, assertion=False, astnode=None):
        if astnode is None:
            content = str(source)
            astnode = compile(content, "source", "exec", 1024)  # 1024 for AST
    
>       start, end = get_statement_startend2(lineno, astnode)

venv/lib/python3.6/site-packages/_pytest/_code/source.py:343: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

lineno = 195, node = <_ast.Module object at 0x7f3f96e08c18>

    def get_statement_startend2(lineno, node):
        import ast
    
        # flatten all statements and except handlers into one lineno-list
        # AST's line numbers start indexing at 1
        values = []
        for x in ast.walk(node):
>           if isinstance(x, (ast.stmt, ast.ExceptHandler)):
E           KeyboardInterrupt

venv/lib/python3.6/site-packages/_pytest/_code/source.py:321: KeyboardInterrupt
========================= no tests ran in 1.56 seconds =========================
@asottile

This comment has been minimized.

Show comment
Hide comment
@asottile

asottile Aug 11, 2018

Member

This one seemed fun, my fix is in #3805

Member

asottile commented Aug 11, 2018

This one seemed fun, my fix is in #3805

@jcugat

This comment has been minimized.

Show comment
Hide comment
@jcugat

jcugat Aug 11, 2018

The funniest thing was creating the minimal reproducible example, since the original issue appeared at work and was spread between 3 different libraries. At the beginning I wasn't even sure it was a pytest bug.

Thanks for taking a loot at it @asottile!

jcugat commented Aug 11, 2018

The funniest thing was creating the minimal reproducible example, since the original issue appeared at work and was spread between 3 different libraries. At the beginning I wasn't even sure it was a pytest bug.

Thanks for taking a loot at it @asottile!

sfdye added a commit to pydanny/cookiecutter-django that referenced this issue Aug 19, 2018

Update pytest to 3.7.2 (#1755)
This PR updates [pytest](https://pypi.org/project/pytest) from **3.7.1** to **3.7.2**.



<details>
  <summary>Changelog</summary>
  
  
   ### 3.7.2
   ```
   =========================

Bug Fixes
---------

- `3671 &lt;https://github.com/pytest-dev/pytest/issues/3671&gt;`_: Fix ``filterwarnings`` not being registered as a builtin mark.


- `3768 &lt;https://github.com/pytest-dev/pytest/issues/3768&gt;`_, `3789 &lt;https://github.com/pytest-dev/pytest/issues/3789&gt;`_: Fix test collection from packages mixed with normal directories.


- `3771 &lt;https://github.com/pytest-dev/pytest/issues/3771&gt;`_: Fix infinite recursion during collection if a ``pytest_ignore_collect`` hook returns ``False`` instead of ``None``.


- `3774 &lt;https://github.com/pytest-dev/pytest/issues/3774&gt;`_: Fix bug where decorated fixtures would lose functionality (for example ``mock.patch``).


- `3775 &lt;https://github.com/pytest-dev/pytest/issues/3775&gt;`_: Fix bug where importing modules or other objects with prefix ``pytest_`` prefix would raise a ``PluginValidationError``.


- `3788 &lt;https://github.com/pytest-dev/pytest/issues/3788&gt;`_: Fix ``AttributeError`` during teardown of ``TestCase`` subclasses which raise an exception during ``__init__``.


- `3804 &lt;https://github.com/pytest-dev/pytest/issues/3804&gt;`_: Fix traceback reporting for exceptions with ``__cause__`` cycles.



Improved Documentation
----------------------

- `3746 &lt;https://github.com/pytest-dev/pytest/issues/3746&gt;`_: Add documentation for ``metafunc.config`` that had been mistakenly hidden.
   ```
   
  
</details>


 

<details>
  <summary>Links</summary>
  
  - PyPI: https://pypi.org/project/pytest
  - Changelog: https://pyup.io/changelogs/pytest/
  - Homepage: http://pytest.org
</details>

cmccandless added a commit to cmccandless/tools that referenced this issue Aug 20, 2018

Update pytest to 3.7.2 (#25)
This PR updates [pytest](https://pypi.org/project/pytest) from **3.7.1** to **3.7.2**.



<details>
  <summary>Changelog</summary>
  
  
   ### 3.7.2
   ```
   =========================

Bug Fixes
---------

- `3671 &lt;https://github.com/pytest-dev/pytest/issues/3671&gt;`_: Fix ``filterwarnings`` not being registered as a builtin mark.


- `3768 &lt;https://github.com/pytest-dev/pytest/issues/3768&gt;`_, `3789 &lt;https://github.com/pytest-dev/pytest/issues/3789&gt;`_: Fix test collection from packages mixed with normal directories.


- `3771 &lt;https://github.com/pytest-dev/pytest/issues/3771&gt;`_: Fix infinite recursion during collection if a ``pytest_ignore_collect`` hook returns ``False`` instead of ``None``.


- `3774 &lt;https://github.com/pytest-dev/pytest/issues/3774&gt;`_: Fix bug where decorated fixtures would lose functionality (for example ``mock.patch``).


- `3775 &lt;https://github.com/pytest-dev/pytest/issues/3775&gt;`_: Fix bug where importing modules or other objects with prefix ``pytest_`` prefix would raise a ``PluginValidationError``.


- `3788 &lt;https://github.com/pytest-dev/pytest/issues/3788&gt;`_: Fix ``AttributeError`` during teardown of ``TestCase`` subclasses which raise an exception during ``__init__``.


- `3804 &lt;https://github.com/pytest-dev/pytest/issues/3804&gt;`_: Fix traceback reporting for exceptions with ``__cause__`` cycles.



Improved Documentation
----------------------

- `3746 &lt;https://github.com/pytest-dev/pytest/issues/3746&gt;`_: Add documentation for ``metafunc.config`` that had been mistakenly hidden.
   ```
   
  
</details>


 

<details>
  <summary>Links</summary>
  
  - PyPI: https://pypi.org/project/pytest
  - Changelog: https://pyup.io/changelogs/pytest/
  - Homepage: http://pytest.org
</details>

cmccandless added a commit to cmccandless/multisite that referenced this issue Aug 20, 2018

Update pytest to 3.7.2 (#8)
This PR updates [pytest](https://pypi.org/project/pytest) from **3.6.4** to **3.7.2**.



<details>
  <summary>Changelog</summary>
  
  
   ### 3.7.2
   ```
   =========================

Bug Fixes
---------

- `3671 &lt;https://github.com/pytest-dev/pytest/issues/3671&gt;`_: Fix ``filterwarnings`` not being registered as a builtin mark.


- `3768 &lt;https://github.com/pytest-dev/pytest/issues/3768&gt;`_, `3789 &lt;https://github.com/pytest-dev/pytest/issues/3789&gt;`_: Fix test collection from packages mixed with normal directories.


- `3771 &lt;https://github.com/pytest-dev/pytest/issues/3771&gt;`_: Fix infinite recursion during collection if a ``pytest_ignore_collect`` hook returns ``False`` instead of ``None``.


- `3774 &lt;https://github.com/pytest-dev/pytest/issues/3774&gt;`_: Fix bug where decorated fixtures would lose functionality (for example ``mock.patch``).


- `3775 &lt;https://github.com/pytest-dev/pytest/issues/3775&gt;`_: Fix bug where importing modules or other objects with prefix ``pytest_`` prefix would raise a ``PluginValidationError``.


- `3788 &lt;https://github.com/pytest-dev/pytest/issues/3788&gt;`_: Fix ``AttributeError`` during teardown of ``TestCase`` subclasses which raise an exception during ``__init__``.


- `3804 &lt;https://github.com/pytest-dev/pytest/issues/3804&gt;`_: Fix traceback reporting for exceptions with ``__cause__`` cycles.



Improved Documentation
----------------------

- `3746 &lt;https://github.com/pytest-dev/pytest/issues/3746&gt;`_: Add documentation for ``metafunc.config`` that had been mistakenly hidden.
   ```
   
  
  
   ### 3.7.1
   ```
   =========================

Bug Fixes
---------

- `3473 &lt;https://github.com/pytest-dev/pytest/issues/3473&gt;`_: Raise immediately if ``approx()`` is given an expected value of a type it doesn&#39;t understand (e.g. strings, nested dicts, etc.).


- `3712 &lt;https://github.com/pytest-dev/pytest/issues/3712&gt;`_: Correctly represent the dimensions of an numpy array when calling ``repr()`` on ``approx()``.

- `3742 &lt;https://github.com/pytest-dev/pytest/issues/3742&gt;`_: Fix incompatibility with third party plugins during collection, which produced the error ``object has no attribute &#39;_collectfile&#39;``.

- `3745 &lt;https://github.com/pytest-dev/pytest/issues/3745&gt;`_: Display the absolute path if ``cache_dir`` is not relative to the ``rootdir`` instead of failing.


- `3747 &lt;https://github.com/pytest-dev/pytest/issues/3747&gt;`_: Fix compatibility problem with plugins and the warning code issued by fixture functions when they are called directly.


- `3748 &lt;https://github.com/pytest-dev/pytest/issues/3748&gt;`_: Fix infinite recursion in ``pytest.approx`` with arrays in ``numpy&lt;1.13``.


- `3757 &lt;https://github.com/pytest-dev/pytest/issues/3757&gt;`_: Pin pathlib2 to ``&gt;=2.2.0`` as we require ``__fspath__`` support.


- `3763 &lt;https://github.com/pytest-dev/pytest/issues/3763&gt;`_: Fix ``TypeError`` when the assertion message is ``bytes`` in python 3.
   ```
   
  
  
   ### 3.7.0
   ```
   =========================

Deprecations and Removals
-------------------------

- `2639 &lt;https://github.com/pytest-dev/pytest/issues/2639&gt;`_: ``pytest_namespace`` has been deprecated.

  See the documentation for ``pytest_namespace`` hook for suggestions on how to deal
  with this in plugins which use this functionality.


- `3661 &lt;https://github.com/pytest-dev/pytest/issues/3661&gt;`_: Calling a fixture function directly, as opposed to request them in a test function, now issues a ``RemovedInPytest4Warning``. It will be changed into an error in pytest ``4.0``.

  This is a great source of confusion to new users, which will often call the fixture functions and request them from test functions interchangeably, which breaks the fixture resolution model.



Features
--------

- `2283 &lt;https://github.com/pytest-dev/pytest/issues/2283&gt;`_: New ``package`` fixture scope: fixtures are finalized when the last test of a *package* finishes. This feature is considered **experimental**, so use it sparingly.


- `3576 &lt;https://github.com/pytest-dev/pytest/issues/3576&gt;`_: ``Node.add_marker`` now supports an ``append=True/False`` parameter to determine whether the mark comes last (default) or first.


- `3579 &lt;https://github.com/pytest-dev/pytest/issues/3579&gt;`_: Fixture ``caplog`` now has a ``messages`` property, providing convenient access to the format-interpolated log messages without the extra data provided by the formatter/handler.


- `3610 &lt;https://github.com/pytest-dev/pytest/issues/3610&gt;`_: New ``--trace`` option to enter the debugger at the start of a test.


- `3623 &lt;https://github.com/pytest-dev/pytest/issues/3623&gt;`_: Introduce ``pytester.copy_example`` as helper to do acceptance tests against examples from the project.



Bug Fixes
---------

- `2220 &lt;https://github.com/pytest-dev/pytest/issues/2220&gt;`_: Fix a bug where fixtures overridden by direct parameters (for example parametrization) were being instantiated even if they were not being used by a test.


- `3695 &lt;https://github.com/pytest-dev/pytest/issues/3695&gt;`_: Fix ``ApproxNumpy`` initialisation argument mixup, ``abs`` and ``rel`` tolerances were flipped causing strange comparsion results.
  Add tests to check ``abs`` and ``rel`` tolerances for ``np.array`` and test for expecting ``nan`` with ``np.array()``


- `980 &lt;https://github.com/pytest-dev/pytest/issues/980&gt;`_: Fix truncated locals output in verbose mode.



Improved Documentation
----------------------

- `3295 &lt;https://github.com/pytest-dev/pytest/issues/3295&gt;`_: Correct the usage documentation of ``--last-failed-no-failures`` by adding the missing ``--last-failed`` argument in the presented examples, because they are misleading and lead to think that the missing argument is not needed.



Trivial/Internal Changes
------------------------

- `3519 &lt;https://github.com/pytest-dev/pytest/issues/3519&gt;`_: Now a ``README.md`` file is created in ``.pytest_cache`` to make it clear why the directory exists.
   ```
   
  
</details>


 

<details>
  <summary>Links</summary>
  
  - PyPI: https://pypi.org/project/pytest
  - Changelog: https://pyup.io/changelogs/pytest/
  - Homepage: http://pytest.org
</details>

bors bot added a commit to rehandalal/therapist that referenced this issue Aug 20, 2018

Merge #28
28: Update pytest to 3.7.2 r=rehandalal a=pyup-bot


This PR updates [pytest](https://pypi.org/project/pytest) from **3.7.1** to **3.7.2**.



<details>
  <summary>Changelog</summary>
  
  
   ### 3.7.2
   ```
   =========================

Bug Fixes
---------

- `3671 &lt;https://github.com/pytest-dev/pytest/issues/3671&gt;`_: Fix ``filterwarnings`` not being registered as a builtin mark.


- `3768 &lt;https://github.com/pytest-dev/pytest/issues/3768&gt;`_, `3789 &lt;https://github.com/pytest-dev/pytest/issues/3789&gt;`_: Fix test collection from packages mixed with normal directories.


- `3771 &lt;https://github.com/pytest-dev/pytest/issues/3771&gt;`_: Fix infinite recursion during collection if a ``pytest_ignore_collect`` hook returns ``False`` instead of ``None``.


- `3774 &lt;https://github.com/pytest-dev/pytest/issues/3774&gt;`_: Fix bug where decorated fixtures would lose functionality (for example ``mock.patch``).


- `3775 &lt;https://github.com/pytest-dev/pytest/issues/3775&gt;`_: Fix bug where importing modules or other objects with prefix ``pytest_`` prefix would raise a ``PluginValidationError``.


- `3788 &lt;https://github.com/pytest-dev/pytest/issues/3788&gt;`_: Fix ``AttributeError`` during teardown of ``TestCase`` subclasses which raise an exception during ``__init__``.


- `3804 &lt;https://github.com/pytest-dev/pytest/issues/3804&gt;`_: Fix traceback reporting for exceptions with ``__cause__`` cycles.



Improved Documentation
----------------------

- `3746 &lt;https://github.com/pytest-dev/pytest/issues/3746&gt;`_: Add documentation for ``metafunc.config`` that had been mistakenly hidden.
   ```
   
  
</details>


 

<details>
  <summary>Links</summary>
  
  - PyPI: https://pypi.org/project/pytest
  - Changelog: https://pyup.io/changelogs/pytest/
  - Homepage: http://pytest.org
</details>



Co-authored-by: pyup-bot <github-bot@pyup.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment