1616
1717__all__ = ["filter" , "fnmatch" , "fnmatchcase" , "translate" ]
1818
19- # Build a thread-safe incrementing counter to help create unique regexp group
20- # names across calls.
21- from itertools import count
22- _nextgroupnum = count ().__next__
23- del count
24-
2519def fnmatch (name , pat ):
2620 """Test whether FILENAME matches PATTERN.
2721
@@ -41,7 +35,7 @@ def fnmatch(name, pat):
4135 pat = os .path .normcase (pat )
4236 return fnmatchcase (name , pat )
4337
44- @functools .lru_cache (maxsize = 256 , typed = True )
38+ @functools .lru_cache (maxsize = 32768 , typed = True )
4539def _compile_pattern (pat ):
4640 if isinstance (pat , bytes ):
4741 pat_str = str (pat , 'ISO-8859-1' )
@@ -84,6 +78,11 @@ def translate(pat):
8478 """
8579
8680 STAR = object ()
81+ parts = _translate (pat , STAR , '.' )
82+ return _join_translated_parts (parts , STAR )
83+
84+
85+ def _translate (pat , STAR , QUESTION_MARK ):
8786 res = []
8887 add = res .append
8988 i , n = 0 , len (pat )
@@ -95,7 +94,7 @@ def translate(pat):
9594 if (not res ) or res [- 1 ] is not STAR :
9695 add (STAR )
9796 elif c == '?' :
98- add ('.' )
97+ add (QUESTION_MARK )
9998 elif c == '[' :
10099 j = i
101100 if j < n and pat [j ] == '!' :
@@ -152,9 +151,11 @@ def translate(pat):
152151 else :
153152 add (re .escape (c ))
154153 assert i == n
154+ return res
155+
155156
157+ def _join_translated_parts (inp , STAR ):
156158 # Deal with STARs.
157- inp = res
158159 res = []
159160 add = res .append
160161 i , n = 0 , len (inp )
@@ -165,17 +166,10 @@ def translate(pat):
165166 # Now deal with STAR fixed STAR fixed ...
166167 # For an interior `STAR fixed` pairing, we want to do a minimal
167168 # .*? match followed by `fixed`, with no possibility of backtracking.
168- # We can't spell that directly, but can trick it into working by matching
169- # .*?fixed
170- # in a lookahead assertion, save the matched part in a group, then
171- # consume that group via a backreference. If the overall match fails,
172- # the lookahead assertion won't try alternatives. So the translation is:
173- # (?=(?P<name>.*?fixed))(?P=name)
174- # Group names are created as needed: g0, g1, g2, ...
175- # The numbers are obtained from _nextgroupnum() to ensure they're unique
176- # across calls and across threads. This is because people rely on the
177- # undocumented ability to join multiple translate() results together via
178- # "|" to build large regexps matching "one of many" shell patterns.
169+ # Atomic groups ("(?>...)") allow us to spell that directly.
170+ # Note: people rely on the undocumented ability to join multiple
171+ # translate() results together via "|" to build large regexps matching
172+ # "one of many" shell patterns.
179173 while i < n :
180174 assert inp [i ] is STAR
181175 i += 1
@@ -192,8 +186,7 @@ def translate(pat):
192186 add (".*" )
193187 add (fixed )
194188 else :
195- groupnum = _nextgroupnum ()
196- add (f"(?=(?P<g{ groupnum } >.*?{ fixed } ))(?P=g{ groupnum } )" )
189+ add (f"(?>.*?{ fixed } )" )
197190 assert i == n
198191 res = "" .join (res )
199192 return fr'(?s:{ res } )\Z'
0 commit comments