You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
@runtime_checkable rejects ordinary protocol subclasses (is_protocol does not propagate through base classes) #21950
@runtime_checkable is only accepted on classes whose direct base is typing.Protocol. A subclass of a protocol class — an ordinary protocol in every other respect — is rejected, which is inconsistent with the runtime behavior and with other type checkers.
main.py:7: error: @runtime_checkable can only be used with protocol classes [misc]
Pyright: no errors on the same file.
CPython runtime: typing.runtime_checkable performs a duck-typed check (the protocol metaclass sets _is_protocol), so decorating NewProto works fine at runtime.
Expected Behavior
NewProto is a protocol class: it inherits the protocol metaclass and the protocol machinery from Mid. @runtime_checkable should be accepted, consistent with the runtime and with Pyright.
Actual Results
mypy rejects it with misc: @runtime_checkable can only be used with protocol classes.
Additional context
In mypy/semanal.py, is_protocol is only set when a direct base expression's fully-qualified name is in PROTOCOL_NAMES (the "also remove bare 'Protocol' bases" branch in analyze_class), and defn.info.is_protocol = is_protocol does not propagate the flag from protocol base classes.
This came up in the discussion on #21940, where the hardcoding of PROTOCOL_NAMES was raised. Unlike removing that hardcoding (which would conflict with mypy's name-based identification of typing features), propagating is_protocol from protocol base classes looks like a well-scoped improvement. Please let me know if the current behavior is intentional.
It makes sense to me that NewProto is not a protocol -- you can inherit from protocols to declare that you support that interface, without being a protocol yourself. However there seems to be an issue where mypy doesn't warn about not implemented methods on the subclasser. The Python typing spec has this to say:
If a class includes a protocol in its MRO, the class is called an explicit subclass of the protocol. If a class defines all attributes and methods of a protocol with types that are assignable to the types of the protocol’s attributes and methods, it is said to implement the protocol and to be assignable to the protocol. If a class is assignable to a protocol but the protocol is not included in the MRO, the class is implicitly assignable to the protocol. (Note that one can explicitly subclass a protocol and still not implement it if a protocol attribute is set to None in the subclass. See Python data model for details.)
Activity
A5rocks commentedon Sep 7, 2026
It makes sense to me that
NewProtois not a protocol -- you can inherit from protocols to declare that you support that interface, without being a protocol yourself. However there seems to be an issue where mypy doesn't warn about not implemented methods on the subclasser. The Python typing spec has this to say:(it seems we do not implement this at all yet)
A5rocks commentedon Sep 7, 2026
Nevermind I read a bit more typing spec: