8000 Move pathlib implementation out of `__init__.py` by barneygale · Pull Request #118582 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

Move pathlib implementation out of __init__.py #118582

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
More consistent import style.
  • Loading branch 8000 information
barneygale committed May 4, 2024
commit 9b815f7d1bbc89ee161cda168b0cb7791633c3d5
29 changes: 2 additions & 27 deletions Lib/pathlib/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@
"""

import functools
import operator
from errno import ENOENT, ENOTDIR, EBADF, ELOOP, EINVAL
from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO

from . import _glob
from ._glob import Globber, no_recurse_symlinks


__all__ = ["UnsupportedOperation"]
Expand Down Expand Up @@ -47,30 +46,6 @@ def _is_case_sensitive(parser):
return parser.normcase('Aa') == 'Aa'


class Globber(_glob.Globber):
lstat = operator.methodcaller('lstat')
add_slash = operator.methodcaller('joinpath', '')

@staticmethod
def scandir(path):
# Emulate os.scandir(), which returns an object that can be used as a
# context manager. This method is called by walk() and glob().
from contextlib import nullcontext
return 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 UnsupportedOperation(NotImplementedError):
"""An exception that is raised when an unsupported operation is called on
a path object.
Expand Down Expand Up @@ -696,7 +671,7 @@ def _glob_selector(self, parts, case_sensitive, recurse_symlinks):
# 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 _glob.no_recurse_symlinks
recursive = True if recurse_symlinks else no_recurse_symlinks
globber = self._globber(self.parser.sep, case_sensitive, case_pedantic, recursive)
return globber.selector(parts)

Expand Down
59 changes: 42 additions & 17 deletions Lib/pathlib/_glob.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,24 +87,28 @@ def __init__(self, sep, case_sensitive, case_pedantic=False, recursive=False):

# Low-level methods

lstat = staticmethod(os.lstat)
scandir = staticmethod(os.scandir)
parse_entry = operator.attrgetter('path')
concat_path = operator.add
lstat = operator.methodcaller('lstat')
add_slash = operator.methodcaller('joinpath', '')

if os.name == 'nt':
@staticmethod
def add_slash(pathname):
tail = os.path.splitroot(pathname)[2]
if not tail or tail[-1] in '\\/':
return pathname
return f'{pathname}\\'
else:
@staticmethod
def add_slash(pathname):
if not pathname or pathname[-1] == '/':
return pathname
return f'{pathname}/'
@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().
"""
from contextlib import nullcontext
return 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

# High-level methods

Expand Down Expand Up @@ -303,3 +307,24 @@ def walk(cls, root, top_down, on_error, follow_symlinks):
if dirnames:
prefix = cls.add_slash(path)
paths += [cls.concat_path(prefix, d) for d in reversed(dirnames)]


class StringGlobber(Globber):
lstat = staticmethod(os.lstat)
scandir = staticmethod(os.scandir)
parse_entry = operator.attrgetter('path')
concat_path = operator.add

if os.name == 'nt':
@staticmethod
def add_slash(pathname):
tail = os.path.splitroot(pathname)[2]
if not tail or tail[-1] in '\\/':
return pathname
return f'{pathname}\\'
else:
@staticmethod
def add_slash(pathname):
if not pathname or pathname[-1] == '/':
return pathname
return f'{pathname}/'
19 changes: 10 additions & 9 deletions Lib/pathlib/_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
except ImportError:
grp = None

from . import _abc, _glob
from ._abc import UnsupportedOperation, PurePathBase, PathBase
from ._glob import StringGlobber


__all__ = [
Expand Down Expand Up @@ -55,7 +56,7 @@ def __repr__(self):
return "<{}.parents>".format(type(self._path).__name__)


class PurePath(_abc.PurePathBase):
class PurePath(PurePathBase):
"""Base class for manipulating paths without I/O.

PurePath represents a filesystem path and offers operations which
Expand Down Expand Up @@ -101,7 +102,7 @@ class PurePath(_abc.PurePathBase):
'_hash',
)
parser = os.path
_globber = _glob.Globber
_globber = StringGlobber

def __new__(cls, *args, **kwargs):
"""Construct a PurePath from one or several strings and or existing
Expand Down Expand Up @@ -176,7 +177,7 @@ def _str_normcase(self):
try:
return self._str_normcase_cached
except AttributeError:
if _abc._is_case_sensitive(self.parser):
if self.parser is posixpath:
self._str_normcase_cached = str(self)
else:
self._str_normcase_cached = str(self).lower()
Expand Down Expand Up @@ -478,7 +479,7 @@ class PureWindowsPath(PurePath):
__slots__ = ()


class Path(_abc.PathBase, PurePath):
class Path(PathBase, PurePath):
"""PurePath subclass that can make system calls.

Path represents a filesystem path but unlike PurePath, also offers
Expand Down Expand Up @@ -542,7 +543,7 @@ def read_text(self, encoding=None, errors=None, newline=None):
# Call io.text_encoding() here to ensure any warning is raised at an
# appropriate stack level.
encoding = io.text_encoding(encoding)
return _abc.PathBase.read_text(self, encoding, errors, newline)
return PathBase.read_text(self, encoding, errors, newline)

def write_text(self, data, encoding=None, errors=None, newline=None):
"""
Expand All @@ -551,7 +552,7 @@ def write_text(self, data, encoding=None, errors=None, newline=None):
# Call io.text_encoding() here to ensure any warning is raised at an
# appropriate stack level.
encoding = io.text_encoding(encoding)
return _abc.PathBase.write_text(self, data, encoding, errors, newline)
return PathBase.write_text(self, data, encoding, errors, newline)

_remove_leading_dot = operator.itemgetter(slice(2, None))
_remove_trailing_slash = operator.itemgetter(slice(-1))
Expand Down Expand Up @@ -842,7 +843,7 @@ class PosixPath(Path, PurePosixPath):

if os.name == 'nt':
def __new__(cls, *args, **kwargs):
raise _abc.UnsupportedOperation(
raise UnsupportedOperation(
f"cannot instantiate {cls.__name__!r} on your system")

class WindowsPath(Path, PureWindowsPath):
Expand All @@ -854,5 +855,5 @@ class WindowsPath(Path, PureWindowsPath):

if os.name != 'nt':
def __new__(cls, *args, **kwargs):
raise _abc.UnsupportedOperation(
raise UnsupportedOperation(
f"cannot instantiate {cls.__name__!r} on your system")
0