Skip to content

Commit 65bc620

Browse files
ilevkivskyiambv
authored andcommitted
bpo-28556: Minor updates to typing module (#3550)
* Copy changes to typing from upstream repo * Add NEWS entry
1 parent f6e61df commit 65bc620

File tree

3 files changed

+38
-50
lines changed

3 files changed

+38
-50
lines changed

Lib/test/test_typing.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,13 @@ class Node(Generic[T]): ...
10691069
for t in things + [Any]:
10701070
self.assertEqual(t, copy(t))
10711071
self.assertEqual(t, deepcopy(t))
1072+
if sys.version_info >= (3, 3):
1073+
# From copy module documentation:
1074+
# It does "copy" functions and classes (shallow and deeply), by returning
1075+
# the original object unchanged; this is compatible with the way these
1076+
# are treated by the pickle module.
1077+
self.assertTrue(t is copy(t))
1078+
self.assertTrue(t is deepcopy(t))
10721079

10731080
def test_weakref_all(self):
10741081
T = TypeVar('T')

Lib/typing.py

Lines changed: 29 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ def _type_check(arg, msg):
376376
if (
377377
type(arg).__name__ in ('_Union', '_Optional') and
378378
not getattr(arg, '__origin__', None) or
379-
isinstance(arg, TypingMeta) and _gorg(arg) in (Generic, _Protocol)
379+
isinstance(arg, TypingMeta) and arg._gorg in (Generic, _Protocol)
380380
):
381381
raise TypeError("Plain %s is not valid as type argument" % arg)
382382
return arg
@@ -849,29 +849,6 @@ def __getitem__(self, arg):
849849
Optional = _Optional(_root=True)
850850

851851

852-
def _gorg(a):
853-
"""Return the farthest origin of a generic class (internal helper)."""
854-
assert isinstance(a, GenericMeta)
855-
while a.__origin__ is not None:
856-
a = a.__origin__
857-
return a
858-
859-
860-
def _geqv(a, b):
861-
"""Return whether two generic classes are equivalent (internal helper).
862-
863-
The intention is to consider generic class X and any of its
864-
parameterized forms (X[T], X[int], etc.) as equivalent.
865-
866-
However, X is not equivalent to a subclass of X.
867-
868-
The relation is reflexive, symmetric and transitive.
869-
"""
870-
assert isinstance(a, GenericMeta) and isinstance(b, GenericMeta)
871-
# Reduce each to its origin.
872-
return _gorg(a) is _gorg(b)
873-
874-
875852
def _next_in_mro(cls):
876853
"""Helper for Generic.__new__.
877854
@@ -881,7 +858,7 @@ def _next_in_mro(cls):
881858
next_in_mro = object
882859
# Look for the last occurrence of Generic or Generic[...].
883860
for i, c in enumerate(cls.__mro__[:-1]):
884-
if isinstance(c, GenericMeta) and _gorg(c) is Generic:
861+
if isinstance(c, GenericMeta) and c._gorg is Generic:
885862
next_in_mro = cls.__mro__[i + 1]
886863
return next_in_mro
887864

@@ -991,14 +968,15 @@ def __new__(cls, name, bases, namespace,
991968
initial_bases = bases
992969
if extra is not None and type(extra) is abc.ABCMeta and extra not in bases:
993970
bases = (extra,) + bases
994-
bases = tuple(_gorg(b) if isinstance(b, GenericMeta) else b for b in bases)
971+
bases = tuple(b._gorg if isinstance(b, GenericMeta) else b for b in bases)
995972

996973
# remove bare Generic from bases if there are other generic bases
997974
if any(isinstance(b, GenericMeta) and b is not Generic for b in bases):
998975
bases = tuple(b for b in bases if b is not Generic)
999976
namespace.update({'__origin__': origin, '__extra__': extra})
1000977
self = super().__new__(cls, name, bases, namespace, _root=True)
1001-
978+
super(GenericMeta, self).__setattr__('_gorg',
979+
self if not origin else origin._gorg)
1002980
self.__parameters__ = tvars
1003981
# Be prepared that GenericMeta will be subclassed by TupleMeta
1004982
# and CallableMeta, those two allow ..., (), or [] in __args___.
@@ -1041,7 +1019,7 @@ def __new__(cls, name, bases, namespace,
10411019
def _abc_negative_cache(self):
10421020
if isinstance(self.__extra__, abc.ABCMeta):
10431021
return self.__extra__._abc_negative_cache
1044-
return _gorg(self)._abc_generic_negative_cache
1022+
return self._gorg._abc_generic_negative_cache
10451023

10461024
@_abc_negative_cache.setter
10471025
def _abc_negative_cache(self, value):
@@ -1055,7 +1033,7 @@ def _abc_negative_cache(self, value):
10551033
def _abc_negative_cache_version(self):
10561034
if isinstance(self.__extra__, abc.ABCMeta):
10571035
return self.__extra__._abc_negative_cache_version
1058-
return _gorg(self)._abc_generic_negative_cache_version
1036+
return self._gorg._abc_generic_negative_cache_version
10591037

10601038
@_abc_negative_cache_version.setter
10611039
def _abc_negative_cache_version(self, value):
@@ -1105,7 +1083,7 @@ def _subs_tree(self, tvars=None, args=None):
11051083
if self.__origin__ is None:
11061084
return self
11071085
tree_args = _subs_tree(self, tvars, args)
1108-
return (_gorg(self),) + tuple(tree_args)
1086+
return (self._gorg,) + tuple(tree_args)
11091087

11101088
def __eq__(self, other):
11111089
if not isinstance(other, GenericMeta):
@@ -1121,7 +1099,7 @@ def __hash__(self):
11211099
def __getitem__(self, params):
11221100
if not isinstance(params, tuple):
11231101
params = (params,)
1124-
if not params and not _gorg(self) is Tuple:
1102+
if not params and self._gorg is not Tuple:
11251103
raise TypeError(
11261104
"Parameter list to %s[...] cannot be empty" % _qualname(self))
11271105
msg = "Parameters to generic types must be types."
@@ -1189,14 +1167,14 @@ def __copy__(self):
11891167
self.__extra__, self.__orig_bases__)
11901168

11911169
def __setattr__(self, attr, value):
1192-
# We consider all the subscripted genrics as proxies for original class
1170+
# We consider all the subscripted generics as proxies for original class
11931171
if (
11941172
attr.startswith('__') and attr.endswith('__') or
11951173
attr.startswith('_abc_')
11961174
):
11971175
super(GenericMeta, self).__setattr__(attr, value)
11981176
else:
1199-
super(GenericMeta, _gorg(self)).__setattr__(attr, value)
1177+
super(GenericMeta, self._gorg).__setattr__(attr, value)
12001178

12011179

12021180
# Prevent checks for Generic to crash when defining Generic.
@@ -1209,7 +1187,7 @@ def _generic_new(base_cls, cls, *args, **kwds):
12091187
if cls.__origin__ is None:
12101188
return base_cls.__new__(cls)
12111189
else:
1212-
origin = _gorg(cls)
1190+
origin = cls._gorg
12131191
obj = base_cls.__new__(origin)
12141192
try:
12151193
obj.__orig_class__ = cls
@@ -1243,7 +1221,7 @@ def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:
12431221
__slots__ = ()
12441222

12451223
def __new__(cls, *args, **kwds):
1246-
if _geqv(cls, Generic):
1224+
if cls._gorg is Generic:
12471225
raise TypeError("Type Generic cannot be instantiated; "
12481226
"it can be used only as a base class")
12491227
return _generic_new(cls.__next_in_mro__, cls, *args, **kwds)
@@ -1265,7 +1243,7 @@ class TupleMeta(GenericMeta):
12651243

12661244
@_tp_cache
12671245
def __getitem__(self, parameters):
1268-
if self.__origin__ is not None or not _geqv(self, Tuple):
1246+
if self.__origin__ is not None or self._gorg is not Tuple:
12691247
# Normal generic rules apply if this is not the first subscription
12701248
# or a subscription of a subclass.
12711249
return super().__getitem__(parameters)
@@ -1307,7 +1285,7 @@ class Tuple(tuple, extra=tuple, metaclass=TupleMeta):
13071285
__slots__ = ()
13081286

13091287
def __new__(cls, *args, **kwds):
1310-
if _geqv(cls, Tuple):
1288+
if cls._gorg is Tuple:
13111289
raise TypeError("Type Tuple cannot be instantiated; "
13121290
"use tuple() instead")
13131291
return _generic_new(tuple, cls, *args, **kwds)
@@ -1322,7 +1300,7 @@ def __repr__(self):
13221300
return self._tree_repr(self._subs_tree())
13231301

13241302
def _tree_repr(self, tree):
1325-
if _gorg(self) is not Callable:
1303+
if self._gorg is not Callable:
13261304
return super()._tree_repr(tree)
13271305
# For actual Callable (not its subclass) we override
13281306
# super()._tree_repr() for nice formatting.
@@ -1342,7 +1320,7 @@ def __getitem__(self, parameters):
13421320
with hashable arguments to improve speed.
13431321
"""
13441322

1345-
if self.__origin__ is not None or not _geqv(self, Callable):
1323+
if self.__origin__ is not None or self._gorg is not Callable:
13461324
return super().__getitem__(parameters)
13471325
if not isinstance(parameters, tuple) or len(parameters) != 2:
13481326
raise TypeError("Callable must be used as "
@@ -1384,7 +1362,7 @@ class Callable(extra=collections_abc.Callable, metaclass=CallableMeta):
13841362
__slots__ = ()
13851363

13861364
def __new__(cls, *args, **kwds):
1387-
if _geqv(cls, Callable):
1365+
if cls._gorg is Callable:
13881366
raise TypeError("Type Callable cannot be instantiated; "
13891367
"use a non-abstract subclass instead")
13901368
return _generic_new(cls.__next_in_mro__, cls, *args, **kwds)
@@ -1568,7 +1546,7 @@ def no_type_check(arg):
15681546
if isinstance(arg, type):
15691547
arg_attrs = arg.__dict__.copy()
15701548
for attr, val in arg.__dict__.items():
1571-
if val in arg.__bases__:
1549+
if val in arg.__bases__ + (arg,):
15721550
arg_attrs.pop(attr)
15731551
for obj in arg_attrs.values():
15741552
if isinstance(obj, types.FunctionType):
@@ -1687,6 +1665,7 @@ def _get_protocol_attrs(self):
16871665
attr != '__annotations__' and
16881666
attr != '__weakref__' and
16891667
attr != '_is_protocol' and
1668+
attr != '_gorg' and
16901669
attr != '__dict__' and
16911670
attr != '__args__' and
16921671
attr != '__slots__' and
@@ -1892,7 +1871,7 @@ class List(list, MutableSequence[T], extra=list):
18921871
__slots__ = ()
18931872

18941873
def __new__(cls, *args, **kwds):
1895-
if _geqv(cls, List):
1874+
if cls._gorg is List:
18961875
raise TypeError("Type List cannot be instantiated; "
18971876
"use list() instead")
18981877
return _generic_new(list, cls, *args, **kwds)
@@ -1903,7 +1882,7 @@ class Deque(collections.deque, MutableSequence[T], extra=collections.deque):
19031882
__slots__ = ()
19041883

19051884
def __new__(cls, *args, **kwds):
1906-
if _geqv(cls, Deque):
1885+
if cls._gorg is Deque:
19071886
return collections.deque(*args, **kwds)
19081887
return _generic_new(collections.deque, cls, *args, **kwds)
19091888

@@ -1913,7 +1892,7 @@ class Set(set, MutableSet[T], extra=set):
19131892
__slots__ = ()
19141893

19151894
def __new__(cls, *args, **kwds):
1916-
if _geqv(cls, Set):
1895+
if cls._gorg is Set:
19171896
raise TypeError("Type Set cannot be instantiated; "
19181897
"use set() instead")
19191898
return _generic_new(set, cls, *args, **kwds)
@@ -1923,7 +1902,7 @@ class FrozenSet(frozenset, AbstractSet[T_co], extra=frozenset):
19231902
__slots__ = ()
19241903

19251904
def __new__(cls, *args, **kwds):
1926-
if _geqv(cls, FrozenSet):
1905+
if cls._gorg is FrozenSet:
19271906
raise TypeError("Type FrozenSet cannot be instantiated; "
19281907
"use frozenset() instead")
19291908
return _generic_new(frozenset, cls, *args, **kwds)
@@ -2014,7 +1993,7 @@ class Dict(dict, MutableMapping[KT, VT], extra=dict):
20141993
__slots__ = ()
20151994

20161995
def __new__(cls, *args, **kwds):
2017-
if _geqv(cls, Dict):
1996+
if cls._gorg is Dict:
20181997
raise TypeError("Type Dict cannot be instantiated; "
20191998
"use dict() instead")
20201999
return _generic_new(dict, cls, *args, **kwds)
@@ -2026,7 +2005,7 @@ class DefaultDict(collections.defaultdict, MutableMapping[KT, VT],
20262005
__slots__ = ()
20272006

20282007
def __new__(cls, *args, **kwds):
2029-
if _geqv(cls, DefaultDict):
2008+
if cls._gorg is DefaultDict:
20302009
return collections.defaultdict(*args, **kwds)
20312010
return _generic_new(collections.defaultdict, cls, *args, **kwds)
20322011

@@ -2036,7 +2015,7 @@ class Counter(collections.Counter, Dict[T, int], extra=collections.Counter):
20362015
__slots__ = ()
20372016

20382017
def __new__(cls, *args, **kwds):
2039-
if _geqv(cls, Counter):
2018+
if cls._gorg is Counter:
20402019
return collections.Counter(*args, **kwds)
20412020
return _generic_new(collections.Counter, cls, *args, **kwds)
20422021

@@ -2051,7 +2030,7 @@ class ChainMap(collections.ChainMap, MutableMapping[KT, VT],
20512030
__slots__ = ()
20522031

20532032
def __new__(cls, *args, **kwds):
2054-
if _geqv(cls, ChainMap):
2033+
if cls._gorg is ChainMap:
20552034
return collections.ChainMap(*args, **kwds)
20562035
return _generic_new(collections.ChainMap, cls, *args, **kwds)
20572036

@@ -2070,7 +2049,7 @@ class Generator(Iterator[T_co], Generic[T_co, T_contra, V_co],
20702049
__slots__ = ()
20712050

20722051
def __new__(cls, *args, **kwds):
2073-
if _geqv(cls, Generator):
2052+
if cls._gorg is Generator:
20742053
raise TypeError("Type Generator cannot be instantiated; "
20752054
"create a subclass instead")
20762055
return _generic_new(_G_base, cls, *args, **kwds)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Speed improvements to the ``typing`` module. Original PRs by Ivan
2+
Levkivskyi and Mitar.

0 commit comments

Comments
 (0)