From 50a001ee41ba6ba777dd653bb205e24057a80ecc Mon Sep 17 00:00:00 2001 From: Glyphack Date: Sat, 23 Nov 2024 16:19:20 +0100 Subject: [PATCH] Use _get_wrapped_function to unwrap fixtures --- src/_pytest/compat.py | 23 ++--------------------- src/_pytest/fixtures.py | 9 +++++---- testing/code/test_source.py | 4 +++- testing/test_compat.py | 6 +++++- 4 files changed, 15 insertions(+), 27 deletions(-) diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index d17dcf9e1e6..ff24058c8eb 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -211,33 +211,14 @@ def ascii_escaped(val: bytes | str) -> str: def get_real_func(obj): """Get the real function object of the (possibly) wrapped object by - :func:`functools.wraps`, or :func:`functools.partial`, or :func:`pytest.fixture`.""" - from _pytest.fixtures import FixtureFunctionDefinition - - obj = inspect.unwrap(obj, stop=lambda x: type(x) is FixtureFunctionDefinition) - - if type(obj) == FixtureFunctionDefinition: - obj = obj._get_wrapped_function() + :func:`functools.wraps`, or :func:`functools.partial`.""" + obj = inspect.unwrap(obj) if isinstance(obj, functools.partial): obj = obj.func return obj -def get_real_method(obj, holder): - """Attempt to obtain the real function object that might be wrapping - ``obj``, while at the same time returning a bound method to ``holder`` if - the original object was a bound method.""" - try: - is_method = hasattr(obj, "__func__") - obj = get_real_func(obj) - except Exception: # pragma: no cover - return obj - if is_method and hasattr(obj, "__get__") and callable(obj.__get__): - obj = obj.__get__(holder) - return obj - - def getimfunc(func): try: return func.__func__ diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 24d99a4f4e4..20de8cb31ea 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -44,7 +44,6 @@ from _pytest._io import TerminalWriter from _pytest.compat import assert_never from _pytest.compat import get_real_func -from _pytest.compat import get_real_method from _pytest.compat import getfuncargnames from _pytest.compat import getimfunc from _pytest.compat import getlocation @@ -1757,7 +1756,9 @@ def parsefactories( if type(obj_ub) is FixtureFunctionDefinition: marker = obj_ub._fixture_function_marker if marker.name: - name = marker.name + fixture_name = marker.name + else: + fixture_name = name # OK we know it is a fixture -- now safe to look up on the _instance_. try: @@ -1766,10 +1767,10 @@ def parsefactories( except AttributeError: obj = obj_ub - func = get_real_method(obj, holderobj) + func = obj._get_wrapped_function() self._register_fixture( - name=name, + name=fixture_name, nodeid=nodeid, func=func, scope=marker.scope, diff --git a/testing/code/test_source.py b/testing/code/test_source.py index 957ff1bb817..b4a485fca0c 100644 --- a/testing/code/test_source.py +++ b/testing/code/test_source.py @@ -483,7 +483,9 @@ def deco_fixture(): # Make sure the decorator is not a wrapped function assert not str(Source(deco_fixture)).startswith("@functools.wraps(function)") assert ( - textwrap.indent(str(Source(get_real_func(deco_fixture))), " ") + "\n" == src + textwrap.indent(str(Source(deco_fixture._get_wrapped_function())), " ") + + "\n" + == src ) diff --git a/testing/test_compat.py b/testing/test_compat.py index c7cdd041f63..d2a5daf7def 100644 --- a/testing/test_compat.py +++ b/testing/test_compat.py @@ -81,7 +81,11 @@ def wrapped_func3(): pass # pragma: no cover wrapped_func4 = decorator(wrapped_func3) - assert get_real_func(wrapped_func4) is wrapped_func3._get_wrapped_function() + assert ( + # get_real_func does not unwrap function that is wrapped by fixture hence we need to call _get_wrapped_function + get_real_func(wrapped_func4)._get_wrapped_function() + is wrapped_func3._get_wrapped_function() + ) def test_get_real_func_partial() -> None: