Pytest fails the following testcase with "fixture 'func' not found" on Python 3.7. On Python 2.7, the same code succeeds. In both cases, pytest 4.6.9 is used:
Content of pytest_decorator_issue/test_issue.py
:
import functools
def my_decorator(func):
def wrapper_func(*args, **kwargs):
# do something on entry
ret = func(*args, **kwargs)
# do something on exit
return ret
return functools.update_wrapper(wrapper_func, my_decorator)
@my_decorator
def test_bla():
# perform some test
pass
Invocation of pytest on Python 3.7:
$ pytest pytest_decorator_issue -vv
=============== ... test session starts ...
platform darwin -- Python 3.7.5, pytest-4.6.9, py-1.8.0, pluggy-0.13.1 -- .../virtualenvs/pywbem37/bin/python
cachedir: .pytest_cache
rootdir: ...
plugins: requests-mock-1.7.0, cov-2.8.1
collected 1 item
pytest_decorator_issue/test_issue.py::test_bla ERROR [100%]
============ ... ERRORS ...
____________ ... ERROR at setup of test_bla ...
file .../pytest_decorator_issue/test_fixture_issue.py, line 3
def my_decorator(func):
E fixture 'func' not found
> available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, requests_mock, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
> use 'pytest --fixtures [testpath]' for help on them.
.../pytest_decorator_issue/test_fixture_issue.py:3
============== ... 1 error in 0.01 seconds =================================================================
Pytest apparently decides to look for a fixture named 'func' when it sees the argument of the decorator function, but why does it not do that on Python 2.7, and how can I have a simple decorator like this on a pytest test function?
Just for comparison of the versions, on Python 2,7, the relevant pytest output is:
platform darwin -- Python 2.7.16, pytest-4.6.9, py-1.8.0, pluggy-0.13.1 -- .../virtualenvs/pywbem27/bin/python
cachedir: .pytest_cache
rootdir: ...
plugins: requests-mock-1.7.0, cov-2.8.1
collected 1 item
Update:
I just found that when using the functools.wraps
decorator instead of functools.update_wrapper()
, pytest is happy on both Python 2.7 and 3.7:
def my_decorator(func):
@functools.wraps(func)
def wrapper_func(*args, **kwargs):
# do something on entry
ret = func(*args, **kwargs)
# do something on exit
return ret
return wrapper_func
Can someone explain this?
The second argument in your call to update_wrapper
has to be func
instead of my_decorator
:
def my_decorator(func):
def wrapper_func(*args, **kwargs):
# do something on entry
ret = func(*args, **kwargs)
# do something on exit
return ret
return functools.update_wrapper(wrapper_func, func)
Not sure why this works under Python 2, though.