[Python-checkins] cpython: Issue #27186: Add os.PathLike support to pathlib.

brett.cannon python-checkins at python.org
Fri Jun 10 15:34:06 EDT 2016


https://hg.python.org/cpython/rev/a5a013ca5687
changeset:   101855:a5a013ca5687
user:        Brett Cannon <brett at python.org>
date:        Fri Jun 10 12:20:49 2016 -0700
summary:
  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.

files:
  Doc/library/pathlib.rst  |  23 ++++++++++++++++-------
  Lib/pathlib.py           |  22 ++++++++++++++++------
  Lib/test/test_pathlib.py |  11 +++++++++++
  Misc/NEWS                |  14 +++++++++++++-
  4 files changed, 56 insertions(+), 14 deletions(-)


diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst
--- a/Doc/library/pathlib.rst
+++ b/Doc/library/pathlib.rst
@@ -31,12 +31,6 @@
    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.
 
-.. 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::
    :pep:`428`: The pathlib module -- object-oriented filesystem paths.
 
@@ -107,7 +101,8 @@
       PurePosixPath('setup.py')
 
    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')
       PurePosixPath('foo/some/path/bar')
@@ -148,6 +143,12 @@
    to ``PurePosixPath('bar')``, which is wrong if ``foo`` is a symbolic link
    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)
 
    A subclass of :class:`PurePath`, this path flavour represents non-Windows
@@ -212,6 +213,14 @@
    >>> '/usr' / q
    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
 (in native form, e.g. with backslashes under Windows), which you can
 pass to any function taking a file path as a string::
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -634,13 +634,16 @@
         for a in args:
             if isinstance(a, PurePath):
                 parts += a._parts
-            elif isinstance(a, str):
-                # Force-cast str subclasses to str (issue #21127)
-                parts.append(str(a))
             else:
-                raise TypeError(
-                    "argument should be a path or str object, not %r"
-                    % type(a))
+                a = os.fspath(a)
+                if isinstance(a, str):
+                    # Force-cast str subclasses to str (issue #21127)
+                    parts.append(str(a))
+                else:
+                    raise TypeError(
+                        "argument should be a str object or an os.PathLike "
+                        "object returning str, not %r"
+                        % type(a))
         return cls._flavour.parse_parts(parts)
 
     @classmethod
@@ -693,6 +696,9 @@
                                                   self._parts) or '.'
             return self._str
 
+    def __fspath__(self):
+        return str(self)
+
     def as_posix(self):
         """Return the string representation of the path with forward (/)
         slashes."""
@@ -943,6 +949,10 @@
                 return False
         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):
     _flavour = _posix_flavour
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -190,13 +190,18 @@
         P = self.cls
         p = P('a')
         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(PathLike())
         self.assertEqual(P(P('a')), P('a'))
         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('c')), P(PathLike()))
 
     def _check_str_subclass(self, *args):
         # Issue #21127: it should be possible to construct a PurePath object
@@ -384,6 +389,12 @@
         parts = p.parts
         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):
         for k, tuples in self.equivalences.items():
             canon = k.replace('/', self.sep)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,8 @@
 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
   negative number without setting an exception.
 
@@ -36,6 +38,14 @@
 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
   features: @overload outside stubs, Reversible, DefaultDict, Text,
   ContextManager, Type[], NewType(), TYPE_CHECKING, and numerous bug
@@ -198,12 +208,14 @@
 Misc
 ----
 
-- Issue #17500, and https://github.com/python/pythondotorg/issues/945: Remove 
+- Issue #17500, and https://github.com/python/pythondotorg/issues/945: Remove
   unused and outdated icons.
 
 C API
 -----
 
+- Issue #27186: Add the PyOS_FSPath() function (part of PEP 519).
+
 - Issue #26282: PyArg_ParseTupleAndKeywords() now supports positional-only
   parameters.
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list