New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
os.PathLike subclasshook causes subclass checks true on abstract implementation #83059
Comments
Quick and small fix. os.PathLike.__subclasshook__ does not check if cls is PathLike as abstract classes should. This in turn causes this bug: class A(PathLike):
pass
class B:
def __fspath__(self):
pass
I will fix the bug later today and push a patch over to python/cpython on GitHub. |
I can't reproduce in Python 3.8.0: >>> import os
>>> class A(os.PathLike): pass
...
>>> class B:
... def __fspath__(self): pass
...
>>> issubclass(B, A)
True Did you check against an older version of Python? |
Hey Brett, that's exactly the bug. It's supposed to be False ofc. On Thu, Nov 21, 2019, 9:45 PM Brett Cannon <report@bugs.python.org> wrote:
|
Ah, your |
Done. On Fri, Nov 22, 2019, 12:23 PM Bar Harel <report@bugs.python.org> wrote:
|
I just realized one problem with this is it explicitly requires subclassing the ABC while os.PathLike is supposed to represent a protocol (before typing.Protocol was a thing). So why is it bad that in the example class B is considered a "subclass" of os.PathLike by implementing the protocol? Since it implements the expected protocol what exactly is being lost by not checking for an explicit registration or subclass? |
This is not bad, my understanding of the problem is that currently B is considered a subclass of A, while the latter should not be structural. To give an analogy with PEP-544 (sorry, this is my favourite one :-)) consider this: class P(Protocol):
def some(self): ...
class C:
def some(self): ... Here C is obviously a "subclass" of P, but: class Bad(P): # <- this is _no_ a protocol, just a nominal class
pass # explicitly subclassing P
class Good(P, Protocol): # <- this is a subprotocol that
pass # happened to be identical to P So here C is a "subclass" of Good, but not a "subclass" of Bad. |
Just for reference/existing behavior: >>> class A(collections.abc.Iterable): pass
...
>>> class B:
... def __iter__(): pass
...
>>> issubclass(B, A)
False
>>> issubclass(B, collections.abc.Iterable)
True
>>> issubclass(A, collections.abc.Iterable)
True |
A better example is this: class A(PathLike):
def foo(self):
"""For all your foo needs"""
class B:
def __fspath__(self):
pass
|
Ready for merge |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: