summaryrefslogtreecommitdiffstats
path: root/Lib/os.py
diff options
context:
space:
mode:
authorBrett Cannon <brett@python.org>2016-06-24 19:03:43 (GMT)
committerBrett Cannon <brett@python.org>2016-06-24 19:03:43 (GMT)
commitc78ca1e044b7ca4c1764bb3670196e72351d4467 (patch)
tree3435d7babe85991192e645d12c9ec2b24b4de04f /Lib/os.py
parent19b2a53a82c8f4d179efdc39fb39f766191cac2b (diff)
downloadcpython-c78ca1e044b7ca4c1764bb3670196e72351d4467.zip
cpython-c78ca1e044b7ca4c1764bb3670196e72351d4467.tar.gz
cpython-c78ca1e044b7ca4c1764bb3670196e72351d4467.tar.bz2
Issue #27186: Update os.fspath()/PyOS_FSPath() to check the return
type of __fspath__(). As part of this change, also make sure that the pure Python implementation of os.fspath() is tested.
Diffstat (limited to 'Lib/os.py')
-rw-r--r--Lib/os.py71
1 files changed, 41 insertions, 30 deletions
diff --git a/Lib/os.py b/Lib/os.py
index 67e1992..c31ecb2 100644
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -881,14 +881,11 @@ def _fscodec():
On Windows, use 'strict' error handler if the file system encoding is
'mbcs' (which is the default encoding).
"""
- filename = fspath(filename)
- if isinstance(filename, bytes):
- return filename
- elif isinstance(filename, str):
+ filename = fspath(filename) # Does type-checking of `filename`.
+ if isinstance(filename, str):
return filename.encode(encoding, errors)
else:
- raise TypeError("expected str, bytes or os.PathLike object, not "
- + type(filename).__name__)
+ return filename
def fsdecode(filename):
"""Decode filename (an os.PathLike, bytes, or str) from the filesystem
@@ -896,14 +893,11 @@ def _fscodec():
Windows, use 'strict' error handler if the file system encoding is
'mbcs' (which is the default encoding).
"""
- filename = fspath(filename)
- if isinstance(filename, str):
- return filename
- elif isinstance(filename, bytes):
+ filename = fspath(filename) # Does type-checking of `filename`.
+ if isinstance(filename, bytes):
return filename.decode(encoding, errors)
else:
- raise TypeError("expected str, bytes or os.PathLike object, not "
- + type(filename).__name__)
+ return filename
return fsencode, fsdecode
@@ -1102,27 +1096,44 @@ def fdopen(fd, *args, **kwargs):
import io
return io.open(fd, *args, **kwargs)
-# Supply os.fspath() if not defined in C
-if not _exists('fspath'):
- def fspath(path):
- """Return the string representation of the path.
- If str or bytes is passed in, it is returned unchanged.
- """
- if isinstance(path, (str, bytes)):
- return path
+# For testing purposes, make sure the function is available when the C
+# implementation exists.
+def _fspath(path):
+ """Return the path representation of a path-like object.
- # Work from the object's type to match method resolution of other magic
- # methods.
- path_type = type(path)
- try:
- return path_type.__fspath__(path)
- except AttributeError:
- if hasattr(path_type, '__fspath__'):
- raise
+ If str or bytes is passed in, it is returned unchanged. Otherwise the
+ os.PathLike interface is used to get the path representation. If the
+ path representation is not str or bytes, TypeError is raised. If the
+ provided path is not str, bytes, or os.PathLike, TypeError is raised.
+ """
+ if isinstance(path, (str, bytes)):
+ return path
+
+ # Work from the object's type to match method resolution of other magic
+ # methods.
+ path_type = type(path)
+ try:
+ path_repr = path_type.__fspath__(path)
+ except AttributeError:
+ if hasattr(path_type, '__fspath__'):
+ raise
+ else:
+ raise TypeError("expected str, bytes or os.PathLike object, "
+ "not " + path_type.__name__)
+ if isinstance(path_repr, (str, bytes)):
+ return path_repr
+ else:
+ raise TypeError("expected {}.__fspath__() to return str or bytes, "
+ "not {}".format(path_type.__name__,
+ type(path_repr).__name__))
+
+# If there is no C implementation, make the pure Python version the
+# implementation as transparently as possible.
+if not _exists('fspath'):
+ fspath = _fspath
+ fspath.__name__ = "fspath"
- raise TypeError("expected str, bytes or os.PathLike object, not "
- + path_type.__name__)
class PathLike(abc.ABC):