[ty] The runtime object typing.Protocol is an instance of _ProtocolMeta (#20488)

## Summary

Fixes https://github.com/astral-sh/ty/issues/1218.

This bug doesn't currently cause us any real-world issues, because we
don't yet understand the signatures typeshed gives us for `isinstance()`
and `issubclass()` (typeshed's annotations there use PEP-613 type
aliases). #20107 demonstrates that this will start causing us issues as
soon as we add support for PEP-613 aliases, however, so it makes sense
to fix it now.

## Test Plan

Added mdtests
This commit is contained in:
Alex Waygood
2025-09-22 08:29:03 +01:00
committed by GitHub
parent 3033d1e5a5
commit f1aacd0f2c
3 changed files with 30 additions and 3 deletions

View File

@@ -264,9 +264,21 @@ def f(
# fmt: on
```
Nonetheless, `Protocol` can still be used as the second argument to `issubclass()` at runtime:
Nonetheless, `Protocol` is an instance of `type` at runtime, and therefore can still be used as the
second argument to `issubclass()` at runtime:
```py
import abc
import typing
from ty_extensions import TypeOf
reveal_type(type(Protocol)) # revealed: <class '_ProtocolMeta'>
# revealed: tuple[<class '_ProtocolMeta'>, <class 'ABCMeta'>, <class 'type'>, <class 'object'>]
reveal_type(type(Protocol).__mro__)
static_assert(is_subtype_of(TypeOf[Protocol], type))
static_assert(is_subtype_of(TypeOf[Protocol], abc.ABCMeta))
static_assert(is_subtype_of(TypeOf[Protocol], typing._ProtocolMeta))
# Could also be `Literal[True]`, but `bool` is fine:
reveal_type(issubclass(MyProtocol, Protocol)) # revealed: bool
```