Skip to content

@runtime_checkable rejects ordinary protocol subclasses (is_protocol does not propagate through base classes) #21950

Description

@istoolsfox

Bug Report

@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.

To Reproduce

from typing import Protocol, runtime_checkable

class Mid(Protocol): ...

@runtime_checkable
class NewProto(Mid): ...

Result (mypy 2.3.1):

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions