@@ -354,16 +354,27 @@ def get_direct_param_fixture_func(request: "FixtureRequest") -> Any:
354
354
355
355
@dataclasses .dataclass (frozen = True )
356
356
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
+
357
369
__slots__ = ("argnames" , "initialnames" , "names_closure" , "name2fixturedefs" )
358
370
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.
361
372
argnames : Tuple [str , ...]
362
- # Fixture names that the function immediately requires. These include
373
+ # Fixture names that the item immediately requires. These include
363
374
# argnames + fixture names specified via usefixtures and via autouse=True in
364
375
# fixture definitions.
365
376
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.
367
378
# Note: can't include dynamic dependencies (`request.getfixturevalue` calls).
368
379
names_closure : List [str ]
369
380
# A map from a fixture name in the transitive closure to the FixtureDefs
@@ -547,8 +558,7 @@ def path(self) -> Path:
547
558
"""Path where the test function was collected."""
548
559
if self .scope not in ("function" , "class" , "module" , "package" ):
549
560
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
552
562
553
563
@property
554
564
def keywords (self ) -> MutableMapping [str , Any ]:
@@ -620,20 +630,17 @@ def getfixturevalue(self, argname: str) -> Any:
620
630
def _get_active_fixturedef (
621
631
self , argname : str
622
632
) -> 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 :
626
635
try :
627
636
fixturedef = self ._getnextfixturedef (argname )
628
637
except FixtureLookupError :
629
638
if argname == "request" :
630
639
cached_result = (self , [0 ], None )
631
640
return PseudoFixtureDef (cached_result , Scope .Function )
632
641
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
637
644
return fixturedef
638
645
639
646
def _get_fixturestack (self ) -> List ["FixtureDef[Any]" ]:
@@ -1039,8 +1046,6 @@ def __init__(
1039
1046
# The names requested by the fixtures.
1040
1047
self .argnames : Final = getfuncargnames (func , name = argname , is_method = unittest )
1041
1048
# Whether the fixture was collected from a unittest TestCase class.
1042
- # Note that it really only makes sense to define autouse fixtures in
1043
- # unittest TestCases.
1044
1049
self .unittest : Final = unittest
1045
1050
# If the fixture was executed, the current value of the fixture.
1046
1051
# Can change if the fixture is executed with different parameters.
@@ -1468,8 +1473,26 @@ def _get_direct_parametrize_args(self, node: nodes.Node) -> List[str]:
1468
1473
return parametrize_argnames
1469
1474
1470
1475
def getfixtureinfo (
1471
- self , node : nodes .Node , func , cls , funcargs : bool = True
1476
+ self ,
1477
+ node : nodes .Item ,
1478
+ func : Callable [..., object ],
1479
+ cls : Optional [type ],
1480
+ funcargs : bool = True ,
1472
1481
) -> FuncFixtureInfo :
1482
+ """Calculate the :class:`FuncFixtureInfo` for an item.
1483
+
1484
+ If ``funcargs`` is false, or if the item sets an attribute
1485
+ ``nofuncargs = True``, then ``func`` is not examined at all.
1486
+
1487
+ :param node:
1488
+ The item requesting the fixtures.
1489
+ :param func:
1490
+ The item's function.
1491
+ :param cls:
1492
+ If the function is a method, the method's class.
1493
+ :param funcargs:
1494
+ Whether to look into func's parameters as fixture requests.
1495
+ """
1473
1496
if funcargs and not getattr (node , "nofuncargs" , False ):
1474
1497
argnames = getfuncargnames (func , name = node .name , cls = cls )
1475
1498
else :
@@ -1479,8 +1502,7 @@ def getfixtureinfo(
1479
1502
arg for mark in node .iter_markers (name = "usefixtures" ) for arg in mark .args
1480
1503
)
1481
1504
initialnames = usefixtures + argnames
1482
- fm = node .session ._fixturemanager
1483
- initialnames , names_closure , arg2fixturedefs = fm .getfixtureclosure (
1505
+ initialnames , names_closure , arg2fixturedefs = self .getfixtureclosure (
1484
1506
initialnames , node , ignore_args = self ._get_direct_parametrize_args (node )
1485
1507
)
1486
1508
return FuncFixtureInfo (argnames , initialnames , names_closure , arg2fixturedefs )
0 commit comments