fixtures: expand comments and annotations on fixture internals
This commit is contained in:
parent
ecfab4dc8b
commit
01f38aca44
|
@ -68,7 +68,7 @@ def is_async_function(func: object) -> bool:
|
||||||
return iscoroutinefunction(func) or inspect.isasyncgenfunction(func)
|
return iscoroutinefunction(func) or inspect.isasyncgenfunction(func)
|
||||||
|
|
||||||
|
|
||||||
def getlocation(function, curdir: str | None = None) -> str:
|
def getlocation(function, curdir: str | os.PathLike[str] | None = None) -> str:
|
||||||
function = get_real_func(function)
|
function = get_real_func(function)
|
||||||
fn = Path(inspect.getfile(function))
|
fn = Path(inspect.getfile(function))
|
||||||
lineno = function.__code__.co_firstlineno
|
lineno = function.__code__.co_firstlineno
|
||||||
|
|
|
@ -582,7 +582,7 @@ def _setup_fixtures(doctest_item: DoctestItem) -> FixtureRequest:
|
||||||
doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined]
|
doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined]
|
||||||
node=doctest_item, func=func, cls=None, funcargs=False
|
node=doctest_item, func=func, cls=None, funcargs=False
|
||||||
)
|
)
|
||||||
fixture_request = FixtureRequest(doctest_item, _ispytest=True)
|
fixture_request = FixtureRequest(doctest_item, _ispytest=True) # type: ignore[arg-type]
|
||||||
fixture_request._fillfixtures()
|
fixture_request._fillfixtures()
|
||||||
return fixture_request
|
return fixture_request
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ from typing import Any
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
from typing import Final
|
||||||
from typing import final
|
from typing import final
|
||||||
from typing import Generator
|
from typing import Generator
|
||||||
from typing import Generic
|
from typing import Generic
|
||||||
|
@ -73,6 +74,7 @@ if TYPE_CHECKING:
|
||||||
from _pytest.scope import _ScopeName
|
from _pytest.scope import _ScopeName
|
||||||
from _pytest.main import Session
|
from _pytest.main import Session
|
||||||
from _pytest.python import CallSpec2
|
from _pytest.python import CallSpec2
|
||||||
|
from _pytest.python import Function
|
||||||
from _pytest.python import Metafunc
|
from _pytest.python import Metafunc
|
||||||
|
|
||||||
|
|
||||||
|
@ -352,17 +354,24 @@ def get_direct_param_fixture_func(request: "FixtureRequest") -> Any:
|
||||||
return request.param
|
return request.param
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass(frozen=True)
|
||||||
class FuncFixtureInfo:
|
class FuncFixtureInfo:
|
||||||
__slots__ = ("argnames", "initialnames", "names_closure", "name2fixturedefs")
|
__slots__ = ("argnames", "initialnames", "names_closure", "name2fixturedefs")
|
||||||
|
|
||||||
# Original function argument names.
|
# Original function argument names, i.e. fixture names that the function
|
||||||
|
# requests directly.
|
||||||
argnames: Tuple[str, ...]
|
argnames: Tuple[str, ...]
|
||||||
# Argnames that function immediately requires. These include argnames +
|
# Fixture names that the function immediately requires. These include
|
||||||
# fixture names specified via usefixtures and via autouse=True in fixture
|
# argnames + fixture names specified via usefixtures and via autouse=True in
|
||||||
# definitions.
|
# fixture definitions.
|
||||||
initialnames: Tuple[str, ...]
|
initialnames: Tuple[str, ...]
|
||||||
|
# The transitive closure of the fixture names that the function requires.
|
||||||
|
# Note: can't include dynamic dependencies (`request.getfixturevalue` calls).
|
||||||
names_closure: List[str]
|
names_closure: List[str]
|
||||||
|
# A map from a fixture name in the transitive closure to the FixtureDefs
|
||||||
|
# matching the name which are applicable to this function.
|
||||||
|
# There may be multiple overriding fixtures with the same name. The
|
||||||
|
# sequence is ordered from furthest to closes to the function.
|
||||||
name2fixturedefs: Dict[str, Sequence["FixtureDef[Any]"]]
|
name2fixturedefs: Dict[str, Sequence["FixtureDef[Any]"]]
|
||||||
|
|
||||||
def prune_dependency_tree(self) -> None:
|
def prune_dependency_tree(self) -> None:
|
||||||
|
@ -401,17 +410,31 @@ class FixtureRequest:
|
||||||
indirectly.
|
indirectly.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, pyfuncitem, *, _ispytest: bool = False) -> None:
|
def __init__(self, pyfuncitem: "Function", *, _ispytest: bool = False) -> None:
|
||||||
check_ispytest(_ispytest)
|
check_ispytest(_ispytest)
|
||||||
self._pyfuncitem = pyfuncitem
|
|
||||||
#: Fixture for which this request is being performed.
|
#: Fixture for which this request is being performed.
|
||||||
self.fixturename: Optional[str] = None
|
self.fixturename: Optional[str] = None
|
||||||
|
self._pyfuncitem = pyfuncitem
|
||||||
|
self._fixturemanager = pyfuncitem.session._fixturemanager
|
||||||
self._scope = Scope.Function
|
self._scope = Scope.Function
|
||||||
self._fixture_defs: Dict[str, FixtureDef[Any]] = {}
|
# The FixtureDefs for each fixture name requested by this item.
|
||||||
fixtureinfo: FuncFixtureInfo = pyfuncitem._fixtureinfo
|
# Starts from the statically-known fixturedefs resolved during
|
||||||
self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy()
|
# collection. Dynamically requested fixtures (using
|
||||||
|
# `request.getfixturevalue("foo")`) are added dynamically.
|
||||||
|
self._arg2fixturedefs = pyfuncitem._fixtureinfo.name2fixturedefs.copy()
|
||||||
|
# A fixture may override another fixture with the same name, e.g. a fixture
|
||||||
|
# in a module can override a fixture in a conftest, a fixture in a class can
|
||||||
|
# override a fixture in the module, and so on.
|
||||||
|
# An overriding fixture can request its own name; in this case it gets
|
||||||
|
# the value of the fixture it overrides, one level up.
|
||||||
|
# The _arg2index state keeps the current depth in the overriding chain.
|
||||||
|
# The fixturedefs list in _arg2fixturedefs for a given name is ordered from
|
||||||
|
# furthest to closest, so we use negative indexing -1, -2, ... to go from
|
||||||
|
# last to first.
|
||||||
self._arg2index: Dict[str, int] = {}
|
self._arg2index: Dict[str, int] = {}
|
||||||
self._fixturemanager: FixtureManager = pyfuncitem.session._fixturemanager
|
# The evaluated argnames so far, mapping to the FixtureDef they resolved
|
||||||
|
# to.
|
||||||
|
self._fixture_defs: Dict[str, FixtureDef[Any]] = {}
|
||||||
# Notes on the type of `param`:
|
# Notes on the type of `param`:
|
||||||
# -`request.param` is only defined in parametrized fixtures, and will raise
|
# -`request.param` is only defined in parametrized fixtures, and will raise
|
||||||
# AttributeError otherwise. Python typing has no notion of "undefined", so
|
# AttributeError otherwise. Python typing has no notion of "undefined", so
|
||||||
|
@ -466,10 +489,14 @@ class FixtureRequest:
|
||||||
fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid)
|
fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid)
|
||||||
if fixturedefs is not None:
|
if fixturedefs is not None:
|
||||||
self._arg2fixturedefs[argname] = fixturedefs
|
self._arg2fixturedefs[argname] = fixturedefs
|
||||||
|
# No fixtures defined with this name.
|
||||||
if fixturedefs is None:
|
if fixturedefs is None:
|
||||||
raise FixtureLookupError(argname, self)
|
raise FixtureLookupError(argname, self)
|
||||||
# fixturedefs list is immutable so we maintain a decreasing index.
|
# The are no fixtures with this name applicable for the function.
|
||||||
|
if not fixturedefs:
|
||||||
|
raise FixtureLookupError(argname, self)
|
||||||
index = self._arg2index.get(argname, 0) - 1
|
index = self._arg2index.get(argname, 0) - 1
|
||||||
|
# The fixture requested its own name, but no remaining to override.
|
||||||
if -index > len(fixturedefs):
|
if -index > len(fixturedefs):
|
||||||
raise FixtureLookupError(argname, self)
|
raise FixtureLookupError(argname, self)
|
||||||
self._arg2index[argname] = index
|
self._arg2index[argname] = index
|
||||||
|
@ -503,7 +530,7 @@ class FixtureRequest:
|
||||||
"""Instance (can be None) on which test function was collected."""
|
"""Instance (can be None) on which test function was collected."""
|
||||||
# unittest support hack, see _pytest.unittest.TestCaseFunction.
|
# unittest support hack, see _pytest.unittest.TestCaseFunction.
|
||||||
try:
|
try:
|
||||||
return self._pyfuncitem._testcase
|
return self._pyfuncitem._testcase # type: ignore[attr-defined]
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
function = getattr(self, "function", None)
|
function = getattr(self, "function", None)
|
||||||
return getattr(function, "__self__", None)
|
return getattr(function, "__self__", None)
|
||||||
|
@ -513,7 +540,9 @@ class FixtureRequest:
|
||||||
"""Python module object where the test function was collected."""
|
"""Python module object where the test function was collected."""
|
||||||
if self.scope not in ("function", "class", "module"):
|
if self.scope not in ("function", "class", "module"):
|
||||||
raise AttributeError(f"module not available in {self.scope}-scoped context")
|
raise AttributeError(f"module not available in {self.scope}-scoped context")
|
||||||
return self._pyfuncitem.getparent(_pytest.python.Module).obj
|
mod = self._pyfuncitem.getparent(_pytest.python.Module)
|
||||||
|
assert mod is not None
|
||||||
|
return mod.obj
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def path(self) -> Path:
|
def path(self) -> Path:
|
||||||
|
@ -829,7 +858,9 @@ class FixtureLookupError(LookupError):
|
||||||
if msg is None:
|
if msg is None:
|
||||||
fm = self.request._fixturemanager
|
fm = self.request._fixturemanager
|
||||||
available = set()
|
available = set()
|
||||||
parentid = self.request._pyfuncitem.parent.nodeid
|
parent = self.request._pyfuncitem.parent
|
||||||
|
assert parent is not None
|
||||||
|
parentid = parent.nodeid
|
||||||
for name, fixturedefs in fm._arg2fixturedefs.items():
|
for name, fixturedefs in fm._arg2fixturedefs.items():
|
||||||
faclist = list(fm._matchfactories(fixturedefs, parentid))
|
faclist = list(fm._matchfactories(fixturedefs, parentid))
|
||||||
if faclist:
|
if faclist:
|
||||||
|
@ -976,15 +1007,15 @@ class FixtureDef(Generic[FixtureValue]):
|
||||||
# directory path relative to the rootdir.
|
# directory path relative to the rootdir.
|
||||||
#
|
#
|
||||||
# For other plugins, the baseid is the empty string (always matches).
|
# For other plugins, the baseid is the empty string (always matches).
|
||||||
self.baseid = baseid or ""
|
self.baseid: Final = baseid or ""
|
||||||
# Whether the fixture was found from a node or a conftest in the
|
# Whether the fixture was found from a node or a conftest in the
|
||||||
# collection tree. Will be false for fixtures defined in non-conftest
|
# collection tree. Will be false for fixtures defined in non-conftest
|
||||||
# plugins.
|
# plugins.
|
||||||
self.has_location = baseid is not None
|
self.has_location: Final = baseid is not None
|
||||||
# The fixture factory function.
|
# The fixture factory function.
|
||||||
self.func = func
|
self.func: Final = func
|
||||||
# The name by which the fixture may be requested.
|
# The name by which the fixture may be requested.
|
||||||
self.argname = argname
|
self.argname: Final = argname
|
||||||
if scope is None:
|
if scope is None:
|
||||||
scope = Scope.Function
|
scope = Scope.Function
|
||||||
elif callable(scope):
|
elif callable(scope):
|
||||||
|
@ -993,23 +1024,23 @@ class FixtureDef(Generic[FixtureValue]):
|
||||||
scope = Scope.from_user(
|
scope = Scope.from_user(
|
||||||
scope, descr=f"Fixture '{func.__name__}'", where=baseid
|
scope, descr=f"Fixture '{func.__name__}'", where=baseid
|
||||||
)
|
)
|
||||||
self._scope = scope
|
self._scope: Final = scope
|
||||||
# If the fixture is directly parametrized, the parameter values.
|
# If the fixture is directly parametrized, the parameter values.
|
||||||
self.params: Optional[Sequence[object]] = params
|
self.params: Final = params
|
||||||
# If the fixture is directly parametrized, a tuple of explicit IDs to
|
# If the fixture is directly parametrized, a tuple of explicit IDs to
|
||||||
# assign to the parameter values, or a callable to generate an ID given
|
# assign to the parameter values, or a callable to generate an ID given
|
||||||
# a parameter value.
|
# a parameter value.
|
||||||
self.ids = ids
|
self.ids: Final = ids
|
||||||
# The names requested by the fixtures.
|
# The names requested by the fixtures.
|
||||||
self.argnames = getfuncargnames(func, name=argname, is_method=unittest)
|
self.argnames: Final = getfuncargnames(func, name=argname, is_method=unittest)
|
||||||
# Whether the fixture was collected from a unittest TestCase class.
|
# Whether the fixture was collected from a unittest TestCase class.
|
||||||
# Note that it really only makes sense to define autouse fixtures in
|
# Note that it really only makes sense to define autouse fixtures in
|
||||||
# unittest TestCases.
|
# unittest TestCases.
|
||||||
self.unittest = unittest
|
self.unittest: Final = unittest
|
||||||
# If the fixture was executed, the current value of the fixture.
|
# If the fixture was executed, the current value of the fixture.
|
||||||
# Can change if the fixture is executed with different parameters.
|
# Can change if the fixture is executed with different parameters.
|
||||||
self.cached_result: Optional[_FixtureCachedResult[FixtureValue]] = None
|
self.cached_result: Optional[_FixtureCachedResult[FixtureValue]] = None
|
||||||
self._finalizers: List[Callable[[], object]] = []
|
self._finalizers: Final[List[Callable[[], object]]] = []
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def scope(self) -> "_ScopeName":
|
def scope(self) -> "_ScopeName":
|
||||||
|
@ -1040,7 +1071,7 @@ class FixtureDef(Generic[FixtureValue]):
|
||||||
# value and remove all finalizers because they may be bound methods
|
# value and remove all finalizers because they may be bound methods
|
||||||
# which will keep instances alive.
|
# which will keep instances alive.
|
||||||
self.cached_result = None
|
self.cached_result = None
|
||||||
self._finalizers = []
|
self._finalizers.clear()
|
||||||
|
|
||||||
def execute(self, request: SubRequest) -> FixtureValue:
|
def execute(self, request: SubRequest) -> FixtureValue:
|
||||||
# Get required arguments and register our own finish()
|
# Get required arguments and register our own finish()
|
||||||
|
@ -1417,10 +1448,14 @@ class FixtureManager:
|
||||||
def __init__(self, session: "Session") -> None:
|
def __init__(self, session: "Session") -> None:
|
||||||
self.session = session
|
self.session = session
|
||||||
self.config: Config = session.config
|
self.config: Config = session.config
|
||||||
self._arg2fixturedefs: Dict[str, List[FixtureDef[Any]]] = {}
|
# Maps a fixture name (argname) to all of the FixtureDefs in the test
|
||||||
self._holderobjseen: Set[object] = set()
|
# suite/plugins defined with this name. Populated by parsefactories().
|
||||||
|
# TODO: The order of the FixtureDefs list of each arg is significant,
|
||||||
|
# explain.
|
||||||
|
self._arg2fixturedefs: Final[Dict[str, List[FixtureDef[Any]]]] = {}
|
||||||
|
self._holderobjseen: Final[Set[object]] = set()
|
||||||
# A mapping from a nodeid to a list of autouse fixtures it defines.
|
# A mapping from a nodeid to a list of autouse fixtures it defines.
|
||||||
self._nodeid_autousenames: Dict[str, List[str]] = {
|
self._nodeid_autousenames: Final[Dict[str, List[str]]] = {
|
||||||
"": self.config.getini("usefixtures"),
|
"": self.config.getini("usefixtures"),
|
||||||
}
|
}
|
||||||
session.config.pluginmanager.register(self, "funcmanage")
|
session.config.pluginmanager.register(self, "funcmanage")
|
||||||
|
@ -1699,11 +1734,16 @@ class FixtureManager:
|
||||||
def getfixturedefs(
|
def getfixturedefs(
|
||||||
self, argname: str, nodeid: str
|
self, argname: str, nodeid: str
|
||||||
) -> Optional[Sequence[FixtureDef[Any]]]:
|
) -> Optional[Sequence[FixtureDef[Any]]]:
|
||||||
"""Get a list of fixtures which are applicable to the given node id.
|
"""Get FixtureDefs for a fixture name which are applicable
|
||||||
|
to a given node.
|
||||||
|
|
||||||
:param str argname: Name of the fixture to search for.
|
Returns None if there are no fixtures at all defined with the given
|
||||||
:param str nodeid: Full node id of the requesting test.
|
name. (This is different from the case in which there are fixtures
|
||||||
:rtype: Sequence[FixtureDef]
|
with the given name, but none applicable to the node. In this case,
|
||||||
|
an empty result is returned).
|
||||||
|
|
||||||
|
:param argname: Name of the fixture to search for.
|
||||||
|
:param nodeid: Full node id of the requesting test.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
fixturedefs = self._arg2fixturedefs[argname]
|
fixturedefs = self._arg2fixturedefs[argname]
|
||||||
|
|
|
@ -699,6 +699,7 @@ class TestRequestBasic:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
(item1,) = pytester.genitems([modcol])
|
(item1,) = pytester.genitems([modcol])
|
||||||
|
assert isinstance(item1, Function)
|
||||||
assert item1.name == "test_method"
|
assert item1.name == "test_method"
|
||||||
arg2fixturedefs = fixtures.FixtureRequest(
|
arg2fixturedefs = fixtures.FixtureRequest(
|
||||||
item1, _ispytest=True
|
item1, _ispytest=True
|
||||||
|
@ -967,6 +968,7 @@ class TestRequestBasic:
|
||||||
def test_request_getmodulepath(self, pytester: Pytester) -> None:
|
def test_request_getmodulepath(self, pytester: Pytester) -> None:
|
||||||
modcol = pytester.getmodulecol("def test_somefunc(): pass")
|
modcol = pytester.getmodulecol("def test_somefunc(): pass")
|
||||||
(item,) = pytester.genitems([modcol])
|
(item,) = pytester.genitems([modcol])
|
||||||
|
assert isinstance(item, Function)
|
||||||
req = fixtures.FixtureRequest(item, _ispytest=True)
|
req = fixtures.FixtureRequest(item, _ispytest=True)
|
||||||
assert req.path == modcol.path
|
assert req.path == modcol.path
|
||||||
|
|
||||||
|
@ -1125,6 +1127,7 @@ class TestRequestMarking:
|
||||||
pass
|
pass
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
assert isinstance(item1, Function)
|
||||||
req1 = fixtures.FixtureRequest(item1, _ispytest=True)
|
req1 = fixtures.FixtureRequest(item1, _ispytest=True)
|
||||||
assert "xfail" not in item1.keywords
|
assert "xfail" not in item1.keywords
|
||||||
req1.applymarker(pytest.mark.xfail)
|
req1.applymarker(pytest.mark.xfail)
|
||||||
|
@ -4009,6 +4012,7 @@ class TestScopeOrdering:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
items, _ = pytester.inline_genitems()
|
items, _ = pytester.inline_genitems()
|
||||||
|
assert isinstance(items[0], Function)
|
||||||
request = FixtureRequest(items[0], _ispytest=True)
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
assert request.fixturenames == "m1 f1".split()
|
assert request.fixturenames == "m1 f1".split()
|
||||||
|
|
||||||
|
@ -4057,6 +4061,7 @@ class TestScopeOrdering:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
items, _ = pytester.inline_genitems()
|
items, _ = pytester.inline_genitems()
|
||||||
|
assert isinstance(items[0], Function)
|
||||||
request = FixtureRequest(items[0], _ispytest=True)
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
# order of fixtures based on their scope and position in the parameter list
|
# order of fixtures based on their scope and position in the parameter list
|
||||||
assert (
|
assert (
|
||||||
|
@ -4084,6 +4089,7 @@ class TestScopeOrdering:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
items, _ = pytester.inline_genitems()
|
items, _ = pytester.inline_genitems()
|
||||||
|
assert isinstance(items[0], Function)
|
||||||
request = FixtureRequest(items[0], _ispytest=True)
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
assert request.fixturenames == "m1 f1".split()
|
assert request.fixturenames == "m1 f1".split()
|
||||||
|
|
||||||
|
@ -4117,6 +4123,7 @@ class TestScopeOrdering:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
items, _ = pytester.inline_genitems()
|
items, _ = pytester.inline_genitems()
|
||||||
|
assert isinstance(items[0], Function)
|
||||||
request = FixtureRequest(items[0], _ispytest=True)
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
assert request.fixturenames == "s1 m1 c1 f2 f1".split()
|
assert request.fixturenames == "s1 m1 c1 f2 f1".split()
|
||||||
|
|
||||||
|
@ -4159,6 +4166,7 @@ class TestScopeOrdering:
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
items, _ = pytester.inline_genitems()
|
items, _ = pytester.inline_genitems()
|
||||||
|
assert isinstance(items[0], Function)
|
||||||
request = FixtureRequest(items[0], _ispytest=True)
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
assert request.fixturenames == "p_sub m_conf m_sub m_test f1".split()
|
assert request.fixturenames == "p_sub m_conf m_sub m_test f1".split()
|
||||||
|
|
||||||
|
@ -4203,6 +4211,7 @@ class TestScopeOrdering:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
items, _ = pytester.inline_genitems()
|
items, _ = pytester.inline_genitems()
|
||||||
|
assert isinstance(items[0], Function)
|
||||||
request = FixtureRequest(items[0], _ispytest=True)
|
request = FixtureRequest(items[0], _ispytest=True)
|
||||||
assert request.fixturenames == "s1 p1 m1 m2 c1 f2 f1".split()
|
assert request.fixturenames == "s1 p1 m1 m2 c1 f2 f1".split()
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,7 @@ def test_cache_makedir(cache: pytest.Cache) -> None:
|
||||||
def test_fixturerequest_getmodulepath(pytester: pytest.Pytester) -> None:
|
def test_fixturerequest_getmodulepath(pytester: pytest.Pytester) -> None:
|
||||||
modcol = pytester.getmodulecol("def test_somefunc(): pass")
|
modcol = pytester.getmodulecol("def test_somefunc(): pass")
|
||||||
(item,) = pytester.genitems([modcol])
|
(item,) = pytester.genitems([modcol])
|
||||||
|
assert isinstance(item, pytest.Function)
|
||||||
req = pytest.FixtureRequest(item, _ispytest=True)
|
req = pytest.FixtureRequest(item, _ispytest=True)
|
||||||
assert req.path == modcol.path
|
assert req.path == modcol.path
|
||||||
assert req.fspath == modcol.fspath # type: ignore[attr-defined]
|
assert req.fspath == modcol.fspath # type: ignore[attr-defined]
|
||||||
|
|
Loading…
Reference in New Issue