@@ -1423,6 +1423,213 @@ def f(x: Union[int, A], a: Type[A]) -> None:
1423
1423
[builtins fixtures/isinstancelist.pyi]
1424
1424
1425
1425
1426
+ [case testIssubclassUnreachable]
1427
+ from typing import Type, Sequence, Union
1428
+ x: Type[str]
1429
+ if issubclass(x, int):
1430
+ reveal_type(x) # unreachable block
1431
+
1432
+
1433
+ class X: pass
1434
+ class Y(X): pass
1435
+ class Z(X): pass
1436
+
1437
+ a: Union[Type[Y], Type[Z]]
1438
+ if issubclass(a, X):
1439
+ reveal_type(a) # E: Revealed type is 'Union[Type[__main__.Y], Type[__main__.Z]]'
1440
+ else:
1441
+ reveal_type(a) # unreachable block
1442
+
1443
+ [builtins fixtures/isinstancelist.pyi]
1444
+
1445
+
1446
+ [case testIssubclasDestructuringUnions]
1447
+ from typing import Union, List, Tuple, Dict, Type
1448
+ def f(x: Union[Type[int], Type[str], Type[List]]) -> None:
1449
+ if issubclass(x, (str, (int,))):
1450
+ reveal_type(x) # E: Revealed type is 'Union[Type[builtins.int], Type[builtins.str]]'
1451
+ reveal_type(x()) # E: Revealed type is 'Union[builtins.int, builtins.str]'
1452
+ x()[1] # E: Value of type "Union[int, str]" is not indexable
1453
+ else:
1454
+ reveal_type(x) # E: Revealed type is 'Type[builtins.list]'
1455
+ reveal_type(x()) # E: Revealed type is 'builtins.list[<uninhabited>]'
1456
+ x()[1]
1457
+ reveal_type(x) # E: Revealed type is 'Union[Type[builtins.int], Type[builtins.str], Type[builtins.list]]'
1458
+ reveal_type(x()) # E: Revealed type is 'Union[builtins.int, builtins.str, builtins.list[<uninhabited>]]'
1459
+ if issubclass(x, (str, (list,))):
1460
+ reveal_type(x) # E: Revealed type is 'Union[Type[builtins.str], Type[builtins.list[Any]]]'
1461
+ reveal_type(x()) # E: Revealed type is 'Union[builtins.str, builtins.list[<uninhabited>]]'
1462
+ x()[1]
1463
+ reveal_type(x) # E: Revealed type is 'Union[Type[builtins.int], Type[builtins.str], Type[builtins.list[Any]]]'
1464
+ reveal_type(x()) # E: Revealed type is 'Union[builtins.int, builtins.str, builtins.list[<uninhabited>]]'
1465
+ [builtins fixtures/isinstancelist.pyi]
1466
+
1467
+
1468
+ [case testIssubclass]
1469
+ from typing import Type, ClassVar
1470
+
1471
+ class Goblin:
1472
+ level: int
1473
+
1474
+ class GoblinAmbusher(Goblin):
1475
+ job: ClassVar[str] = 'Ranger'
1476
+
1477
+ def test_issubclass(cls: Type[Goblin]) -> None:
1478
+ if issubclass(cls, GoblinAmbusher):
1479
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.GoblinAmbusher]'
1480
+ cls.level
1481
+ cls.job
1482
+ ga = cls()
1483
+ ga.level = 15
1484
+ ga.job
1485
+ ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance
1486
+ else:
1487
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.Goblin]'
1488
+ cls.level
1489
+ cls.job # E: Type[Goblin] has no attribute "job"
1490
+ g = cls()
1491
+ g.level = 15
1492
+ g.job # E: "Goblin" has no attribute "job"
1493
+
1494
+
1495
+ [builtins fixtures/isinstancelist.pyi]
1496
+
1497
+
1498
+ [case testIssubclassDeepHierarchy]
1499
+ from typing import Type, ClassVar
1500
+
1501
+ class Mob:
1502
+ pass
1503
+
1504
+ class Goblin(Mob):
1505
+ level: int
1506
+
1507
+ class GoblinAmbusher(Goblin):
1508
+ job: ClassVar[str] = 'Ranger'
1509
+
1510
+ def test_issubclass(cls: Type[Mob]) -> None:
1511
+ if issubclass(cls, Goblin):
1512
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.Goblin]'
1513
+ cls.level
1514
+ cls.job # E: Type[Goblin] has no attribute "job"
1515
+ g = cls()
1516
+ g.level = 15
1517
+ g.job # E: "Goblin" has no attribute "job"
1518
+ if issubclass(cls, GoblinAmbusher):
1519
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.GoblinAmbusher]'
1520
+ cls.level
1521
+ cls.job
1522
+ g = cls()
1523
+ g.level = 15
1524
+ g.job
1525
+ g.job = 'Warrior' # E: Cannot assign to class variable "job" via instance
1526
+ else:
1527
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.Mob]'
1528
+ cls.job # E: Type[Mob] has no attribute "job"
1529
+ cls.level # E: Type[Mob] has no attribute "level"
1530
+ m = cls()
1531
+ m.level = 15 # E: "Mob" has no attribute "level"
1532
+ m.job # E: "Mob" has no attribute "job"
1533
+ if issubclass(cls, GoblinAmbusher):
1534
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.GoblinAmbusher]'
1535
+ cls.job
1536
+ cls.level
1537
+ ga = cls()
1538
+ ga.level = 15
1539
+ ga.job
1540
+ ga.job = 'Warrior' # E: Cannot assign to class variable "job" via instance
1541
+
1542
+ if issubclass(cls, GoblinAmbusher):
1543
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.GoblinAmbusher]'
1544
+ cls.level
1545
+ cls.job
1546
+ ga = cls()
1547
+ ga.level = 15
1548
+ ga.job
1549
+ ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance
1550
+
1551
+ [builtins fixtures/isinstancelist.pyi]
1552
+
1553
+
1554
+ [case testIssubclassTuple]
1555
+ from typing import Type, ClassVar
1556
+
1557
+ class Mob:
1558
+ pass
1559
+
1560
+ class Goblin(Mob):
1561
+ level: int
1562
+
1563
+ class GoblinAmbusher(Goblin):
1564
+ job: ClassVar[str] = 'Ranger'
1565
+
1566
+ class GoblinDigger(Goblin):
1567
+ job: ClassVar[str] = 'Thief'
1568
+
1569
+ def test_issubclass(cls: Type[Mob]) -> None:
1570
+ if issubclass(cls, (Goblin, GoblinAmbusher)):
1571
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.Goblin]'
1572
+ cls.level
1573
+ cls.job # E: Type[Goblin] has no attribute "job"
1574
+ g = cls()
1575
+ g.level = 15
1576
+ g.job # E: "Goblin" has no attribute "job"
1577
+ if issubclass(cls, GoblinAmbusher):
1578
+ cls.level
1579
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.GoblinAmbusher]'
1580
+ cls.job
1581
+ ga = cls()
1582
+ ga.level = 15
1583
+ ga.job
1584
+ ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance
1585
+ else:
1586
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.Mob]'
1587
+ cls.job # E: Type[Mob] has no attribute "job"
1588
+ cls.level # E: Type[Mob] has no attribute "level"
1589
+ m = cls()
1590
+ m.level = 15 # E: "Mob" has no attribute "level"
1591
+ m.job # E: "Mob" has no attribute "job"
1592
+ if issubclass(cls, GoblinAmbusher):
1593
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.GoblinAmbusher]'
1594
+ cls.job
1595
+ cls.level
1596
+ ga = cls()
1597
+ ga.level = 15
1598
+ ga.job
1599
+ ga.job = "Warrior" # E: Cannot assign to class variable "job" via instance
1600
+
1601
+ if issubclass(cls, (GoblinDigger, GoblinAmbusher)):
1602
+ reveal_type(cls) # E: Revealed type is 'Union[Type[__main__.GoblinDigger], Type[__main__.GoblinAmbusher]]'
1603
+ cls.level
1604
+ cls.job
1605
+ g = cls()
1606
+ g.level = 15
1607
+ g.job
1608
+ g.job = "Warrior" # E: Cannot assign to class variable "job" via instance
1609
+
1610
+ [builtins fixtures/isinstancelist.pyi]
1611
+
1612
+
1613
+ [case testIssubclassBuiltins]
1614
+ from typing import List, Type
1615
+
1616
+ class MyList(List): pass
1617
+ class MyIntList(List[int]): pass
1618
+
1619
+ def f(cls: Type[object]) -> None:
1620
+ if issubclass(cls, MyList):
1621
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.MyList]'
1622
+ cls()[0]
1623
+ else:
1624
+ reveal_type(cls) # E: Revealed type is 'Type[builtins.object]'
1625
+ cls()[0] # E: Value of type "object" is not indexable
1626
+
1627
+ if issubclass(cls, MyIntList):
1628
+ reveal_type(cls) # E: Revealed type is 'Type[__main__.MyIntList]'
1629
+ cls()[0] + 1
1630
+
1631
+ [builtins fixtures/isinstancelist.pyi]
1632
+
1426
1633
[case testIsinstanceTypeArgs]
1427
1634
from typing import Iterable, TypeVar
1428
1635
x = 1
0 commit comments