@@ -543,6 +543,11 @@ def getfixturevalue(self, argname: str) -> Any:
543
543
:raises pytest.FixtureLookupError:
544
544
If the given fixture could not be found.
545
545
"""
546
+ # Note that in addition to the use case described in the docstring,
547
+ # getfixturevalue() is also called by pytest itself during item and fixture
548
+ # setup to evaluate the fixtures that are requested statically
549
+ # (using function parameters, autouse, etc).
550
+
546
551
fixturedef = self ._get_active_fixturedef (argname )
547
552
assert fixturedef .cached_result is not None , (
548
553
f'The fixture value for "{ argname } " is not available. '
@@ -587,9 +592,8 @@ def _compute_fixture_value(self, fixturedef: "FixtureDef[object]") -> None:
587
592
"""Create a SubRequest based on "self" and call the execute method
588
593
of the given FixtureDef object.
589
594
590
- This will force the FixtureDef object to throw away any previous
591
- results and compute a new fixture value, which will be stored into
592
- the FixtureDef object itself.
595
+ If the FixtureDef has cached the result it will do nothing, otherwise it will
596
+ setup and run the fixture, cache the value, and schedule a finalizer for it.
593
597
"""
594
598
# prepare a subrequest object before calling fixture function
595
599
# (latter managed by fixturedef)
@@ -646,18 +650,9 @@ def _compute_fixture_value(self, fixturedef: "FixtureDef[object]") -> None:
646
650
subrequest = SubRequest (
647
651
self , scope , param , param_index , fixturedef , _ispytest = True
648
652
)
649
- try :
650
- # Call the fixture function.
651
- fixturedef .execute (request = subrequest )
652
- finally :
653
- self ._schedule_finalizers (fixturedef , subrequest )
654
653
655
- def _schedule_finalizers (
656
- self , fixturedef : "FixtureDef[object]" , subrequest : "SubRequest"
657
- ) -> None :
658
- # If fixture function failed it might have registered finalizers.
659
- finalizer = functools .partial (fixturedef .finish , request = subrequest )
660
- subrequest .node .addfinalizer (finalizer )
654
+ # Make sure the fixture value is cached, running it if it isn't
655
+ fixturedef .execute (request = subrequest )
661
656
662
657
663
658
@final
@@ -788,21 +783,6 @@ def _format_fixturedef_line(self, fixturedef: "FixtureDef[object]") -> str:
788
783
def addfinalizer (self , finalizer : Callable [[], object ]) -> None :
789
784
self ._fixturedef .addfinalizer (finalizer )
790
785
791
- def _schedule_finalizers (
792
- self , fixturedef : "FixtureDef[object]" , subrequest : "SubRequest"
793
- ) -> None :
794
- # If the executing fixturedef was not explicitly requested in the argument list (via
795
- # getfixturevalue inside the fixture call) then ensure this fixture def will be finished
796
- # first.
797
- if (
798
- fixturedef .argname not in self ._fixture_defs
799
- and fixturedef .argname not in self ._pyfuncitem .fixturenames
800
- ):
801
- fixturedef .addfinalizer (
802
- functools .partial (self ._fixturedef .finish , request = self )
803
- )
804
- super ()._schedule_finalizers (fixturedef , subrequest )
805
-
806
786
807
787
@final
808
788
class FixtureLookupError (LookupError ):
@@ -1055,12 +1035,13 @@ def finish(self, request: SubRequest) -> None:
1055
1035
raise BaseExceptionGroup (msg , exceptions [::- 1 ])
1056
1036
1057
1037
def execute (self , request : SubRequest ) -> FixtureValue :
1038
+ finalizer = functools .partial (self .finish , request = request )
1058
1039
# Get required arguments and register our own finish()
1059
1040
# with their finalization.
1060
1041
for argname in self .argnames :
1061
1042
fixturedef = request ._get_active_fixturedef (argname )
1062
1043
if not isinstance (fixturedef , PseudoFixtureDef ):
1063
- fixturedef .addfinalizer (functools . partial ( self . finish , request = request ) )
1044
+ fixturedef .addfinalizer (finalizer )
1064
1045
1065
1046
my_cache_key = self .cache_key (request )
1066
1047
if self .cached_result is not None :
@@ -1080,7 +1061,14 @@ def execute(self, request: SubRequest) -> FixtureValue:
1080
1061
assert self .cached_result is None
1081
1062
1082
1063
ihook = request .node .ihook
1083
- result = ihook .pytest_fixture_setup (fixturedef = self , request = request )
1064
+ try :
1065
+ # Setup the fixture, run the code in it, and cache the value
1066
+ # in self.cached_result
1067
+ result = ihook .pytest_fixture_setup (fixturedef = self , request = request )
1068
+ finally :
1069
+ # schedule our finalizer, even if the setup failed
1070
+ request .node .addfinalizer (finalizer )
1071
+
1084
1072
return result
1085
1073
1086
1074
def cache_key (self , request : SubRequest ) -> object :
0 commit comments