@@ -14,9 +14,16 @@ common usage.
1414
1515### Explicit Super Object
1616
17+ <!-- snapshot-diagnostics -->
18+
1719` super(pivot_class, owner) ` performs attribute lookup along the MRO, starting immediately after the
1820specified pivot class.
1921
22+ ``` toml
23+ [environment ]
24+ python-version = " 3.12"
25+ ```
26+
2027``` py
2128class A :
2229 def a (self ): ...
@@ -34,34 +41,96 @@ reveal_type(C.__mro__) # revealed: tuple[<class 'C'>, <class 'B'>, <class 'A'>,
3441
3542super (C, C()).a
3643super (C, C()).b
37- # error: [unresolved-attribute] "Type `<super: <class 'C'>, C>` has no attribute `c`"
38- super (C, C()).c
44+ super (C, C()).c # error: [unresolved-attribute]
3945
4046super (B, C()).a
41- # error: [unresolved-attribute] "Type `<super: <class 'B'>, C>` has no attribute `b`"
42- super (B, C()).b
43- # error: [unresolved-attribute] "Type `<super: <class 'B'>, C>` has no attribute `c`"
44- super (B, C()).c
45-
46- # error: [unresolved-attribute] "Type `<super: <class 'A'>, C>` has no attribute `a`"
47- super (A, C()).a
48- # error: [unresolved-attribute] "Type `<super: <class 'A'>, C>` has no attribute `b`"
49- super (A, C()).b
50- # error: [unresolved-attribute] "Type `<super: <class 'A'>, C>` has no attribute `c`"
51- super (A, C()).c
47+ super (B, C()).b # error: [unresolved-attribute]
48+ super (B, C()).c # error: [unresolved-attribute]
49+
50+ super (A, C()).a # error: [unresolved-attribute]
51+ super (A, C()).b # error: [unresolved-attribute]
52+ super (A, C()).c # error: [unresolved-attribute]
5253
5354reveal_type(super (C, C()).a) # revealed: bound method C.a() -> Unknown
5455reveal_type(super (C, C()).b) # revealed: bound method C.b() -> Unknown
5556reveal_type(super (C, C()).aa) # revealed: int
5657reveal_type(super (C, C()).bb) # revealed: int
5758```
5859
60+ Examples of explicit ` super() ` with unusual types. We allow almost any type to be passed as the
61+ second argument to ` super() ` -- the only exceptions are "pure abstract" types such as ` Callable ` and
62+ synthesized ` Protocol ` s that cannot be upcast to, or interpreted as, a non-` object ` nominal type.
63+
64+ ``` py
65+ import types
66+ from typing_extensions import Callable, TypeIs, Literal, TypedDict
67+
68+ def f (): ...
69+
70+ class Foo[T]:
71+ def method (self ): ...
72+ @ property
73+ def some_property (self ): ...
74+
75+ type Alias = int
76+
77+ class SomeTypedDict (TypedDict ):
78+ x: int
79+ y: bytes
80+
81+ # revealed: <super: <class 'object'>, FunctionType>
82+ reveal_type(super (object , f))
83+ # revealed: <super: <class 'object'>, WrapperDescriptorType>
84+ reveal_type(super (object , types.FunctionType.__get__ ))
85+ # revealed: <super: <class 'object'>, GenericAlias>
86+ reveal_type(super (object , Foo[int ]))
87+ # revealed: <super: <class 'object'>, _SpecialForm>
88+ reveal_type(super (object , Literal))
89+ # revealed: <super: <class 'object'>, TypeAliasType>
90+ reveal_type(super (object , Alias))
91+ # revealed: <super: <class 'object'>, MethodType>
92+ reveal_type(super (object , Foo().method))
93+ # revealed: <super: <class 'object'>, property>
94+ reveal_type(super (object , Foo.some_property))
95+
96+ def g (x : object ) -> TypeIs[list[object ]]:
97+ return isinstance (x, list )
98+
99+ def _ (x : object , y : SomeTypedDict, z : Callable[[int , str ], bool ]):
100+ if hasattr (x, " bar" ):
101+ # revealed: <Protocol with members 'bar'>
102+ reveal_type(x)
103+ # error: [invalid-super-argument]
104+ # revealed: Unknown
105+ reveal_type(super (object , x))
106+
107+ # error: [invalid-super-argument]
108+ # revealed: Unknown
109+ reveal_type(super (object , z))
110+
111+ is_list = g(x)
112+ # revealed: TypeIs[list[object] @ x]
113+ reveal_type(is_list)
114+ # revealed: <super: <class 'object'>, bool>
115+ reveal_type(super (object , is_list))
116+
117+ # revealed: <super: <class 'object'>, dict[Literal["x", "y"], int | bytes]>
118+ reveal_type(super (object , y))
119+ ```
120+
59121### Implicit Super Object
60122
123+ <!-- snapshot-diagnostics -->
124+
61125The implicit form ` super() ` is same as ` super(__class__, <first argument>) ` . The ` __class__ ` refers
62126to the class that contains the function where ` super() ` is used. The first argument refers to the
63127current method’s first parameter (typically ` self ` or ` cls ` ).
64128
129+ ``` toml
130+ [environment ]
131+ python-version = " 3.12"
132+ ```
133+
65134``` py
66135from __future__ import annotations
67136
@@ -74,6 +143,7 @@ class B(A):
74143 def __init__ (self , a : int ):
75144 # TODO : Once `Self` is supported, this should be `<super: <class 'B'>, B>`
76145 reveal_type(super ()) # revealed: <super: <class 'B'>, Unknown>
146+ reveal_type(super (object , super ())) # revealed: <super: <class 'object'>, super>
77147 super ().__init__ (a)
78148
79149 @ classmethod
@@ -86,6 +156,123 @@ super(B, B(42)).__init__(42)
86156super (B, B).f()
87157```
88158
159+ Some examples with unusual annotations for ` self ` or ` cls ` :
160+
161+ ``` py
162+ import enum
163+ from typing import Any, Self, Never, Protocol, Callable
164+ from ty_extensions import Intersection
165+
166+ class BuilderMeta (type ):
167+ def __new__ (
168+ cls : type[Any],
169+ name : str ,
170+ bases : tuple[type , ... ],
171+ dct : dict[str , Any],
172+ ) -> BuilderMeta:
173+ # revealed: <super: <class 'BuilderMeta'>, Any>
174+ s = reveal_type(super ())
175+ # revealed: Any
176+ return reveal_type(s.__new__ (cls , name, bases, dct))
177+
178+ class BuilderMeta2 (type ):
179+ def __new__ (
180+ cls : type[BuilderMeta2],
181+ name : str ,
182+ bases : tuple[type , ... ],
183+ dct : dict[str , Any],
184+ ) -> BuilderMeta2:
185+ # revealed: <super: <class 'BuilderMeta2'>, <class 'BuilderMeta2'>>
186+ s = reveal_type(super ())
187+ # TODO : should be `BuilderMeta2` (needs https://github.com/astral-sh/ty/issues/501)
188+ # revealed: Unknown
189+ return reveal_type(s.__new__ (cls , name, bases, dct))
190+
191+ class Foo[T]:
192+ x: T
193+
194+ def method (self : Any):
195+ reveal_type(super ()) # revealed: <super: <class 'Foo'>, Any>
196+
197+ if isinstance (self , Foo):
198+ reveal_type(super ()) # revealed: <super: <class 'Foo'>, Any>
199+
200+ def method2 (self : Foo[T]):
201+ # revealed: <super: <class 'Foo'>, Foo[T@Foo]>
202+ reveal_type(super ())
203+
204+ def method3 (self : Foo):
205+ # revealed: <super: <class 'Foo'>, Foo[Unknown]>
206+ reveal_type(super ())
207+
208+ def method4 (self : Self):
209+ # revealed: <super: <class 'Foo'>, Foo[T@Foo]>
210+ reveal_type(super ())
211+
212+ def method5[S: Foo[int ]](self : S, other: S) -> S:
213+ # revealed: <super: <class 'Foo'>, Foo[int]>
214+ reveal_type(super ())
215+ return self
216+
217+ def method6[S: (Foo[int ], Foo[str ])](self : S, other: S) -> S:
218+ # revealed: <super: <class 'Foo'>, Foo[int]> | <super: <class 'Foo'>, Foo[str]>
219+ reveal_type(super ())
220+ return self
221+
222+ def method7[S](self : S, other: S) -> S:
223+ # error: [invalid-super-argument]
224+ # revealed: Unknown
225+ reveal_type(super ())
226+ return self
227+
228+ def method8[S: int ](self : S, other: S) -> S:
229+ # error: [invalid-super-argument]
230+ # revealed: Unknown
231+ reveal_type(super ())
232+ return self
233+
234+ def method9[S: (int , str )](self : S, other: S) -> S:
235+ # error: [invalid-super-argument]
236+ # revealed: Unknown
237+ reveal_type(super ())
238+ return self
239+
240+ def method10[S: Callable[... , str ]](self : S, other: S) -> S:
241+ # error: [invalid-super-argument]
242+ # revealed: Unknown
243+ reveal_type(super ())
244+ return self
245+
246+ type Alias = Bar
247+
248+ class Bar :
249+ def method (self : Alias):
250+ # revealed: <super: <class 'Bar'>, Bar>
251+ reveal_type(super ())
252+
253+ def pls_dont_call_me (self : Never):
254+ # revealed: <super: <class 'Bar'>, Unknown>
255+ reveal_type(super ())
256+
257+ def only_call_me_on_callable_subclasses (self : Intersection[Bar, Callable[... , object ]]):
258+ # revealed: <super: <class 'Bar'>, Bar>
259+ reveal_type(super ())
260+
261+ class P (Protocol ):
262+ def method (self : P):
263+ # revealed: <super: <class 'P'>, P>
264+ reveal_type(super ())
265+
266+ class E (enum .Enum ):
267+ X = 1
268+
269+ def method (self : E):
270+ match self :
271+ case E.X:
272+ # revealed: <super: <class 'E'>, E>
273+ reveal_type(super ())
274+ ```
275+
89276### Unbound Super Object
90277
91278Calling ` super(cls) ` without a second argument returns an _ unbound super object_ . This is treated as
@@ -167,11 +354,19 @@ class A:
167354## Built-ins and Literals
168355
169356``` py
357+ from enum import Enum
358+
170359reveal_type(super (bool , True )) # revealed: <super: <class 'bool'>, bool>
171360reveal_type(super (bool , bool ())) # revealed: <super: <class 'bool'>, bool>
172361reveal_type(super (int , bool ())) # revealed: <super: <class 'int'>, bool>
173362reveal_type(super (int , 3 )) # revealed: <super: <class 'int'>, int>
174363reveal_type(super (str , " " )) # revealed: <super: <class 'str'>, str>
364+ reveal_type(super (bytes , b " " )) # revealed: <super: <class 'bytes'>, bytes>
365+
366+ class E (Enum ):
367+ X = 42
368+
369+ reveal_type(super (E, E.X)) # revealed: <super: <class 'E'>, E>
175370```
176371
177372## Descriptor Behavior with Super
@@ -342,7 +537,7 @@ def f(x: int):
342537 # error: [invalid-super-argument] "`typing.TypeAliasType` is not a valid class"
343538 super (IntAlias, 0 )
344539
345- # error: [invalid-super-argument] "`Literal[""] ` is not an instance or subclass of `<class 'int'>` in `super(<class 'int'>, Literal[""] )` call"
540+ # error: [invalid-super-argument] "`str ` is not an instance or subclass of `<class 'int'>` in `super(<class 'int'>, str )` call"
346541# revealed: Unknown
347542reveal_type(super (int , str ()))
348543
0 commit comments