(fixture) create a new class to represent fixtures

This commit is contained in:
Glyphack 2024-06-19 13:36:28 +02:00
parent 7fd947167d
commit 46d2ccbfd4
1 changed files with 63 additions and 12 deletions

View File

@ -45,7 +45,8 @@ from _pytest._io import TerminalWriter
from _pytest.compat import _PytestWrapper
from _pytest.compat import assert_never
from _pytest.compat import get_real_func
from _pytest.compat import get_real_method
# from _pytest.compat import get_real_method
from _pytest.compat import getfuncargnames
from _pytest.compat import getimfunc
from _pytest.compat import getlocation
@ -1186,7 +1187,7 @@ class FixtureFunctionMarker:
def __post_init__(self, _ispytest: bool) -> None:
check_ispytest(_ispytest)
def __call__(self, function: FixtureFunction) -> FixtureFunction:
def __call__(self, function: FixtureFunction) -> "FixtureFunctionDefinition":
if inspect.isclass(function):
raise ValueError("class fixtures not supported (maybe in the future)")
@ -1198,7 +1199,9 @@ class FixtureFunctionMarker:
if hasattr(function, "pytestmark"):
warnings.warn(MARKED_FIXTURE, stacklevel=2)
function = wrap_function_to_error_out_if_called_directly(function, self)
fixture_definition = FixtureFunctionDefinition(function, self)
# function = wrap_function_to_error_out_if_called_directly(function, self)
name = self.name or function.__name__
if name == "request":
@ -1209,13 +1212,53 @@ class FixtureFunctionMarker:
)
# Type ignored because https://github.com/python/mypy/issues/2087.
function._pytestfixturefunction = self # type: ignore[attr-defined]
return function
# function._pytestfixturefunction = self # type: ignore[attr-defined]
# return function
return fixture_definition
def __repr__(self):
return "fixture"
class FixtureFunctionDefinition:
def __init__(
self,
function: Callable[..., object],
fixture_function_marker: FixtureFunctionMarker,
instance: Optional[type] = None,
):
self.name = fixture_function_marker.name or function.__name__
self._pytestfixturefunction = fixture_function_marker
self.__pytest_wrapped__ = _PytestWrapper(function)
self.fixture_function = function
self.fixture_function_marker = fixture_function_marker
self.scope = fixture_function_marker.scope
self.params = fixture_function_marker.params
self.autouse = fixture_function_marker.autouse
self.ids = fixture_function_marker.ids
self.fixture_function = function
self.instance = instance
def __repr__(self) -> str:
return f"fixture {self.fixture_function}"
def __get__(self, instance, owner=None):
return FixtureFunctionDefinition(
self.fixture_function, self.fixture_function_marker, instance
)
def __call__(self, *args: Any, **kwds: Any) -> Any:
return self.get_real_func(*args, **kwds)
def get_real_func(self):
if self.instance is not None:
return self.fixture_function.__get__(self.instance)
return self.fixture_function
@overload
def fixture(
fixture_function: FixtureFunction,
fixture_function: Callable[..., object],
*,
scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ...,
params: Optional[Iterable[object]] = ...,
@ -1224,7 +1267,7 @@ def fixture(
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
] = ...,
name: Optional[str] = ...,
) -> FixtureFunction: ...
) -> FixtureFunctionDefinition: ...
@overload
@ -1238,7 +1281,7 @@ def fixture(
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
] = ...,
name: Optional[str] = None,
) -> FixtureFunctionMarker: ...
) -> FixtureFunctionDefinition: ...
def fixture(
@ -1251,7 +1294,7 @@ def fixture(
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
] = None,
name: Optional[str] = None,
) -> Union[FixtureFunctionMarker, FixtureFunction]:
) -> Union[FixtureFunctionMarker, FixtureFunctionDefinition]:
"""Decorator to mark a fixture factory function.
This decorator can be used, with or without parameters, to define a
@ -1321,7 +1364,7 @@ def fixture(
def yield_fixture(
fixture_function=None,
*args,
scope="function",
scope: _ScopeName = "function",
params=None,
autouse=False,
ids=None,
@ -1644,6 +1687,13 @@ class FixtureManager:
] = None,
autouse: bool = False,
) -> None:
if name == "fixt2":
print(name)
print(func)
print(nodeid)
print(scope)
print(ids)
print(autouse)
"""Register a fixture
:param name:
@ -1735,7 +1785,7 @@ class FixtureManager:
self._holderobjseen.add(holderobj)
for name in dir(holderobj):
# The attribute can be an arbitrary descriptor, so the attribute
# access below can raise. safe_getatt() ignores such exceptions.
# access below can raise. safe_getattr() ignores such exceptions.
obj = safe_getattr(holderobj, name, None)
marker = getfixturemarker(obj)
if not isinstance(marker, FixtureFunctionMarker):
@ -1750,7 +1800,8 @@ class FixtureManager:
# to issue a warning if called directly, so here we unwrap it in
# order to not emit the warning when pytest itself calls the
# fixture function.
func = get_real_method(obj, holderobj)
# func = get_real_method(obj, holderobj)
func = obj.get_real_func()
self._register_fixture(
name=name,