GH-116380: Move pathlib-specific code from `glob` to `pathlib._abc`. (#120011)

In `glob._Globber`, move pathlib-specific methods to `pathlib._abc.PathGlobber` and replace them with abstract methods. Rename `glob._Globber` to `glob._GlobberBase`. As a result, the `glob` module is no longer befouled by code that can only ever apply to pathlib.

No change of behaviour.
This commit is contained in:
Barney Gale 2024-06-07 17:59:34 +01:00 committed by GitHub
parent 90b7540526
commit 242c7498e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 52 additions and 14 deletions

View File

@ -328,8 +328,8 @@ def _compile_pattern(pat, sep, case_sensitive, recursive=True):
return re.compile(regex, flags=flags).match return re.compile(regex, flags=flags).match
class _Globber: class _GlobberBase:
"""Class providing shell-style pattern matching and globbing. """Abstract class providing shell-style pattern matching and globbing.
""" """
def __init__(self, sep, case_sensitive, case_pedantic=False, recursive=False): def __init__(self, sep, case_sensitive, case_pedantic=False, recursive=False):
@ -338,29 +338,37 @@ class _Globber:
self.case_pedantic = case_pedantic self.case_pedantic = case_pedantic
self.recursive = recursive self.recursive = recursive
# Low-level methods # Abstract methods
lexists = operator.methodcaller('exists', follow_symlinks=False) @staticmethod
add_slash = operator.methodcaller('joinpath', '') def lexists(path):
"""Implements os.path.lexists().
"""
raise NotImplementedError
@staticmethod @staticmethod
def scandir(path): def scandir(path):
"""Emulates os.scandir(), which returns an object that can be used as """Implements os.scandir().
a context manager. This method is called by walk() and glob().
""" """
return contextlib.nullcontext(path.iterdir()) raise NotImplementedError
@staticmethod
def add_slash(path):
"""Returns a path with a trailing slash added.
"""
raise NotImplementedError
@staticmethod @staticmethod
def concat_path(path, text): def concat_path(path, text):
"""Appends text to the given path. """Implements path concatenation.
""" """
return path.with_segments(path._raw_path + text) raise NotImplementedError
@staticmethod @staticmethod
def parse_entry(entry): def parse_entry(entry):
"""Returns the path of an entry yielded from scandir(). """Returns the path of an entry yielded from scandir().
""" """
return entry raise NotImplementedError
# High-level methods # High-level methods
@ -520,7 +528,9 @@ class _Globber:
yield path yield path
class _StringGlobber(_Globber): class _StringGlobber(_GlobberBase):
"""Provides shell-style pattern matching and globbing for string paths.
"""
lexists = staticmethod(os.path.lexists) lexists = staticmethod(os.path.lexists)
scandir = staticmethod(os.scandir) scandir = staticmethod(os.scandir)
parse_entry = operator.attrgetter('path') parse_entry = operator.attrgetter('path')

View File

@ -12,8 +12,9 @@ resemble pathlib's PurePath and Path respectively.
""" """
import functools import functools
import operator
import posixpath import posixpath
from glob import _Globber, _no_recurse_symlinks from glob import _GlobberBase, _no_recurse_symlinks
from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
@ -84,6 +85,33 @@ class ParserBase:
raise UnsupportedOperation(self._unsupported_msg('isabs()')) raise UnsupportedOperation(self._unsupported_msg('isabs()'))
class PathGlobber(_GlobberBase):
"""
Class providing shell-style globbing for path objects.
"""
lexists = operator.methodcaller('exists', follow_symlinks=False)
add_slash = operator.methodcaller('joinpath', '')
@staticmethod
def scandir(path):
"""Emulates os.scandir(), which returns an object that can be used as
a context manager. This method is called by walk() and glob().
"""
import contextlib
return contextlib.nullcontext(path.iterdir())
@staticmethod
def concat_path(path, text):
"""Appends text to the given path."""
return path.with_segments(path._raw_path + text)
@staticmethod
def parse_entry(entry):
"""Returns the path of an entry yielded from scandir()."""
return entry
class PurePathBase: class PurePathBase:
"""Base class for pure path objects. """Base class for pure path objects.
@ -104,7 +132,7 @@ class PurePathBase:
'_resolving', '_resolving',
) )
parser = ParserBase() parser = ParserBase()
_globber = _Globber _globber = PathGlobber
def __init__(self, path, *paths): def __init__(self, path, *paths):
self._raw_path = self.parser.join(path, *paths) if paths else path self._raw_path = self.parser.join(path, *paths) if paths else path