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