Skip to content

Commit

Permalink
Fix using typing_extensions.runtime_checkable in combination with `…
Browse files Browse the repository at this point in the history
…typing.Protocol` on 3.12.2+ (#373)
  • Loading branch information
AlexWaygood committed Apr 21, 2024
1 parent 2a7945b commit c79c561
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 3 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,9 @@
`__static_attributes__` attribute to all classes in Python,
which broke some assumptions made by the implementation of
`typing_extensions.Protocol`.
- Fix `AttributeError` when using `typing_extensions.runtime_checkable`
in combination with `typing.Protocol` on Python 3.12.2 or newer.
Patch by Alex Waygood.
- At runtime, `assert_never` now includes the repr of the argument
in the `AssertionError`. Patch by Hashem, backporting of the original
fix https://github.com/python/cpython/pull/91720 by Jelle Zijlstra.
Expand Down
12 changes: 12 additions & 0 deletions src/test_typing_extensions.py
Expand Up @@ -3536,6 +3536,18 @@ class Commentable(Protocol):
)
self.assertIs(type(exc.__cause__), CustomError)

def test_extensions_runtimecheckable_on_typing_Protocol(self):
@runtime_checkable
class Functor(typing.Protocol):
def foo(self) -> None: ...

self.assertNotIsSubclass(object, Functor)

class Bar:
def foo(self): pass

self.assertIsSubclass(Bar, Functor)


class Point2DGeneric(Generic[T], TypedDict):
a: T
Expand Down
11 changes: 8 additions & 3 deletions src/typing_extensions.py
Expand Up @@ -676,9 +676,14 @@ def close(self): ...
' got %r' % cls)
cls._is_runtime_protocol = True

# Only execute the following block if it's a typing_extensions.Protocol class.
# typing.Protocol classes don't need it.
if isinstance(cls, _ProtocolMeta):
# typing.Protocol classes on <=3.11 break if we execute this block,
# because typing.Protocol classes on <=3.11 don't have a
# `__protocol_attrs__` attribute, and this block relies on the
# `__protocol_attrs__` attribute. Meanwhile, typing.Protocol classes on 3.12.2+
# break if we *don't* execute this block, because *they* assume that all
# protocol classes have a `__non_callable_proto_members__` attribute
# (which this block sets)
if isinstance(cls, _ProtocolMeta) or sys.version_info >= (3, 12, 2):
# PEP 544 prohibits using issubclass()
# with protocols that have non-method members.
# See gh-113320 for why we compute this attribute here,
Expand Down

0 comments on commit c79c561

Please sign in to comment.