mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 10:22:24 +00:00

## Summary - Write tests for member lookups on union types - Remove TODO comment part of: #14022 ## Test Plan New MD tests
2.3 KiB
2.3 KiB
Class attributes
Union of attributes
def bool_instance() -> bool:
return True
flag = bool_instance()
if flag:
class C1:
x = 1
else:
class C1:
x = 2
class C2:
if flag:
x = 3
else:
x = 4
reveal_type(C1.x) # revealed: Literal[1, 2]
reveal_type(C2.x) # revealed: Literal[3, 4]
Inherited attributes
class A:
X = "foo"
class B(A): ...
class C(B): ...
reveal_type(C.X) # revealed: Literal["foo"]
Inherited attributes (multiple inheritance)
class O: ...
class F(O):
X = 56
class E(O):
X = 42
class D(O): ...
class C(D, F): ...
class B(E, D): ...
class A(B, C): ...
# revealed: tuple[Literal[A], Literal[B], Literal[E], Literal[C], Literal[D], Literal[F], Literal[O], Literal[object]]
reveal_type(A.__mro__)
# `E` is earlier in the MRO than `F`, so we should use the type of `E.X`
reveal_type(A.X) # revealed: Literal[42]
Unions with possibly unbound paths
Definite boundness within a class
In this example, the x
attribute is not defined in the C2
element of the union:
def bool_instance() -> bool:
return True
class C1:
x = 1
class C2: ...
class C3:
x = 3
flag1 = bool_instance()
flag2 = bool_instance()
C = C1 if flag1 else C2 if flag2 else C3
# error: [possibly-unbound-attribute] "Attribute `x` on type `Literal[C1, C2, C3]` is possibly unbound"
reveal_type(C.x) # revealed: Literal[1, 3]
Possibly-unbound within a class
We raise the same diagnostic if the attribute is possibly-unbound in at least one element of the union:
def bool_instance() -> bool:
return True
class C1:
x = 1
class C2:
if bool_instance():
x = 2
class C3:
x = 3
flag1 = bool_instance()
flag2 = bool_instance()
C = C1 if flag1 else C2 if flag2 else C3
# error: [possibly-unbound-attribute] "Attribute `x` on type `Literal[C1, C2, C3]` is possibly unbound"
reveal_type(C.x) # revealed: Literal[1, 2, 3]
Unions with all paths unbound
If the symbol is unbound in all elements of the union, we detect that:
def bool_instance() -> bool:
return True
class C1: ...
class C2: ...
flag = bool_instance()
C = C1 if flag else C2
# error: [unresolved-attribute] "Type `Literal[C1, C2]` has no attribute `x`"
reveal_type(C.x) # revealed: Unknown