From c790f7475e33be7790c63c18001e66577e69d58e Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 30 Nov 2015 16:13:15 +0100 Subject: [PATCH] Fix getting line number with nasty __getattr__. When an object has a custom __getattr__ which always returns a non-int, we tried to get compat_co_firstlineno from it and checked it was a integer, which caused an exception if such a class is mistakenly collected. If we still mistakenly collect such a class (which is likely to be something other than a test), we now skip it with a warning (because it probably has an __init__) instead of producing an error. See #1204. --- CHANGELOG | 3 +++ _pytest/python.py | 5 +++-- testing/python/collect.py | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ae766aa0d..3299513d8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,9 @@ module. Thanks Mikhail Chernykh for the report and Bruno Oliveira for the PR. +- fix #1204: another error when collecting with a nasty __getattr__(). + Thanks Florian Bruhin for the PR. + 2.8.3 ----- diff --git a/_pytest/python.py b/_pytest/python.py index c3a951772..67d5e5c52 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -384,12 +384,13 @@ class PyobjMixin(PyobjContext): def reportinfo(self): # XXX caching? obj = self.obj - if hasattr(obj, 'compat_co_firstlineno'): + compat_co_firstlineno = getattr(obj, 'compat_co_firstlineno', None) + if isinstance(compat_co_firstlineno, int): # nose compatibility fspath = sys.modules[obj.__module__].__file__ if fspath.endswith(".pyc"): fspath = fspath[:-1] - lineno = obj.compat_co_firstlineno + lineno = compat_co_firstlineno else: fspath, lineno = getfslineno(obj) modpath = self.getmodpath() diff --git a/testing/python/collect.py b/testing/python/collect.py index 636f9597e..1a85faf9c 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -880,6 +880,21 @@ class TestReportInfo: pass """ + def test_reportinfo_with_nasty_getattr(self, testdir): + # https://github.com/pytest-dev/pytest/issues/1204 + modcol = testdir.getmodulecol(""" + # lineno 0 + class TestClass: + def __getattr__(self, name): + return "this is not an int" + + def test_foo(self): + pass + """) + classcol = testdir.collect_by_name(modcol, "TestClass") + instance = classcol.collect()[0] + fspath, lineno, msg = instance.reportinfo() + def test_customized_python_discovery(testdir): testdir.makeini("""