44
44
from pathlib import Path
45
45
from typing import (
46
46
TYPE_CHECKING ,
47
- Callable ,
48
47
Dict ,
49
48
Iterable ,
50
49
Iterator ,
61
60
from distutils .util import convert_path
62
61
63
62
_Path = Union [str , os .PathLike ]
64
- _Filter = Callable [[str ], bool ]
65
63
StrIter = Iterator [str ]
66
64
67
65
chain_iter = itertools .chain .from_iterable
@@ -75,6 +73,22 @@ def _valid_name(path: _Path) -> bool:
75
73
return os .path .basename (path ).isidentifier ()
76
74
77
75
76
+ class _Filter :
77
+ """
78
+ Given a list of patterns, create a callable that will be true only if
79
+ the input matches at least one of the patterns.
80
+ """
81
+
82
+ def __init__ (self , * patterns : str ):
83
+ self ._patterns = dict .fromkeys (patterns )
84
+
85
+ def __call__ (self , item : str ) -> bool :
86
+ return any (fnmatchcase (item , pat ) for pat in self ._patterns )
87
+
88
+ def __contains__ (self , item : str ) -> bool :
89
+ return item in self ._patterns
90
+
91
+
78
92
class _Finder :
79
93
"""Base class that exposes functionality for module/package finders"""
80
94
@@ -111,23 +125,15 @@ def find(
111
125
return list (
112
126
cls ._find_iter (
113
127
convert_path (str (where )),
114
- cls . _build_filter (* cls .ALWAYS_EXCLUDE , * exclude ),
115
- cls . _build_filter (* include ),
128
+ _Filter (* cls .ALWAYS_EXCLUDE , * exclude ),
129
+ _Filter (* include ),
116
130
)
117
131
)
118
132
119
133
@classmethod
120
134
def _find_iter (cls , where : _Path , exclude : _Filter , include : _Filter ) -> StrIter :
121
135
raise NotImplementedError
122
136
123
- @staticmethod
124
- def _build_filter (* patterns : str ) -> _Filter :
125
- """
126
- Given a list of patterns, return a callable that will be true only if
127
- the input matches at least one of the patterns.
128
- """
129
- return lambda name : any (fnmatchcase (name , pat ) for pat in patterns )
130
-
131
137
132
138
class PackageFinder (_Finder ):
133
139
"""
@@ -160,6 +166,10 @@ def _find_iter(cls, where: _Path, exclude: _Filter, include: _Filter) -> StrIter
160
166
if include (package ) and not exclude (package ):
161
167
yield package
162
168
169
+ # Early pruning if there is nothing else to be scanned
170
+ if f"{ package } *" in exclude or f"{ package } .*" in exclude :
171
+ continue
172
+
163
173
# Keep searching subdirectories, as there may be more packages
164
174
# down there, even if the parent was excluded.
165
175
dirs .append (dir )
0 commit comments