8000 Prevent generic subclasses from inheriting __extra__ · python/typing@2ef2a50 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2ef2a50

Browse files
committed
Prevent generic subclasses from inheriting __extra__
1 parent a22b68e commit 2ef2a50

File tree

2 files changed

+31
-14
lines changed

src/test_typing.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import contextlib
2+
import collections
23
import pickle
34
import re
45
import sys
@@ -1195,13 +1196,17 @@ def test_no_list_instantiation(self):
11951196
with self.assertRaises(TypeError):
11961197
typing.List[int]()
11971198

1198-
def test_list_subclass_instantiation(self):
1199+
def test_list_subclass(self):
11991200

12001201
class MyList(typing.List[int]):
12011202
pass
12021203

12031204
a = MyList()
12041205
assert isinstance(a, MyList)
1206+
assert isinstance(a, typing.Sequence)
1207+
1208+
assert issubclass(MyList, list)
1209+
assert not issubclass(list, MyList)
12051210

12061211
def test_no_dict_instantiation(self):
12071212
with self.assertRaises(TypeError):
@@ -1211,13 +1216,17 @@ def test_no_dict_instantiation(self):
12111216
with self.assertRaises(TypeError):
12121217
typing.Dict[str, int]()
12131218

1214-
def test_dict_subclass_instantiation(self):
1219+
def test_dict_subclass(self):
12151220

12161221
class MyDict(typing.Dict[str, int]):
12171222
pass
12181223

12191224
d = MyDict()
12201225
assert isinstance(d, MyDict)
1226+
assert isinstance(d, typing.MutableMapping)
1227+
< 8000 /td>1228+
assert issubclass(MyDict, dict)
1229+
assert not issubclass(dict, MyDict)
12211230

12221231
def test_no_defaultdict_instantiation(self):
12231232
with self.assertRaises(TypeError):
@@ -1227,14 +1236,17 @@ def test_no_defaultdict_instantiation(self):
12271236
with self.assertRaises(TypeError):
12281237
typing.DefaultDict[str, int]()
12291238

1230-
def test_defaultdict_subclass_instantiation(self):
1239+
def test_defaultdict_subclass(self):
12311240

12321241
class MyDefDict(typing.DefaultDict[str, int]):
12331242
pass
12341243

12351244
dd = MyDefDict()
12361245
assert isinstance(dd, MyDefDict)
12371246

1247+
assert issubclass(MyDefDict, collections.defaultdict)
1248+
assert not issubclass(collections.defaultdict, MyDefDict)
1249+
12381250
def test_no_set_instantiation(self):
12391251
with self.assertRaises(TypeError):
1240< 10000 code>1252
typing.Set()
@@ -1315,6 +1327,13 @@ def __len__(self):
13151327
assert len(MMB[str, str]()) == 0
13161328
assert len(MMB[KT, VT]()) == 0
13171329

1330+
assert not issubclass(dict, MMA)
1331+
assert not issubclass(dict, MMB)
1332+
1333+
assert issubclass(MMA, typing.Mapping)
1334+
assert issubclass(MMB, typing.Mapping)
1335+
assert issubclass(MMC, typing.Mapping)
1336+
13181337

13191338
class OtherABCTests(TestCase):
13201339

src/typing.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -894,8 +894,6 @@ def _next_in_mro(cls):
894894
class GenericMeta(TypingMeta, abc.ABCMeta):
895895
"""Metaclass for generic types."""
896896

897-
__extra__ = None
898-
899897
def __new__(cls, name, bases, namespace,
900898
tvars=None, args=None, origin=None, extra=None):
901899
self = super().__new__(cls, name, bases, namespace, _root=True)
@@ -943,10 +941,7 @@ def __new__(cls, name, bases, namespace,
943941
self.__parameters__ = tvars
944942
self.__args__ = args
945943
self.__origin__ = origin
946-
if extra is not None:
947-
self.__extra__ = extra
948-
# Else __extra__ is inherited, eventually from the
949-
# (meta-)class default above.
944+
self.__extra__ = extra
950945
# Speed hack (https://github.com/python/typing/issues/196).
951946
self.__next_in_mro__ = _next_in_mro(self)
952947
return self
@@ -1307,6 +1302,7 @@ def _get_protocol_attrs(self):
13071302
attr != '__next_in_mro__' and
13081303
attr != '__parameters__' and
13091304
attr != '__origin__' and
1305+
attr != '__extra__' and
13101306
attr != '__module__'):
13111307
attrs.add(attr)
13121308

@@ -1470,7 +1466,7 @@ class ByteString(Sequence[int], extra=collections_abc.ByteString):
14701466
ByteString.register(type(memoryview(b'')))
14711467

14721468

1473-
class List(list, MutableSequence[T]):
1469+
class List(list, MutableSequence[T], extra=list):
14741470

14751471
def __new__(cls, *args, **kwds):
14761472
if _geqv(cls, List):
@@ -1479,7 +1475,7 @@ def __new__(cls, *args, **kwds):
14791475
return list.__new__(cls, *args, **kwds)
14801476

14811477

1482-
class Set(set, MutableSet[T]):
1478+
class Set(set, MutableSet[T], extra=set):
14831479

14841480
def __new__(cls, *args, **kwds):
14851481
if _geqv(cls, Set):
@@ -1502,7 +1498,8 @@ def __subclasscheck__(self, cls):
15021498
return super().__subclasscheck__(cls)
15031499

15041500

1505-
class FrozenSet(frozenset, AbstractSet[T_co], metaclass=_FrozenSetMeta):
1501+
class FrozenSet(frozenset, AbstractSet[T_co], metaclass=_FrozenSetMeta,
1502+
extra=frozenset):
15061503
__slots__ = ()
15071504

15081505
def __new__(cls, *args, **kwds):
@@ -1538,15 +1535,16 @@ class ContextManager(Generic[T_co], extra=contextlib.AbstractContextManager):
15381535
__all__.append('ContextManager')
15391536

15401537

1541-
class Dict(dict, MutableMapping[KT, VT]):
1538+
class Dict(dict, MutableMapping[KT, VT], extra=dict):
15421539

15431540
def __new__(cls, *args, **kwds):
15441541
if _geqv(cls, Dict):
15451542
raise TypeError("Type Dict cannot be instantiated; "
15461543
"use dict() instead")
15471544
return dict.__new__(cls, *args, **kwds)
15481545

1549-
class DefaultDict(collections.defaultdict, MutableMapping[KT, VT]):
1546+
class DefaultDict(collections.defaultdict, MutableMapping[KT, VT],
1547+
extra=collections.defaultdict):
15501548

15511549
def __new__(cls, *args, **kwds):
15521550
if _geqv(cls, DefaultDict):

0 commit comments

Comments
 (0)
0