Skip to content

Commit 0e0ed2a

Browse files
committed
fixtures: some code comments and minor improvements
1 parent a3fbf24 commit 0e0ed2a

File tree

2 files changed

+41
-17
lines changed

2 files changed

+41
-17
lines changed

src/_pytest/compat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def num_mock_patch_args(function) -> int:
102102

103103

104104
def getfuncargnames(
105-
function: Callable[..., Any],
105+
function: Callable[..., object],
106106
*,
107107
name: str = "",
108108
is_method: bool = False,

src/_pytest/fixtures.py

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -354,16 +354,27 @@ def get_direct_param_fixture_func(request: "FixtureRequest") -> Any:
354354

355355
@dataclasses.dataclass(frozen=True)
356356
class FuncFixtureInfo:
357+
"""Fixture-related information for a fixture-requesting item (e.g. test
358+
function).
359+
360+
This is used to examine the fixtures which an item requests statically
361+
(known during collection). This includes autouse fixtures, fixtures
362+
requested by the `usefixtures` marker, fixtures requested in the function
363+
parameters, and the transitive closure of these.
364+
365+
An item may also request fixtures dynamically (using `request.getfixturevalue`);
366+
these are not reflected here.
367+
"""
368+
357369
__slots__ = ("argnames", "initialnames", "names_closure", "name2fixturedefs")
358370

359-
# Original function argument names, i.e. fixture names that the function
360-
# requests directly.
371+
# Fixture names that the item requests directly by function parameters.
361372
argnames: Tuple[str, ...]
362-
# Fixture names that the function immediately requires. These include
373+
# Fixture names that the item immediately requires. These include
363374
# argnames + fixture names specified via usefixtures and via autouse=True in
364375
# fixture definitions.
365376
initialnames: Tuple[str, ...]
366-
# The transitive closure of the fixture names that the function requires.
377+
# The transitive closure of the fixture names that the item requires.
367378
# Note: can't include dynamic dependencies (`request.getfixturevalue` calls).
368379
names_closure: List[str]
369380
# A map from a fixture name in the transitive closure to the FixtureDefs
@@ -547,8 +558,7 @@ def path(self) -> Path:
547558
"""Path where the test function was collected."""
548559
if self.scope not in ("function", "class", "module", "package"):
549560
raise AttributeError(f"path not available in {self.scope}-scoped context")
550-
# TODO: Remove ignore once _pyfuncitem is properly typed.
551-
return self._pyfuncitem.path # type: ignore
561+
return self._pyfuncitem.path
552562

553563
@property
554564
def keywords(self) -> MutableMapping[str, Any]:
@@ -620,20 +630,17 @@ def getfixturevalue(self, argname: str) -> Any:
620630
def _get_active_fixturedef(
621631
self, argname: str
622632
) -> Union["FixtureDef[object]", PseudoFixtureDef[object]]:
623-
try:
624-
return self._fixture_defs[argname]
625-
except KeyError:
633+
fixturedef = self._fixture_defs.get(argname)
634+
if fixturedef is None:
626635
try:
627636
fixturedef = self._getnextfixturedef(argname)
628637
except FixtureLookupError:
629638
if argname == "request":
630639
cached_result = (self, [0], None)
631640
return PseudoFixtureDef(cached_result, Scope.Function)
632641
raise
633-
# Remove indent to prevent the python3 exception
634-
# from leaking into the call.
635-
self._compute_fixture_value(fixturedef)
636-
self._fixture_defs[argname] = fixturedef
642+
self._compute_fixture_value(fixturedef)
643+
self._fixture_defs[argname] = fixturedef
637644
return fixturedef
638645

639646
def _get_fixturestack(self) -> List["FixtureDef[Any]"]:
@@ -1467,8 +1474,26 @@ def _get_direct_parametrize_args(self, node: nodes.Node) -> List[str]:
14671474
return parametrize_argnames
14681475

14691476
def getfixtureinfo(
1470-
self, node: nodes.Node, func, cls, funcargs: bool = True
1477+
self,
1478+
node: nodes.Item,
1479+
func: Callable[..., object],
1480+
cls: Optional[type],
1481+
funcargs: bool = True,
14711482
) -> FuncFixtureInfo:
1483+
"""Calculate the :class:`FuncFixtureInfo` for an item.
1484+
1485+
If ``funcargs`` is false, or if the item sets an attribute
1486+
``nofuncargs = True``, then ``func`` is not examined at all.
1487+
1488+
:param node:
1489+
The item requesting the fixtures.
1490+
:param func:
1491+
The item's function.
1492+
:param cls:
1493+
If the function is a method, the method's class.
1494+
:param funcargs:
1495+
Whether to look into func's parameters as fixture requests.
1496+
"""
14721497
if funcargs and not getattr(node, "nofuncargs", False):
14731498
argnames = getfuncargnames(func, name=node.name, cls=cls)
14741499
else:
@@ -1478,8 +1503,7 @@ def getfixtureinfo(
14781503
arg for mark in node.iter_markers(name="usefixtures") for arg in mark.args
14791504
)
14801505
initialnames = usefixtures + argnames
1481-
fm = node.session._fixturemanager
1482-
initialnames, names_closure, arg2fixturedefs = fm.getfixtureclosure(
1506+
initialnames, names_closure, arg2fixturedefs = self.getfixtureclosure(
14831507
initialnames, node, ignore_args=self._get_direct_parametrize_args(node)
14841508
)
14851509
return FuncFixtureInfo(argnames, initialnames, names_closure, arg2fixturedefs)

0 commit comments

Comments
 (0)