Update class literal display to use <class 'Foo'> style (#17889)

## Summary

Closes https://github.com/astral-sh/ruff/issues/17238.
This commit is contained in:
Charlie Marsh 2025-05-06 20:11:25 -04:00 committed by GitHub
parent b2de749c32
commit a2e9a7732a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 311 additions and 309 deletions

View file

@ -76,7 +76,7 @@ from typing_extensions import Annotated
class C(Annotated[int, "foo"]): ...
# TODO: Should be `tuple[Literal[C], Literal[int], Literal[object]]`
reveal_type(C.__mro__) # revealed: tuple[Literal[C], @Todo(Inference of subscript on special form), Literal[object]]
reveal_type(C.__mro__) # revealed: tuple[<class 'C'>, @Todo(Inference of subscript on special form), <class 'object'>]
```
### Not parameterized
@ -88,5 +88,5 @@ from typing_extensions import Annotated
# error: [invalid-base]
class C(Annotated): ...
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Unknown, Literal[object]]
reveal_type(C.__mro__) # revealed: tuple[<class 'C'>, Unknown, <class 'object'>]
```

View file

@ -59,7 +59,7 @@ from typing import Any
class SubclassOfAny(Any): ...
reveal_type(SubclassOfAny.__mro__) # revealed: tuple[Literal[SubclassOfAny], Any, Literal[object]]
reveal_type(SubclassOfAny.__mro__) # revealed: tuple[<class 'SubclassOfAny'>, Any, <class 'object'>]
x: SubclassOfAny = 1 # error: [invalid-assignment]
y: int = SubclassOfAny()

View file

@ -85,25 +85,25 @@ import typing
class ListSubclass(typing.List): ...
# TODO: generic protocols
# revealed: tuple[Literal[ListSubclass], Literal[list], Literal[MutableSequence], Literal[Sequence], Literal[Reversible], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, Literal[object]]
# revealed: tuple[<class 'ListSubclass'>, <class 'list'>, <class 'MutableSequence'>, <class 'Sequence'>, <class 'Reversible'>, <class 'Collection'>, <class 'Iterable'>, <class 'Container'>, @Todo(`Protocol[]` subscript), typing.Generic, <class 'object'>]
reveal_type(ListSubclass.__mro__)
class DictSubclass(typing.Dict): ...
# TODO: generic protocols
# revealed: tuple[Literal[DictSubclass], Literal[dict[Unknown, Unknown]], Literal[MutableMapping[Unknown, Unknown]], Literal[Mapping[Unknown, Unknown]], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], Literal[object]]
# revealed: tuple[<class 'DictSubclass'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection'>, <class 'Iterable'>, <class 'Container'>, @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], <class 'object'>]
reveal_type(DictSubclass.__mro__)
class SetSubclass(typing.Set): ...
# TODO: generic protocols
# revealed: tuple[Literal[SetSubclass], Literal[set], Literal[MutableSet], Literal[AbstractSet], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, Literal[object]]
# revealed: tuple[<class 'SetSubclass'>, <class 'set'>, <class 'MutableSet'>, <class 'AbstractSet'>, <class 'Collection'>, <class 'Iterable'>, <class 'Container'>, @Todo(`Protocol[]` subscript), typing.Generic, <class 'object'>]
reveal_type(SetSubclass.__mro__)
class FrozenSetSubclass(typing.FrozenSet): ...
# TODO: should have `Generic`, should not have `Unknown`
# revealed: tuple[Literal[FrozenSetSubclass], Literal[frozenset], Unknown, Literal[object]]
# revealed: tuple[<class 'FrozenSetSubclass'>, <class 'frozenset'>, Unknown, <class 'object'>]
reveal_type(FrozenSetSubclass.__mro__)
####################
@ -113,30 +113,30 @@ reveal_type(FrozenSetSubclass.__mro__)
class ChainMapSubclass(typing.ChainMap): ...
# TODO: generic protocols
# revealed: tuple[Literal[ChainMapSubclass], Literal[ChainMap[Unknown, Unknown]], Literal[MutableMapping[Unknown, Unknown]], Literal[Mapping[Unknown, Unknown]], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], Literal[object]]
# revealed: tuple[<class 'ChainMapSubclass'>, <class 'ChainMap[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection'>, <class 'Iterable'>, <class 'Container'>, @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], <class 'object'>]
reveal_type(ChainMapSubclass.__mro__)
class CounterSubclass(typing.Counter): ...
# TODO: Should be (CounterSubclass, Counter, dict, MutableMapping, Mapping, Collection, Sized, Iterable, Container, Generic, object)
# revealed: tuple[Literal[CounterSubclass], Literal[Counter[Unknown]], Literal[dict[Unknown, int]], Literal[MutableMapping[Unknown, int]], Literal[Mapping[Unknown, int]], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], typing.Generic[_T], Literal[object]]
# revealed: tuple[<class 'CounterSubclass'>, <class 'Counter[Unknown]'>, <class 'dict[Unknown, int]'>, <class 'MutableMapping[Unknown, int]'>, <class 'Mapping[Unknown, int]'>, <class 'Collection'>, <class 'Iterable'>, <class 'Container'>, @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], typing.Generic[_T], <class 'object'>]
reveal_type(CounterSubclass.__mro__)
class DefaultDictSubclass(typing.DefaultDict): ...
# TODO: Should be (DefaultDictSubclass, defaultdict, dict, MutableMapping, Mapping, Collection, Sized, Iterable, Container, Generic, object)
# revealed: tuple[Literal[DefaultDictSubclass], Literal[defaultdict[Unknown, Unknown]], Literal[dict[Unknown, Unknown]], Literal[MutableMapping[Unknown, Unknown]], Literal[Mapping[Unknown, Unknown]], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], Literal[object]]
# revealed: tuple[<class 'DefaultDictSubclass'>, <class 'defaultdict[Unknown, Unknown]'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection'>, <class 'Iterable'>, <class 'Container'>, @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], <class 'object'>]
reveal_type(DefaultDictSubclass.__mro__)
class DequeSubclass(typing.Deque): ...
# TODO: generic protocols
# revealed: tuple[Literal[DequeSubclass], Literal[deque], Literal[MutableSequence], Literal[Sequence], Literal[Reversible], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, Literal[object]]
# revealed: tuple[<class 'DequeSubclass'>, <class 'deque'>, <class 'MutableSequence'>, <class 'Sequence'>, <class 'Reversible'>, <class 'Collection'>, <class 'Iterable'>, <class 'Container'>, @Todo(`Protocol[]` subscript), typing.Generic, <class 'object'>]
reveal_type(DequeSubclass.__mro__)
class OrderedDictSubclass(typing.OrderedDict): ...
# TODO: Should be (OrderedDictSubclass, OrderedDict, dict, MutableMapping, Mapping, Collection, Sized, Iterable, Container, Generic, object)
# revealed: tuple[Literal[OrderedDictSubclass], Literal[OrderedDict[Unknown, Unknown]], Literal[dict[Unknown, Unknown]], Literal[MutableMapping[Unknown, Unknown]], Literal[Mapping[Unknown, Unknown]], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], Literal[object]]
# revealed: tuple[<class 'OrderedDictSubclass'>, <class 'OrderedDict[Unknown, Unknown]'>, <class 'dict[Unknown, Unknown]'>, <class 'MutableMapping[Unknown, Unknown]'>, <class 'Mapping[Unknown, Unknown]'>, <class 'Collection'>, <class 'Iterable'>, <class 'Container'>, @Todo(`Protocol[]` subscript), typing.Generic, typing.Generic[_KT, _VT_co], <class 'object'>]
reveal_type(OrderedDictSubclass.__mro__)
```

View file

@ -73,7 +73,7 @@ class E(Concatenate): ... # error: [invalid-base]
class F(Callable): ...
class G(Generic): ... # error: [invalid-base] "Cannot inherit from plain `Generic`"
reveal_type(F.__mro__) # revealed: tuple[Literal[F], @Todo(Support for Callable as a base class), Literal[object]]
reveal_type(F.__mro__) # revealed: tuple[<class 'F'>, @Todo(Support for Callable as a base class), <class 'object'>]
```
## Subscriptability

View file

@ -54,11 +54,11 @@ c_instance.declared_and_bound = False
c_instance.declared_and_bound = "incompatible"
# mypy shows no error here, but pyright raises "reportAttributeAccessIssue"
# error: [unresolved-attribute] "Attribute `inferred_from_value` can only be accessed on instances, not on the class object `Literal[C]` itself."
# error: [unresolved-attribute] "Attribute `inferred_from_value` can only be accessed on instances, not on the class object `<class 'C'>` itself."
reveal_type(C.inferred_from_value) # revealed: Unknown
# mypy shows no error here, but pyright raises "reportAttributeAccessIssue"
# error: [invalid-attribute-access] "Cannot assign to instance attribute `inferred_from_value` from the class object `Literal[C]`"
# error: [invalid-attribute-access] "Cannot assign to instance attribute `inferred_from_value` from the class object `<class 'C'>`"
C.inferred_from_value = "overwritten on class"
# This assignment is fine:
@ -90,11 +90,11 @@ reveal_type(c_instance.declared_and_bound) # revealed: str | None
# Note that both mypy and pyright show no error in this case! So we may reconsider this in
# the future, if it turns out to produce too many false positives. We currently emit:
# error: [unresolved-attribute] "Attribute `declared_and_bound` can only be accessed on instances, not on the class object `Literal[C]` itself."
# error: [unresolved-attribute] "Attribute `declared_and_bound` can only be accessed on instances, not on the class object `<class 'C'>` itself."
reveal_type(C.declared_and_bound) # revealed: Unknown
# Same as above. Mypy and pyright do not show an error here.
# error: [invalid-attribute-access] "Cannot assign to instance attribute `declared_and_bound` from the class object `Literal[C]`"
# error: [invalid-attribute-access] "Cannot assign to instance attribute `declared_and_bound` from the class object `<class 'C'>`"
C.declared_and_bound = "overwritten on class"
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to attribute `declared_and_bound` of type `str | None`"
@ -115,10 +115,10 @@ c_instance = C()
reveal_type(c_instance.only_declared) # revealed: str
# Mypy and pyright do not show an error here. We treat this as a pure instance variable.
# error: [unresolved-attribute] "Attribute `only_declared` can only be accessed on instances, not on the class object `Literal[C]` itself."
# error: [unresolved-attribute] "Attribute `only_declared` can only be accessed on instances, not on the class object `<class 'C'>` itself."
reveal_type(C.only_declared) # revealed: Unknown
# error: [invalid-attribute-access] "Cannot assign to instance attribute `only_declared` from the class object `Literal[C]`"
# error: [invalid-attribute-access] "Cannot assign to instance attribute `only_declared` from the class object `<class 'C'>`"
C.only_declared = "overwritten on class"
```
@ -191,10 +191,10 @@ reveal_type(c_instance.declared_only) # revealed: bytes
reveal_type(c_instance.declared_and_bound) # revealed: bool
# error: [unresolved-attribute] "Attribute `inferred_from_value` can only be accessed on instances, not on the class object `Literal[C]` itself."
# error: [unresolved-attribute] "Attribute `inferred_from_value` can only be accessed on instances, not on the class object `<class 'C'>` itself."
reveal_type(C.inferred_from_value) # revealed: Unknown
# error: [invalid-attribute-access] "Cannot assign to instance attribute `inferred_from_value` from the class object `Literal[C]`"
# error: [invalid-attribute-access] "Cannot assign to instance attribute `inferred_from_value` from the class object `<class 'C'>`"
C.inferred_from_value = "overwritten on class"
```
@ -718,7 +718,7 @@ reveal_type(C.pure_class_variable) # revealed: Unknown
# TODO: should be no error when descriptor protocol is supported
# and the assignment is properly attributed to the class method.
# error: [invalid-attribute-access] "Cannot assign to instance attribute `pure_class_variable` from the class object `Literal[C]`"
# error: [invalid-attribute-access] "Cannot assign to instance attribute `pure_class_variable` from the class object `<class 'C'>`"
C.pure_class_variable = "overwritten on class"
# TODO: should be `Unknown | Literal["value set in class method"]` or
@ -925,7 +925,7 @@ def _(flag: bool):
reveal_type(C1.y) # revealed: int | str
C1.y = 100
# error: [invalid-assignment] "Object of type `Literal["problematic"]` is not assignable to attribute `y` on type `Literal[C1, C1]`"
# error: [invalid-assignment] "Object of type `Literal["problematic"]` is not assignable to attribute `y` on type `<class 'C1'> | <class 'C1'>`"
C1.y = "problematic"
class C2:
@ -1002,10 +1002,10 @@ def _(flag1: bool, flag2: bool):
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"
# error: [possibly-unbound-attribute] "Attribute `x` on type `<class 'C1'> | <class 'C2'> | <class 'C3'>` is possibly unbound"
reveal_type(C.x) # revealed: Unknown | Literal[1, 3]
# error: [invalid-assignment] "Object of type `Literal[100]` is not assignable to attribute `x` on type `Literal[C1, C2, C3]`"
# error: [invalid-assignment] "Object of type `Literal[100]` is not assignable to attribute `x` on type `<class 'C1'> | <class 'C2'> | <class 'C3'>`"
C.x = 100
# error: [possibly-unbound-attribute] "Attribute `x` on type `C1 | C2 | C3` is possibly unbound"
@ -1034,7 +1034,7 @@ def _(flag: bool, flag1: bool, flag2: bool):
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"
# error: [possibly-unbound-attribute] "Attribute `x` on type `<class 'C1'> | <class 'C2'> | <class 'C3'>` is possibly unbound"
reveal_type(C.x) # revealed: Unknown | Literal[1, 2, 3]
# error: [possibly-unbound-attribute]
@ -1165,12 +1165,12 @@ def _(flag: bool):
class C2: ...
C = C1 if flag else C2
# error: [unresolved-attribute] "Type `Literal[C1, C2]` has no attribute `x`"
# error: [unresolved-attribute] "Type `<class 'C1'> | <class 'C2'>` has no attribute `x`"
reveal_type(C.x) # revealed: Unknown
# TODO: This should ideally be a `unresolved-attribute` error. We need better union
# handling in `validate_attribute_assignment` for this.
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to attribute `x` on type `Literal[C1, C2]`"
# error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to attribute `x` on type `<class 'C1'> | <class 'C2'>`"
C.x = 1
```
@ -1206,7 +1206,7 @@ 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]]
# revealed: tuple[<class 'A'>, <class 'B'>, <class 'E'>, <class 'C'>, <class 'D'>, <class 'F'>, <class 'O'>, <class 'object'>]
reveal_type(A.__mro__)
# `E` is earlier in the MRO than `F`, so we should use the type of `E.X`
@ -1399,7 +1399,7 @@ class A:
class B(Any): ...
class C(B, A): ...
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[B], Any, Literal[A], Literal[object]]
reveal_type(C.__mro__) # revealed: tuple[<class 'C'>, <class 'B'>, Any, <class 'A'>, <class 'object'>]
reveal_type(C.x) # revealed: Literal[1] & Any
```
@ -1556,31 +1556,31 @@ The type of `x.__class__` is the same as `x`'s meta-type. `x.__class__` is alway
```py
import typing_extensions
reveal_type(typing_extensions.__class__) # revealed: Literal[ModuleType]
reveal_type(type(typing_extensions)) # revealed: Literal[ModuleType]
reveal_type(typing_extensions.__class__) # revealed: <class 'ModuleType'>
reveal_type(type(typing_extensions)) # revealed: <class 'ModuleType'>
a = 42
reveal_type(a.__class__) # revealed: Literal[int]
reveal_type(type(a)) # revealed: Literal[int]
reveal_type(a.__class__) # revealed: <class 'int'>
reveal_type(type(a)) # revealed: <class 'int'>
b = "42"
reveal_type(b.__class__) # revealed: Literal[str]
reveal_type(b.__class__) # revealed: <class 'str'>
c = b"42"
reveal_type(c.__class__) # revealed: Literal[bytes]
reveal_type(c.__class__) # revealed: <class 'bytes'>
d = True
reveal_type(d.__class__) # revealed: Literal[bool]
reveal_type(d.__class__) # revealed: <class 'bool'>
e = (42, 42)
reveal_type(e.__class__) # revealed: Literal[tuple]
reveal_type(e.__class__) # revealed: <class 'tuple'>
def f(a: int, b: typing_extensions.LiteralString, c: int | str, d: type[str]):
reveal_type(a.__class__) # revealed: type[int]
reveal_type(type(a)) # revealed: type[int]
reveal_type(b.__class__) # revealed: Literal[str]
reveal_type(type(b)) # revealed: Literal[str]
reveal_type(b.__class__) # revealed: <class 'str'>
reveal_type(type(b)) # revealed: <class 'str'>
reveal_type(c.__class__) # revealed: type[int] | type[str]
reveal_type(type(c)) # revealed: type[int] | type[str]
@ -1591,11 +1591,11 @@ def f(a: int, b: typing_extensions.LiteralString, c: int | str, d: type[str]):
# All we know is that the metaclass must be a (non-strict) subclass of `type`.
reveal_type(d.__class__) # revealed: type[type]
reveal_type(f.__class__) # revealed: Literal[FunctionType]
reveal_type(f.__class__) # revealed: <class 'FunctionType'>
class Foo: ...
reveal_type(Foo.__class__) # revealed: Literal[type]
reveal_type(Foo.__class__) # revealed: <class 'type'>
```
## Module attributes

View file

@ -22,6 +22,6 @@ reveal_type(A | B) # revealed: UnionType
class A: ...
class B: ...
# error: "Operator `|` is unsupported between objects of type `Literal[A]` and `Literal[B]`"
# error: "Operator `|` is unsupported between objects of type `<class 'A'>` and `<class 'B'>`"
reveal_type(A | B) # revealed: Unknown
```

View file

@ -307,11 +307,11 @@ class Yes:
class Sub(Yes): ...
class No: ...
# error: [unsupported-operator] "Operator `+` is unsupported between objects of type `Literal[Yes]` and `Literal[Yes]`"
# error: [unsupported-operator] "Operator `+` is unsupported between objects of type `<class 'Yes'>` and `<class 'Yes'>`"
reveal_type(Yes + Yes) # revealed: Unknown
# error: [unsupported-operator] "Operator `+` is unsupported between objects of type `Literal[Sub]` and `Literal[Sub]`"
# error: [unsupported-operator] "Operator `+` is unsupported between objects of type `<class 'Sub'>` and `<class 'Sub'>`"
reveal_type(Sub + Sub) # revealed: Unknown
# error: [unsupported-operator] "Operator `+` is unsupported between objects of type `Literal[No]` and `Literal[No]`"
# error: [unsupported-operator] "Operator `+` is unsupported between objects of type `<class 'No'>` and `<class 'No'>`"
reveal_type(No + No) # revealed: Unknown
```

View file

@ -388,13 +388,13 @@ class A(metaclass=Meta): ...
class B(metaclass=Meta): ...
reveal_type(A + B) # revealed: int
# error: [unsupported-operator] "Operator `-` is unsupported between objects of type `Literal[A]` and `Literal[B]`"
# error: [unsupported-operator] "Operator `-` is unsupported between objects of type `<class 'A'>` and `<class 'B'>`"
reveal_type(A - B) # revealed: Unknown
reveal_type(A < B) # revealed: bool
reveal_type(A > B) # revealed: bool
# error: [unsupported-operator] "Operator `<=` is not supported for types `Literal[A]` and `Literal[B]`"
# error: [unsupported-operator] "Operator `<=` is not supported for types `<class 'A'>` and `<class 'B'>`"
reveal_type(A <= B) # revealed: Unknown
reveal_type(A[0]) # revealed: str

View file

@ -312,8 +312,8 @@ class C:
```py
from mod import MyInt, C
reveal_type(MyInt) # revealed: Literal[int]
reveal_type(C.MyStr) # revealed: Literal[str]
reveal_type(MyInt) # revealed: <class 'int'>
reveal_type(C.MyStr) # revealed: <class 'str'>
```
### Undeclared and possibly unbound
@ -336,8 +336,8 @@ if flag():
# error: [possibly-unbound-import]
from mod import MyInt, C
reveal_type(MyInt) # revealed: Literal[int]
reveal_type(C.MyStr) # revealed: Literal[str]
reveal_type(MyInt) # revealed: <class 'int'>
reveal_type(C.MyStr) # revealed: <class 'str'>
```
### Undeclared and unbound

View file

@ -20,7 +20,7 @@ tested more extensively in `crates/ty_python_semantic/resources/mdtest/attribute
tests for the `__class__` attribute.)
```py
reveal_type(type(1)) # revealed: Literal[int]
reveal_type(type(1)) # revealed: <class 'int'>
```
But a three-argument call to type creates a dynamic instance of the `type` class:

