@@ -693,8 +693,53 @@ def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]:
693
693
col = collect_root ._collectfile (argpath , handle_dupes = False )
694
694
if col :
695
695
self ._collection_node_cache1 [argpath ] = col
696
- m = self .matchnodes (col , names )
697
- if not m :
696
+
697
+ matching = []
698
+ work = [
699
+ (col , names )
700
+ ] # type: List[Tuple[Sequence[Union[nodes.Item, nodes.Collector]], Sequence[str]]]
701
+ while work :
702
+ self .trace ("matchnodes" , col , names )
703
+ self .trace .root .indent += 1
704
+
705
+ matchnodes , matchnames = work .pop ()
706
+ for node in matchnodes :
707
+ if not matchnames :
708
+ matching .append (node )
709
+ continue
710
+ if not isinstance (node , nodes .Collector ):
711
+ continue
712
+ key = (type (node ), node .nodeid )
713
+ if key in self ._collection_matchnodes_cache :
714
+ rep = self ._collection_matchnodes_cache [key ]
715
+ else :
716
+ rep = collect_one_node (node )
717
+ self ._collection_matchnodes_cache [key ] = rep
718
+ if rep .passed :
719
+ submatchnodes = []
720
+ for r in rep .result :
721
+ # TODO: Remove parametrized workaround once collection structure contains
722
+ # parametrization.
723
+ if (
724
+ r .name == matchnames [0 ]
725
+ or r .name .split ("[" )[0 ] == matchnames [0 ]
726
+ ):
727
+ submatchnodes .append (r )
728
+ if submatchnodes :
729
+ work .append ((submatchnodes , matchnames [1 :]))
730
+ # XXX Accept IDs that don't have "()" for class instances.
731
+ elif len (rep .result ) == 1 and rep .result [0 ].name == "()" :
732
+ work .append ((rep .result , matchnames ))
733
+ else :
734
+ # Report collection failures here to avoid failing to run some test
735
+ # specified in the command line because the module could not be
736
+ # imported (#134).
737
+ node .ihook .pytest_collectreport (report = rep )
738
+
739
+ self .trace ("matchnodes finished -> " , len (matching ), "nodes" )
740
+ self .trace .root .indent -= 1
741
+
742
+ if not matching :
698
743
report_arg = "::" .join ((str (argpath ), * names ))
699
744
self ._notfound .append ((report_arg , col ))
700
745
continue
@@ -704,68 +749,24 @@ def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]:
704
749
# Module itself, so just use that. If this special case isn't taken, then all
705
750
# the files in the package will be yielded.
706
751
if argpath .basename == "__init__.py" :
707
- assert isinstance (m [0 ], nodes .Collector )
752
+ assert isinstance (matching [0 ], nodes .Collector )
708
753
try :
709
- yield next (iter (m [0 ].collect ()))
754
+ yield next (iter (matching [0 ].collect ()))
710
755
except StopIteration :
711
756
# The package collects nothing with only an __init__.py
712
757
# file in it, which gets ignored by the default
713
758
# "python_files" option.
714
759
pass
715
760
continue
716
- yield from m
761
+
762
+ yield from matching
717
763
718
764
self .trace .root .indent -= 1
719
765
self ._collection_node_cache1 .clear ()
720
766
self ._collection_node_cache2 .clear ()
721
767
self ._collection_matchnodes_cache .clear ()
722
768
self ._collection_pkg_roots .clear ()
723
769
724
- def matchnodes (
725
- self ,
726
- matching : Sequence [Union [nodes .Item , nodes .Collector ]],
727
- names : Sequence [str ],
728
- ) -> Sequence [Union [nodes .Item , nodes .Collector ]]:
729
- result = []
730
- work = [(matching , names )]
731
- while work :
732
- self .trace ("matchnodes" , matching , names )
733
- self .trace .root .indent += 1
734
-
735
- matching , names = work .pop ()
736
- for node in matching :
737
- if not names :
738
- result .append (node )
739
- continue
740
- if not isinstance (node , nodes .Collector ):
741
- continue
742
- key = (type (node ), node .nodeid )
743
- if key in self ._collection_matchnodes_cache :
744
- rep = self ._collection_matchnodes_cache [key ]
745
- else :
746
- rep = collect_one_node (node )
747
- self ._collection_matchnodes_cache [key ] = rep
748
- if rep .passed :
749
- submatching = []
750
- for x in rep .result :
751
- # TODO: Remove parametrized workaround once collection structure contains parametrization.
752
- if x .name == names [0 ] or x .name .split ("[" )[0 ] == names [0 ]:
753
- submatching .append (x )
754
- if submatching :
755
- work .append ((submatching , names [1 :]))
756
- # XXX Accept IDs that don't have "()" for class instances.
757
- elif len (rep .result ) == 1 and rep .result [0 ].name == "()" :
758
- work .append ((rep .result , names ))
759
- else :
760
- # Report collection failures here to avoid failing to run some test
761
- # specified in the command line because the module could not be
762
- # imported (#134).
763
- node .ihook .pytest_collectreport (report = rep )
764
-
765
- self .trace ("matchnodes finished -> " , len (result ), "nodes" )
766
- self .trace .root .indent -= 1
767
- return result
768
-
769
770
def genitems (
770
771
self , node : Union [nodes .Item , nodes .Collector ]
771
772
) -> Iterator [nodes .Item ]:
0 commit comments