Skip to content
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

Behaviour change in py312 for protocols with non-callable members and custom __subclasshook__ methods #105974

Closed
AlexWaygood opened this issue Jun 21, 2023 · 4 comments
Assignees
Labels
3.12 bugs and security fixes 3.13 bugs and security fixes stdlib Python modules in the Lib dir topic-typing type-bug An unexpected behavior, bug, or error

Comments

@AlexWaygood
Copy link
Member

AlexWaygood commented Jun 21, 2023

Bug report

On Python 3.11:

>>> from typing import *
>>> @runtime_checkable
... class Foo(Protocol):
...     x = 1
...     @classmethod
...     def __subclasshook__(cls, other):
...         return hasattr(other, 'x')
...
>>> issubclass(object, Foo)
False

On Python 3.12:

>>> from typing import *
>>> @runtime_checkable
... class Foo(Protocol):
...     x = 1
...     @classmethod
...     def __subclasshook__(cls, other):
...         return hsattr(cls, 'x')
...
>>> issubclass(object, Foo)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\alexw\coding\cpython\Lib\typing.py", line 1829, in __subclasscheck__
    raise TypeError(
TypeError: Protocols with non-method members don't support issubclass()

I think I prefer the Python 3.11 behaviour here, since the whole point of allowing protocols to define custom __subclasshook__ methods is so that users can customise how issubclass() works on user-defined protocols.

Linked PRs

@AlexWaygood AlexWaygood added type-bug An unexpected behavior, bug, or error stdlib Python modules in the Lib dir topic-typing 3.12 bugs and security fixes 3.13 bugs and security fixes labels Jun 21, 2023
@AlexWaygood AlexWaygood self-assigned this Jun 21, 2023
AlexWaygood added a commit to AlexWaygood/cpython that referenced this issue Jun 21, 2023
…with non-callable members and custom `__subclasshook__` methods
@AlexWaygood
Copy link
Member Author

AlexWaygood commented Jun 21, 2023

I think I prefer the Python 3.11 behaviour here, since the whole point of allowing protocols to define custom __subclasshook__ methods is so that users can customise how issubclass() works on user-defined protocols.

There is an argument that this behaviour change should be considered a feature rather than a bug. Mypy will complain about issubclass() checks against protocols with non-callable members, whether or not a custom __subclasshook__ method is defined: https://mypy-play.net/?mypy=latest&python=3.11&gist=83529c67737e01d8d837b700012e763b. It's good for the behaviour at runtime to closely reflect how type checkers understand Protocol wherever possible.

The "feature" where users can define custom __subclasshook__ methods on protocol classes is undocumented (and, apparently, untested). I think it was actually also unintentional, and only worked in Python <=3.11 because of some logic to ensure that concrete subclasses of protocol classes are able to define custom __subclasshook__ methods.

But the behaviour change in Python 3.12 was unintentional, and could break some users? I'm not sure really.

@AlexWaygood
Copy link
Member Author

AlexWaygood commented Jun 23, 2023

There is an argument that this behaviour change should be considered a feature rather than a bug.

@JelleZijlstra, thoughts on this? Is there a case to be made that the new behaviour should be considered a feature rather than a bug?

@JelleZijlstra
Copy link
Member

I think the new behavior is a bug; we shouldn't be clobbering people's __subclasshook__ if they explicitly set one. It's fine if mypy rejects such classes as it's static, but the runtime can be more lenient.

@AlexWaygood
Copy link
Member Author

SGTM

AlexWaygood added a commit that referenced this issue Jun 23, 2023
…on-callable members and custom `__subclasshook__` methods (#105976)
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Jun 23, 2023
…with non-callable members and custom `__subclasshook__` methods (pythonGH-105976)

(cherry picked from commit 9499b0f)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
AlexWaygood added a commit that referenced this issue Jun 23, 2023
… with non-callable members and custom `__subclasshook__` methods (GH-105976) (#106032)

gh-105974: Revert unintentional behaviour change for protocols with non-callable members and custom `__subclasshook__` methods (GH-105976)
(cherry picked from commit 9499b0f)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.12 bugs and security fixes 3.13 bugs and security fixes stdlib Python modules in the Lib dir topic-typing type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

2 participants