View file

@ -270,7 +270,7 @@ class Meta(type):
class C(metaclass=Meta):
pass
reveal_type(C.f) # revealed: bound method Literal[C].f(arg: int) -> str
reveal_type(C.f) # revealed: bound method <class 'C'>.f(arg: int) -> str
reveal_type(C.f(1)) # revealed: str
```
@ -322,7 +322,7 @@ class C:
def f(cls: type[C], x: int) -> str:
return "a"
reveal_type(C.f) # revealed: bound method Literal[C].f(x: int) -> str
reveal_type(C.f) # revealed: bound method <class 'C'>.f(x: int) -> str
reveal_type(C().f) # revealed: bound method type[C].f(x: int) -> str
```
@ -350,7 +350,7 @@ class D:
# This function is wrongly annotated, it should be `type[D]` instead of `D`
pass
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `D`, found `Literal[D]`"
# error: [invalid-argument-type] "Argument to this function is incorrect: Expected `D`, found `<class 'D'>`"
D.f()
```
@ -360,7 +360,7 @@ When a class method is accessed on a derived class, it is bound to that derived
class Derived(C):
pass
reveal_type(Derived.f) # revealed: bound method Literal[Derived].f(x: int) -> str
reveal_type(Derived.f) # revealed: bound method <class 'Derived'>.f(x: int) -> str
reveal_type(Derived().f) # revealed: bound method type[Derived].f(x: int) -> str
reveal_type(Derived.f(1)) # revealed: str
@ -386,15 +386,15 @@ reveal_type(getattr_static(C, "f").__get__) # revealed: <method-wrapper `__get_
But we correctly model how the `classmethod` descriptor works:
```py
reveal_type(getattr_static(C, "f").__get__(None, C)) # revealed: bound method Literal[C].f() -> Unknown
reveal_type(getattr_static(C, "f").__get__(C(), C)) # revealed: bound method Literal[C].f() -> Unknown
reveal_type(getattr_static(C, "f").__get__(None, C)) # revealed: bound method <class 'C'>.f() -> Unknown
reveal_type(getattr_static(C, "f").__get__(C(), C)) # revealed: bound method <class 'C'>.f() -> Unknown
reveal_type(getattr_static(C, "f").__get__(C())) # revealed: bound method type[C].f() -> Unknown
```
The `owner` argument takes precedence over the `instance` argument:
```py
reveal_type(getattr_static(C, "f").__get__("dummy", C)) # revealed: bound method Literal[C].f() -> Unknown
reveal_type(getattr_static(C, "f").__get__("dummy", C)) # revealed: bound method <class 'C'>.f() -> Unknown
```
### Classmethods mixed with other decorators

View file

