Skip to content

Commit 6ea7eae

Browse files
committed
Remove flavour.parse_parts(), flavour.splitroot() and flavour.pathmod
1 parent 00f6126 commit 6ea7eae

File tree

2 files changed

+255
-267
lines changed

2 files changed

+255
-267
lines changed

Lib/pathlib.py

Lines changed: 128 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -50,103 +50,15 @@ class _Flavour(object):
5050
"""A flavour implements a particular (platform-specific) set of path
5151
semantics."""
5252

53-
def parse_parts(self, parts):
54-
parsed = []
55-
sep = self.pathmod.sep
56-
altsep = self.pathmod.altsep
57-
drv = root = ''
58-
it = reversed(parts)
59-
for part in it:
60-
if not part:
61-
continue
62-
if altsep:
63-
part = part.replace(altsep, sep)
64-
drv, root, rel = self.splitroot(part)
65-
if sep in rel:
66-
for x in reversed(rel.split(sep)):
67-
if x and x != '.':
68-
parsed.append(sys.intern(x))
69-
else:
70-
if rel and rel != '.':
71-
parsed.append(sys.intern(rel))
72-
if drv or root:
73-
if not drv:
74-
# If no drive is present, try to find one in the previous
75-
# parts. This makes the result of parsing e.g.
76-
# ("C:", "/", "a") reasonably intuitive.
77-
for part in it:
78-
if not part:
79-
continue
80-
if altsep:
81-
part = part.replace(altsep, sep)
82-
drv = self.splitroot(part)[0]
83-
if drv:
84-
break
85-
break
86-
if drv or root:
87-
parsed.append(drv + root)
88-
parsed.reverse()
89-
return drv, root, parsed
90-
9153

9254
class _WindowsFlavour(_Flavour):
9355
# Reference for Windows paths can be found at
9456
# http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx
9557

9658
has_drv = True
97-
pathmod = ntpath
9859

9960
is_supported = (os.name == 'nt')
10061

101-
drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
102-
ext_namespace_prefix = '\\\\?\\'
103-
104-
# Interesting findings about extended paths:
105-
# - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported
106-
# but '\\?\c:/a' is not
107-
# - extended paths are always absolute; "relative" extended paths will
108-
# fail.
109-
110-
def splitroot(self, part):
111-
sep = self.pathmod.sep
112-
first = part[0:1]
113-
second = part[1:2]
114-
if (second == sep and first == sep):
115-
# XXX extended paths should also disable the collapsing of "."
116-
# components (according to MSDN docs).
117-
prefix, part = self._split_extended_path(part)
118-
first = part[0:1]
119-
second = part[1:2]
120-
else:
121-
prefix = ''
122-
third = part[2:3]
123-
if (second == sep and first == sep and third != sep):
124-
# is a UNC path:
125-
# vvvvvvvvvvvvvvvvvvvvv root
126-
# \\machine\mountpoint\directory\etc\...
127-
# directory ^^^^^^^^^^^^^^
128-
index = part.find(sep, 2)
129-
if index != -1:
130-
index2 = part.find(sep, index + 1)
131-
# a UNC path can't have two slashes in a row
132-
# (after the initial two)
133-
if index2 != index + 1:
134-
if index2 == -1:
135-
index2 = len(part)
136-
if prefix:
137-
return prefix + part[1:index2], sep, part[index2+1:]
138-
else:
139-
return part[:index2], sep, part[index2+1:]
140-
drv = root = ''
141-
if second == ':' and first in self.drive_letters:
142-
drv = part[:2]
143-
part = part[2:]
144-
first = third
145-
if first == sep:
146-
root = first
147-
part = part.lstrip(sep)
148-
return prefix + drv, root, part
149-
15062
def casefold(self, s):
15163
return s.lower()
15264

@@ -156,39 +68,12 @@ def casefold_parts(self, parts):
15668
def compile_pattern(self, pattern):
15769
return re.compile(fnmatch.translate(pattern), re.IGNORECASE).fullmatch
15870

159-
def _split_extended_path(self, s, ext_prefix=ext_namespace_prefix):
160-
prefix = ''
161-
if s.startswith(ext_prefix):
162-
prefix = s[:4]
163-
s = s[4:]
164-
if s.startswith('UNC\\'):
165-
prefix += s[:3]
166-
s = '\\' + s[3:]
167-
return prefix, s
168-
16971

17072
class _PosixFlavour(_Flavour):
17173
has_drv = False
172-
pathmod = posixpath
17374

17475
is_supported = (os.name != 'nt')
17576

