diff --git a/CHANGELOG b/CHANGELOG index ce74c0740..1ddc67002 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,6 +44,9 @@ Changes between 2.2.4 and 2.3.0.dev - fix issue 178: xml binary escapes are now wrapped in py.xml.raw +- factory discovery no longer fails with magic global callables + that provide no sane __code__ object (mock.call for example) + - reporting refinements: - pytest_report_header now receives a "startdir" so that diff --git a/_pytest/python.py b/_pytest/python.py index e128be9ce..e03240089 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1303,10 +1303,14 @@ class FuncargManager: obj = getattr(holderobj, name) if not callable(obj): continue + # to avoid breaking on magic global callables + # we explicitly check if we get a sane code object + # else having mock.call in the globals fails for example + code = py.code.getrawcode(obj) + if not inspect.iscode(code): + continue # resource factories either have a pytest_funcarg__ prefix # or are "funcarg" marked - if not callable(obj): - continue marker = getattr(obj, "_pytestfactory", None) if marker is not None: assert not name.startswith(self._argprefix) diff --git a/testing/test_python.py b/testing/test_python.py index 62633b6bb..e2fe18317 100644 --- a/testing/test_python.py +++ b/testing/test_python.py @@ -1761,6 +1761,23 @@ class TestSetupDiscovery: reprec = testdir.inline_run("-s") reprec.assertoutcome(passed=1) + def test_callables_nocode(self, testdir): + """ + a imported mock.call would break setup/factory discovery + due to it being callable and __code__ not being a code object + """ + testdir.makepyfile(""" + class _call(tuple): + def __call__(self, *k, **kw): + pass + def __getattr__(self, k): + return self + + call = _call() + """) + reprec = testdir.inline_run("-s") + reprec.assertoutcome(failed=0, passed=0) + class TestSetupManagement: def test_funcarg_and_setup(self, testdir):