@ -1,6 +1,6 @@
# Super
Python defines the terms *bound super object* and *unbound super object*.
Python defines the terms _bound super object_ and _unbound super object_.
An **unbound super object** is created when `super` is called with only one argument. (e.g.
`super(A)`). This object may later be bound using the `super.__get__` method. However, this form is
@ -30,24 +30,24 @@ class C(B):
def c(self): ...
cc: int = 3
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[B], Literal[A], Literal[object]]
reveal_type(C.__mro__) # revealed: tuple[<class 'C'>, <class 'B'>, <class 'A'>, <class 'object'>]
super(C, C()).a
super(C, C()).b
# error: [unresolved-attribute] "Type `<super: Literal[C], C>` has no attribute `c`"
# error: [unresolved-attribute] "Type `<super: <class 'C'>, C>` has no attribute `c`"
super(C, C()).c
super(B, C()).a
# error: [unresolved-attribute] "Type `<super: Literal[B], C>` has no attribute `b`"
# error: [unresolved-attribute] "Type `<super: <class 'B'>, C>` has no attribute `b`"
super(B, C()).b
# error: [unresolved-attribute] "Type `<super: Literal[B], C>` has no attribute `c`"
# error: [unresolved-attribute] "Type `<super: <class 'B'>, C>` has no attribute `c`"
super(B, C()).c
# error: [unresolved-attribute] "Type `<super: Literal[A], C>` has no attribute `a`"
# error: [unresolved-attribute] "Type `<super: <class 'A'>, C>` has no attribute `a`"
super(A, C()).a
# error: [unresolved-attribute] "Type `<super: Literal[A], C>` has no attribute `b`"
# error: [unresolved-attribute] "Type `<super: <class 'A'>, C>` has no attribute `b`"
super(A, C()).b
# error: [unresolved-attribute] "Type `<super: Literal[A], C>` has no attribute `c`"
# error: [unresolved-attribute] "Type `<super: <class 'A'>, C>` has no attribute `c`"
super(A, C()).c
reveal_type(super(C, C()).a) # revealed: bound method C.a() -> Unknown
@ -72,14 +72,14 @@ class A:
class B(A):
def __init__(self, a: int):
# TODO: Once `Self` is supported, this should be `<super: Literal[B], B>`
reveal_type(super()) # revealed: <super: Literal[B], Unknown>
# TODO: Once `Self` is supported, this should be `<super: <class 'B'>, B>`
reveal_type(super()) # revealed: <super: <class 'B'>, Unknown>
super().__init__(a)
@classmethod
def f(cls):
# TODO: Once `Self` is supported, this should be `<super: Literal[B], Literal[B]>`
reveal_type(super()) # revealed: <super: Literal[B], Unknown>
# TODO: Once `Self` is supported, this should be `<super: <class 'B'>, <class 'B'>>`
reveal_type(super()) # revealed: <super: <class 'B'>, Unknown>
super().f()
super(B, B(42)).__init__(42)
@ -88,7 +88,7 @@ super(B, B).f()
### Unbound Super Object
Calling `super(cls)` without a second argument returns an *unbound super object*. This is treated as
Calling `super(cls)` without a second argument returns an _unbound super object_. This is treated as
a plain `super` instance and does not support name lookup via the MRO.
```py
@ -115,7 +115,7 @@ class A:
class B(A): ...
reveal_type(super(B, B()).a) # revealed: int
# error: [invalid-assignment] "Cannot assign to attribute `a` on type `<super: Literal[B], B>`"
# error: [invalid-assignment] "Cannot assign to attribute `a` on type `<super: <class 'B'>, B>`"
super(B, B()).a = 3
# error: [invalid-assignment] "Cannot assign to attribute `a` on type `super`"
super(B).a = 5
@ -134,7 +134,7 @@ def f(x):
reveal_type(x) # revealed: Unknown
reveal_type(super(x, x)) # revealed: <super: Unknown, Unknown>
reveal_type(super(A, x)) # revealed: <super: Literal[A], Unknown>
reveal_type(super(A, x)) # revealed: <super: <class 'A'>, Unknown>
reveal_type(super(x, A())) # revealed: <super: Unknown, A>
reveal_type(super(x, x).a) # revealed: Unknown
@ -149,29 +149,29 @@ from __future__ import annotations
class A:
def test(self):
reveal_type(super()) # revealed: <super: Literal[A], Unknown>
reveal_type(super()) # revealed: <super: <class 'A'>, Unknown>
class B:
def test(self):
reveal_type(super()) # revealed: <super: Literal[B], Unknown>
reveal_type(super()) # revealed: <super: <class 'B'>, Unknown>
class C(A.B):
def test(self):
reveal_type(super()) # revealed: <super: Literal[C], Unknown>
reveal_type(super()) # revealed: <super: <class 'C'>, Unknown>
def inner(t: C):
reveal_type(super()) # revealed: <super: Literal[B], C>
lambda x: reveal_type(super()) # revealed: <super: Literal[B], Unknown>
reveal_type(super()) # revealed: <super: <class 'B'>, C>
lambda x: reveal_type(super()) # revealed: <super: <class 'B'>, Unknown>
```
## Built-ins and Literals
```py
reveal_type(super(bool, True)) # revealed: <super: Literal[bool], bool>
reveal_type(super(bool, bool())) # revealed: <super: Literal[bool], bool>
reveal_type(super(int, bool())) # revealed: <super: Literal[int], bool>
reveal_type(super(int, 3)) # revealed: <super: Literal[int], int>
reveal_type(super(str, "")) # revealed: <super: Literal[str], str>
reveal_type(super(bool, True)) # revealed: <super: <class 'bool'>, bool>
reveal_type(super(bool, bool())) # revealed: <super: <class 'bool'>, bool>
reveal_type(super(int, bool())) # revealed: <super: <class 'int'>, bool>
reveal_type(super(int, 3)) # revealed: <super: <class 'int'>, int>
reveal_type(super(str, "")) # revealed: <super: <class 'str'>, str>
```
## Descriptor Behavior with Super
@ -195,7 +195,7 @@ reveal_type(super(B, B()).a2) # revealed: bound method type[B].a2() -> Unknown
# A.__dict__["a1"].__get__(None, B)
reveal_type(super(B, B).a1) # revealed: def a1(self) -> Unknown
# A.__dict__["a2"].__get__(None, B)
reveal_type(super(B, B).a2) # revealed: bound method Literal[B].a2() -> Unknown
reveal_type(super(B, B).a2) # revealed: bound method <class 'B'>.a2() -> Unknown
```
## Union of Supers
@ -213,22 +213,22 @@ class C(A, B): ...
class D(B, A): ...
def f(x: C | D):
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[A], Literal[B], Literal[object]]
reveal_type(D.__mro__) # revealed: tuple[Literal[D], Literal[B], Literal[A], Literal[object]]
reveal_type(C.__mro__) # revealed: tuple[<class 'C'>, <class 'A'>, <class 'B'>, <class 'object'>]
reveal_type(D.__mro__) # revealed: tuple[<class 'D'>, <class 'B'>, <class 'A'>, <class 'object'>]
s = super(A, x)
reveal_type(s) # revealed: <super: Literal[A], C> | <super: Literal[A], D>
reveal_type(s) # revealed: <super: <class 'A'>, C> | <super: <class 'A'>, D>
# error: [possibly-unbound-attribute] "Attribute `b` on type `<super: Literal[A], C> | <super: Literal[A], D>` is possibly unbound"
# error: [possibly-unbound-attribute] "Attribute `b` on type `<super: <class 'A'>, C> | <super: <class 'A'>, D>` is possibly unbound"
s.b
def f(flag: bool):
x = str() if flag else str("hello")
reveal_type(x) # revealed: Literal["", "hello"]
reveal_type(super(str, x)) # revealed: <super: Literal[str], str>
reveal_type(super(str, x)) # revealed: <super: <class 'str'>, str>
def f(x: int | str):
# error: [invalid-super-argument] "`str` is not an instance or subclass of `Literal[int]` in `super(Literal[int], str)` call"
# error: [invalid-super-argument] "`str` is not an instance or subclass of `<class 'int'>` in `super(<class 'int'>, str)` call"
super(int, x)
```
@ -254,12 +254,12 @@ def f(flag: bool):
class D(C): ...
s = super(D, D())
reveal_type(s) # revealed: <super: Literal[B], B> | <super: Literal[D], D>
reveal_type(s) # revealed: <super: <class 'B'>, B> | <super: <class 'D'>, D>
reveal_type(s.x) # revealed: Unknown | Literal[1, 2]
reveal_type(s.y) # revealed: int | str
# error: [possibly-unbound-attribute] "Attribute `a` on type `<super: Literal[B], B> | <super: Literal[D], D>` is possibly unbound"
# error: [possibly-unbound-attribute] "Attribute `a` on type `<super: <class 'B'>, B> | <super: <class 'D'>, D>` is possibly unbound"
reveal_type(s.a) # revealed: str
```
@ -339,30 +339,30 @@ def f(x: int):
# error: [invalid-super-argument] "`typing.TypeAliasType` is not a valid class"
super(IntAlias, 0)
# error: [invalid-super-argument] "`Literal[""]` is not an instance or subclass of `Literal[int]` in `super(Literal[int], Literal[""])` call"
# error: [invalid-super-argument] "`Literal[""]` is not an instance or subclass of `<class 'int'>` in `super(<class 'int'>, Literal[""])` call"
# revealed: Unknown
reveal_type(super(int, str()))
# error: [invalid-super-argument] "`Literal[str]` is not an instance or subclass of `Literal[int]` in `super(Literal[int], Literal[str])` call"
# error: [invalid-super-argument] "`<class 'str'>` is not an instance or subclass of `<class 'int'>` in `super(<class 'int'>, <class 'str'>)` call"
# revealed: Unknown
reveal_type(super(int, str))
class A: ...
class B(A): ...
# error: [invalid-super-argument] "`A` is not an instance or subclass of `Literal[B]` in `super(Literal[B], A)` call"
# error: [invalid-super-argument] "`A` is not an instance or subclass of `<class 'B'>` in `super(<class 'B'>, A)` call"
# revealed: Unknown
reveal_type(super(B, A()))
# error: [invalid-super-argument] "`object` is not an instance or subclass of `Literal[B]` in `super(Literal[B], object)` call"
# error: [invalid-super-argument] "`object` is not an instance or subclass of `<class 'B'>` in `super(<class 'B'>, object)` call"
# revealed: Unknown
reveal_type(super(B, object()))
# error: [invalid-super-argument] "`Literal[A]` is not an instance or subclass of `Literal[B]` in `super(Literal[B], Literal[A])` call"
# error: [invalid-super-argument] "`<class 'A'>` is not an instance or subclass of `<class 'B'>` in `super(<class 'B'>, <class 'A'>)` call"
# revealed: Unknown
reveal_type(super(B, A))
# error: [invalid-super-argument] "`Literal[object]` is not an instance or subclass of `Literal[B]` in `super(Literal[B], Literal[object])` call"
# error: [invalid-super-argument] "`<class 'object'>` is not an instance or subclass of `<class 'B'>` in `super(<class 'B'>, <class 'object'>)` call"
# revealed: Unknown
reveal_type(super(B, object))
@ -386,7 +386,7 @@ class B(A):
# TODO: Once `Self` is supported, this should raise `unresolved-attribute` error
super().a
# error: [unresolved-attribute] "Type `<super: Literal[B], B>` has no attribute `a`"
# error: [unresolved-attribute] "Type `<super: <class 'B'>, B>` has no attribute `a`"
super(B, B(42)).a
```
@ -405,6 +405,6 @@ class B(A): ...
reveal_type(A()[0]) # revealed: int
reveal_type(super(B, B()).__getitem__) # revealed: bound method B.__getitem__(key: int) -> int
# error: [non-subscriptable] "Cannot subscript object of type `<super: Literal[B], B>` with no `__getitem__` method"
# error: [non-subscriptable] "Cannot subscript object of type `<super: <class 'B'>, B>` with no `__getitem__` method"
super(B, B())[0]
```

View file

@ -181,7 +181,7 @@ class D:
class_literal: TypeOf[SomeClass]
class_subtype_of: type[SomeClass]
# revealed: (function_literal: def some_function() -> None, class_literal: Literal[SomeClass], class_subtype_of: type[SomeClass]) -> None
# revealed: (function_literal: def some_function() -> None, class_literal: <class 'SomeClass'>, class_subtype_of: type[SomeClass]) -> None
reveal_type(D.__init__)
```
@ -489,7 +489,7 @@ class DataWithDescription[T]:
data: T
description: str
reveal_type(DataWithDescription[int]) # revealed: Literal[DataWithDescription[int]]
reveal_type(DataWithDescription[int]) # revealed: <class 'DataWithDescription[int]'>
d_int = DataWithDescription[int](1, "description") # OK
reveal_type(d_int.data) # revealed: int
@ -675,7 +675,7 @@ from dataclasses import dataclass
class C:
x: int
# error: [unresolved-attribute] "Attribute `x` can only be accessed on instances, not on the class object `Literal[C]` itself."
# error: [unresolved-attribute] "Attribute `x` can only be accessed on instances, not on the class object `<class 'C'>` itself."
C.x
```
@ -715,8 +715,8 @@ class Person:
name: str
age: int | None = None
reveal_type(type(Person)) # revealed: Literal[type]
reveal_type(Person.__mro__) # revealed: tuple[Literal[Person], Literal[object]]
reveal_type(type(Person)) # revealed: <class 'type'>
reveal_type(Person.__mro__) # revealed: tuple[<class 'Person'>, <class 'object'>]
```
The generated methods have the following signatures:

