[Python-ideas] tweaking the file system path protocol

Wolfgang Maier wolfgang.maier at biologie.uni-freiburg.de
Tue May 23 06:12:11 EDT 2017


What do you think of this idea for a slight modification to os.fspath:
the current version checks whether its arg is an instance of str, bytes 
or any subclass and, if so, returns the arg unchanged. In all other 
cases it tries to call the type's __fspath__ method to see if it can get 
str, bytes, or a subclass thereof this way.

My proposal is to change this to:
1) check whether the type of the argument is str or bytes *exactly*; if 
so, return the argument unchanged
2) check wether __fspath__ can be called on the type and returns an 
instance of str, bytes, or any subclass (just like in the current version)
3) check whether the type is a subclass of str or bytes and, if so, 
return it unchanged

This would have the following implications:
a) it would speed up the very common case when the arg is either a str 
or a bytes instance exactly
b) user-defined classes that inherit from str or bytes could control 
their path representation just like any other class
c) subclasses of str/bytes that don't define __fspath__ would still work 
like they do now, but their processing would be slower
d) subclasses of str/bytes that accidentally define a __fspath__ method 
would change their behavior

I think cases c) and d) could be sufficiently rare that the pros 
outweigh the cons?


Here's how the proposal could be implemented in the pure Python version 
(os._fspath):

def _fspath(path):
     path_type = type(path)
     if path_type is str or path_type is bytes:
         return path

     # Work from the object's type to match method resolution of other magic
     # methods.
     try:
         path_repr = path_type.__fspath__(path)
     except AttributeError:
         if hasattr(path_type, '__fspath__'):
             raise
         elif issubclass(path_type, (str, bytes)):
             return path
         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__))



More information about the Python-ideas mailing list