176-
def splitroot(self, part):
177-
sep = self.pathmod.sep
178-
if part and part[0] == sep:
179-
stripped_part = part.lstrip(sep)
180-
# According to POSIX path resolution:
181-
# http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
182-
# "A pathname that begins with two successive slashes may be
183-
# interpreted in an implementation-defined manner, although more
184-
# than two leading slashes shall be treated as a single slash".
185-
if len(part) - len(stripped_part) == 2:
186-
return '', sep * 2, stripped_part
187-
else:
188-
return '', sep, stripped_part
189-
else:
190-
return '', '', part
191-
19277
def casefold(self, s):
19378
return s
19479

@@ -511,7 +396,46 @@ def _parse_args(cls, args):
511396
"argument should be a str object or an os.PathLike "
512397
"object returning str, not %r"
513398
% type(a))
514-
return cls._flavour.parse_parts(parts)
399+
return cls._parse_parts(parts)
400+
401+
@classmethod
402+
def _parse_parts(cls, parts):
403+
parsed = []
404+
sep = cls._pathmod.sep
405+
altsep = cls._pathmod.altsep
406+
drv = root = ''
407+
it = reversed(parts)
408+
for part in it:
409+
if not part:
410+
continue
411+
if altsep:
412+
part = part.replace(altsep, sep)
413+
drv, root, rel = cls._splitroot(part)
414+
if sep in rel:
415+
for x in reversed(rel.split(sep)):
416+
if x and x != '.':
417+
parsed.append(sys.intern(x))
418+
else:
419+
if rel and rel != '.':
420+
parsed.append(sys.intern(rel))
421+
if drv or root:
422+
if not drv:
423+
# If no drive is present, try to find one in the previous
424+
# parts. This makes the result of parsing e.g.
425+
# ("C:", "/", "a") reasonably intuitive.
426+
for part in it:
427+
if not part:
428+
continue
429+
if altsep:
430+
part = part.replace(altsep, sep)
431+
drv = cls._splitroot(part)[0]
432+
if drv:
433+
break
434+
break
435+
if drv or root:
436+
parsed.append(drv + root)
437+
parsed.reverse()
438+
return drv, root, parsed
515439

516440
@classmethod
517441
def _from_parts(cls, args):
@@ -535,9 +459,9 @@ def _from_parsed_parts(cls, drv, root, parts):
535459
@classmethod
536460
def _format_parsed_parts(cls, drv, root, parts):
537461
if drv or root:
538-
return drv + root + cls._flavour.pathmod.sep.join(parts[1:])
462+
return drv + root + cls._pathmod.sep.join(parts[1:])
539463
else:
540-
return cls._flavour.pathmod.sep.join(parts)
464+
return cls._pathmod.sep.join(parts)
541465

542466
def _make_child(self, args):
543467
drv, root, parts = self._parse_args(args)
@@ -578,8 +502,7 @@ def __fspath__(self):
578502
def as_posix(self):
579503
"""Return the string representation of the path with forward (/)
580504
slashes."""
581-
f = self._flavour
582-
return str(self).replace(f.pathmod.sep, '/')
505+
return str(self).replace(self._pathmod.sep, '/')
583506

584507
def __bytes__(self):
585508
"""Return the bytes representation of the path. This is only
@@ -698,8 +621,8 @@ def with_name(self, name):
698621
"""Return a new path with the file name changed."""
699622
if not self.name:
700623
raise ValueError("%r has an empty name" % (self,))
701-
drv, root, parts = self._flavour.parse_parts((name,))
702-
m = self._flavour.pathmod
624+
drv, root, parts = self._parse_parts((name,))
625+
m = self._pathmod
703626
if (not name or name[-1] in [m.sep, m.altsep]
704627
or drv or root or len(parts) != 1):
705628
raise ValueError("Invalid name %r" % (name))
@@ -715,7 +638,7 @@ def with_suffix(self, suffix):
715638
has no suffix, add given suffix. If the given suffix is an empty
716639
string, remove the suffix from the path.
717640
"""
718-
m = self._flavour.pathmod
641+
m = self._pathmod
719642
if m.sep in suffix or m.altsep and m.altsep in suffix:
720643
raise ValueError("Invalid suffix %r" % (suffix,))
721644
if suffix and not suffix.startswith('.') or suffix == '.':
@@ -838,7 +761,7 @@ def match(self, path_pattern):
838761
"""
839762
cf = self._flavour.casefold
840763
path_pattern = cf(path_pattern)
841-
drv, root, pat_parts = self._flavour.parse_parts((path_pattern,))
764+
drv, root, pat_parts = self._parse_parts((path_pattern,))
842765
if not pat_parts:
843766
raise ValueError("empty pattern")
844767
if drv and drv != cf(self._drv):
@@ -869,8 +792,26 @@ class PurePosixPath(PurePath):
869792
However, you can also instantiate it directly on any system.
870793
"""
871794
_flavour = _posix_flavour
795+
_pathmod = posixpath
872796
__slots__ = ()
873797