View file

@ -269,7 +269,7 @@ on the metaclass:
```py
C1.meta_data_descriptor = 1
# error: [invalid-assignment] "Invalid assignment to data descriptor attribute `meta_data_descriptor` on type `Literal[C1]` with custom `__set__` method"
# error: [invalid-assignment] "Invalid assignment to data descriptor attribute `meta_data_descriptor` on type `<class 'C1'>` with custom `__set__` method"
C1.meta_data_descriptor = "invalid"
```
@ -371,7 +371,7 @@ def _(flag: bool):
# TODO: We currently emit two diagnostics here, corresponding to the two states of `flag`. The diagnostics are not
# wrong, but they could be subsumed under a higher-level diagnostic.
# error: [invalid-assignment] "Invalid assignment to data descriptor attribute `meta_data_descriptor1` on type `Literal[C5]` with custom `__set__` method"
# error: [invalid-assignment] "Invalid assignment to data descriptor attribute `meta_data_descriptor1` on type `<class 'C5'>` with custom `__set__` method"
# error: [invalid-assignment] "Object of type `None` is not assignable to attribute `meta_data_descriptor1` of type `Literal["value on class"]`"
C5.meta_data_descriptor1 = None
@ -724,13 +724,13 @@ def _(flag: bool):
non_data: NonDataDescriptor = NonDataDescriptor()
data: DataDescriptor = DataDescriptor()
# error: [possibly-unbound-attribute] "Attribute `non_data` on type `Literal[PossiblyUnbound]` is possibly unbound"
# error: [possibly-unbound-attribute] "Attribute `non_data` on type `<class 'PossiblyUnbound'>` is possibly unbound"
reveal_type(PossiblyUnbound.non_data) # revealed: int
# error: [possibly-unbound-attribute] "Attribute `non_data` on type `PossiblyUnbound` is possibly unbound"
reveal_type(PossiblyUnbound().non_data) # revealed: int
# error: [possibly-unbound-attribute] "Attribute `data` on type `Literal[PossiblyUnbound]` is possibly unbound"
# error: [possibly-unbound-attribute] "Attribute `data` on type `<class 'PossiblyUnbound'>` is possibly unbound"
reveal_type(PossiblyUnbound.data) # revealed: int
# error: [possibly-unbound-attribute] "Attribute `data` on type `PossiblyUnbound` is possibly unbound"

View file

@ -600,12 +600,12 @@ except:
reveal_type(x) # revealed: E
x = Bar
reveal_type(x) # revealed: Literal[Bar]
reveal_type(x) # revealed: <class 'Bar'>
finally:
# TODO: should be `Literal[1] | Literal[foo] | Literal[Bar]`
reveal_type(x) # revealed: (def foo(param=A) -> Unknown) | Literal[Bar]
# TODO: should be `Literal[1] | <class 'foo'> | <class 'Bar'>`
reveal_type(x) # revealed: (def foo(param=A) -> Unknown) | <class 'Bar'>
reveal_type(x) # revealed: (def foo(param=A) -> Unknown) | Literal[Bar]
reveal_type(x) # revealed: (def foo(param=A) -> Unknown) | <class 'Bar'>
```
[1]: https://astral-sh.notion.site/Exception-handler-control-flow-11348797e1ca80bb8ce1e9aedbbe439d

View file

@ -26,9 +26,9 @@ def _(flag: bool):
reveal_type(A.union_declared) # revealed: int | str
# error: [possibly-unbound-attribute] "Attribute `possibly_unbound` on type `Literal[A]` is possibly unbound"
# error: [possibly-unbound-attribute] "Attribute `possibly_unbound` on type `<class 'A'>` is possibly unbound"
reveal_type(A.possibly_unbound) # revealed: str
# error: [unresolved-attribute] "Type `Literal[A]` has no attribute `non_existent`"
# error: [unresolved-attribute] "Type `<class 'A'>` has no attribute `non_existent`"
reveal_type(A.non_existent) # revealed: Unknown
```

View file

@ -29,7 +29,7 @@ class RepeatedTypevar(Generic[T, T]): ...
You can only specialize `typing.Generic` with typevars (TODO: or param specs or typevar tuples).
```py
# error: [invalid-argument-type] "`Literal[int]` is not a valid argument to `typing.Generic`"
# error: [invalid-argument-type] "`<class 'int'>` is not a valid argument to `typing.Generic`"
class GenericOfType(Generic[int]): ...
```
@ -436,7 +436,7 @@ T = TypeVar("T")
class Base(Generic[T]): ...
class Sub(Base[Sub]): ...
reveal_type(Sub) # revealed: Literal[Sub]
reveal_type(Sub) # revealed: <class 'Sub'>
```
#### With string forward references
@ -451,7 +451,7 @@ T = TypeVar("T")
class Base(Generic[T]): ...
class Sub(Base["Sub"]): ...
reveal_type(Sub) # revealed: Literal[Sub]
reveal_type(Sub) # revealed: <class 'Sub'>
```
#### Without string forward references

View file

@ -19,7 +19,7 @@ in newer Python releases.
from typing import TypeVar
T = TypeVar("T")
reveal_type(type(T)) # revealed: Literal[TypeVar]
reveal_type(type(T)) # revealed: <class 'TypeVar'>
reveal_type(T) # revealed: typing.TypeVar
reveal_type(T.__name__) # revealed: Literal["T"]
```

View file

@ -362,7 +362,7 @@ Here, `Sub` is not a generic class, since it fills its superclass's type paramet
class Base[T]: ...
class Sub(Base[Sub]): ...
reveal_type(Sub) # revealed: Literal[Sub]
reveal_type(Sub) # revealed: <class 'Sub'>
```
#### With string forward references
@ -373,7 +373,7 @@ A similar case can work in a non-stub file, if forward references are stringifie
class Base[T]: ...
class Sub(Base["Sub"]): ...
reveal_type(Sub) # revealed: Literal[Sub]
reveal_type(Sub) # revealed: <class 'Sub'>
```
#### Without string forward references

View file

@ -16,7 +16,7 @@ instances of `typing.TypeVar`, just like legacy type variables.
```py
def f[T]():
reveal_type(type(T)) # revealed: Literal[TypeVar]
reveal_type(type(T)) # revealed: <class 'TypeVar'>
reveal_type(T) # revealed: typing.TypeVar
reveal_type(T.__name__) # revealed: Literal["T"]
```

View file

@ -6,7 +6,7 @@
from b import C as D
E = D
reveal_type(E) # revealed: Literal[C]
reveal_type(E) # revealed: <class 'C'>
```
`b.py`:
@ -21,7 +21,7 @@ class C: ...
import b
D = b.C
reveal_type(D) # revealed: Literal[C]
reveal_type(D) # revealed: <class 'C'>
```
`b.py`:
@ -35,7 +35,7 @@ class C: ...
```py
import a.b
reveal_type(a.b.C) # revealed: Literal[C]
reveal_type(a.b.C) # revealed: <class 'C'>
```
`a/__init__.py`:
@ -54,7 +54,7 @@ class C: ...
```py
import a.b.c
reveal_type(a.b.c.C) # revealed: Literal[C]
reveal_type(a.b.c.C) # revealed: <class 'C'>
```
`a/__init__.py`:
@ -78,7 +78,7 @@ class C: ...
```py
import a.b as b
reveal_type(b.C) # revealed: Literal[C]
reveal_type(b.C) # revealed: <class 'C'>
```
`a/__init__.py`:
@ -97,7 +97,7 @@ class C: ...
```py
import a.b.c as c
reveal_type(c.C) # revealed: Literal[C]
reveal_type(c.C) # revealed: <class 'C'>
```
`a/__init__.py`:

View file

@ -16,7 +16,7 @@ Or used implicitly:
```py
reveal_type(chr) # revealed: def chr(i: SupportsIndex, /) -> str
reveal_type(str) # revealed: Literal[str]
reveal_type(str) # revealed: <class 'str'>
```
## Builtin symbol from custom typeshed

View file

@ -95,6 +95,7 @@ from typing import Any, Literal
`foo.pyi`:
```pyi
```
## Nested non-exports
@ -187,7 +188,7 @@ reveal_type(Foo) # revealed: Unknown
```pyi
from b import AnyFoo as Foo
reveal_type(Foo) # revealed: Literal[AnyFoo]
reveal_type(Foo) # revealed: <class 'AnyFoo'>
```
`b.pyi`:
@ -251,11 +252,13 @@ class Foo: ...
`a/b/__init__.pyi`:
```pyi
```
`a/b/c.pyi`:
```pyi
```
## Conditional re-export in stub file
@ -281,7 +284,7 @@ def coinflip() -> bool: ...
if coinflip():
Foo: str = ...
reveal_type(Foo) # revealed: Literal[Foo] | str
reveal_type(Foo) # revealed: <class 'Foo'> | str
```
`b.pyi`:
@ -299,7 +302,7 @@ the other does not.
# error: "Member `Foo` of module `a` is possibly unbound"
from a import Foo
reveal_type(Foo) # revealed: Literal[Foo]
reveal_type(Foo) # revealed: <class 'Foo'>
```
`a.pyi`:
@ -312,7 +315,7 @@ if coinflip():
else:
from b import Foo as Foo
reveal_type(Foo) # revealed: Literal[Foo]
reveal_type(Foo) # revealed: <class 'Foo'>
```
`b.pyi`:
@ -327,7 +330,7 @@ class Foo: ...
# error: "Member `Foo` of module `a` is possibly unbound"
from a import Foo
reveal_type(Foo) # revealed: Literal[Foo]
reveal_type(Foo) # revealed: <class 'Foo'>
```
`a.pyi`:

View file

@ -69,12 +69,12 @@ x = "foo" # error: [invalid-assignment] "Object of type `Literal["foo"]"
```py
class A: ...
reveal_type(A.__mro__) # revealed: tuple[Literal[A], Literal[object]]
reveal_type(A.__mro__) # revealed: tuple[<class 'A'>, <class 'object'>]
import b
class C(b.B): ...
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[B], Literal[A], Literal[object]]
reveal_type(C.__mro__) # revealed: tuple[<class 'C'>, <class 'B'>, <class 'A'>, <class 'object'>]
```
`b.py`:
@ -84,5 +84,5 @@ from a import A
class B(A): ...
reveal_type(B.__mro__) # revealed: tuple[Literal[B], Literal[A], Literal[object]]
reveal_type(B.__mro__) # revealed: tuple[<class 'B'>, <class 'A'>, <class 'object'>]
```

View file

@ -255,7 +255,7 @@ python-version = "3.13"
```py
from foo import A
reveal_type(A) # revealed: Literal[A]
reveal_type(A) # revealed: <class 'A'>
```
`/src/.venv/<path-to-site-packages>/foo/__init__.py`:

View file

@ -1353,7 +1353,7 @@ are present due to `*` imports.
```py
import collections.abc
reveal_type(collections.abc.Sequence) # revealed: Literal[Sequence]
reveal_type(collections.abc.Sequence) # revealed: <class 'Sequence'>
reveal_type(collections.abc.Callable) # revealed: typing.Callable
# TODO: false positive as it's only re-exported from `_collections.abc` due to presence in `__all__`

View file

