1
1
from __future__ import absolute_import , division , print_function
2
2
3
+ import functools
3
4
import inspect
4
5
import sys
5
6
import warnings
7
+ from collections import OrderedDict
6
8
9
+ import attr
7
10
import py
8
11
from py ._code .code import FormattedExcinfo
9
12
10
- import attr
11
13
import _pytest
12
14
from _pytest import nodes
13
15
from _pytest ._code .code import TerminalRepr
22
24
from _pytest .outcomes import fail , TEST_OUTCOME
23
25
24
26
25
- from collections import OrderedDict
26
-
27
-
28
27
def pytest_sessionstart (session ):
29
28
import _pytest .python
30
29
@@ -519,7 +518,7 @@ def _getfixturevalue(self, fixturedef):
519
518
val = fixturedef .execute (request = subrequest )
520
519
finally :
521
520
# if fixture function failed it might have registered finalizers
522
- self .session ._setupstate .addfinalizer (fixturedef .finish ,
521
+ self .session ._setupstate .addfinalizer (functools . partial ( fixturedef .finish , request = subrequest ) ,
523
522
subrequest .node )
524
523
return val
525
524
@@ -573,7 +572,6 @@ def __init__(self, request, scope, param, param_index, fixturedef):
573
572
self .param_index = param_index
574
573
self .scope = scope
575
574
self ._fixturedef = fixturedef
576
- self .addfinalizer = fixturedef .addfinalizer
577
575
self ._pyfuncitem = request ._pyfuncitem
578
576
self ._fixture_values = request ._fixture_values
579
577
self ._fixture_defs = request ._fixture_defs
@@ -584,6 +582,9 @@ def __init__(self, request, scope, param, param_index, fixturedef):
584
582
def __repr__ (self ):
585
583
return "<SubRequest %r for %r>" % (self .fixturename , self ._pyfuncitem )
586
584
585
+ def addfinalizer (self , finalizer ):
586
+ self ._fixturedef .addfinalizer (finalizer )
587
+
587
588
588
589
class ScopeMismatchError (Exception ):
589
590
""" A fixture function tries to use a different fixture function which
@@ -734,17 +735,17 @@ def __init__(self, fixturemanager, baseid, argname, func, scope, params,
734
735
self .argnames = getfuncargnames (func , is_method = unittest )
735
736
self .unittest = unittest
736
737
self .ids = ids
737
- self ._finalizer = []
738
+ self ._finalizers = []
738
739
739
740
def addfinalizer (self , finalizer ):
740
- self ._finalizer .append (finalizer )
741
+ self ._finalizers .append (finalizer )
741
742
742
- def finish (self ):
743
+ def finish (self , request ):
743
744
exceptions = []
744
745
try :
745
- while self ._finalizer :
746
+ while self ._finalizers :
746
747
try :
747
- func = self ._finalizer .pop ()
748
+ func = self ._finalizers .pop ()
748
749
func ()
749
750
except : # noqa
750
751
exceptions .append (sys .exc_info ())
@@ -754,20 +755,23 @@ def finish(self):
754
755
py .builtin ._reraise (* e )
755
756
756
757
finally :
757
- ihook = self ._fixturemanager .session .ihook
758
- ihook .pytest_fixture_post_finalizer (fixturedef = self )
758
+ hook = self ._fixturemanager .session .gethookproxy ( request . node . fspath )
759
+ hook .pytest_fixture_post_finalizer (fixturedef = self , request = request )
759
760
# even if finalization fails, we invalidate
760
- # the cached fixture value
761
+ # the cached fixture value and remove
762
+ # all finalizers because they may be bound methods which will
763
+ # keep instances alive
761
764
if hasattr (self , "cached_result" ):
762
765
del self .cached_result
766
+ self ._finalizers = []
763
767
764
768
def execute (self , request ):
765
769
# get required arguments and register our own finish()
766
770
# with their finalization
767
771
for argname in self .argnames :
768
772
fixturedef = request ._get_active_fixturedef (argname )
769
773
if argname != "request" :
770
- fixturedef .addfinalizer (self .finish )
774
+ fixturedef .addfinalizer (functools . partial ( self .finish , request = request ) )
771
775
772
776
my_cache_key = request .param_index
773
777
cached_result = getattr (self , "cached_result" , None )
@@ -780,11 +784,11 @@ def execute(self, request):
780
784
return result
781
785
# we have a previous but differently parametrized fixture instance
782
786
# so we need to tear it down before creating a new one
783
- self .finish ()
787
+ self .finish (request )
784
788
assert not hasattr (self , "cached_result" )
785
789
786
- ihook = self ._fixturemanager .session .ihook
787
- return ihook .pytest_fixture_setup (fixturedef = self , request = request )
790
+ hook = self ._fixturemanager .session .gethookproxy ( request . node . fspath )
791
+ return hook .pytest_fixture_setup (fixturedef = self , request = request )
788
792
789
793
def __repr__ (self ):
790
794
return ("<FixtureDef name=%r scope=%r baseid=%r >" %
0 commit comments