-
-
Notifications
You must be signed in to change notification settings - Fork 30.3k
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
Typing: runtime-checkable protocols are broken on main
#104555
Comments
(I'm working on a fix) |
Thanks for catching! I suppose this is about |
Yes. |
I'm getting very confused here. The fix for the original issue is simple, and I've fixed it locally. But as part of the PR, I tried adding this test, and the last assertion fails (the test reports that def test_pep695_generic_protocol_noncallable_members(self):
@runtime_checkable
class Spam[T](Protocol):
x: T
class Eggs[T]:
def __init__(self, x: T) -> None:
self.x = x
self.assertIsInstance(Eggs(42), Spam)
with self.assertRaises(TypeError):
issubclass(Eggs, Spam) But I can't reproduce the failure in the REPL: >>> from typing import *
>>> @runtime_checkable
... class Spam[T](Protocol):
... x: T
...
...
>>> class Eggs[T]:
... def __init__(self, x: T) -> None:
... self.x = x
...
...
>>> issubclass(Eggs, Spam)
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
issubclass(Eggs, Spam)
File "C:\Users\alexw\coding\cpython\Lib\abc.py", line 123, in __subclasscheck__
return _abc_subclasscheck(cls, subclass)
File "C:\Users\alexw\coding\cpython\Lib\typing.py", line 1875, in _proto_hook
raise TypeError("Protocols with non-method members"
TypeError: Protocols with non-method members don't support issubclass() |
Anyway, I'll submit a PR without that test for now... |
I'll look into this more. |
Okay, cool. I'll enable automerge on my PR for now, as it definitely gets us closer to correct behaviour. |
The issue you saw also reproduces for me without PEP 695 syntax. It seems to be due to the |
Aha, so we've discovered a bug, it just isn't a new bug. |
It's possible this bug was introduced by the fact that Generic is now a C class, haven't tried on 3.11 yet. |
Yes, looks like the bug is new in 3.12. Running this test file passes on 3.11, but not on import unittest
from typing import runtime_checkable, Generic, Protocol, TypeVar
T = TypeVar("T")
class TestProtocols(unittest.TestCase):
def test_pep695_generic_protocol_noncallable_members(self):
@runtime_checkable
class Spam(Protocol[T]):
x: T
class Eggs(Generic[T]):
def __init__(self, x: T) -> None:
self.x = x
self.assertIsInstance(Eggs(42), Spam)
with self.assertRaises(TypeError):
issubclass(Eggs, Spam)
if __name__ == "__main__":
unittest.main() |
It's easier to keep the discussion in one place, so I'm reopening so we can continue discussing the other bug |
A few things I found:
|
main
|
(I am, again, working on a fix :) |
…ng._ProtocolMeta.__instancecheck__
Incredible stuff: Python 3.12.0a7+ (heads/main:1163782868, May 16 2023, 18:09:28) [MSC v.1932 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from typing import *
>>> @runtime_checkable
... class Foo(Protocol):
... x: int
...
>>> class Bar:
... x = 42
...
>>> issubclass(Bar, Foo)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\alexw\coding\cpython\Lib\abc.py", line 123, in __subclasscheck__
return _abc_subclasscheck(cls, subclass)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\alexw\coding\cpython\Lib\typing.py", line 1875, in _proto_hook
raise TypeError("Protocols with non-method members"
TypeError: Protocols with non-method members don't support issubclass()
>>> isinstance(Bar(), Foo)
True
>>> issubclass(Bar, Foo)
False |
This comment was marked as outdated.
This comment was marked as outdated.
@sunmy2019 I was just about to file 2601138 as a PR, which fixes things, but do you think we could fix it by just adjusting the |
Oh sorry, ignore my previous comment. |
Confirmed that the code path that does not raise TypeError goes through L606. Lines 589 to 608 in 03e3c34
@AlexWaygood You are right! |
@sunmy2019 thanks for checking! |
Oh, now I see the whole picture!
|
More details for (2) (3) The
It then raises an exception. In the problematic scenarios (3):
It does raise an exception. |
* main: (26 commits) pythonGH-101520: Move tracemalloc functionality into core, leaving interface in Modules. (python#104508) typing: Add more tests for TypeVar (python#104571) pythongh-104572: Improve error messages for invalid constructs in PEP 695 contexts (python#104573) typing: Use PEP 695 syntax in typing.py (python#104553) pythongh-102153: Start stripping C0 control and space chars in `urlsplit` (python#102508) pythongh-104469: Update README.txt for _testcapi (pythongh-104529) pythonGH-103092: isolate `_elementtree` (python#104561) pythongh-104050: Add typing to Argument Clinic converters (python#104547) pythonGH-103906: Remove immortal refcounting in the interpreter (pythonGH-103909) pythongh-87474: Fix file descriptor leaks in subprocess.Popen (python#96351) pythonGH-103092: isolate `pyexpat` (python#104506) pythongh-75367: Fix data descriptor detection in inspect.getattr_static (python#104517) pythongh-104050: Add more annotations to `Tools/clinic.py` (python#104544) pythongh-104555: Fix isinstance() and issubclass() for runtime-checkable protocols that use PEP 695 (python#104556) pythongh-103865: add monitoring support to LOAD_SUPER_ATTR (python#103866) CODEOWNERS: Assign new PEP 695 files to myself (python#104551) pythonGH-104510: Fix refleaks in `_io` base types (python#104516) pythongh-104539: Fix indentation error in logging.config.rst (python#104545) pythongh-104050: Don't star-import 'types' in Argument Clinic (python#104543) pythongh-104050: Add basic typing to CConverter in clinic.py (python#104538) ...
…isinstance()` influence whether `issubclass()` raises an exception (#104559) Co-authored-by: Carl Meyer <[email protected]>
…s to `isinstance()` influence whether `issubclass()` raises an exception (python#104559) Co-authored-by: Carl Meyer <[email protected]>
PEP-695 protocols don't work as intended:
Here's the behaviour you get with protocols that use pre-PEP 695 syntax, which is correct:
And here's the behaviour you get on
main
with protocols that use PEP 695 syntax, which is incorrect:Linked PRs
isinstance()
influence whetherissubclass()
raises an exception #104559The text was updated successfully, but these errors were encountered: