mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
Issue #27186: Add os.PathLike support to pathlib.
This adds support both to pathlib.PurePath's constructor as well as implementing __fspath__(). This removes the provisional status for pathlib. Initial patch by Dusty Phillips.
This commit is contained in:
parent
f41b82fb19
commit
568be63248
4 changed files with 56 additions and 14 deletions
|
@ -31,12 +31,6 @@ Pure paths are useful in some special cases; for example:
|
||||||
accessing the OS. In this case, instantiating one of the pure classes may be
|
accessing the OS. In this case, instantiating one of the pure classes may be
|
||||||
useful since those simply don't have any OS-accessing operations.
|
useful since those simply don't have any OS-accessing operations.
|
||||||
|
|
||||||
.. note::
|
|
||||||
This module has been included in the standard library on a
|
|
||||||
:term:`provisional basis <provisional package>`. Backwards incompatible
|
|
||||||
changes (up to and including removal of the package) may occur if deemed
|
|
||||||
necessary by the core developers.
|
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
:pep:`428`: The pathlib module -- object-oriented filesystem paths.
|
:pep:`428`: The pathlib module -- object-oriented filesystem paths.
|
||||||
|
|
||||||
|
@ -107,7 +101,8 @@ we also call *flavours*:
|
||||||
PurePosixPath('setup.py')
|
PurePosixPath('setup.py')
|
||||||
|
|
||||||
Each element of *pathsegments* can be either a string representing a
|
Each element of *pathsegments* can be either a string representing a
|
||||||
path segment, or another path object::
|
path segment, an object implementing the :class:`os.PathLike` interface
|
||||||
|
which returns a string, or another path object::
|
||||||
|
|
||||||
>>> PurePath('foo', 'some/path', 'bar')
|
>>> PurePath('foo', 'some/path', 'bar')
|
||||||
PurePosixPath('foo/some/path/bar')
|
PurePosixPath('foo/some/path/bar')
|
||||||
|
@ -148,6 +143,12 @@ we also call *flavours*:
|
||||||
to ``PurePosixPath('bar')``, which is wrong if ``foo`` is a symbolic link
|
to ``PurePosixPath('bar')``, which is wrong if ``foo`` is a symbolic link
|
||||||
to another directory)
|
to another directory)
|
||||||
|
|
||||||
|
Pure path objects implement the :class:`os.PathLike` interface, allowing them
|
||||||
|
to be used anywhere the interface is accepted.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.6
|
||||||
|
Added support for the :class:`os.PathLike` interface.
|
||||||
|
|
||||||
.. class:: PurePosixPath(*pathsegments)
|
.. class:: PurePosixPath(*pathsegments)
|
||||||
|
|
||||||
A subclass of :class:`PurePath`, this path flavour represents non-Windows
|
A subclass of :class:`PurePath`, this path flavour represents non-Windows
|
||||||
|
@ -212,6 +213,14 @@ The slash operator helps create child paths, similarly to :func:`os.path.join`::
|
||||||
>>> '/usr' / q
|
>>> '/usr' / q
|
||||||
PurePosixPath('/usr/bin')
|
PurePosixPath('/usr/bin')
|
||||||
|
|
||||||
|
A path object can be used anywhere an object implementing :class:`os.PathLike`
|
||||||
|
is accepted::
|
||||||
|
|
||||||
|
>>> import os
|
||||||
|
>>> p = PurePath('/etc')
|
||||||
|
>>> os.fspath(p)
|
||||||
|
'/etc'
|
||||||
|
|
||||||
The string representation of a path is the raw filesystem path itself
|
The string representation of a path is the raw filesystem path itself
|
||||||
(in native form, e.g. with backslashes under Windows), which you can
|
(in native form, e.g. with backslashes under Windows), which you can
|
||||||
pass to any function taking a file path as a string::
|
pass to any function taking a file path as a string::
|
||||||
|
|
|
@ -634,12 +634,15 @@ class PurePath(object):
|
||||||
for a in args:
|
for a in args:
|
||||||
if isinstance(a, PurePath):
|
if isinstance(a, PurePath):
|
||||||
parts += a._parts
|
parts += a._parts
|
||||||
elif isinstance(a, str):
|
else:
|
||||||
|
a = os.fspath(a)
|
||||||
|
if isinstance(a, str):
|
||||||
# Force-cast str subclasses to str (issue #21127)
|
# Force-cast str subclasses to str (issue #21127)
|
||||||
parts.append(str(a))
|
parts.append(str(a))
|
||||||
else:
|
else:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"argument should be a path or str object, not %r"
|
"argument should be a str object or an os.PathLike "
|
||||||
|
"object returning str, not %r"
|
||||||
% type(a))
|
% type(a))
|
||||||
return cls._flavour.parse_parts(parts)
|
return cls._flavour.parse_parts(parts)
|
||||||
|
|
||||||
|
@ -693,6 +696,9 @@ class PurePath(object):
|
||||||
self._parts) or '.'
|
self._parts) or '.'
|
||||||
return self._str
|
return self._str
|
||||||
|
|
||||||
|
def __fspath__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
def as_posix(self):
|
def as_posix(self):
|
||||||
"""Return the string representation of the path with forward (/)
|
"""Return the string representation of the path with forward (/)
|
||||||
slashes."""
|
slashes."""
|
||||||
|
@ -943,6 +949,10 @@ class PurePath(object):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# Can't subclass os.PathLike from PurePath and keep the constructor
|
||||||
|
# optimizations in PurePath._parse_args().
|
||||||
|
os.PathLike.register(PurePath)
|
||||||
|
|
||||||
|
|
||||||
class PurePosixPath(PurePath):
|
class PurePosixPath(PurePath):
|
||||||
_flavour = _posix_flavour
|
_flavour = _posix_flavour
|
||||||
|
|
|
@ -190,13 +190,18 @@ class _BasePurePathTest(object):
|
||||||
P = self.cls
|
P = self.cls
|
||||||
p = P('a')
|
p = P('a')
|
||||||
self.assertIsInstance(p, P)
|
self.assertIsInstance(p, P)
|
||||||
|
class PathLike:
|
||||||
|
def __fspath__(self):
|
||||||
|
return "a/b/c"
|
||||||
P('a', 'b', 'c')
|
P('a', 'b', 'c')
|
||||||
P('/a', 'b', 'c')
|
P('/a', 'b', 'c')
|
||||||
P('a/b/c')
|
P('a/b/c')
|
||||||
P('/a/b/c')
|
P('/a/b/c')
|
||||||
|
P(PathLike())
|
||||||
self.assertEqual(P(P('a')), P('a'))
|
self.assertEqual(P(P('a')), P('a'))
|
||||||
self.assertEqual(P(P('a'), 'b'), P('a/b'))
|
self.assertEqual(P(P('a'), 'b'), P('a/b'))
|
||||||
self.assertEqual(P(P('a'), P('b')), P('a/b'))
|
self.assertEqual(P(P('a'), P('b')), P('a/b'))
|
||||||
|
self.assertEqual(P(P('a'), P('b'), P('c')), P(PathLike()))
|
||||||
|
|
||||||
def _check_str_subclass(self, *args):
|
def _check_str_subclass(self, *args):
|
||||||
# Issue #21127: it should be possible to construct a PurePath object
|
# Issue #21127: it should be possible to construct a PurePath object
|
||||||
|
@ -384,6 +389,12 @@ class _BasePurePathTest(object):
|
||||||
parts = p.parts
|
parts = p.parts
|
||||||
self.assertEqual(parts, (sep, 'a', 'b'))
|
self.assertEqual(parts, (sep, 'a', 'b'))
|
||||||
|
|
||||||
|
def test_fspath_common(self):
|
||||||
|
P = self.cls
|
||||||
|
p = P('a/b')
|
||||||
|
self._check_str(p.__fspath__(), ('a/b',))
|
||||||
|
self._check_str(os.fspath(p), ('a/b',))
|
||||||
|
|
||||||
def test_equivalences(self):
|
def test_equivalences(self):
|
||||||
for k, tuples in self.equivalences.items():
|
for k, tuples in self.equivalences.items():
|
||||||
canon = k.replace('/', self.sep)
|
canon = k.replace('/', self.sep)
|
||||||
|
|
12
Misc/NEWS
12
Misc/NEWS
|
@ -10,6 +10,8 @@ What's New in Python 3.6.0 alpha 2
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #27186: Add support for os.PathLike objects to open() (part of PEP 519).
|
||||||
|
|
||||||
- Issue #27066: Fixed SystemError if a custom opener (for open()) returns a
|
- Issue #27066: Fixed SystemError if a custom opener (for open()) returns a
|
||||||
negative number without setting an exception.
|
negative number without setting an exception.
|
||||||
|
|
||||||
|
@ -36,6 +38,14 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #27186: Add os.PathLike support to pathlib, removing its provisional
|
||||||
|
status (part of PEP 519).
|
||||||
|
|
||||||
|
- Issue #27186: Add support for os.PathLike objects to os.fsencode() and
|
||||||
|
os.fsdecode() (part of PEP 519).
|
||||||
|
|
||||||
|
- Issue #27186: Introduce os.PathLike and os.fspath() (part of PEP 519).
|
||||||
|
|
||||||
- A new version of typing.py provides several new classes and
|
- A new version of typing.py provides several new classes and
|
||||||
features: @overload outside stubs, Reversible, DefaultDict, Text,
|
features: @overload outside stubs, Reversible, DefaultDict, Text,
|
||||||
ContextManager, Type[], NewType(), TYPE_CHECKING, and numerous bug
|
ContextManager, Type[], NewType(), TYPE_CHECKING, and numerous bug
|
||||||
|
@ -204,6 +214,8 @@ Misc
|
||||||
C API
|
C API
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
- Issue #27186: Add the PyOS_FSPath() function (part of PEP 519).
|
||||||
|
|
||||||
- Issue #26282: PyArg_ParseTupleAndKeywords() now supports positional-only
|
- Issue #26282: PyArg_ParseTupleAndKeywords() now supports positional-only
|
||||||
parameters.
|
parameters.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue