Use a custom holder class so we can be sure __pytest_wrapper__ was set by us

This commit is contained in:
Bruno Oliveira
2018-08-09 09:20:37 -03:00
parent ef8ec01e39
commit 67106f056b
3 changed files with 18 additions and 7 deletions

View File

@@ -228,6 +228,18 @@ else:
return val.encode("unicode-escape")
class _PytestWrapper(object):
"""Dummy wrapper around a function object for internal use only.
Used to correctly unwrap the underlying function object
when we are creating fixtures, because we wrap the function object ourselves with a decorator
to issue warnings when the fixture function is called directly.
"""
def __init__(self, obj):
self.obj = obj
def get_real_func(obj):
""" gets the real function object of the (possibly) wrapped object by
functools.wraps or functools.partial.
@@ -238,8 +250,8 @@ def get_real_func(obj):
# to trigger a warning if it gets called directly instead of by pytest: we don't
# want to unwrap further than this otherwise we lose useful wrappings like @mock.patch (#3774)
new_obj = getattr(obj, "__pytest_wrapped__", None)
if new_obj is not None:
obj = new_obj
if isinstance(new_obj, _PytestWrapper):
obj = new_obj.obj
break
new_obj = getattr(obj, "__wrapped__", None)
if new_obj is None:

View File

@@ -31,6 +31,7 @@ from _pytest.compat import (
safe_getattr,
FuncargnamesCompatAttr,
get_real_method,
_PytestWrapper,
)
from _pytest.deprecated import FIXTURE_FUNCTION_CALL, RemovedInPytest4Warning
from _pytest.outcomes import fail, TEST_OUTCOME
@@ -981,7 +982,7 @@ def wrap_function_to_warning_if_called_directly(function, fixture_marker):
# keep reference to the original function in our own custom attribute so we don't unwrap
# further than this point and lose useful wrappings like @mock.patch (#3774)
result.__pytest_wrapped__ = function
result.__pytest_wrapped__ = _PytestWrapper(function)
return result