diff options
author | Brett Cannon <brett@python.org> | 2016-06-24 19:03:43 (GMT) |
---|---|---|
committer | Brett Cannon <brett@python.org> | 2016-06-24 19:03:43 (GMT) |
commit | c78ca1e044b7ca4c1764bb3670196e72351d4467 (patch) | |
tree | 3435d7babe85991192e645d12c9ec2b24b4de04f /Lib/os.py | |
parent | 19b2a53a82c8f4d179efdc39fb39f766191cac2b (diff) | |
download | cpython-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.py | 71 |
1 files changed, 41 insertions, 30 deletions
@@ -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): |