Search code examples
pythonpytestintrospection

AttributeError: 'function' object has no attribute 'im_class'


After upgrading pytest, our custom plugin fails like this:

Traceback (most recent call last):
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/main.py", line 94, in wrap_session
    session.exitstatus = doit(config, session) or 0
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/main.py", line 124, in _main
    config.hook.pytest_collection(session=session)
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py", line 724, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py", line 338, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py", line 333, in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py", line 596, in execute
    res = hook_impl.function(*args)
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/main.py", line 133, in pytest_collection
    return session.perform_collect()
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/main.py", line 567, in perform_collect
    config=self.config, items=items)
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py", line 724, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py", line 338, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py", line 333, in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/_pytest/vendored_packages/pluggy.py", line 596, in execute
    res = hook_impl.function(*args)
  File "/home/foo_eins_d/local/lib/python2.7/site-packages/pytest_djangotools/hooks.py", line 71, in pytest_collection_modifyitems
    if not _safe_to_run(item._obj.im_class):
AttributeError: 'function' object has no attribute 'im_class'

The plugin code:

def pytest_collection_modifyitems(session, config, items):
    new=[]
    for item in items:
        if not _safe_to_run(item._obj.im_class):
            continue
        new.append(item)
    items[:] = new

With item._obj.im_class we accessed the class from the test-method.

How to get the TestCase class?


Solution

  • Not all of your item objects are bound methods. pytest can run plain functions as tests too, and there is no TestCase associated with those.

    You could skip these:

    def pytest_collection_modifyitems(session, config, items):
        new=[]
        for item in items:
            if not hasattr(item._obj, 'im_class'):
                # not a method, can't check if safe
                continue
            if not _safe_to_run(item._obj.im_class):
                continue
            new.append(item)
        items[:] = new