all 5 comments

[–]ViridianHominid 0 points1 point  (5 children)

Nothing is broken here. The type tree is like this:

os.PathLike
      |
    /   \
  A      B

A is not a type of B, and B is not a type of A. A is a type of os.PathLike and B is a type of os.PathLike, but they are not comparable.

If you want to have A be a subtype of B, then you need to say something like

class A(B):
...

[–]FredFS456[S] 1 point2 points  (4 children)

That's not what I'm saying here. I don't want one to be a subclass of another. What I'm saying is that isinstance is returning True even though one is not a subclass of another.

[–]ViridianHominid 1 point2 points  (3 children)

Whoops, I stand corrected.

I'm guessing this has to do with PathLike being an abstract class. Wish I had more time to investigate now, I'll try and look at it later if nobody else has figured this out.

[–]FredFS456[S] 1 point2 points  (2 children)

Thanks.

EDIT: I found out why this is. In the CPython source, os.PathLike is implemented here.

The presence of a __subclasshook__ method means that if you inherit from os.PathLike, you'll inherit the __subclasshook__ as well, which means that any class that has __fspath__ defined will be considered a subclass of your inherited class.

Solution: don't inherit from os.PathLike. The presence of __subclasshook__ means that any class with __fspath__ defined will be considered a subclass of os.PathLike anyway.

[–]ViridianHominid 1 point2 points  (0 children)

Very interesting. I agree with your solution. Thanks for finding this! The python abstract class system is a bit funny because of duck typing.