mirror of
https://github.com/python/cpython.git
synced 2025-08-03 00:23:06 +00:00
[3.9] bpo-42195: Ensure consistency of Callable's __args__ in collections.abc and typing (GH-23765)
Backport of GH-23060.
This commit is contained in:
parent
14f2a124e2
commit
33b3fedd43
7 changed files with 202 additions and 43 deletions
|
@ -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,76 @@ 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):
|
||||
try:
|
||||
return cls.__create_ga(origin, args)
|
||||
except TypeError as exc:
|
||||
import warnings
|
||||
warnings.warn(f'{str(exc)} '
|
||||
f'(This will raise a TypeError in Python 3.10.)',
|
||||
DeprecationWarning)
|
||||
return GenericAlias(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 +497,7 @@ class Callable(metaclass=ABCMeta):
|
|||
return _check_methods(C, "__call__")
|
||||
return NotImplemented
|
||||
|
||||
__class_getitem__ = classmethod(GenericAlias)
|
||||
__class_getitem__ = classmethod(_CallableGenericAlias)
|
||||
|
||||
|
||||
### SETS ###
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue