@@ -1423,6 +1423,213 @@ def f(x: Union[int, A], a: Type[A]) -> None:
14231423[builtins fixtures/isinstancelist.pyi]
14241424
14251425
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+
14261633[case testIsinstanceTypeArgs]
14271634from typing import Iterable, TypeVar
14281635x = 1
0 commit comments