mirror of
https://github.com/python/cpython.git
synced 2025-08-23 10:16:01 +00:00
bpo-31202: Preserve case of literal parts in Path.glob() on Windows. (GH-16860)
This commit is contained in:
parent
1e73945470
commit
10ecbadb79
3 changed files with 26 additions and 18 deletions
|
@ -187,6 +187,9 @@ class _WindowsFlavour(_Flavour):
|
|||
def casefold_parts(self, parts):
|
||||
return [p.lower() for p in parts]
|
||||
|
||||
def compile_pattern(self, pattern):
|
||||
return re.compile(fnmatch.translate(pattern), re.IGNORECASE).fullmatch
|
||||
|
||||
def resolve(self, path, strict=False):
|
||||
s = str(path)
|
||||
if not s:
|
||||
|
@ -309,6 +312,9 @@ class _PosixFlavour(_Flavour):
|
|||
def casefold_parts(self, parts):
|
||||
return parts
|
||||
|
||||
def compile_pattern(self, pattern):
|
||||
return re.compile(fnmatch.translate(pattern)).fullmatch
|
||||
|
||||
def resolve(self, path, strict=False):
|
||||
sep = self.sep
|
||||
accessor = path._accessor
|
||||
|
@ -446,7 +452,7 @@ _normal_accessor = _NormalAccessor()
|
|||
# Globbing helpers
|
||||
#
|
||||
|
||||
def _make_selector(pattern_parts):
|
||||
def _make_selector(pattern_parts, flavour):
|
||||
pat = pattern_parts[0]
|
||||
child_parts = pattern_parts[1:]
|
||||
if pat == '**':
|
||||
|
@ -457,7 +463,7 @@ def _make_selector(pattern_parts):
|
|||
cls = _WildcardSelector
|
||||
else:
|
||||
cls = _PreciseSelector
|
||||
return cls(pat, child_parts)
|
||||
return cls(pat, child_parts, flavour)
|
||||
|
||||
if hasattr(functools, "lru_cache"):
|
||||
_make_selector = functools.lru_cache()(_make_selector)
|
||||
|
@ -467,10 +473,10 @@ class _Selector:
|
|||
"""A selector matches a specific glob pattern part against the children
|
||||
of a given path."""
|
||||
|
||||
def __init__(self, child_parts):
|
||||
def __init__(self, child_parts, flavour):
|
||||
self.child_parts = child_parts
|
||||
if child_parts:
|
||||
self.successor = _make_selector(child_parts)
|
||||
self.successor = _make_selector(child_parts, flavour)
|
||||
self.dironly = True
|
||||
else:
|
||||
self.successor = _TerminatingSelector()
|
||||
|
@ -496,9 +502,9 @@ class _TerminatingSelector:
|
|||
|
||||
class _PreciseSelector(_Selector):
|
||||
|
||||
def __init__(self, name, child_parts):
|
||||
def __init__(self, name, child_parts, flavour):
|
||||
self.name = name
|
||||
_Selector.__init__(self, child_parts)
|
||||
_Selector.__init__(self, child_parts, flavour)
|
||||
|
||||
def _select_from(self, parent_path, is_dir, exists, scandir):
|
||||
try:
|
||||
|
@ -512,13 +518,12 @@ class _PreciseSelector(_Selector):
|
|||
|
||||
class _WildcardSelector(_Selector):
|
||||
|
||||
def __init__(self, pat, child_parts):
|
||||
self.pat = re.compile(fnmatch.translate(pat))
|
||||
_Selector.__init__(self, child_parts)
|
||||
def __init__(self, pat, child_parts, flavour):
|
||||
self.match = flavour.compile_pattern(pat)
|
||||
_Selector.__init__(self, child_parts, flavour)
|
||||
|
||||
def _select_from(self, parent_path, is_dir, exists, scandir):
|
||||
try:
|
||||
cf = parent_path._flavour.casefold
|
||||
entries = list(scandir(parent_path))
|
||||
for entry in entries:
|
||||
entry_is_dir = False
|
||||
|
@ -529,8 +534,7 @@ class _WildcardSelector(_Selector):
|
|||
raise
|
||||
if not self.dironly or entry_is_dir:
|
||||
name = entry.name
|
||||
casefolded = cf(name)
|
||||
if self.pat.match(casefolded):
|
||||
if self.match(name):
|
||||
path = parent_path._make_child_relpath(name)
|
||||
for p in self.successor._select_from(path, is_dir, exists, scandir):
|
||||
yield p
|
||||
|
@ -541,8 +545,8 @@ class _WildcardSelector(_Selector):
|
|||
|
||||
class _RecursiveWildcardSelector(_Selector):
|
||||
|
||||
def __init__(self, pat, child_parts):
|
||||
_Selector.__init__(self, child_parts)
|
||||
def __init__(self, pat, child_parts, flavour):
|
||||
_Selector.__init__(self, child_parts, flavour)
|
||||
|
||||
def _iterate_directories(self, parent_path, is_dir, scandir):
|
||||
yield parent_path
|
||||
|
@ -1118,11 +1122,10 @@ class Path(PurePath):
|
|||
"""
|
||||
if not pattern:
|
||||
raise ValueError("Unacceptable pattern: {!r}".format(pattern))
|
||||
pattern = self._flavour.casefold(pattern)
|
||||
drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
|
||||
if drv or root:
|
||||
raise NotImplementedError("Non-relative patterns are unsupported")
|
||||
selector = _make_selector(tuple(pattern_parts))
|
||||
selector = _make_selector(tuple(pattern_parts), self._flavour)
|
||||
for p in selector.select_from(self):
|
||||
yield p
|
||||
|
||||
|
@ -1131,11 +1134,10 @@ class Path(PurePath):
|
|||
directories) matching the given relative pattern, anywhere in
|
||||
this subtree.
|
||||
"""
|
||||
pattern = self._flavour.casefold(pattern)
|
||||
drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
|
||||
if drv or root:
|
||||
raise NotImplementedError("Non-relative patterns are unsupported")
|
||||
selector = _make_selector(("**",) + tuple(pattern_parts))
|
||||
selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)
|
||||
for p in selector.select_from(self):
|
||||
yield p
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue