[Python-Dev] proposed os.fspath() change

Ethan Furman ethan at stoneleaf.us
Wed Jun 15 14:46:21 EDT 2016

On 06/15/2016 10:59 AM, Brett Cannon wrote:
> On Wed, 15 Jun 2016 at 09:48 Guido van Rossum wrote:

>> These are really two separate proposals.
>> I'm okay with checking the return value of calling obj.__fspath__;
>> that's an error in the object anyways, and it doesn't matter much
>> whether we do this or not (though when approving the PEP I
>> considered this and decided not to insert a check for this). But it
>> doesn't affect your example, does it? I guess it's easier to raise
>> now and change the API in the future to avoid raising in this case
>> (if we find that raising is undesirable) than the other way around,
>> so I'm +0 on this.
> +0 from me as well. I know in some code in the stdlib that has been
> ported which prior to adding support was explicitly checking for
> str/bytes this will eliminate its own checking (obviously not a
> motivating factor as it's pretty minor).

If we accept both parts of this proposal the checking will have to stay 
in place as the original argument may not have been bytes, str, nor 

>> The other proposal (passing anything that's not understood right
>> through) is more interesting and your use case is somewhat
>> compelling. Catching the exception coming out of os.fspath() would
>> certainly be much messier. The question remaining is whether, when
>> this behavior is not desired (e.g. when the caller of os.fspath()
>> just wants a string that it can pass to open()), the condition of
>> passing that's neither a string not supports __fspath__ still
>> produces an understandable error.

This is no different than before os.fspath() existed -- if the function 
wasn't checking that the "filename" was a str but just used it as-is, 
then whatever strange, possibly-hard-to-debug error they would get now 
is the same as what they would have gotten before.

>> I'm not sure that that's the case.
>> E.g. open() accepts file descriptors in addition to paths, but I'm
>> not sure that accepting an integer is a good idea in most cases --
>> it either gives a mystery "Bad file descriptor" error or starts
>> reading/writing some random system file, which it then closes once
>> the stream is closed.

My vision of os.fspath() is simply to reduce rich-path objects to their 
component str or bytes representation, and pass anything else through.

The advantage:

- if os.open accepts str/bytes/fd it can prep the argument by
   calling os.fspath() and then do it's argument checking all
   in one place;

- if lzma accepts bytes/str/filelike-obj it can prep its argument
   by calling os.fspath() and then do it's argument checking all in
   one place

- if Path accepts str/os.PathLike it can prep it's argument(s)
   with os.fspath() and then do its argument checking all in one

> The FD issue of magically passing through an int was also a concern when
> Ethan brought this up in an issue on the tracker. My argument is that
> FDs are not file paths and so shouldn't magically pass through if we're
> going to type-check anything or claim os.fspath() only works with paths
> (FDs are already open file objects). So in my view  either we go ahead
> and type-check the return value of __fspath__() and thus restrict
> everything coming out of os.fspath() to Union[str, bytes] or we don't
> type check anything and be consistent that os.fspath() simply does is
> call __fspath__() if present.

This is better than what os.fspath() currently does as it has all the 
advantages listed above, but why is checking the output of __fspath__ 
incompatible with not checking anything else?

> And just  because I'm thinking about it, I would special-case the FDs,
> not os.PathLike (clearer why you care and faster as it skips the
> override of __subclasshook__):
> # Can be a single-line ternary operator if preferred.
> if not isinstance(filename, int):
>      filename = os.fspath(filename)

That example will not do the right thing in the lzma case.


More information about the Python-Dev mailing list