Skip to content

Commit edc1e20

Browse files
committed
[ty] The runtime object typing.Protocol is an instance of _ProtocolMeta
1 parent 3ffe56d commit edc1e20

File tree

3 files changed

+29
-3
lines changed

3 files changed

+29
-3
lines changed

crates/ty_python_semantic/resources/mdtest/protocols.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,20 @@ def f(
264264
# fmt: on
265265
```
266266

267-
Nonetheless, `Protocol` can still be used as the second argument to `issubclass()` at runtime:
267+
Nonetheless, `Protocol` is an instance of `type` at runtime, and therefore can still be used as the
268+
second argument to `issubclass()` at runtime:
268269

269270
```py
271+
import abc
272+
import typing
273+
from ty_extensions import TypeOf
274+
275+
reveal_type(type(Protocol)) # revealed: <class '_ProtocolMeta'>
276+
reveal_type(type(Protocol).__mro__) # revealed: tuple[<class '_ProtocolMeta'>, <class 'ABCMeta'>, <class 'type'>, <class 'object'>]
277+
static_assert(is_subtype_of(TypeOf[Protocol], type))
278+
static_assert(is_subtype_of(TypeOf[Protocol], abc.ABCMeta))
279+
static_assert(is_subtype_of(TypeOf[Protocol], typing._ProtocolMeta))
280+
270281
# Could also be `Literal[True]`, but `bool` is fine:
271282
reveal_type(issubclass(MyProtocol, Protocol)) # revealed: bool
272283
```

crates/ty_python_semantic/src/types/class.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3694,6 +3694,7 @@ pub enum KnownClass {
36943694
ParamSpec,
36953695
ParamSpecArgs,
36963696
ParamSpecKwargs,
3697+
ProtocolMeta,
36973698
TypeVarTuple,
36983699
TypeAliasType,
36993700
NoDefaultType,
@@ -3821,6 +3822,7 @@ impl KnownClass {
38213822
| Self::NamedTupleFallback
38223823
| Self::NamedTupleLike
38233824
| Self::ConstraintSet
3825+
| Self::ProtocolMeta
38243826
| Self::TypedDictFallback => Some(Truthiness::Ambiguous),
38253827

38263828
Self::Tuple => None,
@@ -3903,6 +3905,7 @@ impl KnownClass {
39033905
| KnownClass::ConstraintSet
39043906
| KnownClass::TypedDictFallback
39053907
| KnownClass::BuiltinFunctionType
3908+
| KnownClass::ProtocolMeta
39063909
| KnownClass::Template => false,
39073910
}
39083911
}
@@ -3982,6 +3985,7 @@ impl KnownClass {
39823985
| KnownClass::ConstraintSet
39833986
| KnownClass::TypedDictFallback
39843987
| KnownClass::BuiltinFunctionType
3988+
| KnownClass::ProtocolMeta
39853989
| KnownClass::Template => false,
39863990
}
39873991
}
@@ -4060,6 +4064,7 @@ impl KnownClass {
40604064
| KnownClass::NamedTupleFallback
40614065
| KnownClass::ConstraintSet
40624066
| KnownClass::BuiltinFunctionType
4067+
| KnownClass::ProtocolMeta
40634068
| KnownClass::Template => false,
40644069
}
40654070
}
@@ -4151,6 +4156,7 @@ impl KnownClass {
41514156
| Self::ConstraintSet
41524157
| Self::TypedDictFallback
41534158
| Self::BuiltinFunctionType
4159+
| Self::ProtocolMeta
41544160
| Self::Template => false,
41554161
}
41564162
}
@@ -4250,6 +4256,7 @@ impl KnownClass {
42504256
Self::ConstraintSet => "ConstraintSet",
42514257
Self::TypedDictFallback => "TypedDictFallback",
42524258
Self::Template => "Template",
4259+
Self::ProtocolMeta => "_ProtocolMeta",
42534260
}
42544261
}
42554262

@@ -4477,6 +4484,7 @@ impl KnownClass {
44774484
| Self::StdlibAlias
44784485
| Self::Iterable
44794486
| Self::Iterator
4487+
| Self::ProtocolMeta
44804488
| Self::SupportsIndex => KnownModule::Typing,
44814489
Self::TypeAliasType
44824490
| Self::TypeVarTuple
@@ -4596,6 +4604,7 @@ impl KnownClass {
45964604
| Self::ConstraintSet
45974605
| Self::TypedDictFallback
45984606
| Self::BuiltinFunctionType
4607+
| Self::ProtocolMeta
45994608
| Self::Template => Some(false),
46004609

46014610
Self::Tuple => None,
@@ -4680,6 +4689,7 @@ impl KnownClass {
46804689
| Self::ConstraintSet
46814690
| Self::TypedDictFallback
46824691
| Self::BuiltinFunctionType
4692+
| Self::ProtocolMeta
46834693
| Self::Template => false,
46844694
}
46854695
}
@@ -4773,6 +4783,7 @@ impl KnownClass {
47734783
"ConstraintSet" => Self::ConstraintSet,
47744784
"TypedDictFallback" => Self::TypedDictFallback,
47754785
"Template" => Self::Template,
4786+
"_ProtocolMeta" => Self::ProtocolMeta,
47764787
_ => return None,
47774788
};
47784789

@@ -4855,9 +4866,9 @@ impl KnownClass {
48554866
| Self::TypeVarTuple
48564867
| Self::Iterable
48574868
| Self::Iterator
4869+
| Self::ProtocolMeta
48584870
| Self::NewType => matches!(module, KnownModule::Typing | KnownModule::TypingExtensions),
48594871
Self::Deprecated => matches!(module, KnownModule::Warnings | KnownModule::TypingExtensions),
4860-
48614872
}
48624873
}
48634874

crates/ty_python_semantic/src/types/special_form.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,13 @@ impl SpecialFormType {
160160
| Self::Bottom
161161
| Self::Intersection
162162
| Self::CallableTypeOf
163-
| Self::Protocol // actually `_ProtocolMeta` at runtime but this is what typeshed says
164163
| Self::ReadOnly => KnownClass::SpecialForm,
165164

165+
// Typeshed says it's an instance of `_SpecialForm`,
166+
// but then we wouldn't recognise things like `issubclass(`X, Protocol)`
167+
// as being valid.
168+
Self::Protocol => KnownClass::ProtocolMeta,
169+
166170
Self::Generic | Self::Any => KnownClass::Type,
167171

168172
Self::List

0 commit comments

Comments
 (0)