@@ -54,18 +54,16 @@ def _ignore_error(exception):
54
54
return (getattr (exception , 'errno' , None ) in _IGNORED_ERRNOS or
55
55
getattr (exception , 'winerror' , None ) in _IGNORED_WINERRORS )
56
56
57
-
58
- def _is_wildcard_pattern (pat ):
59
- # Whether this pattern needs actual matching using fnmatch, or can
60
- # be looked up directly as a file.
61
- return "*" in pat or "?" in pat or "[" in pat
62
-
63
57
#
64
58
# Globbing helpers
65
59
#
66
60
61
+ def _is_case_sensitive (flavour ):
62
+ return flavour .normcase ('Aa' ) == 'Aa'
63
+
64
+
67
65
@functools .lru_cache ()
68
- def _make_selector (pattern_parts , flavour ):
66
+ def _make_selector (pattern_parts , case_sensitive ):
69
67
pat = pattern_parts [0 ]
70
68
child_parts = pattern_parts [1 :]
71
69
if not pat :
@@ -74,21 +72,21 @@ def _make_selector(pattern_parts, flavour):
74
72
cls = _RecursiveWildcardSelector
75
73
elif '**' in pat :
76
74
raise ValueError ("Invalid pattern: '**' can only be an entire path component" )
77
- elif _is_wildcard_pattern ( pat ) :
78
- cls = _WildcardSelector
75
+ elif pat == '..' :
76
+ cls = _ParentSelector
79
77
else :
80
- cls = _PreciseSelector
81
- return cls (pat , child_parts , flavour )
78
+ cls = _WildcardSelector
79
+ return cls (pat , child_parts , case_sensitive )
82
80
83
81
84
82
class _Selector :
85
83
"""A selector matches a specific glob pattern part against the children
86
84
of a given path."""
87
85
88
- def __init__ (self , child_parts , flavour ):
86
+ def __init__ (self , child_parts , case_sensitive ):
89
87
self .child_parts = child_parts
90
88
if child_parts :
91
- self .successor = _make_selector (child_parts , flavour )
89
+ self .successor = _make_selector (child_parts , case_sensitive )
92
90
self .dironly = True
93
91
else :
94
92
self .successor = _TerminatingSelector ()
@@ -98,44 +96,36 @@ def select_from(self, parent_path):
98
96
"""Iterate over all child paths of `parent_path` matched by this
99
97
selector. This can contain parent_path itself."""
100
98
path_cls = type (parent_path )
101
- is_dir = path_cls .is_dir
102
- exists = path_cls .exists
103
99
scandir = path_cls ._scandir
104
- normcase = path_cls ._flavour .normcase
105
- if not is_dir (parent_path ):
100
+ if not parent_path .is_dir ():
106
101
return iter ([])
107
- return self ._select_from (parent_path , is_dir , exists , scandir , normcase )
102
+ return self ._select_from (parent_path , scandir )
108
103
109
104
110
105
class _TerminatingSelector :
111
106
112
- def _select_from (self , parent_path , is_dir , exists , scandir , normcase ):
107
+ def _select_from (self , parent_path , scandir ):
113
108
yield parent_path
114
109
115
110
116
- class _PreciseSelector (_Selector ):
111
+ class _ParentSelector (_Selector ):
117
112
118
- def __init__ (self , name , child_parts , flavour ):
119
- self .name = name
120
- _Selector .__init__ (self , child_parts , flavour )
113
+ def __init__ (self , name , child_parts , case_sensitive ):
114
+ _Selector .__init__ (self , child_parts , case_sensitive )
121
115
122
- def _select_from (self , parent_path , is_dir , exists , scandir , normcase ):
123
- try :
124
- path = parent_path ._make_child_relpath (self .name )
125
- if (is_dir if self .dironly else exists )(path ):
126
- for p in self .successor ._select_from (path , is_dir , exists , scandir , normcase ):
127
- yield p
128
- except PermissionError :
129
- return
116
+ def _select_from (self , parent_path , scandir ):
117
+ path = parent_path ._make_child_relpath ('..' )
118
+ return self .successor ._select_from (path , scandir )
130
119
131
120
132
121
class _WildcardSelector (_Selector ):
133
122
134
- def __init__ (self , pat , child_parts , flavour ):
135
- self .match = re .compile (fnmatch .translate (flavour .normcase (pat ))).fullmatch
136
- _Selector .__init__ (self , child_parts , flavour )
123
+ def __init__ (self , pat , child_parts , case_sensitive ):
124
+ flags = re .NOFLAG if case_sensitive else re .IGNORECASE
125
+ self .match = re .compile (fnmatch .translate (pat ), flags = flags ).fullmatch
126
+ _Selector .__init__ (self , child_parts , case_sensitive )
137
127
138
- def _select_from (self , parent_path , is_dir , exists , scandir , normcase ):
128
+ def _select_from (self , parent_path , scandir ):
139
129
try :
140
130
# We must close the scandir() object before proceeding to
141
131
# avoid exhausting file descriptors when globbing deep trees.
@@ -154,20 +144,20 @@ def _select_from(self, parent_path, is_dir, exists, scandir, normcase):
154
144
raise
155
145
continue
156
146
name = entry .name
157
- if self .match (normcase ( name ) ):
147
+ if self .match (name ):
158
148
path = parent_path ._make_child_relpath (name )
159
- for p in self .successor ._select_from (path , is_dir , exists , scandir , normcase ):
149
+ for p in self .successor ._select_from (path , scandir ):
160
150
yield p
161
151
except PermissionError :
162
152
return
163
153
164
154
165
155
class _RecursiveWildcardSelector (_Selector ):
166
156
167
- def __init__ (self , pat , child_parts , flavour ):
168
- _Selector .__init__ (self , child_parts , flavour )
157
+ def __init__ (self , pat , child_parts , case_sensitive ):
158
+ _Selector .__init__ (self , child_parts , case_sensitive )
169
159
170
- def _iterate_directories (self , parent_path , is_dir , scandir ):
160
+ def _iterate_directories (self , parent_path , scandir ):
171
161
yield parent_path
172
162
try :
173
163
# We must close the scandir() object before proceeding to
@@ -183,18 +173,18 @@ def _iterate_directories(self, parent_path, is_dir, scandir):
183
173
raise
184
174
if entry_is_dir and not entry .is_symlink ():
185
175
path = parent_path ._make_child_relpath (entry .name )
186
- for p in self ._iterate_directories (path , is_dir , scandir ):
176
+ for p in self ._iterate_directories (path , scandir ):
187
177
yield p
188
178
except PermissionError :
189
179
return
190
180
191
- def _select_from (self , parent_path , is_dir , exists , scandir , normcase ):
181
+ def _select_from (self , parent_path , scandir ):
192
182
try :
193
183
yielded = set ()
194
184
try :
195
185
successor_select = self .successor ._select_from
196
- for starting_point in self ._iterate_directories (parent_path , is_dir , scandir ):
197
- for p in successor_select (starting_point , is_dir , exists , scandir , normcase ):
186
+ for starting_point in self ._iterate_directories (parent_path , scandir ):
187
+ for p in successor_select (starting_point , scandir ):
198
188
if p not in yielded :
199
189
yield p
200
190
yielded .add (p )
@@ -763,7 +753,7 @@ def _scandir(self):
763
753
# includes scandir(), which is used to implement glob().
764
754
return os .scandir (self )
765
755
766
- def glob (self , pattern ):
756
+ def glob (self , pattern , * , case_sensitive = None ):
767
757
"""Iterate over this subtree and yield all existing files (of any
768
758
kind, including directories) matching the given relative pattern.
769
759
"""
@@ -775,11 +765,13 @@ def glob(self, pattern):
775
765
raise NotImplementedError ("Non-relative patterns are unsupported" )
776
766
if pattern [- 1 ] in (self ._flavour .sep , self ._flavour .altsep ):
777
767
pattern_parts .append ('' )
778
- selector = _make_selector (tuple (pattern_parts ), self ._flavour )
768
+ if case_sensitive is None :
769
+ case_sensitive = _is_case_sensitive (self ._flavour )
770
+ selector = _make_selector (tuple (pattern_parts ), case_sensitive )
779
771
for p in selector .select_from (self ):
780
772
yield p
781
773
782
- def rglob (self , pattern ):
774
+ def rglob (self , pattern , * , case_sensitive = None ):
783
775
"""Recursively yield all existing files (of any kind, including
784
776
directories) matching the given relative pattern, anywhere in
785
777
this subtree.
@@ -790,7 +782,9 @@ def rglob(self, pattern):
790
782
raise NotImplementedError ("Non-relative patterns are unsupported" )
791
783
if pattern and pattern [- 1 ] in (self ._flavour .sep , self ._flavour .altsep ):
792
784
pattern_parts .append ('' )
793
- selector = _make_selector (("**" ,) + tuple (pattern_parts ), self ._flavour )
785
+ if case_sensitive is None :
786
+ case_sensitive = _is_case_sensitive (self ._flavour )
787
+ selector = _make_selector (("**" ,) + tuple (pattern_parts ), case_sensitive )
794
788
for p in selector .select_from (self ):
795
789
yield p
796
790
0 commit comments