mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-09 21:28:21 +00:00
[ty] get_protocol_members
returns a frozenset, not a tuple (#18284)
This commit is contained in:
parent
53d19f8368
commit
e293411679
2 changed files with 18 additions and 27 deletions
|
@ -375,8 +375,7 @@ class Foo(Protocol):
|
|||
def method_member(self) -> bytes:
|
||||
return b"foo"
|
||||
|
||||
# TODO: actually a frozenset (requires support for legacy generics)
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: tuple[Literal["method_member"], Literal["x"], Literal["y"], Literal["z"]]
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: frozenset[Literal["method_member", "x", "y", "z"]]
|
||||
```
|
||||
|
||||
Certain special attributes and methods are not considered protocol members at runtime, and should
|
||||
|
@ -394,8 +393,7 @@ class Lumberjack(Protocol):
|
|||
def __init__(self, x: int) -> None:
|
||||
self.x = x
|
||||
|
||||
# TODO: actually a frozenset
|
||||
reveal_type(get_protocol_members(Lumberjack)) # revealed: tuple[Literal["x"]]
|
||||
reveal_type(get_protocol_members(Lumberjack)) # revealed: frozenset[Literal["x"]]
|
||||
```
|
||||
|
||||
A sub-protocol inherits and extends the members of its superclass protocol(s):
|
||||
|
@ -407,13 +405,11 @@ class Bar(Protocol):
|
|||
class Baz(Bar, Protocol):
|
||||
ham: memoryview
|
||||
|
||||
# TODO: actually a frozenset
|
||||
reveal_type(get_protocol_members(Baz)) # revealed: tuple[Literal["ham"], Literal["spam"]]
|
||||
reveal_type(get_protocol_members(Baz)) # revealed: frozenset[Literal["ham", "spam"]]
|
||||
|
||||
class Baz2(Bar, Foo, Protocol): ...
|
||||
|
||||
# TODO: actually a frozenset
|
||||
# revealed: tuple[Literal["method_member"], Literal["spam"], Literal["x"], Literal["y"], Literal["z"]]
|
||||
# revealed: frozenset[Literal["method_member", "spam", "x", "y", "z"]]
|
||||
reveal_type(get_protocol_members(Baz2))
|
||||
```
|
||||
|
||||
|
@ -441,8 +437,7 @@ class Foo(Protocol):
|
|||
e = 56
|
||||
def f(self) -> None: ...
|
||||
|
||||
# TODO: actually a frozenset
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: tuple[Literal["d"], Literal["e"], Literal["f"]]
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: frozenset[Literal["d", "e", "f"]]
|
||||
```
|
||||
|
||||
## Invalid calls to `get_protocol_members()`
|
||||
|
@ -673,8 +668,7 @@ class LotsOfBindings(Protocol):
|
|||
case l: # TODO: this should error with `[invalid-protocol]` (`l` is not declared)
|
||||
...
|
||||
|
||||
# TODO: actually a frozenset
|
||||
# revealed: tuple[Literal["Nested"], Literal["NestedProtocol"], Literal["a"], Literal["b"], Literal["c"], Literal["d"], Literal["e"], Literal["f"], Literal["g"], Literal["h"], Literal["i"], Literal["j"], Literal["k"], Literal["l"]]
|
||||
# revealed: frozenset[Literal["Nested", "NestedProtocol", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]]
|
||||
reveal_type(get_protocol_members(LotsOfBindings))
|
||||
```
|
||||
|
||||
|
@ -702,9 +696,7 @@ class Foo(Protocol):
|
|||
|
||||
# Note: the list of members does not include `a`, `b` or `c`,
|
||||
# as none of these attributes is declared in the class body.
|
||||
#
|
||||
# TODO: actually a frozenset
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: tuple[Literal["non_init_method"], Literal["x"], Literal["y"]]
|
||||
reveal_type(get_protocol_members(Foo)) # revealed: frozenset[Literal["non_init_method", "x", "y"]]
|
||||
```
|
||||
|
||||
If a member is declared in a superclass of a protocol class, it is fine for it to be assigned to in
|
||||
|
@ -717,9 +709,8 @@ class Super(Protocol):
|
|||
class Sub(Super, Protocol):
|
||||
x = 42 # no error here, since it's declared in the superclass
|
||||
|
||||
# TODO: actually frozensets
|
||||
reveal_type(get_protocol_members(Super)) # revealed: tuple[Literal["x"]]
|
||||
reveal_type(get_protocol_members(Sub)) # revealed: tuple[Literal["x"]]
|
||||
reveal_type(get_protocol_members(Super)) # revealed: frozenset[Literal["x"]]
|
||||
reveal_type(get_protocol_members(Sub)) # revealed: frozenset[Literal["x"]]
|
||||
```
|
||||
|
||||
If a protocol has 0 members, then all other types are assignable to it, and all fully static types
|
||||
|
|
|
@ -667,15 +667,15 @@ impl<'db> Bindings<'db> {
|
|||
Some(KnownFunction::GetProtocolMembers) => {
|
||||
if let [Some(Type::ClassLiteral(class))] = overload.parameter_types() {
|
||||
if let Some(protocol_class) = class.into_protocol_class(db) {
|
||||
// TODO: actually a frozenset at runtime (requires support for legacy generic classes)
|
||||
overload.set_return_type(Type::Tuple(TupleType::new(
|
||||
db,
|
||||
protocol_class
|
||||
.interface(db)
|
||||
.members(db)
|
||||
.map(|member| Type::string_literal(db, member.name()))
|
||||
.collect::<Box<[Type<'db>]>>(),
|
||||
)));
|
||||
let member_names = protocol_class
|
||||
.interface(db)
|
||||
.members(db)
|
||||
.map(|member| Type::string_literal(db, member.name()));
|
||||
let specialization = UnionType::from_elements(db, member_names);
|
||||
overload.set_return_type(
|
||||
KnownClass::FrozenSet
|
||||
.to_specialized_instance(db, [specialization]),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue