mirror of
https://github.com/python/cpython.git
synced 2025-10-17 20:28:43 +00:00
Add pathlib._abc.PathModuleBase
(#113893)
Path modules provide a subset of the `os.path` API, specifically those functions needed to provide `PurePathBase` functionality. Each `PurePathBase` subclass references its path module via a `pathmod` class attribute. This commit adds a new `PathModuleBase` class, which provides abstract methods that unconditionally raise `UnsupportedOperation`. An instance of this class is assigned to `PurePathBase.pathmod`, replacing `posixpath`. As a result, `PurePathBase` is no longer POSIX-y by default, and all its methods raise `UnsupportedOperation` courtesy of `pathmod`. Users who subclass `PurePathBase` or `PathBase` should choose the path syntax by setting `pathmod` to `posixpath`, `ntpath`, `os.path`, or their own subclass of `PathModuleBase`, as circumstances demand.
This commit is contained in:
parent
c2808431b3
commit
ca6cf56330
4 changed files with 182 additions and 59 deletions
|
@ -33,6 +33,15 @@ __all__ = [
|
|||
]
|
||||
|
||||
|
||||
# Reference for Windows paths can be found at
|
||||
# https://learn.microsoft.com/en-gb/windows/win32/fileio/naming-a-file .
|
||||
_WIN_RESERVED_NAMES = frozenset(
|
||||
{'CON', 'PRN', 'AUX', 'NUL', 'CONIN$', 'CONOUT$'} |
|
||||
{f'COM{c}' for c in '123456789\xb9\xb2\xb3'} |
|
||||
{f'LPT{c}' for c in '123456789\xb9\xb2\xb3'}
|
||||
)
|
||||
|
||||
|
||||
class _PathParents(Sequence):
|
||||
"""This object provides sequence-like access to the logical ancestors
|
||||
of a path. Don't try to construct it yourself."""
|
||||
|
@ -76,6 +85,10 @@ class PurePath(_abc.PurePathBase):
|
|||
"""
|
||||
|
||||
__slots__ = (
|
||||
# The `_raw_paths` slot stores unnormalized string paths. This is set
|
||||
# in the `__init__()` method.
|
||||
'_raw_paths',
|
||||
|
||||
# The `_drv`, `_root` and `_tail_cached` slots store parsed and
|
||||
# normalized parts of the path. They are set when any of the `drive`,
|
||||
# `root` or `_tail` properties are accessed for the first time. The
|
||||
|
@ -141,6 +154,26 @@ class PurePath(_abc.PurePathBase):
|
|||
# Avoid calling super().__init__, as an optimisation
|
||||
self._raw_paths = paths
|
||||
|
||||
def joinpath(self, *pathsegments):
|
||||
"""Combine this path with one or several arguments, and return a
|
||||
new path representing either a subpath (if all arguments are relative
|
||||
paths) or a totally different path (if one of the arguments is
|
||||
anchored).
|
||||
"""
|
||||
return self.with_segments(self, *pathsegments)
|
||||
|
||||
def __truediv__(self, key):
|
||||
try:
|
||||
return self.with_segments(self, key)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
|
||||
def __rtruediv__(self, key):
|
||||
try:
|
||||
return self.with_segments(key, self)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
|
||||
def __reduce__(self):
|
||||
# Using the parts tuple helps share interned path parts
|
||||
# when pickling related paths.
|
||||
|
@ -386,6 +419,33 @@ class PurePath(_abc.PurePathBase):
|
|||
other = self.with_segments(other)
|
||||
return other == self or other in self.parents
|
||||
|
||||
def is_absolute(self):
|
||||
"""True if the path is absolute (has both a root and, if applicable,
|
||||
a drive)."""
|
||||
if self.pathmod is posixpath:
|
||||
# Optimization: work with raw paths on POSIX.
|
||||
for path in self._raw_paths:
|
||||
if path.startswith('/'):
|
||||
return True
|
||||
return False
|
||||
return self.pathmod.isabs(self)
|
||||
|
||||
def is_reserved(self):
|
||||
"""Return True if the path contains one of the special names reserved
|
||||
by the system, if any."""
|
||||
if self.pathmod is not ntpath or not self.name:
|
||||
return False
|
||||
|
||||
# NOTE: the rules for reserved names seem somewhat complicated
|
||||
# (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not
|
||||
# exist). We err on the side of caution and return True for paths
|
||||
# which are not considered reserved by Windows.
|
||||
if self.drive.startswith('\\\\'):
|
||||
# UNC paths are never reserved.
|
||||
return False
|
||||
name = self.name.partition('.')[0].partition(':')[0].rstrip(' ')
|
||||
return name.upper() in _WIN_RESERVED_NAMES
|
||||
|
||||
def as_uri(self):
|
||||
"""Return the path as a URI."""
|
||||
if not self.is_absolute():
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue