Skip to content

Commit

Permalink
pythonGH-127456: pathlib ABCs: remove ParserBase.sep
Browse files Browse the repository at this point in the history
Remove `ParserBase.sep`, which is the class's only non-method member.
Instead, we compute the separator from `PathBase.__init_subclass__()` by
calling `parser.join('a', 'a').strip('a')`, and store the result on the
subclass as `cls._sep`. We also set `cls._case_sensitive` according to
`parser.normcase('Aa') == 'Aa'`, which was previously done in a caching
function.
  • Loading branch information
barneygale committed Dec 7, 2024
1 parent 31c9f3c commit c09307d
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 21 deletions.
34 changes: 15 additions & 19 deletions Lib/pathlib/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
resemble pathlib's PurePath and Path respectively.
"""

import functools
import operator
from errno import EINVAL
from glob import _GlobberBase, _no_recurse_symlinks
Expand All @@ -28,12 +27,6 @@ class UnsupportedOperation(NotImplementedError):
pass


@functools.cache
def _is_case_sensitive(parser):
return parser.normcase('Aa') == 'Aa'



class ParserBase:
"""Base class for path parsers, which do low-level path manipulation.
Expand All @@ -48,11 +41,6 @@ class ParserBase:
def _unsupported_msg(cls, attribute):
return f"{cls.__name__}.{attribute} is unsupported"

@property
def sep(self):
"""The character used to separate path components."""
raise UnsupportedOperation(self._unsupported_msg('sep'))

def join(self, path, *paths):
"""Join path segments."""
raise UnsupportedOperation(self._unsupported_msg('join()'))
Expand Down Expand Up @@ -116,8 +104,16 @@ class PurePathBase:
'_raw_paths',
)
parser = ParserBase()
_sep = '/'
_case_sensitive = True
_globber = PathGlobber

def __init_subclass__(cls):
super().__init_subclass__()
if 'parser' in cls.__dict__:
cls._sep = cls.parser.join('a', 'a').strip('a')
cls._case_sensitive = cls.parser.normcase('Aa') == 'Aa'

def __init__(self, *args):
for arg in args:
if not isinstance(arg, str):
Expand Down Expand Up @@ -152,7 +148,7 @@ def __str__(self):
def as_posix(self):
"""Return the string representation of the path with forward (/)
slashes."""
return str(self).replace(self.parser.sep, '/')
return str(self).replace(self._sep, '/')

@property
def drive(self):
Expand Down Expand Up @@ -368,8 +364,8 @@ def match(self, path_pattern, *, case_sensitive=None):
if not isinstance(path_pattern, PurePathBase):
path_pattern = self.with_segments(path_pattern)
if case_sensitive is None:
case_sensitive = _is_case_sensitive(self.parser)
sep = path_pattern.parser.sep
case_sensitive = self._case_sensitive
sep = path_pattern._sep
path_parts = self.parts[::-1]
pattern_parts = path_pattern.parts[::-1]
if not pattern_parts:
Expand All @@ -393,8 +389,8 @@ def full_match(self, pattern, *, case_sensitive=None):
if not isinstance(pattern, PurePathBase):
pattern = self.with_segments(pattern)
if case_sensitive is None:
case_sensitive = _is_case_sensitive(self.parser)
globber = self._globber(pattern.parser.sep, case_sensitive, recursive=True)
case_sensitive = self._case_sensitive
globber = self._globber(pattern._sep, case_sensitive, recursive=True)
match = globber.compile(pattern._pattern_str)
return match(self._pattern_str) is not None

Expand Down Expand Up @@ -639,15 +635,15 @@ def iterdir(self):

def _glob_selector(self, parts, case_sensitive, recurse_symlinks):
if case_sensitive is None:
case_sensitive = _is_case_sensitive(self.parser)
case_sensitive = self._case_sensitive
case_pedantic = False
else:
# The user has expressed a case sensitivity choice, but we don't
# know the case sensitivity of the underlying filesystem, so we
# must use scandir() for everything, including non-wildcard parts.
case_pedantic = True
recursive = True if recurse_symlinks else _no_recurse_symlinks
globber = self._globber(self.parser.sep, case_sensitive, case_pedantic, recursive)
globber = self._globber(self._sep, case_sensitive, case_pedantic, recursive)
return globber.selector(parts)

def glob(self, pattern, *, case_sensitive=None, recurse_symlinks=True):
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_pathlib/test_pathlib_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ class ParserBaseTest(unittest.TestCase):
def test_unsupported_operation(self):
m = self.cls()
e = UnsupportedOperation
with self.assertRaises(e):
m.sep
self.assertRaises(e, m.join, 'foo')
self.assertRaises(e, m.split, 'foo')
self.assertRaises(e, m.splitdrive, 'foo')
Expand Down

0 comments on commit c09307d

Please sign in to comment.