@@ -173,7 +173,7 @@ if hasattr(DoesNotExist, "__mro__"):
173
173
if not isinstance (DoesNotExist, type ):
174
174
reveal_type(DoesNotExist) # revealed: Unknown & ~type
175
175
176
- class Foo (DoesNotExist ): ... # error: [invalid -base]
176
+ class Foo (DoesNotExist ): ... # error: [unsupported -base]
177
177
reveal_type(Foo.__mro__ ) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
178
178
```
179
179
@@ -232,11 +232,15 @@ reveal_type(AA.__mro__) # revealed: tuple[<class 'AA'>, <class 'Z'>, Unknown, <
232
232
233
233
## ` __bases__ ` includes a ` Union `
234
234
235
+ <!-- snapshot-diagnostics -->
236
+
235
237
We don't support union types in a class's bases; a base must resolve to a single ` ClassType ` . If we
236
238
find a union type in a class's bases, we infer the class's ` __mro__ ` as being
237
239
` [<class>, Unknown, object] ` , the same as for MROs that cause errors at runtime.
238
240
239
241
``` py
242
+ from typing_extensions import reveal_type
243
+
240
244
def returns_bool () -> bool :
241
245
return True
242
246
@@ -250,7 +254,7 @@ else:
250
254
251
255
reveal_type(x) # revealed: <class 'A'> | <class 'B'>
252
256
253
- # error: 11 [invalid -base] "Invalid class base with type `<class 'A'> | <class 'B'>` (all bases must be a class, `Any`, `Unknown` or `Todo`) "
257
+ # error: 11 [unsupported -base] "Unsupported class base with type `<class 'A'> | <class 'B'>`"
254
258
class Foo (x ): ...
255
259
256
260
reveal_type(Foo.__mro__ ) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
@@ -259,8 +263,8 @@ reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'obje
259
263
## ` __bases__ ` is a union of a dynamic type and valid bases
260
264
261
265
If a dynamic type such as ` Any ` or ` Unknown ` is one of the elements in the union, and all other
262
- types * would be* valid class bases, we do not emit an ` invalid-base ` diagnostic and use the dynamic
263
- type as a base to prevent further downstream errors.
266
+ types * would be* valid class bases, we do not emit an ` invalid-base ` or ` unsupported-base `
267
+ diagnostic, and we use the dynamic type as a base to prevent further downstream errors.
264
268
265
269
``` py
266
270
from typing import Any
@@ -299,8 +303,8 @@ else:
299
303
reveal_type(x) # revealed: <class 'A'> | <class 'B'>
300
304
reveal_type(y) # revealed: <class 'C'> | <class 'D'>
301
305
302
- # error: 11 [invalid -base] "Invalid class base with type `<class 'A'> | <class 'B'>` (all bases must be a class, `Any`, `Unknown` or `Todo`) "
303
- # error: 14 [invalid -base] "Invalid class base with type `<class 'C'> | <class 'D'>` (all bases must be a class, `Any`, `Unknown` or `Todo`) "
306
+ # error: 11 [unsupported -base] "Unsupported class base with type `<class 'A'> | <class 'B'>`"
307
+ # error: 14 [unsupported -base] "Unsupported class base with type `<class 'C'> | <class 'D'>`"
304
308
class Foo (x , y ): ...
305
309
306
310
reveal_type(Foo.__mro__ ) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
@@ -321,7 +325,7 @@ if returns_bool():
321
325
else :
322
326
foo = object
323
327
324
- # error: 21 [invalid -base] "Invalid class base with type `<class 'Y'> | <class 'object'>` (all bases must be a class, `Any`, `Unknown` or `Todo`) "
328
+ # error: 21 [unsupported -base] "Unsupported class base with type `<class 'Y'> | <class 'object'>`"
325
329
class PossibleError (foo , X ): ...
326
330
327
331
reveal_type(PossibleError.__mro__ ) # revealed: tuple[<class 'PossibleError'>, Unknown, <class 'object'>]
@@ -339,12 +343,47 @@ else:
339
343
# revealed: tuple[<class 'B'>, <class 'X'>, <class 'Y'>, <class 'O'>, <class 'object'>] | tuple[<class 'B'>, <class 'Y'>, <class 'X'>, <class 'O'>, <class 'object'>]
340
344
reveal_type(B.__mro__ )
341
345
342
- # error: 12 [invalid -base] "Invalid class base with type `<class 'B'> | <class 'B'>` (all bases must be a class, `Any`, `Unknown` or `Todo`) "
346
+ # error: 12 [unsupported -base] "Unsupported class base with type `<class 'B'> | <class 'B'>`"
343
347
class Z (A , B ): ...
344
348
345
349
reveal_type(Z.__mro__ ) # revealed: tuple[<class 'Z'>, Unknown, <class 'object'>]
346
350
```
347
351
352
+ ## ` __bases__ ` lists that include objects that are not instances of ` type `
353
+
354
+ <!-- snapshot-diagnostics -->
355
+
356
+ ``` py
357
+ class Foo (2 ): ... # error: [invalid-base]
358
+ ```
359
+
360
+ A base that is not an instance of ` type ` but does have an ` __mro_entries__ ` method will not raise an
361
+ exception at runtime, so we issue ` unsupported-base ` rather than ` invalid-base ` :
362
+
363
+ ``` py
364
+ class Foo :
365
+ def __mro_entries__ (self , bases : tuple[type , ... ]) -> tuple[type , ... ]:
366
+ return ()
367
+
368
+ class Bar (Foo ()): ... # error: [unsupported-base]
369
+ ```
370
+
371
+ But for objects that have badly defined ` __mro_entries__ ` , ` invalid-base ` is emitted rather than
372
+ ` unsupported-base ` :
373
+
374
+ ``` py
375
+ class Bad1 :
376
+ def __mro_entries__ (self , bases , extra_arg ):
377
+ return ()
378
+
379
+ class Bad2 :
380
+ def __mro_entries__ (self , bases ) -> int :
381
+ return 42
382
+
383
+ class BadSub1 (Bad1 ()): ... # error: [invalid-base]
384
+ class BadSub2 (Bad2 ()): ... # error: [invalid-base]
385
+ ```
386
+
348
387
## ` __bases__ ` lists with duplicate bases
349
388
350
389
<!-- snapshot-diagnostics -->
0 commit comments