@ -27,7 +27,7 @@ has been imported.
import a
# Would be an error with flow-sensitive tracking
reveal_type(a.b.C) # revealed: Literal[C]
reveal_type(a.b.C) # revealed: <class 'C'>
import a.b
```
@ -53,10 +53,10 @@ submodule `b`, even though `a.b` is never imported in the main module.
from q import a, b
reveal_type(b) # revealed: <module 'a.b'>
reveal_type(b.C) # revealed: Literal[C]
reveal_type(b.C) # revealed: <class 'C'>
reveal_type(a.b) # revealed: <module 'a.b'>
reveal_type(a.b.C) # revealed: Literal[C]
reveal_type(a.b.C) # revealed: <class 'C'>
```
`a/__init__.py`:

View file

@ -3,19 +3,19 @@
```py
class M(type): ...
reveal_type(M.__class__) # revealed: Literal[type]
reveal_type(M.__class__) # revealed: <class 'type'>
```
## `object`
```py
reveal_type(object.__class__) # revealed: Literal[type]
reveal_type(object.__class__) # revealed: <class 'type'>
```
## `type`
```py
reveal_type(type.__class__) # revealed: Literal[type]
reveal_type(type.__class__) # revealed: <class 'type'>
```
## Basic
@ -24,7 +24,7 @@ reveal_type(type.__class__) # revealed: Literal[type]
class M(type): ...
class B(metaclass=M): ...
reveal_type(B.__class__) # revealed: Literal[M]
reveal_type(B.__class__) # revealed: <class 'M'>
```
## Invalid metaclass
@ -37,7 +37,7 @@ class M: ...
class A(metaclass=M): ...
# TODO: emit a diagnostic for the invalid metaclass
reveal_type(A.__class__) # revealed: Literal[M]
reveal_type(A.__class__) # revealed: <class 'M'>
```
## Linear inheritance
@ -50,7 +50,7 @@ class M(type): ...
class A(metaclass=M): ...
class B(A): ...
reveal_type(B.__class__) # revealed: Literal[M]
reveal_type(B.__class__) # revealed: <class 'M'>
```
## Linear inheritance with PEP 695 generic class
@ -68,8 +68,8 @@ class A[T](metaclass=M): ...
class B(A): ...
class C(A[int]): ...
reveal_type(B.__class__) # revealed: Literal[M]
reveal_type(C.__class__) # revealed: Literal[M]
reveal_type(B.__class__) # revealed: <class 'M'>
reveal_type(C.__class__) # revealed: <class 'M'>
```
## Conflict (1)
@ -117,7 +117,7 @@ class A(metaclass=M): ...
class B(metaclass=M): ...
class C(A, B): ...
reveal_type(C.__class__) # revealed: Literal[M]
reveal_type(C.__class__) # revealed: <class 'M'>
```
## Metaclass metaclass
@ -131,7 +131,7 @@ class M3(M2): ...
class A(metaclass=M3): ...
class B(A): ...
reveal_type(A.__class__) # revealed: Literal[M3]
reveal_type(A.__class__) # revealed: <class 'M3'>
```
## Diamond inheritance
@ -159,14 +159,14 @@ from nonexistent_module import UnknownClass # error: [unresolved-import]
class C(UnknownClass): ...
# TODO: should be `type[type] & Unknown`
reveal_type(C.__class__) # revealed: Literal[type]
reveal_type(C.__class__) # revealed: <class 'type'>
class M(type): ...
class A(metaclass=M): ...
class B(A, UnknownClass): ...
# TODO: should be `type[M] & Unknown`
reveal_type(B.__class__) # revealed: Literal[M]
reveal_type(B.__class__) # revealed: <class 'M'>
```
## Duplicate
@ -176,7 +176,7 @@ class M(type): ...
class A(metaclass=M): ...
class B(A, A): ... # error: [duplicate-base] "Duplicate base class `A`"
reveal_type(B.__class__) # revealed: Literal[M]
reveal_type(B.__class__) # revealed: <class 'M'>
```
## Non-class
@ -191,14 +191,14 @@ def f(*args, **kwargs) -> int:
class A(metaclass=f): ...
# TODO: Should be `int`
reveal_type(A) # revealed: Literal[A]
reveal_type(A) # revealed: <class 'A'>
reveal_type(A.__class__) # revealed: type[int]
def _(n: int):
# error: [invalid-metaclass]
class B(metaclass=n): ...
# TODO: Should be `Unknown`
reveal_type(B) # revealed: Literal[B]
reveal_type(B) # revealed: <class 'B'>
reveal_type(B.__class__) # revealed: type[Unknown]
def _(flag: bool):
@ -207,7 +207,7 @@ def _(flag: bool):
# error: [invalid-metaclass]
class C(metaclass=m): ...
# TODO: Should be `int | Unknown`
reveal_type(C) # revealed: Literal[C]
reveal_type(C) # revealed: <class 'C'>
reveal_type(C.__class__) # revealed: type[Unknown]
class SignatureMismatch: ...
@ -216,9 +216,9 @@ class SignatureMismatch: ...
class D(metaclass=SignatureMismatch): ...
# TODO: Should be `Unknown`
reveal_type(D) # revealed: Literal[D]
reveal_type(D) # revealed: <class 'D'>
# TODO: Should be `type[Unknown]`
reveal_type(D.__class__) # revealed: Literal[SignatureMismatch]
reveal_type(D.__class__) # revealed: <class 'SignatureMismatch'>
```
## Cyclic
@ -244,7 +244,7 @@ python-version = "3.12"
class M(type): ...
class A[T: str](metaclass=M): ...
reveal_type(A.__class__) # revealed: Literal[M]
reveal_type(A.__class__) # revealed: <class 'M'>
```
## Metaclasses of metaclasses
@ -255,9 +255,9 @@ class Bar(type, metaclass=Foo): ...
class Baz(type, metaclass=Bar): ...
class Spam(metaclass=Baz): ...
reveal_type(Spam.__class__) # revealed: Literal[Baz]
reveal_type(Spam.__class__.__class__) # revealed: Literal[Bar]
reveal_type(Spam.__class__.__class__.__class__) # revealed: Literal[Foo]
reveal_type(Spam.__class__) # revealed: <class 'Baz'>
reveal_type(Spam.__class__.__class__) # revealed: <class 'Bar'>
reveal_type(Spam.__class__.__class__.__class__) # revealed: <class 'Foo'>
def test(x: Spam):
reveal_type(x.__class__) # revealed: type[Spam]

View file

