Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 47770a1

Browse filesBrowse files
authored
GH-104104: Optimize pathlib.Path.glob() by avoiding repeated calls to os.path.normcase() (GH-104105)
Use `re.IGNORECASE` to implement case-insensitive matching. This restores behaviour from before GH-31691.
1 parent 1f53844 commit 47770a1
Copy full SHA for 47770a1

File tree

2 files changed

+16
-11
lines changed
Filter options

2 files changed

+16
-11
lines changed

‎Lib/pathlib.py

Copy file name to clipboardExpand all lines: Lib/pathlib.py
+14-11Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ def _is_wildcard_pattern(pat):
5959
# be looked up directly as a file.
6060
return "*" in pat or "?" in pat or "[" in pat
6161

62+
def _is_case_sensitive(flavour):
63+
return flavour.normcase('Aa') == 'Aa'
64+
6265
#
6366
# Globbing helpers
6467
#
@@ -100,15 +103,14 @@ def select_from(self, parent_path):
100103
is_dir = path_cls.is_dir
101104
exists = path_cls.exists
102105
scandir = path_cls._scandir
103-
normcase = path_cls._flavour.normcase
104106
if not is_dir(parent_path):
105107
return iter([])
106-
return self._select_from(parent_path, is_dir, exists, scandir, normcase)
108+
return self._select_from(parent_path, is_dir, exists, scandir)
107109

108110

109111
class _TerminatingSelector:
110112

111-
def _select_from(self, parent_path, is_dir, exists, scandir, normcase):
113+
def _select_from(self, parent_path, is_dir, exists, scandir):
112114
yield parent_path
113115

114116

@@ -118,11 +120,11 @@ def __init__(self, name, child_parts, flavour):
118120
self.name = name
119121
_Selector.__init__(self, child_parts, flavour)
120122

121-
def _select_from(self, parent_path, is_dir, exists, scandir, normcase):
123+
def _select_from(self, parent_path, is_dir, exists, scandir):
122124
try:
123125
path = parent_path._make_child_relpath(self.name)
124126
if (is_dir if self.dironly else exists)(path):
125-
for p in self.successor._select_from(path, is_dir, exists, scandir, normcase):
127+
for p in self.successor._select_from(path, is_dir, exists, scandir):
126128
yield p
127129
except PermissionError:
128130
return
@@ -131,10 +133,11 @@ def _select_from(self, parent_path, is_dir, exists, scandir, normcase):
131133
class _WildcardSelector(_Selector):
132134

133135
def __init__(self, pat, child_parts, flavour):
134-
self.match = re.compile(fnmatch.translate(flavour.normcase(pat))).fullmatch
136+
flags = re.NOFLAG if _is_case_sensitive(flavour) else re.IGNORECASE
137+
self.match = re.compile(fnmatch.translate(pat), flags=flags).fullmatch
135138
_Selector.__init__(self, child_parts, flavour)
136139

137-
def _select_from(self, parent_path, is_dir, exists, scandir, normcase):
140+
def _select_from(self, parent_path, is_dir, exists, scandir):
138141
try:
139142
# We must close the scandir() object before proceeding to
140143
# avoid exhausting file descriptors when globbing deep trees.
@@ -153,9 +156,9 @@ def _select_from(self, parent_path, is_dir, exists, scandir, normcase):
153156
raise
154157
continue
155158
name = entry.name
156-
if self.match(normcase(name)):
159+
if self.match(name):
157160
path = parent_path._make_child_relpath(name)
158-
for p in self.successor._select_from(path, is_dir, exists, scandir, normcase):
161+
for p in self.successor._select_from(path, is_dir, exists, scandir):
159162
yield p
160163
except PermissionError:
161164
return
@@ -187,13 +190,13 @@ def _iterate_directories(self, parent_path, is_dir, scandir):
187190
except PermissionError:
188191
return
189192

190-
def _select_from(self, parent_path, is_dir, exists, scandir, normcase):
193+
def _select_from(self, parent_path, is_dir, exists, scandir):
191194
try:
192195
yielded = set()
193196
try:
194197
successor_select = self.successor._select_from
195198
for starting_point in self._iterate_directories(parent_path, is_dir, scandir):
196-
for p in successor_select(starting_point, is_dir, exists, scandir, normcase):
199+
for p in successor_select(starting_point, is_dir, exists, scandir):
197200
if p not in yielded:
198201
yield p
199202
yielded.add(p)
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve performance of :meth:`pathlib.Path.glob` by using
2+
:data:`re.IGNORECASE` to implement case-insensitive matching.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.