Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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