58
58
from _pytest .config .argparsing import Parser
59
59
from _pytest .deprecated import check_ispytest
60
60
from _pytest .deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH
61
+ from _pytest .deprecated import INSTANCE_COLLECTOR
61
62
from _pytest .fixtures import FuncFixtureInfo
62
63
from _pytest .main import Session
63
64
from _pytest .mark import MARK_GEN
@@ -275,20 +276,14 @@ def cls(self):
275
276
node = self .getparent (Class )
276
277
return node .obj if node is not None else None
277
278
278
- @property
279
- def instance (self ):
280
- """Python instance object this node was collected from (can be None)."""
281
- node = self .getparent (Instance )
282
- return node .obj if node is not None else None
283
-
284
279
@property
285
280
def obj (self ):
286
281
"""Underlying Python object."""
287
282
obj = getattr (self , "_obj" , None )
288
283
if obj is None :
289
284
self ._obj = obj = self ._getobj ()
290
285
# XXX evil hack
291
- # used to avoid Instance collector marker duplication
286
+ # used to avoid Function marker duplication
292
287
if self ._ALLOW_MARKERS :
293
288
self .own_markers .extend (get_unpacked_marks (self .obj ))
294
289
return obj
@@ -310,8 +305,6 @@ def getmodpath(self, stopatmodule: bool = True, includemodule: bool = False) ->
310
305
chain .reverse ()
311
306
parts = []
312
307
for node in chain :
313
- if isinstance (node , Instance ):
314
- continue
315
308
name = node .name
316
309
if isinstance (node , Module ):
317
310
name = os .path .splitext (name )[0 ]
@@ -410,8 +403,9 @@ def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
410
403
411
404
# Avoid random getattrs and peek in the __dict__ instead.
412
405
dicts = [getattr (self .obj , "__dict__" , {})]
413
- for basecls in self .obj .__class__ .__mro__ :
414
- dicts .append (basecls .__dict__ )
406
+ if isinstance (self .obj , type ):
407
+ for basecls in self .obj .__mro__ :
408
+ dicts .append (basecls .__dict__ )
415
409
416
410
# In each class, nodes should be definition ordered. Since Python 3.6,
417
411
# __dict__ is definition ordered.
@@ -491,7 +485,6 @@ def _genfunctions(self, name: str, funcobj) -> Iterator["Function"]:
491
485
self ,
492
486
name = subname ,
493
487
callspec = callspec ,
494
- callobj = funcobj ,
495
488
fixtureinfo = fixtureinfo ,
496
489
keywords = {callspec .id : True },
497
490
originalname = name ,
@@ -776,6 +769,9 @@ def from_parent(cls, parent, *, name, obj=None, **kw):
776
769
"""The public constructor."""
777
770
return super ().from_parent (name = name , parent = parent , ** kw )
778
771
772
+ def newinstance (self ):
773
+ return self .obj ()
774
+
779
775
def collect (self ) -> Iterable [Union [nodes .Item , nodes .Collector ]]:
780
776
if not safe_getattr (self .obj , "__test__" , True ):
781
777
return []
@@ -803,7 +799,9 @@ def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]:
803
799
self ._inject_setup_class_fixture ()
804
800
self ._inject_setup_method_fixture ()
805
801
806
- return [Instance .from_parent (self , name = "()" )]
802
+ self .session ._fixturemanager .parsefactories (self .newinstance (), self .nodeid )
803
+
804
+ return super ().collect ()
807
805
808
806
def _inject_setup_class_fixture (self ) -> None :
809
807
"""Inject a hidden autouse, class scoped fixture into the collected class object
@@ -874,25 +872,22 @@ def xunit_setup_method_fixture(self, request) -> Generator[None, None, None]:
874
872
self .obj .__pytest_setup_method = xunit_setup_method_fixture
875
873
876
874
877
- class Instance ( PyCollector ) :
878
- _ALLOW_MARKERS = False # hack, destroy later
879
- # Instances share the object with their parents in a way
880
- # that duplicates markers instances if not taken out
881
- # can be removed at node structure reorganization time.
875
+ class InstanceDummy :
876
+ """Instance used to be a node type between Class and Function. It has been
877
+ removed in pytest 7.0. Some plugins exist which reference `pytest.Instance`
878
+ only to ignore it; this dummy class keeps them working. This will be removed
879
+ in pytest 8."""
882
880
883
- def _getobj (self ):
884
- # TODO: Improve the type of `parent` such that assert/ignore aren't needed.
885
- assert self .parent is not None
886
- obj = self .parent .obj # type: ignore[attr-defined]
887
- return obj ()
881
+ pass
888
882
889
- def collect (self ) -> Iterable [Union [nodes .Item , nodes .Collector ]]:
890
- self .session ._fixturemanager .parsefactories (self )
891
- return super ().collect ()
892
883
893
- def newinstance (self ):
894
- self .obj = self ._getobj ()
895
- return self .obj
884
+ # Note: module __getattr__ only works on Python>=3.7. Unfortunately
885
+ # we can't provide this deprecation warning on Python 3.6.
886
+ def __getattr__ (name : str ) -> object :
887
+ if name == "Instance" :
888
+ warnings .warn (INSTANCE_COLLECTOR , 2 )
889
+ return InstanceDummy
890
+ raise AttributeError (f"module { __name__ } has no attribute { name } " )
896
891
897
892
898
893
def hasinit (obj : object ) -> bool :
@@ -1686,9 +1681,23 @@ def function(self):
1686
1681
"""Underlying python 'function' object."""
1687
1682
return getimfunc (self .obj )
1688
1683
1684
+ @property
1685
+ def instance (self ):
1686
+ """Python instance object the function is bound to.
1687
+
1688
+ Returns None if not a test method, e.g. for a standalone test function
1689
+ or a staticmethod.
1690
+ """
1691
+ return getattr (self .obj , "__self__" , None )
1692
+
1689
1693
def _getobj (self ):
1690
1694
assert self .parent is not None
1691
- return getattr (self .parent .obj , self .originalname ) # type: ignore[attr-defined]
1695
+ if isinstance (self .parent , Class ):
1696
+ # Each Function gets a fresh class instance.
1697
+ parent_obj = self .parent .newinstance ()
1698
+ else :
1699
+ parent_obj = self .parent .obj # type: ignore[attr-defined]
1700
+ return getattr (parent_obj , self .originalname )
1692
1701
1693
1702
@property
1694
1703
def _pyfuncitem (self ):
@@ -1700,9 +1709,6 @@ def runtest(self) -> None:
1700
1709
self .ihook .pytest_pyfunc_call (pyfuncitem = self )
1701
1710
1702
1711
def setup (self ) -> None :
1703
- if isinstance (self .parent , Instance ):
1704
- self .parent .newinstance ()
1705
- self .obj = self ._getobj ()
1706
1712
self ._request ._fillfixtures ()
1707
1713
1708
1714
def _prunetraceback (self , excinfo : ExceptionInfo [BaseException ]) -> None :
0 commit comments