From 311b0a9683b8e2111cbe25480a5587c603fe0bc2 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 16 Oct 2015 20:08:12 -0300 Subject: [PATCH] Fix situation where a traceback entry "path" returns a str object Fix #1133 --- CHANGELOG | 20 ++++++++++++-------- _pytest/python.py | 7 +++++-- testing/python/collect.py | 36 ++++++++++++++++++++++++++++++------ 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d699bdd84..6f585b8c7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,10 @@ - fix #331: don't collect tests if their failure cannot be reported correctly e.g. they are a callable instance of a class. +- fix #1133: fixed internal error when filtering tracebacks where one entry + belongs to a file which is no longer available. + Thanks Bruno Oliveira for the PR. + 2.8.2 ----- @@ -50,9 +54,9 @@ "pytest-xdist" plugin, with test reports being assigned to the wrong tests. Thanks Daniel Grunwald for the report and Bruno Oliveira for the PR. -- (experimental) adapt more SEMVER style versioning and change meaning of - master branch in git repo: "master" branch now keeps the bugfixes, changes - aimed for micro releases. "features" branch will only be be released +- (experimental) adapt more SEMVER style versioning and change meaning of + master branch in git repo: "master" branch now keeps the bugfixes, changes + aimed for micro releases. "features" branch will only be be released with minor or major pytest releases. - Fix issue #766 by removing documentation references to distutils. @@ -77,7 +81,7 @@ ----------------------------- - new ``--lf`` and ``-ff`` options to run only the last failing tests or - "failing tests first" from the last run. This functionality is provided + "failing tests first" from the last run. This functionality is provided through porting the formerly external pytest-cache plugin into pytest core. BACKWARD INCOMPAT: if you used pytest-cache's functionality to persist data between test runs be aware that we don't serialize sets anymore. @@ -183,9 +187,9 @@ - fix issue735: assertion failures on debug versions of Python 3.4+ -- new option ``--import-mode`` to allow to change test module importing - behaviour to append to sys.path instead of prepending. This better allows - to run test modules against installated versions of a package even if the +- new option ``--import-mode`` to allow to change test module importing + behaviour to append to sys.path instead of prepending. This better allows + to run test modules against installated versions of a package even if the package under test has the same import root. In this example:: testing/__init__.py @@ -193,7 +197,7 @@ pkg_under_test/ the tests will run against the installed version - of pkg_under_test when ``--import-mode=append`` is used whereas + of pkg_under_test when ``--import-mode=append`` is used whereas by default they would always pick up the local version. Thanks Holger Krekel. - pytester: add method ``TmpTestdir.delete_loaded_modules()``, and call it diff --git a/_pytest/python.py b/_pytest/python.py index b7a737a94..c3a951772 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -58,14 +58,17 @@ def _has_positional_arg(func): def filter_traceback(entry): - # entry.path might sometimes return a str() object when the entry + # entry.path might sometimes return a str object when the entry # points to dynamically generated code # see https://bitbucket.org/pytest-dev/py/issues/71 raw_filename = entry.frame.code.raw.co_filename is_generated = '<' in raw_filename and '>' in raw_filename if is_generated: return False - return entry.path != cutdir1 and not entry.path.relto(cutdir2) + # entry.path might point to an inexisting file, in which case it will + # alsso return a str object. see #1133 + p = py.path.local(entry.path) + return p != cutdir1 and not p.relto(cutdir2) def get_real_func(obj): diff --git a/testing/python/collect.py b/testing/python/collect.py index b78374fd5..636f9597e 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -771,10 +771,12 @@ class TestTracebackCutting: "* 1 error in *", ]) - def test_filter_traceback_accepts_non_paths(self): - """test that filter_traceback() works around py.code.Code bug - where sometimes its "path" attribute is not a py.path.local object: - https://bitbucket.org/pytest-dev/py/issues/71 + def test_filter_traceback_generated_code(self): + """test that filter_traceback() works with the fact that + py.code.Code.path attribute might return an str object. + In this case, one of the entries on the traceback was produced by + dynamically generated code. + See: https://bitbucket.org/pytest-dev/py/issues/71 This fixes #995. """ from _pytest.python import filter_traceback @@ -783,13 +785,35 @@ class TestTracebackCutting: exec('def foo(): raise ValueError', ns) ns['foo']() except ValueError: - import sys _, _, tb = sys.exc_info() tb = py.code.Traceback(tb) - assert isinstance(tb[-1].path, str) # symptom of the py.code bug + assert isinstance(tb[-1].path, str) assert not filter_traceback(tb[-1]) + def test_filter_traceback_path_no_longer_valid(self, testdir): + """test that filter_traceback() works with the fact that + py.code.Code.path attribute might return an str object. + In this case, one of the files in the traceback no longer exists. + This fixes #1133. + """ + from _pytest.python import filter_traceback + testdir.syspathinsert() + testdir.makepyfile(filter_traceback_entry_as_str=''' + def foo(): + raise ValueError + ''') + try: + import filter_traceback_entry_as_str + filter_traceback_entry_as_str.foo() + except ValueError: + _, _, tb = sys.exc_info() + + testdir.tmpdir.join('filter_traceback_entry_as_str.py').remove() + tb = py.code.Traceback(tb) + assert isinstance(tb[-1].path, str) + assert filter_traceback(tb[-1]) + class TestReportInfo: def test_itemreport_reportinfo(self, testdir, linecomp):