4

I've seen lines like that in typeshed:

https://github.com/python/typeshed/blob/994b69ef8f18e76689daca3947879c3d7f76173e/stdlib/_typeshed/__init__.pyi#L77

But os.PathLike doesn't appear to be generic. It doesn't let strings be passed.

import os
import pathlib

def test(f: os.PathLike[str]):
    print(pathlib.Path(f))


test(r"C:\Program Files")

The above snippet fails Mypy.

Alex Waygood
  • 6,304
  • 3
  • 24
  • 46
Greedo
  • 4,967
  • 2
  • 30
  • 78
  • 1
    You should really transcribe the relevant code snippets from typeshed (besides including the link). Python is open source so it's ok, and it makes the question more self-contained and better for the readers. – bad_coder Jun 09 '22 at 20:38

1 Answers1

5

The source code that you link to in your question shows that os.PathLike is an Abstract Base Class that has a single abstractmethod, __fspath__. Due to the implementation of __subclasshook__, any classes that define __fspath__ are considered to be subclasses of os.PathLike even if PathLike is not in the class's method resolution order.

The str data type, however, does not have an __fspath__ method. As such, it does not conform to the PathLike interface, and so it makes sense that MyPy should reject an argument of type str if an argument of type PathLike was expected.

If your function can accept either a str object or a PathLike object, you should annotate the argument as being of type Union[str, PathLike[str]], much as typeshed does here.

As an aside, I'm slightly confused as to why you say "os.PathLike doesn't appear to be generic". The class defines __class_getitem__, so it's perfectly parametriseable at runtime. In Python >= 3.9:

>>> from os import PathLike
>>> PathLike[str]
os.PathLike[str]
>>> PathLike[bytes]
os.PathLike[bytes]
>>> PathLike['idk, anything you like really']
os.PathLike['idk, anything you like really']
Alex Waygood
  • 6,304
  • 3
  • 24
  • 46
  • 1
    Ok thanks, I guess I was wondering what the significance of [str] or [bytes] was. It's the return type of `__fspath__` - so I thought str would be automatically allowed by mypy since `PathLike[str]` means "a class with a named function that returns a `str`", so I assumed passing a str instead would be deemed acceptable. – Greedo Oct 22 '21 at 16:34
  • @Greedo yeah, I'd always look at the typeshed stubs over the cpython source code if you want to find out the significance of `[str]`, `[bytes]`, etc. The runtime source code doesn't have any type hints at all; if you want to find out *why* a class is parametriseable, and what that means in terms of type-hinting, I'd always go look at the typeshed stubs :) – Alex Waygood Oct 22 '21 at 17:27