[Python-Dev] proposed os.fspath() change (original) (raw)
Koos Zevenhoven k7hoven at gmail.com
Wed Jun 15 13:39:03 EDT 2016
- Previous message (by thread): [Python-Dev] proposed os.fspath() change
- Next message (by thread): [Python-Dev] proposed os.fspath() change
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
My proposal at the point of the first PEP draft solved both of these issues.
That version of the fspath function passed anything right through that
was an instance of the keyword-only type_constraint
. If not, it
would ask fspath, and before returning the result, it would check
that fspath returned an instance of type_constraint
and
otherwise raise a TypeError. type_constraint=object
would then have
given the behavior you want. I always wanted fspath to spare the
caller from all the instance checking (most of which it does even
now).
The main problem with setting type_constraint to something broader than (str, bytes) is that then that parameter would affect the return type of the function, which would at least complicate the type hinting issue. Mypy might now support things like
@overload def fspath(path: T, type_constraint: Type[T] = (str, bytes)) -> T: ...
but then again, isinstance and Union are not compatible (for a reason?), and PEP484 for a reason does not allow tuples like (str, bytes) in place of Unions.
Anyway, if we were to go back to this behavior, we would need to decide whether to officially allow a wider type constraint or whether to leave that to Stack Overflow, so to speak.
-- Koos
On Wed, Jun 15, 2016 at 7:46 PM, Guido van Rossum <guido at python.org> 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. 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. 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. On Wed, Jun 15, 2016 at 9:12 AM, Ethan Furman <ethan at stoneleaf.us> wrote:
I would like to make a change to os.fspath(). Specifically, os.fspath() currently raises an exception if something besides str, bytes, or os.PathLike is passed in, but makes no checks if an os.PathLike object returns something besides a str or bytes. I would like to change that to the opposite: if a non-os.PathLike is passed in, return it unchanged (so no change for str and bytes); if an os.PathLike object returns something that is not a str nor bytes, raise. An example of the difference in the lzma file: Current code (has not been upgraded to use os.fspath() yet) ----------------------------------------------------------- if isinstance(filename, (str, bytes)): if "b" not in mode: mode += "b" self.fp = builtins.open(filename, mode) self.closefp = True self.mode = modecode elif hasattr(filename, "read") or hasattr(filename, "write"): self.fp = filename self.mode = modecode else: raise TypeError( "filename must be a str or bytes object, or a file" ) Code change if using upgraded os.fspath() (placed before above stanza): filename = os.fspath(filename) Code change with current os.fspath() (ditto): if isinstance(filename, os.PathLike): filename = os.fspath(filename) My intention with the os.fspath() function was to minimize boiler-plate code and make PathLike objects easy and painless to support; having to discover if any given parameter is PathLike before calling os.fspath() on it is, IMHO, just the opposite. There is also precedent for having a dunder check the return type: --> class Huh: ... def int(self): ... return 'string' ... def index(self): ... return b'bytestring' ... def bool(self): ... return 'true-ish' ... --> h = Huh() --> int(h) Traceback (most recent call last): File "", line 1, in TypeError: int returned non-int (type str) --> ''[h] Traceback (most recent call last): File "", line 1, in TypeError: index returned non-int (type bytes) --> bool(h) Traceback (most recent call last): File "", line 1, in TypeError: bool should return bool, returned str Arguments in favor or against? --
Ethan
Python-Dev mailing list Python-Dev at python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/guido%40python.org
-- --Guido van Rossum (python.org/~guido)
Python-Dev mailing list Python-Dev at python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/k7hoven%40gmail.com
--
- Koos Zevenhoven + http://twitter.com/k7hoven +
- Previous message (by thread): [Python-Dev] proposed os.fspath() change
- Next message (by thread): [Python-Dev] proposed os.fspath() change
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]