summaryrefslogtreecommitdiffstats
path: root/Lib/typing.py
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2020-05-10 08:53:16 (GMT)
committerGitHub <noreply@github.com>2020-05-10 08:53:16 (GMT)
commitfcb285609a2e55f2dc63dcfbb32e4e2fddf71546 (patch)
treecf2cdb4fd593f45133542b905cd25b2af527f253 /Lib/typing.py
parent85bdec1def789cdb60ab7ffe115e426267b00a60 (diff)
downloadcpython-fcb285609a2e55f2dc63dcfbb32e4e2fddf71546.zip
cpython-fcb285609a2e55f2dc63dcfbb32e4e2fddf71546.tar.gz
cpython-fcb285609a2e55f2dc63dcfbb32e4e2fddf71546.tar.bz2
bpo-40397: Remove __args__ and __parameters__ from _SpecialGenericAlias (GH-19984)
Diffstat (limited to 'Lib/typing.py')
-rw-r--r--Lib/typing.py167
1 files changed, 87 insertions, 80 deletions
diff --git a/Lib/typing.py b/Lib/typing.py
index 681ab6d..e31fc99 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -186,14 +186,13 @@ def _collect_type_vars(types):
return tuple(tvars)
-def _check_generic(cls, parameters):
+def _check_generic(cls, parameters, elen):
"""Check correct count for parameters of a generic cls (internal helper).
This gives a nice error message in case of count mismatch.
"""
- if not cls.__parameters__:
+ if not elen:
raise TypeError(f"{cls} is not a generic class")
alen = len(parameters)
- elen = len(cls.__parameters__)
if alen != elen:
raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};"
f" actual {alen}, expected {elen}")
@@ -592,17 +591,6 @@ class TypeVar(_Final, _Immutable, _root=True):
return self.__name__
-# Special typing constructs Union, Optional, Generic, Callable and Tuple
-# use three special attributes for internal bookkeeping of generic types:
-# * __parameters__ is a tuple of unique free type parameters of a generic
-# type, for example, Dict[T, T].__parameters__ == (T,);
-# * __origin__ keeps a reference to a type that was subscripted,
-# e.g., Union[T, int].__origin__ == Union, or the non-generic version of
-# the type.
-# * __args__ is a tuple of all arguments used in subscripting,
-# e.g., Dict[T, int].__args__ == (T, int).
-
-
def _is_dunder(attr):
return attr.startswith('__') and attr.endswith('__')
@@ -615,28 +603,11 @@ class _BaseGenericAlias(_Final, _root=True):
have 'name' always set. If 'inst' is False, then the alias can't be instantiated,
this is used by e.g. typing.List and typing.Dict.
"""
- def __init__(self, origin, params, *, inst=True, name=None):
+ def __init__(self, origin, *, inst=True, name=None):
self._inst = inst
self._name = name
- if not isinstance(params, tuple):
- params = (params,)
self.__origin__ = origin
- self.__args__ = tuple(... if a is _TypingEllipsis else
- () if a is _TypingEmpty else
- a for a in params)
- self.__parameters__ = _collect_type_vars(params)
self.__slots__ = None # This is not documented.
- if not name:
- self.__module__ = origin.__module__
-
- def __eq__(self, other):
- if not isinstance(other, _BaseGenericAlias):
- return NotImplemented
- return (self.__origin__ == other.__origin__
- and self.__args__ == other.__args__)
-
- def __hash__(self):
- return hash((self.__origin__, self.__args__))
def __call__(self, *args, **kwargs):
if not self._inst:
@@ -669,7 +640,7 @@ class _BaseGenericAlias(_Final, _root=True):
raise AttributeError(attr)
def __setattr__(self, attr, val):
- if _is_dunder(attr) or attr in ('_name', '_inst'):
+ if _is_dunder(attr) or attr in ('_name', '_inst', '_nparams'):
super().__setattr__(attr, val)
else:
setattr(self.__origin__, attr, val)
@@ -682,7 +653,38 @@ class _BaseGenericAlias(_Final, _root=True):
" class and instance checks")
+# Special typing constructs Union, Optional, Generic, Callable and Tuple
+# use three special attributes for internal bookkeeping of generic types:
+# * __parameters__ is a tuple of unique free type parameters of a generic
+# type, for example, Dict[T, T].__parameters__ == (T,);
+# * __origin__ keeps a reference to a type that was subscripted,
+# e.g., Union[T, int].__origin__ == Union, or the non-generic version of
+# the type.
+# * __args__ is a tuple of all arguments used in subscripting,
+# e.g., Dict[T, int].__args__ == (T, int).
+
+
class _GenericAlias(_BaseGenericAlias, _root=True):
+ def __init__(self, origin, params, *, inst=True, name=None):
+ super().__init__(origin, inst=inst, name=name)
+ if not isinstance(params, tuple):
+ params = (params,)
+ self.__args__ = tuple(... if a is _TypingEllipsis else
+ () if a is _TypingEmpty else
+ a for a in params)
+ self.__parameters__ = _collect_type_vars(params)
+ if not name:
+ self.__module__ = origin.__module__
+
+ def __eq__(self, other):
+ if not isinstance(other, _GenericAlias):
+ return NotImplemented
+ return (self.__origin__ == other.__origin__
+ and self.__args__ == other.__args__)
+
+ def __hash__(self):
+ return hash((self.__origin__, self.__args__))
+
@_tp_cache
def __getitem__(self, params):
if self.__origin__ in (Generic, Protocol):
@@ -692,14 +694,14 @@ class _GenericAlias(_BaseGenericAlias, _root=True):
params = (params,)
msg = "Parameters to generic types must be types."
params = tuple(_type_check(p, msg) for p in params)
- _check_generic(self, params)
+ _check_generic(self, params, len(self.__parameters__))
subst = dict(zip(self.__parameters__, params))
new_args = []
for arg in self.__args__:
if isinstance(arg, TypeVar):
arg = subst[arg]
- elif isinstance(arg, (_BaseGenericAlias, GenericAlias)):
+ elif isinstance(arg, (_GenericAlias, GenericAlias)):
subargs = tuple(subst[x] for x in arg.__parameters__)
arg = arg[subargs]
new_args.append(arg)
@@ -739,11 +741,16 @@ class _GenericAlias(_BaseGenericAlias, _root=True):
return (self.__origin__,)
+# _nparams is the number of accepted parameters, e.g. 0 for Hashable,
+# 1 for List and 2 for Dict. It may be -1 if variable number of
+# parameters are accepted (needs custom __getitem__).
+
class _SpecialGenericAlias(_BaseGenericAlias, _root=True):
- def __init__(self, origin, params, *, inst=True, name=None):
+ def __init__(self, origin, nparams, *, inst=True, name=None):
if name is None:
name = origin.__name__
- super().__init__(origin, params, inst=inst, name=name)
+ super().__init__(origin, inst=inst, name=name)
+ self._nparams = nparams
self.__doc__ = f'A generic version of {origin.__module__}.{origin.__qualname__}'
@_tp_cache
@@ -752,8 +759,7 @@ class _SpecialGenericAlias(_BaseGenericAlias, _root=True):
params = (params,)
msg = "Parameters to generic types must be types."
params = tuple(_type_check(p, msg) for p in params)
- _check_generic(self, params)
- assert self.__args__ == self.__parameters__
+ _check_generic(self, params, self._nparams)
return self.copy_with(params)
def copy_with(self, params):
@@ -912,7 +918,7 @@ class Generic:
f"Parameters to {cls.__name__}[...] must all be unique")
else:
# Subscripting a regular Generic subclass.
- _check_generic(cls, params)
+ _check_generic(cls, params, len(cls.__parameters__))
return _GenericAlias(cls, params)
def __init_subclass__(cls, *args, **kwargs):
@@ -1571,18 +1577,18 @@ AnyStr = TypeVar('AnyStr', bytes, str)
# Various ABCs mimicking those in collections.abc.
_alias = _SpecialGenericAlias
-Hashable = _alias(collections.abc.Hashable, ()) # Not generic.
-Awaitable = _alias(collections.abc.Awaitable, T_co)
-Coroutine = _alias(collections.abc.Coroutine, (T_co, T_contra, V_co))
-AsyncIterable = _alias(collections.abc.AsyncIterable, T_co)
-AsyncIterator = _alias(collections.abc.AsyncIterator, T_co)
-Iterable = _alias(collections.abc.Iterable, T_co)
-Iterator = _alias(collections.abc.Iterator, T_co)
-Reversible = _alias(collections.abc.Reversible, T_co)
-Sized = _alias(collections.abc.Sized, ()) # Not generic.
-Container = _alias(collections.abc.Container, T_co)
-Collection = _alias(collections.abc.Collection, T_co)
-Callable = _CallableType(collections.abc.Callable, ())
+Hashable = _alias(collections.abc.Hashable, 0) # Not generic.
+Awaitable = _alias(collections.abc.Awaitable, 1)
+Coroutine = _alias(collections.abc.Coroutine, 3)
+AsyncIterable = _alias(collections.abc.AsyncIterable, 1)
+AsyncIterator = _alias(collections.abc.AsyncIterator, 1)
+Iterable = _alias(collections.abc.Iterable, 1)
+Iterator = _alias(collections.abc.Iterator, 1)
+Reversible = _alias(collections.abc.Reversible, 1)
+Sized = _alias(collections.abc.Sized, 0) # Not generic.
+Container = _alias(collections.abc.Container, 1)
+Collection = _alias(collections.abc.Collection, 1)
+Callable = _CallableType(collections.abc.Callable, 2)
Callable.__doc__ = \
"""Callable type; Callable[[int], str] is a function of (int) -> str.
@@ -1593,15 +1599,16 @@ Callable.__doc__ = \
There is no syntax to indicate optional or keyword arguments,
such function types are rarely used as callback types.
"""
-AbstractSet = _alias(collections.abc.Set, T_co, name='AbstractSet')
-MutableSet = _alias(collections.abc.MutableSet, T)
+AbstractSet = _alias(collections.abc.Set, 1, name='AbstractSet')
+MutableSet = _alias(collections.abc.MutableSet, 1)
# NOTE: Mapping is only covariant in the value type.
-Mapping = _alias(collections.abc.Mapping, (KT, VT_co))
-MutableMapping = _alias(collections.abc.MutableMapping, (KT, VT))
-Sequence = _alias(collections.abc.Sequence, T_co)
-MutableSequence = _alias(collections.abc.MutableSequence, T)
-ByteString = _alias(collections.abc.ByteString, ()) # Not generic
-Tuple = _TupleType(tuple, (), inst=False, name='Tuple')
+Mapping = _alias(collections.abc.Mapping, 2)
+MutableMapping = _alias(collections.abc.MutableMapping, 2)
+Sequence = _alias(collections.abc.Sequence, 1)
+MutableSequence = _alias(collections.abc.MutableSequence, 1)
+ByteString = _alias(collections.abc.ByteString, 0) # Not generic
+# Tuple accepts variable number of parameters.
+Tuple = _TupleType(tuple, -1, inst=False, name='Tuple')
Tuple.__doc__ = \
"""Tuple type; Tuple[X, Y] is the cross-product type of X and Y.
@@ -1611,24 +1618,24 @@ Tuple.__doc__ = \
To specify a variable-length tuple of homogeneous type, use Tuple[T, ...].
"""
-List = _alias(list, T, inst=False, name='List')
-Deque = _alias(collections.deque, T, name='Deque')
-Set = _alias(set, T, inst=False, name='Set')
-FrozenSet = _alias(frozenset, T_co, inst=False, name='FrozenSet')
-MappingView = _alias(collections.abc.MappingView, T_co)
-KeysView = _alias(collections.abc.KeysView, KT)
-ItemsView = _alias(collections.abc.ItemsView, (KT, VT_co))
-ValuesView = _alias(collections.abc.ValuesView, VT_co)
-ContextManager = _alias(contextlib.AbstractContextManager, T_co, name='ContextManager')
-AsyncContextManager = _alias(contextlib.AbstractAsyncContextManager, T_co, name='AsyncContextManager')
-Dict = _alias(dict, (KT, VT), inst=False, name='Dict')
-DefaultDict = _alias(collections.defaultdict, (KT, VT), name='DefaultDict')
-OrderedDict = _alias(collections.OrderedDict, (KT, VT))
-Counter = _alias(collections.Counter, T)
-ChainMap = _alias(collections.ChainMap, (KT, VT))
-Generator = _alias(collections.abc.Generator, (T_co, T_contra, V_co))
-AsyncGenerator = _alias(collections.abc.AsyncGenerator, (T_co, T_contra))
-Type = _alias(type, CT_co, inst=False, name='Type')
+List = _alias(list, 1, inst=False, name='List')
+Deque = _alias(collections.deque, 1, name='Deque')
+Set = _alias(set, 1, inst=False, name='Set')
+FrozenSet = _alias(frozenset, 1, inst=False, name='FrozenSet')
+MappingView = _alias(collections.abc.MappingView, 1)
+KeysView = _alias(collections.abc.KeysView, 1)
+ItemsView = _alias(collections.abc.ItemsView, 2)
+ValuesView = _alias(collections.abc.ValuesView, 1)
+ContextManager = _alias(contextlib.AbstractContextManager, 1, name='ContextManager')
+AsyncContextManager = _alias(contextlib.AbstractAsyncContextManager, 1, name='AsyncContextManager')
+Dict = _alias(dict, 2, inst=False, name='Dict')
+DefaultDict = _alias(collections.defaultdict, 2, name='DefaultDict')
+OrderedDict = _alias(collections.OrderedDict, 2)
+Counter = _alias(collections.Counter, 1)
+ChainMap = _alias(collections.ChainMap, 2)
+Generator = _alias(collections.abc.Generator, 3)
+AsyncGenerator = _alias(collections.abc.AsyncGenerator, 2)
+Type = _alias(type, 1, inst=False, name='Type')
Type.__doc__ = \
"""A special construct usable to annotate class objects.
@@ -2122,8 +2129,8 @@ class io:
io.__name__ = __name__ + '.io'
sys.modules[io.__name__] = io
-Pattern = _alias(stdlib_re.Pattern, AnyStr)
-Match = _alias(stdlib_re.Match, AnyStr)
+Pattern = _alias(stdlib_re.Pattern, 1)
+Match = _alias(stdlib_re.Match, 1)
class re:
"""Wrapper namespace for re type aliases."""