mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 05:15:12 +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:
|
def method_member(self) -> bytes:
|
||||||
return b"foo"
|
return b"foo"
|
||||||
|
|
||||||
# TODO: actually a frozenset (requires support for legacy generics)
|
reveal_type(get_protocol_members(Foo)) # revealed: frozenset[Literal["method_member", "x", "y", "z"]]
|
||||||
reveal_type(get_protocol_members(Foo)) # revealed: tuple[Literal["method_member"], Literal["x"], Literal["y"], Literal["z"]]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Certain special attributes and methods are not considered protocol members at runtime, and should
|
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:
|
def __init__(self, x: int) -> None:
|
||||||
self.x = x
|
self.x = x
|
||||||
|
|
||||||
# TODO: actually a frozenset
|
reveal_type(get_protocol_members(Lumberjack)) # revealed: frozenset[Literal["x"]]
|
||||||
reveal_type(get_protocol_members(Lumberjack)) # revealed: tuple[Literal["x"]]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
A sub-protocol inherits and extends the members of its superclass protocol(s):
|
A sub-protocol inherits and extends the members of its superclass protocol(s):
|
||||||
|
@ -407,13 +405,11 @@ class Bar(Protocol):
|
||||||
class Baz(Bar, Protocol):
|
class Baz(Bar, Protocol):
|
||||||
ham: memoryview
|
ham: memoryview
|
||||||
|
|
||||||
# TODO: actually a frozenset
|
reveal_type(get_protocol_members(Baz)) # revealed: frozenset[Literal["ham", "spam"]]
|
||||||
reveal_type(get_protocol_members(Baz)) # revealed: tuple[Literal["ham"], Literal["spam"]]
|
|
||||||
|
|
||||||
class Baz2(Bar, Foo, Protocol): ...
|
class Baz2(Bar, Foo, Protocol): ...
|
||||||
|
|
||||||
# TODO: actually a frozenset
|
# revealed: frozenset[Literal["method_member", "spam", "x", "y", "z"]]
|
||||||
# revealed: tuple[Literal["method_member"], Literal["spam"], Literal["x"], Literal["y"], Literal["z"]]
|
|
||||||
reveal_type(get_protocol_members(Baz2))
|
reveal_type(get_protocol_members(Baz2))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -441,8 +437,7 @@ class Foo(Protocol):
|
||||||
e = 56
|
e = 56
|
||||||
def f(self) -> None: ...
|
def f(self) -> None: ...
|
||||||
|
|
||||||
# TODO: actually a frozenset
|
reveal_type(get_protocol_members(Foo)) # revealed: frozenset[Literal["d", "e", "f"]]
|
||||||
reveal_type(get_protocol_members(Foo)) # revealed: tuple[Literal["d"], Literal["e"], Literal["f"]]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Invalid calls to `get_protocol_members()`
|
## 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)
|
case l: # TODO: this should error with `[invalid-protocol]` (`l` is not declared)
|
||||||
...
|
...
|
||||||
|
|
||||||
# TODO: actually a frozenset
|
# revealed: frozenset[Literal["Nested", "NestedProtocol", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"]]
|
||||||
# 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"]]
|
|
||||||
reveal_type(get_protocol_members(LotsOfBindings))
|
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`,
|
# Note: the list of members does not include `a`, `b` or `c`,
|
||||||
# as none of these attributes is declared in the class body.
|
# as none of these attributes is declared in the class body.
|
||||||
#
|
reveal_type(get_protocol_members(Foo)) # revealed: frozenset[Literal["non_init_method", "x", "y"]]
|
||||||
# TODO: actually a frozenset
|
|
||||||
reveal_type(get_protocol_members(Foo)) # revealed: tuple[Literal["non_init_method"], Literal["x"], Literal["y"]]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If a member is declared in a superclass of a protocol class, it is fine for it to be assigned to in
|
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):
|
class Sub(Super, Protocol):
|
||||||
x = 42 # no error here, since it's declared in the superclass
|
x = 42 # no error here, since it's declared in the superclass
|
||||||
|
|
||||||
# TODO: actually frozensets
|
reveal_type(get_protocol_members(Super)) # revealed: frozenset[Literal["x"]]
|
||||||
reveal_type(get_protocol_members(Super)) # revealed: tuple[Literal["x"]]
|
reveal_type(get_protocol_members(Sub)) # revealed: frozenset[Literal["x"]]
|
||||||
reveal_type(get_protocol_members(Sub)) # revealed: tuple[Literal["x"]]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If a protocol has 0 members, then all other types are assignable to it, and all fully static types
|
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) => {
|
Some(KnownFunction::GetProtocolMembers) => {
|
||||||
if let [Some(Type::ClassLiteral(class))] = overload.parameter_types() {
|
if let [Some(Type::ClassLiteral(class))] = overload.parameter_types() {
|
||||||
if let Some(protocol_class) = class.into_protocol_class(db) {
|
if let Some(protocol_class) = class.into_protocol_class(db) {
|
||||||
// TODO: actually a frozenset at runtime (requires support for legacy generic classes)
|
let member_names = protocol_class
|
||||||
overload.set_return_type(Type::Tuple(TupleType::new(
|
|
||||||
db,
|
|
||||||
protocol_class
|
|
||||||
.interface(db)
|
.interface(db)
|
||||||
.members(db)
|
.members(db)
|
||||||
.map(|member| Type::string_literal(db, member.name()))
|
.map(|member| Type::string_literal(db, member.name()));
|
||||||
.collect::<Box<[Type<'db>]>>(),
|
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