summaryrefslogtreecommitdiffstats
path: root/Lib/_collections_abc.py
diff options
context:
space:
mode:
authorkj <28750310+Fidget-Spinner@users.noreply.github.com>2020-12-13 18:38:24 (GMT)
committerGitHub <noreply@github.com>2020-12-13 18:38:24 (GMT)
commit463c7d3d149283814d879a9bb8411af64e656c8e (patch)
tree204f9b460e5740291fd33d03908131bad317a922 /Lib/_collections_abc.py
parent43c4fb6c90c013a00cb820cb61e4990cd8ec7f5e (diff)
downloadcpython-463c7d3d149283814d879a9bb8411af64e656c8e.zip
cpython-463c7d3d149283814d879a9bb8411af64e656c8e.tar.gz
cpython-463c7d3d149283814d879a9bb8411af64e656c8e.tar.bz2
bpo-42195: Ensure consistency of Callable's __args__ in collections.abc and typing (GH-23060)
Diffstat (limited to 'Lib/_collections_abc.py')
-rw-r--r--Lib/_collections_abc.py69
1 files changed, 68 insertions, 1 deletions
diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py
index 28690f8..7c3faa6 100644
--- a/Lib/_collections_abc.py
+++ b/Lib/_collections_abc.py
@@ -10,6 +10,10 @@ from abc import ABCMeta, abstractmethod
import sys
GenericAlias = type(list[int])
+EllipsisType = type(...)
+def _f(): pass
+FunctionType = type(_f)
+del _f
__all__ = ["Awaitable", "Coroutine",
"AsyncIterable", "AsyncIterator", "AsyncGenerator",
@@ -409,6 +413,69 @@ class Collection(Sized, Iterable, Container):
return NotImplemented
+class _CallableGenericAlias(GenericAlias):
+ """ Represent `Callable[argtypes, resulttype]`.
+
+ This sets ``__args__`` to a tuple containing the flattened``argtypes``
+ followed by ``resulttype``.
+
+ Example: ``Callable[[int, str], float]`` sets ``__args__`` to
+ ``(int, str, float)``.
+ """
+
+ __slots__ = ()
+
+ def __new__(cls, origin, args):
+ return cls.__create_ga(origin, args)
+
+ @classmethod
+ def __create_ga(cls, origin, args):
+ if not isinstance(args, tuple) or len(args) != 2:
+ raise TypeError(
+ "Callable must be used as Callable[[arg, ...], result].")
+ t_args, t_result = args
+ if isinstance(t_args, list):
+ ga_args = tuple(t_args) + (t_result,)
+ # This relaxes what t_args can be on purpose to allow things like
+ # PEP 612 ParamSpec. Responsibility for whether a user is using
+ # Callable[...] properly is deferred to static type checkers.
+ else:
+ ga_args = args
+ return super().__new__(cls, origin, ga_args)
+
+ def __repr__(self):
+ if len(self.__args__) == 2 and self.__args__[0] is Ellipsis:
+ return super().__repr__()
+ return (f'collections.abc.Callable'
+ f'[[{", ".join([_type_repr(a) for a in self.__args__[:-1]])}], '
+ f'{_type_repr(self.__args__[-1])}]')
+
+ def __reduce__(self):
+ args = self.__args__
+ if not (len(args) == 2 and args[0] is Ellipsis):
+ args = list(args[:-1]), args[-1]
+ return _CallableGenericAlias, (Callable, args)
+
+
+def _type_repr(obj):
+ """Return the repr() of an object, special-casing types (internal helper).
+
+ Copied from :mod:`typing` since collections.abc
+ shouldn't depend on that module.
+ """
+ if isinstance(obj, GenericAlias):
+ return repr(obj)
+ if isinstance(obj, type):
+ if obj.__module__ == 'builtins':
+ return obj.__qualname__
+ return f'{obj.__module__}.{obj.__qualname__}'
+ if obj is Ellipsis:
+ return '...'
+ if isinstance(obj, FunctionType):
+ return obj.__name__
+ return repr(obj)
+
+
class Callable(metaclass=ABCMeta):
__slots__ = ()
@@ -423,7 +490,7 @@ class Callable(metaclass=ABCMeta):
return _check_methods(C, "__call__")
return NotImplemented
- __class_getitem__ = classmethod(GenericAlias)
+ __class_getitem__ = classmethod(_CallableGenericAlias)
### SETS ###