diff options
author | Miss Skeleton (bot) <31488909+miss-islington@users.noreply.github.com> | 2019-10-21 18:12:17 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-21 18:12:17 (GMT) |
commit | 175abccbbfccb2f6489dc5c73f4630c1b25ce504 (patch) | |
tree | e39fcd9f7b0726ece043623bf1873fbd63e23f76 | |
parent | 3dec84f40ef49bab994a1af4e6082bf81021feab (diff) | |
download | cpython-175abccbbfccb2f6489dc5c73f4630c1b25ce504.zip cpython-175abccbbfccb2f6489dc5c73f4630c1b25ce504.tar.gz cpython-175abccbbfccb2f6489dc5c73f4630c1b25ce504.tar.bz2 |
bpo-31202: Preserve case of literal parts in Path.glob() on Windows. (GH-16860)
(cherry picked from commit 10ecbadb799ddf3393d1fc80119a3db14724d381)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
-rw-r--r-- | Lib/pathlib.py | 38 | ||||
-rw-r--r-- | Lib/test/test_pathlib.py | 4 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2019-10-20-12-04-48.bpo-31202.NfdIus.rst | 2 |
3 files changed, 26 insertions, 18 deletions
diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 24437f8..af9747b 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -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 @@ -444,7 +450,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 == '**': @@ -455,7 +461,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) @@ -465,10 +471,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() @@ -494,9 +500,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: @@ -510,13 +516,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 @@ -527,8 +532,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 @@ -539,8 +543,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 @@ -1101,11 +1105,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 @@ -1114,11 +1117,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 diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index 9c82c64..e1d699a 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -2216,11 +2216,15 @@ class WindowsPathTest(_BasePathTest, unittest.TestCase): P = self.cls p = P(BASE) self.assertEqual(set(p.glob("FILEa")), { P(BASE, "fileA") }) + self.assertEqual(set(p.glob("F*a")), { P(BASE, "fileA") }) + self.assertEqual(set(map(str, p.glob("FILEa"))), {f"{p}\\FILEa"}) + self.assertEqual(set(map(str, p.glob("F*a"))), {f"{p}\\fileA"}) def test_rglob(self): P = self.cls p = P(BASE, "dirC") self.assertEqual(set(p.rglob("FILEd")), { P(BASE, "dirC/dirD/fileD") }) + self.assertEqual(set(map(str, p.rglob("FILEd"))), {f"{p}\\dirD\\FILEd"}) def test_expanduser(self): P = self.cls diff --git a/Misc/NEWS.d/next/Library/2019-10-20-12-04-48.bpo-31202.NfdIus.rst b/Misc/NEWS.d/next/Library/2019-10-20-12-04-48.bpo-31202.NfdIus.rst new file mode 100644 index 0000000..8edb09d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-10-20-12-04-48.bpo-31202.NfdIus.rst @@ -0,0 +1,2 @@ +The case the result of :func:`pathlib.WindowsPath.glob` matches now the case +of the pattern for literal parts. |