@ -16,13 +16,13 @@ For documentation on method resolution orders, see:
```py
class C: ...
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[object]]
reveal_type(C.__mro__) # revealed: tuple[<class 'C'>, <class 'object'>]
```
## The special case: `object` itself
```py
reveal_type(object.__mro__) # revealed: tuple[Literal[object]]
reveal_type(object.__mro__) # revealed: tuple[<class 'object'>]
```
## Explicit inheritance from `object`
@ -30,7 +30,7 @@ reveal_type(object.__mro__) # revealed: tuple[Literal[object]]
```py
class C(object): ...
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[object]]
reveal_type(C.__mro__) # revealed: tuple[<class 'C'>, <class 'object'>]
```
## Explicit inheritance from non-`object` single base
@ -39,7 +39,7 @@ reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[object]]
class A: ...
class B(A): ...
reveal_type(B.__mro__) # revealed: tuple[Literal[B], Literal[A], Literal[object]]
reveal_type(B.__mro__) # revealed: tuple[<class 'B'>, <class 'A'>, <class 'object'>]
```
## Linearization of multiple bases
@ -49,7 +49,7 @@ class A: ...
class B: ...
class C(A, B): ...
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[A], Literal[B], Literal[object]]
reveal_type(C.__mro__) # revealed: tuple[<class 'C'>, <class 'A'>, <class 'B'>, <class 'object'>]
```
## Complex diamond inheritance (1)
@ -63,8 +63,8 @@ class Y(O): ...
class A(X, Y): ...
class B(Y, X): ...
reveal_type(A.__mro__) # revealed: tuple[Literal[A], Literal[X], Literal[Y], Literal[O], Literal[object]]
reveal_type(B.__mro__) # revealed: tuple[Literal[B], Literal[Y], Literal[X], Literal[O], Literal[object]]
reveal_type(A.__mro__) # revealed: tuple[<class 'A'>, <class 'X'>, <class 'Y'>, <class 'O'>, <class 'object'>]
reveal_type(B.__mro__) # revealed: tuple[<class 'B'>, <class 'Y'>, <class 'X'>, <class 'O'>, <class 'object'>]
```
## Complex diamond inheritance (2)
@ -80,11 +80,11 @@ class C(D, F): ...
class B(D, E): ...
class A(B, C): ...
# revealed: tuple[Literal[C], Literal[D], Literal[F], Literal[O], Literal[object]]
# revealed: tuple[<class 'C'>, <class 'D'>, <class 'F'>, <class 'O'>, <class 'object'>]
reveal_type(C.__mro__)
# revealed: tuple[Literal[B], Literal[D], Literal[E], Literal[O], Literal[object]]
# revealed: tuple[<class 'B'>, <class 'D'>, <class 'E'>, <class 'O'>, <class 'object'>]
reveal_type(B.__mro__)
# revealed: tuple[Literal[A], Literal[B], Literal[C], Literal[D], Literal[E], Literal[F], Literal[O], Literal[object]]
# revealed: tuple[<class 'A'>, <class 'B'>, <class 'C'>, <class 'D'>, <class 'E'>, <class 'F'>, <class 'O'>, <class 'object'>]
reveal_type(A.__mro__)
```
@ -101,11 +101,11 @@ class C(D, F): ...
class B(E, D): ...
class A(B, C): ...
# revealed: tuple[Literal[C], Literal[D], Literal[F], Literal[O], Literal[object]]
# revealed: tuple[<class 'C'>, <class 'D'>, <class 'F'>, <class 'O'>, <class 'object'>]
reveal_type(C.__mro__)
# revealed: tuple[Literal[B], Literal[E], Literal[D], Literal[O], Literal[object]]
# revealed: tuple[<class 'B'>, <class 'E'>, <class 'D'>, <class 'O'>, <class 'object'>]
reveal_type(B.__mro__)
# revealed: tuple[Literal[A], Literal[B], Literal[E], Literal[C], Literal[D], Literal[F], Literal[O], Literal[object]]
# revealed: tuple[<class 'A'>, <class 'B'>, <class 'E'>, <class 'C'>, <class 'D'>, <class 'F'>, <class 'O'>, <class 'object'>]
reveal_type(A.__mro__)
```
@ -125,13 +125,13 @@ class K2(D, B, E): ...
class K3(D, A): ...
class Z(K1, K2, K3): ...
# revealed: tuple[Literal[K1], Literal[A], Literal[B], Literal[C], Literal[O], Literal[object]]
# revealed: tuple[<class 'K1'>, <class 'A'>, <class 'B'>, <class 'C'>, <class 'O'>, <class 'object'>]
reveal_type(K1.__mro__)
# revealed: tuple[Literal[K2], Literal[D], Literal[B], Literal[E], Literal[O], Literal[object]]
# revealed: tuple[<class 'K2'>, <class 'D'>, <class 'B'>, <class 'E'>, <class 'O'>, <class 'object'>]
reveal_type(K2.__mro__)
# revealed: tuple[Literal[K3], Literal[D], Literal[A], Literal[O], Literal[object]]
# revealed: tuple[<class 'K3'>, <class 'D'>, <class 'A'>, <class 'O'>, <class 'object'>]
reveal_type(K3.__mro__)
# revealed: tuple[Literal[Z], Literal[K1], Literal[K2], Literal[K3], Literal[D], Literal[A], Literal[B], Literal[C], Literal[E], Literal[O], Literal[object]]
# revealed: tuple[<class 'Z'>, <class 'K1'>, <class 'K2'>, <class 'K3'>, <class 'D'>, <class 'A'>, <class 'B'>, <class 'C'>, <class 'E'>, <class 'O'>, <class 'object'>]
reveal_type(Z.__mro__)
```
@ -147,10 +147,11 @@ class D(A, B, C): ...
class E(B, C): ...
class F(E, A): ...
reveal_type(A.__mro__) # revealed: tuple[Literal[A], Unknown, Literal[object]]
reveal_type(D.__mro__) # revealed: tuple[Literal[D], Literal[A], Unknown, Literal[B], Literal[C], Literal[object]]
reveal_type(E.__mro__) # revealed: tuple[Literal[E], Literal[B], Literal[C], Literal[object]]
reveal_type(F.__mro__) # revealed: tuple[Literal[F], Literal[E], Literal[B], Literal[C], Literal[A], Unknown, Literal[object]]
reveal_type(A.__mro__) # revealed: tuple[<class 'A'>, Unknown, <class 'object'>]
reveal_type(D.__mro__) # revealed: tuple[<class 'D'>, <class 'A'>, Unknown, <class 'B'>, <class 'C'>, <class 'object'>]
reveal_type(E.__mro__) # revealed: tuple[<class 'E'>, <class 'B'>, <class 'C'>, <class 'object'>]
# revealed: tuple[<class 'F'>, <class 'E'>, <class 'B'>, <class 'C'>, <class 'A'>, Unknown, <class 'object'>]
reveal_type(F.__mro__)
```
## `__bases__` lists that cause errors at runtime
@ -162,11 +163,11 @@ creation to fail, we infer the class's `__mro__` as being `[<class>, Unknown, ob
# error: [inconsistent-mro] "Cannot create a consistent method resolution order (MRO) for class `Foo` with bases list `[<class 'object'>, <class 'int'>]`"
class Foo(object, int): ...
reveal_type(Foo.__mro__) # revealed: tuple[Literal[Foo], Unknown, Literal[object]]
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
class Bar(Foo): ...
reveal_type(Bar.__mro__) # revealed: tuple[Literal[Bar], Literal[Foo], Unknown, Literal[object]]
reveal_type(Bar.__mro__) # revealed: tuple[<class 'Bar'>, <class 'Foo'>, Unknown, <class 'object'>]
# This is the `TypeError` at the bottom of "ex_2"
# in the examples at <https://docs.python.org/3/howto/mro.html#the-end>
@ -176,17 +177,17 @@ class Y(O): ...
class A(X, Y): ...
class B(Y, X): ...
reveal_type(A.__mro__) # revealed: tuple[Literal[A], Literal[X], Literal[Y], Literal[O], Literal[object]]
reveal_type(B.__mro__) # revealed: tuple[Literal[B], Literal[Y], Literal[X], Literal[O], Literal[object]]
reveal_type(A.__mro__) # revealed: tuple[<class 'A'>, <class 'X'>, <class 'Y'>, <class 'O'>, <class 'object'>]
reveal_type(B.__mro__) # revealed: tuple[<class 'B'>, <class 'Y'>, <class 'X'>, <class 'O'>, <class 'object'>]
# error: [inconsistent-mro] "Cannot create a consistent method resolution order (MRO) for class `Z` with bases list `[<class 'A'>, <class 'B'>]`"
class Z(A, B): ...
reveal_type(Z.__mro__) # revealed: tuple[Literal[Z], Unknown, Literal[object]]
reveal_type(Z.__mro__) # revealed: tuple[<class 'Z'>, Unknown, <class 'object'>]
class AA(Z): ...
reveal_type(AA.__mro__) # revealed: tuple[Literal[AA], Literal[Z], Unknown, Literal[object]]
reveal_type(AA.__mro__) # revealed: tuple[<class 'AA'>, <class 'Z'>, Unknown, <class 'object'>]
```
## `__bases__` includes a `Union`
@ -207,12 +208,12 @@ if returns_bool():
else:
x = B
reveal_type(x) # revealed: Literal[A, B]
reveal_type(x) # revealed: <class 'A'> | <class 'B'>
# error: 11 [invalid-base] "Invalid class base with type `Literal[A, B]` (all bases must be a class, `Any`, `Unknown` or `Todo`)"
# error: 11 [invalid-base] "Invalid class base with type `<class 'A'> | <class 'B'>` (all bases must be a class, `Any`, `Unknown` or `Todo`)"
class Foo(x): ...
reveal_type(Foo.__mro__) # revealed: tuple[Literal[Foo], Unknown, Literal[object]]
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
```
## `__bases__` includes multiple `Union`s
@ -236,14 +237,14 @@ if returns_bool():
else:
y = D
reveal_type(x) # revealed: Literal[A, B]
reveal_type(y) # revealed: Literal[C, D]
reveal_type(x) # revealed: <class 'A'> | <class 'B'>
reveal_type(y) # revealed: <class 'C'> | <class 'D'>
# error: 11 [invalid-base] "Invalid class base with type `Literal[A, B]` (all bases must be a class, `Any`, `Unknown` or `Todo`)"
# error: 14 [invalid-base] "Invalid class base with type `Literal[C, D]` (all bases must be a class, `Any`, `Unknown` or `Todo`)"
# error: 11 [invalid-base] "Invalid class base with type `<class 'A'> | <class 'B'>` (all bases must be a class, `Any`, `Unknown` or `Todo`)"
# error: 14 [invalid-base] "Invalid class base with type `<class 'C'> | <class 'D'>` (all bases must be a class, `Any`, `Unknown` or `Todo`)"
class Foo(x, y): ...
reveal_type(Foo.__mro__) # revealed: tuple[Literal[Foo], Unknown, Literal[object]]
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
```
## `__bases__` lists that cause errors... now with `Union`s
@ -261,14 +262,14 @@ if returns_bool():
else:
foo = object
# error: 21 [invalid-base] "Invalid class base with type `Literal[Y, object]` (all bases must be a class, `Any`, `Unknown` or `Todo`)"
# error: 21 [invalid-base] "Invalid class base with type `<class 'Y'> | <class 'object'>` (all bases must be a class, `Any`, `Unknown` or `Todo`)"
class PossibleError(foo, X): ...
reveal_type(PossibleError.__mro__) # revealed: tuple[Literal[PossibleError], Unknown, Literal[object]]
reveal_type(PossibleError.__mro__) # revealed: tuple[<class 'PossibleError'>, Unknown, <class 'object'>]
class A(X, Y): ...
reveal_type(A.__mro__) # revealed: tuple[Literal[A], Literal[X], Literal[Y], Literal[O], Literal[object]]
reveal_type(A.__mro__) # revealed: tuple[<class 'A'>, <class 'X'>, <class 'Y'>, <class 'O'>, <class 'object'>]
if returns_bool():
class B(X, Y): ...
@ -276,13 +277,13 @@ if returns_bool():
else:
class B(Y, X): ...
# revealed: tuple[Literal[B], Literal[X], Literal[Y], Literal[O], Literal[object]] | tuple[Literal[B], Literal[Y], Literal[X], Literal[O], Literal[object]]
# revealed: tuple[<class 'B'>, <class 'X'>, <class 'Y'>, <class 'O'>, <class 'object'>] | tuple[<class 'B'>, <class 'Y'>, <class 'X'>, <class 'O'>, <class 'object'>]
reveal_type(B.__mro__)
# error: 12 [invalid-base] "Invalid class base with type `Literal[B, B]` (all bases must be a class, `Any`, `Unknown` or `Todo`)"
# error: 12 [invalid-base] "Invalid class base with type `<class 'B'> | <class 'B'>` (all bases must be a class, `Any`, `Unknown` or `Todo`)"
class Z(A, B): ...
reveal_type(Z.__mro__) # revealed: tuple[Literal[Z], Unknown, Literal[object]]
reveal_type(Z.__mro__) # revealed: tuple[<class 'Z'>, Unknown, <class 'object'>]
```
## `__bases__` lists with duplicate bases
@ -290,7 +291,7 @@ reveal_type(Z.__mro__) # revealed: tuple[Literal[Z], Unknown, Literal[object]]
```py
class Foo(str, str): ... # error: 16 [duplicate-base] "Duplicate base class `str`"
reveal_type(Foo.__mro__) # revealed: tuple[Literal[Foo], Unknown, Literal[object]]
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
class Spam: ...
class Eggs: ...
@ -301,12 +302,12 @@ class Ham(
Eggs, # error: [duplicate-base] "Duplicate base class `Eggs`"
): ...
reveal_type(Ham.__mro__) # revealed: tuple[Literal[Ham], Unknown, Literal[object]]
reveal_type(Ham.__mro__) # revealed: tuple[<class 'Ham'>, Unknown, <class 'object'>]
class Mushrooms: ...
class Omelette(Spam, Eggs, Mushrooms, Mushrooms): ... # error: [duplicate-base]
reveal_type(Omelette.__mro__) # revealed: tuple[Literal[Omelette], Unknown, Literal[object]]
reveal_type(Omelette.__mro__) # revealed: tuple[<class 'Omelette'>, Unknown, <class 'object'>]
```
## `__bases__` lists with duplicate `Unknown` bases
@ -330,7 +331,7 @@ reveal_type(unknown_object_2) # revealed: Unknown
# error: [inconsistent-mro] "Cannot create a consistent method resolution order (MRO) for class `Foo` with bases list `[Unknown, Unknown]`"
class Foo(unknown_object_1, unknown_object_2): ...
reveal_type(Foo.__mro__) # revealed: tuple[Literal[Foo], Unknown, Literal[object]]
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
```
## Unrelated objects inferred as `Any`/`Unknown` do not have special `__mro__` attributes
@ -349,15 +350,15 @@ These are invalid, but we need to be able to handle them gracefully without pani
```pyi
class Foo(Foo): ... # error: [cyclic-class-definition]
reveal_type(Foo) # revealed: Literal[Foo]
reveal_type(Foo.__mro__) # revealed: tuple[Literal[Foo], Unknown, Literal[object]]
reveal_type(Foo) # revealed: <class 'Foo'>
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
class Bar: ...
class Baz: ...
class Boz(Bar, Baz, Boz): ... # error: [cyclic-class-definition]
reveal_type(Boz) # revealed: Literal[Boz]
reveal_type(Boz.__mro__) # revealed: tuple[Literal[Boz], Unknown, Literal[object]]
reveal_type(Boz) # revealed: <class 'Boz'>
reveal_type(Boz.__mro__) # revealed: tuple[<class 'Boz'>, Unknown, <class 'object'>]
```
## Classes with indirect cycles in their MROs
@ -369,9 +370,9 @@ class Foo(Bar): ... # error: [cyclic-class-definition]
class Bar(Baz): ... # error: [cyclic-class-definition]
class Baz(Foo): ... # error: [cyclic-class-definition]
reveal_type(Foo.__mro__) # revealed: tuple[Literal[Foo], Unknown, Literal[object]]
reveal_type(Bar.__mro__) # revealed: tuple[Literal[Bar], Unknown, Literal[object]]
reveal_type(Baz.__mro__) # revealed: tuple[Literal[Baz], Unknown, Literal[object]]
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
reveal_type(Bar.__mro__) # revealed: tuple[<class 'Bar'>, Unknown, <class 'object'>]
reveal_type(Baz.__mro__) # revealed: tuple[<class 'Baz'>, Unknown, <class 'object'>]
```
## Classes with cycles in their MROs, and multiple inheritance
@ -382,9 +383,9 @@ class Foo(Bar): ... # error: [cyclic-class-definition]
class Bar(Baz): ... # error: [cyclic-class-definition]
class Baz(Foo, Spam): ... # error: [cyclic-class-definition]
reveal_type(Foo.__mro__) # revealed: tuple[Literal[Foo], Unknown, Literal[object]]
reveal_type(Bar.__mro__) # revealed: tuple[Literal[Bar], Unknown, Literal[object]]
reveal_type(Baz.__mro__) # revealed: tuple[Literal[Baz], Unknown, Literal[object]]
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
reveal_type(Bar.__mro__) # revealed: tuple[<class 'Bar'>, Unknown, <class 'object'>]
reveal_type(Baz.__mro__) # revealed: tuple[<class 'Baz'>, Unknown, <class 'object'>]
```
## Classes with cycles in their MRO, and a sub-graph
@ -400,8 +401,8 @@ class Bar(Foo): ...
class Baz(Bar, BarCycle): ...
class Spam(Baz): ...
reveal_type(FooCycle.__mro__) # revealed: tuple[Literal[FooCycle], Unknown, Literal[object]]
reveal_type(BarCycle.__mro__) # revealed: tuple[Literal[BarCycle], Unknown, Literal[object]]
reveal_type(Baz.__mro__) # revealed: tuple[Literal[Baz], Unknown, Literal[object]]
reveal_type(Spam.__mro__) # revealed: tuple[Literal[Spam], Unknown, Literal[object]]
reveal_type(FooCycle.__mro__) # revealed: tuple[<class 'FooCycle'>, Unknown, <class 'object'>]
reveal_type(BarCycle.__mro__) # revealed: tuple[<class 'BarCycle'>, Unknown, <class 'object'>]
reveal_type(Baz.__mro__) # revealed: tuple[<class 'Baz'>, Unknown, <class 'object'>]
reveal_type(Spam.__mro__) # revealed: tuple[<class 'Spam'>, Unknown, <class 'object'>]
```

View file

@ -43,9 +43,9 @@ def _(flag: bool):
C = A if flag else B
if C != A:
reveal_type(C) # revealed: Literal[B]
reveal_type(C) # revealed: <class 'B'>
else:
reveal_type(C) # revealed: Literal[A]
reveal_type(C) # revealed: <class 'A'>
```
## `x != y` where `y` has multiple single-valued options

View file

@ -14,15 +14,15 @@ def _(flag: bool):
reveal_type(t) # revealed: Never
if issubclass(t, object):
reveal_type(t) # revealed: Literal[int, str]
reveal_type(t) # revealed: <class 'int'> | <class 'str'>
if issubclass(t, int):
reveal_type(t) # revealed: Literal[int]
reveal_type(t) # revealed: <class 'int'>
else:
reveal_type(t) # revealed: Literal[str]
reveal_type(t) # revealed: <class 'str'>
if issubclass(t, str):
reveal_type(t) # revealed: Literal[str]
reveal_type(t) # revealed: <class 'str'>
if issubclass(t, int):
reveal_type(t) # revealed: Never
```
@ -34,16 +34,16 @@ def _(flag1: bool, flag2: bool):
t = int if flag1 else str if flag2 else bytes
if issubclass(t, int):
reveal_type(t) # revealed: Literal[int]
reveal_type(t) # revealed: <class 'int'>
else:
reveal_type(t) # revealed: Literal[str, bytes]
reveal_type(t) # revealed: <class 'str'> | <class 'bytes'>
if issubclass(t, int):
reveal_type(t) # revealed: Literal[int]
reveal_type(t) # revealed: <class 'int'>
elif issubclass(t, str):
reveal_type(t) # revealed: Literal[str]
reveal_type(t) # revealed: <class 'str'>
else:
reveal_type(t) # revealed: Literal[bytes]
reveal_type(t) # revealed: <class 'bytes'>
```
### Multiple derived classes
@ -58,24 +58,24 @@ def _(flag1: bool, flag2: bool, flag3: bool):
t1 = Derived1 if flag1 else Derived2
if issubclass(t1, Base):
reveal_type(t1) # revealed: Literal[Derived1, Derived2]
reveal_type(t1) # revealed: <class 'Derived1'> | <class 'Derived2'>
if issubclass(t1, Derived1):
reveal_type(t1) # revealed: Literal[Derived1]
reveal_type(t1) # revealed: <class 'Derived1'>
else:
reveal_type(t1) # revealed: Literal[Derived2]
reveal_type(t1) # revealed: <class 'Derived2'>
t2 = Derived1 if flag2 else Base
if issubclass(t2, Base):
reveal_type(t2) # revealed: Literal[Derived1, Base]
reveal_type(t2) # revealed: <class 'Derived1'> | <class 'Base'>
t3 = Derived1 if flag3 else Unrelated
if issubclass(t3, Base):
reveal_type(t3) # revealed: Literal[Derived1]
reveal_type(t3) # revealed: <class 'Derived1'>
else:
reveal_type(t3) # revealed: Literal[Unrelated]
reveal_type(t3) # revealed: <class 'Unrelated'>
```
### Narrowing for non-literals
@ -109,10 +109,10 @@ def _(flag: bool):
t = int if flag else NoneType
if issubclass(t, NoneType):
reveal_type(t) # revealed: Literal[NoneType]
reveal_type(t) # revealed: <class 'NoneType'>
if issubclass(t, type(None)):
reveal_type(t) # revealed: Literal[NoneType]
reveal_type(t) # revealed: <class 'NoneType'>
```
## `classinfo` contains multiple types
@ -126,9 +126,9 @@ def _(flag1: bool, flag2: bool):
t = int if flag1 else str if flag2 else bytes
if issubclass(t, (int, (Unrelated, (bytes,)))):
reveal_type(t) # revealed: Literal[int, bytes]
reveal_type(t) # revealed: <class 'int'> | <class 'bytes'>
else:
reveal_type(t) # revealed: Literal[str]
reveal_type(t) # revealed: <class 'str'>
```
## Special cases
@ -175,7 +175,7 @@ def flag() -> bool:
t = int if flag() else str
if issubclass(t, int):
reveal_type(t) # revealed: Literal[int, str]
reveal_type(t) # revealed: <class 'int'> | <class 'str'>
```
### Do support narrowing if `issubclass` is aliased
@ -188,7 +188,7 @@ def flag() -> bool:
t = int if flag() else str
if issubclass_alias(t, int):
reveal_type(t) # revealed: Literal[int]
reveal_type(t) # revealed: <class 'int'>
```
### Do support narrowing if `issubclass` is imported
@ -201,7 +201,7 @@ def flag() -> bool:
t = int if flag() else str
if imported_issubclass(t, int):
reveal_type(t) # revealed: Literal[int]
reveal_type(t) # revealed: <class 'int'>
```
### Do not narrow if second argument is not a proper `classinfo` argument
@ -217,17 +217,17 @@ t = int if flag() else str
# TODO: this should cause us to emit a diagnostic during
# type checking
if issubclass(t, "str"):
reveal_type(t) # revealed: Literal[int, str]
reveal_type(t) # revealed: <class 'int'> | <class 'str'>
# TODO: this should cause us to emit a diagnostic during
# type checking
if issubclass(t, (bytes, "str")):
reveal_type(t) # revealed: Literal[int, str]
reveal_type(t) # revealed: <class 'int'> | <class 'str'>
# TODO: this should cause us to emit a diagnostic during
# type checking
if issubclass(t, Any):
reveal_type(t) # revealed: Literal[int, str]
reveal_type(t) # revealed: <class 'int'> | <class 'str'>
```
### Do not narrow if there are keyword arguments
@ -240,7 +240,7 @@ t = int if flag() else str
# error: [unknown-argument]
if issubclass(t, int, foo="bar"):
reveal_type(t) # revealed: Literal[int, str]
reveal_type(t) # revealed: <class 'int'> | <class 'str'>
```
### `type[]` types are narrowed as well as class-literal types

View file

@ -108,12 +108,12 @@ def flag() -> bool:
return True
x = int if flag() else str
reveal_type(x) # revealed: Literal[int, str]
reveal_type(x) # revealed: <class 'int'> | <class 'str'>
if x:
reveal_type(x) # revealed: (Literal[int] & ~AlwaysFalsy) | (Literal[str] & ~AlwaysFalsy)
reveal_type(x) # revealed: (<class 'int'> & ~AlwaysFalsy) | (<class 'str'> & ~AlwaysFalsy)
else:
reveal_type(x) # revealed: (Literal[int] & ~AlwaysTruthy) | (Literal[str] & ~AlwaysTruthy)
reveal_type(x) # revealed: (<class 'int'> & ~AlwaysTruthy) | (<class 'str'> & ~AlwaysTruthy)
```
## Determined Truthiness
@ -276,12 +276,12 @@ def _(
reveal_type(d) # revealed: type[DeferredClass] & ~AlwaysFalsy
tf = TruthyClass if flag else FalsyClass
reveal_type(tf) # revealed: Literal[TruthyClass, FalsyClass]
reveal_type(tf) # revealed: <class 'TruthyClass'> | <class 'FalsyClass'>
if tf:
reveal_type(tf) # revealed: Literal[TruthyClass]
reveal_type(tf) # revealed: <class 'TruthyClass'>
else:
reveal_type(tf) # revealed: Literal[FalsyClass]
reveal_type(tf) # revealed: <class 'FalsyClass'>
```
## Narrowing in chained boolean expressions

View file

@ -150,7 +150,7 @@ def _(x: Base):
```py
def _(x: object):
if (y := type(x)) is bool:
reveal_type(y) # revealed: Literal[bool]
reveal_type(y) # revealed: <class 'bool'>
if (type(y := x)) is bool:
reveal_type(y) # revealed: bool
```

View file

@ -28,7 +28,7 @@ from typing import Protocol
class MyProtocol(Protocol): ...
reveal_type(MyProtocol.__mro__) # revealed: tuple[Literal[MyProtocol], typing.Protocol, typing.Generic, Literal[object]]
reveal_type(MyProtocol.__mro__) # revealed: tuple[<class 'MyProtocol'>, typing.Protocol, typing.Generic, <class 'object'>]
```
Just like for any other class base, it is an error for `Protocol` to appear multiple times in a
@ -37,7 +37,7 @@ class's bases:
```py
class Foo(Protocol, Protocol): ... # error: [inconsistent-mro]
reveal_type(Foo.__mro__) # revealed: tuple[Literal[Foo], Unknown, Literal[object]]
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
```
Protocols can also be generic, either by including `Generic[]` in the bases list, subscripting
@ -71,7 +71,7 @@ class DuplicateBases(Protocol, Protocol[T]):
x: T
# TODO: should not have `Protocol` multiple times
# revealed: tuple[Literal[DuplicateBases], typing.Protocol, @Todo(`Protocol[]` subscript), typing.Generic, Literal[object]]
# revealed: tuple[<class 'DuplicateBases'>, typing.Protocol, @Todo(`Protocol[]` subscript), typing.Generic, <class 'object'>]
reveal_type(DuplicateBases.__mro__)
```
@ -107,7 +107,7 @@ it is not sufficient for it to have `Protocol` in its MRO.
```py
class SubclassOfMyProtocol(MyProtocol): ...
# revealed: tuple[Literal[SubclassOfMyProtocol], Literal[MyProtocol], typing.Protocol, typing.Generic, Literal[object]]
# revealed: tuple[<class 'SubclassOfMyProtocol'>, <class 'MyProtocol'>, typing.Protocol, typing.Generic, <class 'object'>]
reveal_type(SubclassOfMyProtocol.__mro__)
reveal_type(is_protocol(SubclassOfMyProtocol)) # revealed: Literal[False]
@ -126,7 +126,7 @@ class OtherProtocol(Protocol):
class ComplexInheritance(SubProtocol, OtherProtocol, Protocol): ...
# revealed: tuple[Literal[ComplexInheritance], Literal[SubProtocol], Literal[MyProtocol], Literal[OtherProtocol], typing.Protocol, typing.Generic, Literal[object]]
# revealed: tuple[<class 'ComplexInheritance'>, <class 'SubProtocol'>, <class 'MyProtocol'>, <class 'OtherProtocol'>, typing.Protocol, typing.Generic, <class 'object'>]
reveal_type(ComplexInheritance.__mro__)
reveal_type(is_protocol(ComplexInheritance)) # revealed: Literal[True]
@ -139,13 +139,13 @@ or `TypeError` is raised at runtime when the class is created.
# error: [invalid-protocol] "Protocol class `Invalid` cannot inherit from non-protocol class `NotAProtocol`"
class Invalid(NotAProtocol, Protocol): ...
# revealed: tuple[Literal[Invalid], Literal[NotAProtocol], typing.Protocol, typing.Generic, Literal[object]]
# revealed: tuple[<class 'Invalid'>, <class 'NotAProtocol'>, typing.Protocol, typing.Generic, <class 'object'>]
reveal_type(Invalid.__mro__)
# error: [invalid-protocol] "Protocol class `AlsoInvalid` cannot inherit from non-protocol class `NotAProtocol`"
class AlsoInvalid(MyProtocol, OtherProtocol, NotAProtocol, Protocol): ...
# revealed: tuple[Literal[AlsoInvalid], Literal[MyProtocol], Literal[OtherProtocol], Literal[NotAProtocol], typing.Protocol, typing.Generic, Literal[object]]
# revealed: tuple[<class 'AlsoInvalid'>, <class 'MyProtocol'>, <class 'OtherProtocol'>, <class 'NotAProtocol'>, typing.Protocol, typing.Generic, <class 'object'>]
reveal_type(AlsoInvalid.__mro__)
```
@ -163,7 +163,7 @@ T = TypeVar("T")
# type checkers.
class Fine(Protocol, object): ...
reveal_type(Fine.__mro__) # revealed: tuple[Literal[Fine], typing.Protocol, typing.Generic, Literal[object]]
reveal_type(Fine.__mro__) # revealed: tuple[<class 'Fine'>, typing.Protocol, typing.Generic, <class 'object'>]
class StillFine(Protocol, Generic[T], object): ...
class EvenThis[T](Protocol, object): ...
@ -177,7 +177,7 @@ And multiple inheritance from a mix of protocol and non-protocol classes is fine
```py
class FineAndDandy(MyProtocol, OtherProtocol, NotAProtocol): ...
# revealed: tuple[Literal[FineAndDandy], Literal[MyProtocol], Literal[OtherProtocol], typing.Protocol, typing.Generic, Literal[NotAProtocol], Literal[object]]
# revealed: tuple[<class 'FineAndDandy'>, <class 'MyProtocol'>, <class 'OtherProtocol'>, typing.Protocol, typing.Generic, <class 'NotAProtocol'>, <class 'object'>]
reveal_type(FineAndDandy.__mro__)
```

View file

@ -56,7 +56,7 @@ reveal_type(typing.__init__) # revealed: bound method ModuleType.__init__(name:
# These come from `builtins.object`, not `types.ModuleType`:
reveal_type(typing.__eq__) # revealed: bound method ModuleType.__eq__(value: object, /) -> bool
reveal_type(typing.__class__) # revealed: Literal[ModuleType]
reveal_type(typing.__class__) # revealed: <class 'ModuleType'>
reveal_type(typing.__dict__) # revealed: dict[str, Any]
```

View file

@ -16,7 +16,7 @@ class C:
if flag:
x = 2
# error: [possibly-unbound-attribute] "Attribute `x` on type `Literal[C]` is possibly unbound"
# error: [possibly-unbound-attribute] "Attribute `x` on type `<class 'C'>` is possibly unbound"
reveal_type(C.x) # revealed: Unknown | Literal[2]
reveal_type(C.y) # revealed: Unknown | Literal[1]
```

View file

@ -26,7 +26,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/attribute_as
# Diagnostics
```
warning: lint:possibly-unbound-attribute: Attribute `attr` on type `Literal[C]` is possibly unbound
warning: lint:possibly-unbound-attribute: Attribute `attr` on type `<class 'C'>` is possibly unbound
--> src/mdtest_snippet.py:6:5
|
4 | attr: int = 0

View file

@ -41,7 +41,7 @@ info: `lint:invalid-assignment` is enabled by default
```
```
error: lint:invalid-attribute-access: Cannot assign to instance attribute `attr` from the class object `Literal[C]`
error: lint:invalid-attribute-access: Cannot assign to instance attribute `attr` from the class object `<class 'C'>`
--> src/mdtest_snippet.py:9:1
|
7 | instance.attr = "wrong" # error: [invalid-assignment]

View file

@ -37,7 +37,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/attribute_as
# Diagnostics
```
error: lint:invalid-assignment: Object of type `Literal[1]` is not assignable to attribute `attr` on type `Literal[C1, C1]`
error: lint:invalid-assignment: Object of type `Literal[1]` is not assignable to attribute `attr` on type `<class 'C1'> | <class 'C1'>`
--> src/mdtest_snippet.py:11:5
|
10 | # TODO: The error message here could be improved to explain why the assignment fails.

View file

@ -23,7 +23,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/attribute_as
# Diagnostics
```
error: lint:unresolved-attribute: Unresolved attribute `non_existent` on type `Literal[C]`.
error: lint:unresolved-attribute: Unresolved attribute `non_existent` on type `<class 'C'>`.
--> src/mdtest_snippet.py:3:1
|
1 | class C: ...

View file

@ -15,8 +15,8 @@ class Foo[T]: ...
class Bar(Foo[Bar]): ...
reveal_type(Bar) # revealed: Literal[Bar]
reveal_type(Bar.__mro__) # revealed: tuple[Literal[Bar], Literal[Foo[Bar]], Literal[object]]
reveal_type(Bar) # revealed: <class 'Bar'>
reveal_type(Bar.__mro__) # revealed: tuple[<class 'Bar'>, <class 'Foo[Bar]'>, <class 'object'>]
```
## Access to attributes declared in stubs

View file

@ -5,7 +5,8 @@
```py
class NotSubscriptable: ...
a = NotSubscriptable[0] # error: "Cannot subscript object of type `Literal[NotSubscriptable]` with no `__class_getitem__` method"
# error: "Cannot subscript object of type `<class 'NotSubscriptable'>` with no `__class_getitem__` method"
a = NotSubscriptable[0]
```
## Class getitem
@ -47,7 +48,7 @@ def _(flag: bool):
x = A if flag else B
reveal_type(x) # revealed: Literal[A, B]
reveal_type(x) # revealed: <class 'A'> | <class 'B'>
reveal_type(x[0]) # revealed: str | int
```
@ -62,7 +63,7 @@ def _(flag: bool):
else:
class Spam: ...
# error: [call-possibly-unbound-method] "Method `__class_getitem__` of type `Literal[Spam, Spam]` is possibly unbound"
# error: [call-possibly-unbound-method] "Method `__class_getitem__` of type `<class 'Spam'> | <class 'Spam'>` is possibly unbound"
# revealed: str
reveal_type(Spam[42])
```
@ -79,7 +80,7 @@ def _(flag: bool):
else:
Eggs = 1
a = Eggs[42] # error: "Cannot subscript object of type `Literal[Eggs] | Literal[1]` with no `__getitem__` method"
a = Eggs[42] # error: "Cannot subscript object of type `<class 'Eggs'> | Literal[1]` with no `__getitem__` method"
# TODO: should _probably_ emit `str | Unknown`
reveal_type(a) # revealed: Unknown

View file

@ -85,7 +85,7 @@ class A(tuple[int, str]): ...
# Runtime value: `(A, tuple, object)`
# TODO: Generics
reveal_type(A.__mro__) # revealed: tuple[Literal[A], @Todo(GenericAlias instance), Literal[object]]
reveal_type(A.__mro__) # revealed: tuple[<class 'A'>, @Todo(GenericAlias instance), <class 'object'>]
```
## `typing.Tuple`
@ -116,6 +116,6 @@ from typing import Tuple
class C(Tuple): ...
# TODO: generic protocols
# revealed: tuple[Literal[C], Literal[tuple], Literal[Sequence], Literal[Reversible], Literal[Collection], Literal[Iterable], Literal[Container], @Todo(`Protocol[]` subscript), typing.Generic, Literal[object]]
# revealed: tuple[<class 'C'>, <class 'tuple'>, <class 'Sequence'>, <class 'Reversible'>, <class 'Collection'>, <class 'Iterable'>, <class 'Container'>, @Todo(`Protocol[]` subscript), typing.Generic, <class 'object'>]
reveal_type(C.__mro__)
```

View file

@ -105,7 +105,7 @@ def explicit_unknown(x: Unknown, y: tuple[str, Unknown], z: Unknown = 1) -> None
```py
class C(Unknown): ...
# revealed: tuple[Literal[C], Unknown, Literal[object]]
# revealed: tuple[<class 'C'>, Unknown, <class 'object'>]
reveal_type(C.__mro__)
# error: "Special form `ty_extensions.Unknown` expected no type parameter"

View file

@ -147,8 +147,8 @@ _: type[A, B]
```py
class Foo(type[int]): ...
# TODO: should be `tuple[Literal[Foo], Literal[type], Literal[object]]
reveal_type(Foo.__mro__) # revealed: tuple[Literal[Foo], @Todo(GenericAlias instance), Literal[object]]
# TODO: should be `tuple[<class 'Foo'>, <class 'type'>, <class 'object'>]
reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, @Todo(GenericAlias instance), <class 'object'>]
```
## `@final` classes
@ -169,6 +169,6 @@ from typing import final
class Foo: ...
def _(x: type[Foo], y: type[EllipsisType]):
reveal_type(x) # revealed: Literal[Foo]
reveal_type(y) # revealed: Literal[EllipsisType]
reveal_type(x) # revealed: <class 'Foo'>
reveal_type(y) # revealed: <class 'EllipsisType'>
```

View file

@ -28,5 +28,5 @@ class C(Type): ...
# Runtime value: `(C, type, typing.Generic, object)`
# TODO: Add `Generic` to the MRO
reveal_type(C.__mro__) # revealed: tuple[Literal[C], Literal[type], Literal[object]]
reveal_type(C.__mro__) # revealed: tuple[<class 'C'>, <class 'type'>, <class 'object'>]
```

View file

@ -52,25 +52,25 @@ class Yes:
class Sub(Yes): ...
class No: ...
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[Yes]`"
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `<class 'Yes'>`"
reveal_type(+Yes) # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[Yes]`"
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `<class 'Yes'>`"
reveal_type(-Yes) # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[Yes]`"
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `<class 'Yes'>`"
reveal_type(~Yes) # revealed: Unknown
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[Sub]`"
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `<class 'Sub'>`"
reveal_type(+Sub) # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[Sub]`"
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `<class 'Sub'>`"
reveal_type(-Sub) # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[Sub]`"
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `<class 'Sub'>`"
reveal_type(~Sub) # revealed: Unknown
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[No]`"
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `<class 'No'>`"
reveal_type(+No) # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[No]`"
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `<class 'No'>`"
reveal_type(-No) # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[No]`"
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `<class 'No'>`"
reveal_type(~No) # revealed: Unknown
```
@ -160,10 +160,10 @@ reveal_type(+Sub) # revealed: bool
reveal_type(-Sub) # revealed: str
reveal_type(~Sub) # revealed: int
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[No]`"
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `<class 'No'>`"
reveal_type(+No) # revealed: Unknown
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[No]`"
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `<class 'No'>`"
reveal_type(-No) # revealed: Unknown
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[No]`"
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `<class 'No'>`"
reveal_type(~No) # revealed: Unknown
```

View file

@ -42,9 +42,7 @@ impl Display for DisplayType<'_> {
Type::IntLiteral(_)
| Type::BooleanLiteral(_)
| Type::StringLiteral(_)
| Type::BytesLiteral(_)
| Type::ClassLiteral(_)
| Type::GenericAlias(_) => {
| Type::BytesLiteral(_) => {
write!(f, "Literal[{representation}]")
}
_ => representation.fmt(f),
@ -102,9 +100,10 @@ impl Display for DisplayRepresentation<'_> {
Type::ModuleLiteral(module) => {
write!(f, "<module '{}'>", module.module(self.db).name())
}
// TODO functions and classes should display using a fully qualified name
Type::ClassLiteral(class) => f.write_str(class.name(self.db)),
Type::GenericAlias(generic) => generic.display(self.db).fmt(f),
Type::ClassLiteral(class) => {
write!(f, "<class '{}'>", class.name(self.db))
}
Type::GenericAlias(generic) => write!(f, "<class '{}'>", generic.display(self.db)),
Type::SubclassOf(subclass_of_ty) => match subclass_of_ty.subclass_of() {
// Only show the bare class name here; ClassBase::display would render this as
// type[<class 'Foo'>] instead of type[Foo].
@ -605,7 +604,6 @@ impl Display for DisplayLiteralGroup<'_> {
/// For example, `Literal[1] | Literal[2] | Literal["s"]` is displayed as `"Literal[1, 2, "s"]"`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum CondensedDisplayTypeKind {
Class,
LiteralExpression,
}
@ -614,7 +612,6 @@ impl TryFrom<Type<'_>> for CondensedDisplayTypeKind {
fn try_from(value: Type<'_>) -> Result<Self, Self::Error> {
match value {
Type::ClassLiteral(_) => Ok(Self::Class),
Type::IntLiteral(_)
| Type::StringLiteral(_)
| Type::BytesLiteral(_)