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.
This commit is contained in:
Florian Bruhin 2015-11-30 16:13:15 +01:00
parent bced5a3f81
commit c790f7475e
3 changed files with 21 additions and 2 deletions

View File

@ -6,6 +6,9 @@
module. Thanks Mikhail Chernykh for the report and Bruno Oliveira for the module. Thanks Mikhail Chernykh for the report and Bruno Oliveira for the
PR. PR.
- fix #1204: another error when collecting with a nasty __getattr__().
Thanks Florian Bruhin for the PR.
2.8.3 2.8.3
----- -----

View File

@ -384,12 +384,13 @@ class PyobjMixin(PyobjContext):
def reportinfo(self): def reportinfo(self):
# XXX caching? # XXX caching?
obj = self.obj 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 # nose compatibility
fspath = sys.modules[obj.__module__].__file__ fspath = sys.modules[obj.__module__].__file__
if fspath.endswith(".pyc"): if fspath.endswith(".pyc"):
fspath = fspath[:-1] fspath = fspath[:-1]
lineno = obj.compat_co_firstlineno lineno = compat_co_firstlineno
else: else:
fspath, lineno = getfslineno(obj) fspath, lineno = getfslineno(obj)
modpath = self.getmodpath() modpath = self.getmodpath()

View File

@ -880,6 +880,21 @@ class TestReportInfo:
pass 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): def test_customized_python_discovery(testdir):
testdir.makeini(""" testdir.makeini("""