Pytest: PyTest won't inject fixtures into decorated functions in Python 2.7

Created on 14 Sep 2017  路  7Comments  路  Source: pytest-dev/pytest

_pytest.compat.get_real_func doesn't work as expected in Python 2.7:

Example:

from _pytest.compat import get_real_func

import functools

def my_decorator(f):
    @functools.wraps(f)
    def wrapper(*args, **kwds):
        print('Calling decorated function')
        return f(*args, **kwds)
    return wrapper

#@my_decorator
def example():
    """Docstring"""
    print('Called example function')

decorated_example = my_decorator(example)

if get_real_func(decorated_example) is example:
    print('get_real_func works')
else:
    print('get_real_func fails')

Python 3.5 output:

$ python3.5 test.py
get_real_func works

Python 2.7 output:

$ python2.7 test.py
get_real_func fails

Tested with PyTest 3.0.6 though the same idea (isinstance(obj, functools.partial)) is attempted in master.

python 2 only fixtures bug

All 7 comments

I believe this is because of a limitation in Python 2's functools.wrap, I recall a discussion about this recently but can't find it at the moment. Perhaps @RonnyPfannschmidt can point to that discussion?

Well, yes, functools.wraps won't leave any metadata in Python 2. But the testing the decorated function for inheritance from functools.partial is wrong. While isinstance(functools.wraps(f), functools.partial) == True for most Python versions, the partial function would be executed and another function would be produced, thus losing the inheritance. So, it's better to give up completely in py2 or do some magic with code inspection maybe.

i recall six has a fixed version, also you can just put the __wraps__ attribute there manually

It can by solved by either using wraps from six module or by getting wrapped function from obj.__closure__[0].cell_contents in get_real_func function.

What is the preferred general solution to this?

@kchomski-reef using six is the preferred solution as the guess abut what closure cell to use is potentially incorrect in edge cases

can this be closed as upstream python issue fixed by six?

can this be closed as upstream python issue fixed by six?

There's nothing we can reliably do about this otherwise, so I'm happy to close as "Use six or upgrade to Python3" :snake::snake::snake:

Was this page helpful?
0 / 5 - 0 ratings