798+
@classmethod
799+
def _splitroot(cls, part):
800+
sep = cls._pathmod.sep
801+
if part and part[0] == sep:
802+
stripped_part = part.lstrip(sep)
803+
# According to POSIX path resolution:
804+
# http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11
805+
# "A pathname that begins with two successive slashes may be
806+
# interpreted in an implementation-defined manner, although more
807+
# than two leading slashes shall be treated as a single slash".
808+
if len(part) - len(stripped_part) == 2:
809+
return '', sep * 2, stripped_part
810+
else:
811+
return '', sep, stripped_part
812+
else:
813+
return '', '', part
814+
874815
def is_reserved(self):
875816
return False
876817

@@ -890,13 +831,74 @@ class PureWindowsPath(PurePath):
890831
However, you can also instantiate it directly on any system.
891832
"""
892833
_flavour = _windows_flavour
834+
_pathmod = ntpath
835+
_drive_letters = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
836+
_ext_namespace_prefix = '\\\\?\\'
893837
_reserved_names = (
894838
{'CON', 'PRN', 'AUX', 'NUL'} |
895839
{'COM%d' % i for i in range(1, 10)} |
896840
{'LPT%d' % i for i in range(1, 10)}
897841
)
898842
__slots__ = ()
899843

844+
# Interesting findings about extended paths:
845+
# - '\\?\c:\a', '//?/c:\a' and '//?/c:/a' are all supported
846+
# but '\\?\c:/a' is not
847+
# - extended paths are always absolute; "relative" extended paths will
848+
# fail.
849+
850+
@classmethod
851+
def _splitroot(cls, part):
852+
sep = cls._pathmod.sep
853+
first = part[0:1]
854+
second = part[1:2]
855+
if (second == sep and first == sep):
856+
# XXX extended paths should also disable the collapsing of "."
857+
# components (according to MSDN docs).
858+
prefix, part = cls._split_extended_path(part)
859+
first = part[0:1]
860+
second = part[1:2]
861+
else:
862+
prefix = ''
863+
third = part[2:3]
864+
if (second == sep and first == sep and third != sep):
865+
# is a UNC path:
866+
# vvvvvvvvvvvvvvvvvvvvv root
867+
# \\machine\mountpoint\directory\etc\...
868+
# directory ^^^^^^^^^^^^^^
869+
index = part.find(sep, 2)
870+
if index != -1:
871+
index2 = part.find(sep, index + 1)
872+
# a UNC path can't have two slashes in a row
873+
# (after the initial two)
874+
if index2 != index + 1:
875+
if index2 == -1:
876+
index2 = len(part)
877+
if prefix:
878+
return prefix + part[1:index2], sep, part[index2+1:]
879+
else:
880+
return part[:index2], sep, part[index2+1:]
881+
drv = root = ''
882+
if second == ':' and first in cls._drive_letters:
883+
drv = part[:2]
884+
part = part[2:]
885+
first = third
886+
if first == sep:
887+
root = first
888+
part = part.lstrip(sep)
889+
return prefix + drv, root, part
890+
891+
@classmethod
892+
def _split_extended_path(cls, s, ext_prefix=_ext_namespace_prefix):
893+
prefix = ''
894+
if s.startswith(ext_prefix):
895+
prefix = s[:4]
896+
s = s[4:]
897+
if s.startswith('UNC\\'):
898+
prefix += s[:3]
899+
s = '\\' + s[3:]
900+
return prefix, s
901+
900902
def is_reserved(self):
901903
# NOTE: the rules for reserved names seem somewhat complicated
902904
# (e.g. r"..\NUL" is reserved but not r"foo\NUL").
@@ -1011,7 +1013,7 @@ def glob(self, pattern):
10111013
sys.audit("pathlib.Path.glob", self, pattern)
10121014
if not pattern:
10131015
raise ValueError("Unacceptable pattern: {!r}".format(pattern))
1014-
drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1016+
drv, root, pattern_parts = self._parse_parts((pattern,))
10151017
if drv or root:
10161018
raise NotImplementedError("Non-relative patterns are unsupported")
10171019
selector = _make_selector(tuple(pattern_parts), self._flavour)
@@ -1024,7 +1026,7 @@ def rglob(self, pattern):
10241026
this subtree.
10251027
"""
10261028
sys.audit("pathlib.Path.rglob", self, pattern)
1027-
drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
1029+
drv, root, pattern_parts = self._parse_parts((pattern,))
10281030
if drv or root:
10291031
raise NotImplementedError("Non-relative patterns are unsupported")
10301032
selector = _make_selector(("**",) + tuple(pattern_parts), self._flavour)

0 commit comments

Comments
 (0)