Many changes from the upstream repo (https://github.com/python/typing).

This syncs to rev 7b43ada77821d23e55e3a4b35f6055a59b9e1ad7 there.

Summary:

- Add typing.DefaultDict (as a generic variant of collections.defaultdict).

- Use collections.Reversible if it exists (only relevant for Python 3.6).

- Revamped generic class behavior to conform to updated PEP 484.

- Improve speed of Generic.__new__.

- Make sure __init__ is called for new Generic instances. Fix issue #26391.

- Refactor async support to be compatible with 3.2, 3.3, 3.4.

- Remove 'io' and 're' from __all__ (they still exist, just not
  included by "import *"). Fix issue #26234.

- Change @overload -- you can now use it outside stubs (you still
  cannot call the decorated function though).
This commit is contained in:
Guido van Rossum 2016-04-05 08:28:52 -07:00
parent 0f7673943a
commit bd5b9a0742
2 changed files with 372 additions and 180 deletions

View File

@ -1,8 +1,7 @@
import asyncio
import pickle
import re
import sys
from unittest import TestCase, main
from unittest import TestCase, main, skipUnless
from typing import Any
from typing import TypeVar, AnyStr
@ -133,6 +132,7 @@ class TypeVarTests(TestCase):
def test_constrained_error(self):
with self.assertRaises(TypeError):
X = TypeVar('X', int)
X
def test_union_unique(self):
X = TypeVar('X')
@ -317,6 +317,7 @@ class UnionTests(TestCase):
def test_union_str_pattern(self):
# Shouldn't crash; see http://bugs.python.org/issue25390
A = Union[str, Pattern]
A
class TypeVarUnionTests(TestCase):
@ -487,7 +488,7 @@ class SimpleMapping(Generic[XK, XV]):
...
class MySimpleMapping(SimpleMapping):
class MySimpleMapping(SimpleMapping[XK, XV]):
def __init__(self):
self.store = {}
@ -541,6 +542,7 @@ class ProtocolTests(TestCase):
assert not issubclass(str, typing.SupportsAbs)
def test_supports_round(self):
issubclass(float, typing.SupportsRound)
assert issubclass(float, typing.SupportsRound)
assert issubclass(int, typing.SupportsRound)
assert not issubclass(str, typing.SupportsRound)
@ -551,20 +553,23 @@ class ProtocolTests(TestCase):
def test_protocol_instance_type_error(self):
with self.assertRaises(TypeError):
isinstance([], typing.Reversible)
isinstance(0, typing.SupportsAbs)
class GenericTests(TestCase):
def test_basics(self):
X = SimpleMapping[str, Any]
assert X.__parameters__ == ()
with self.assertRaises(TypeError):
X[str]
with self.assertRaises(TypeError):
X[str, str]
Y = SimpleMapping[XK, str]
X[str, str]
Y[str, str]
assert Y.__parameters__ == (XK,)
Y[str]
with self.assertRaises(TypeError):
X[int, str]
with self.assertRaises(TypeError):
Y[str, bytes]
Y[str, str]
def test_init(self):
T = TypeVar('T')
@ -576,30 +581,61 @@ class GenericTests(TestCase):
def test_repr(self):
self.assertEqual(repr(SimpleMapping),
__name__ + '.' + 'SimpleMapping[~XK, ~XV]')
__name__ + '.' + 'SimpleMapping<~XK, ~XV>')
self.assertEqual(repr(MySimpleMapping),
__name__ + '.' + 'MySimpleMapping[~XK, ~XV]')
__name__ + '.' + 'MySimpleMapping<~XK, ~XV>')
def test_chain_repr(self):
T = TypeVar('T')
S = TypeVar('S')
class C(Generic[T]):
pass
X = C[Tuple[S, T]]
assert X == C[Tuple[S, T]]
assert X != C[Tuple[T, S]]
Y = X[T, int]
assert Y == X[T, int]
assert Y != X[S, int]
assert Y != X[T, str]
Z = Y[str]
assert Z == Y[str]
assert Z != Y[int]
assert Z != Y[T]
assert str(Z).endswith(
'.C<~T>[typing.Tuple[~S, ~T]]<~S, ~T>[~T, int]<~T>[str]')
def test_dict(self):
T = TypeVar('T')
class B(Generic[T]):
pass
b = B()
b.foo = 42
self.assertEqual(b.__dict__, {'foo': 42})
class C(B[int]):
pass
c = C()
c.bar = 'abc'
self.assertEqual(c.__dict__, {'bar': 'abc'})
def test_pickle(self):
global C # pickle wants to reference the class by name
T = TypeVar('T')
class B(Generic[T]):
pass
global C # pickle wants to reference the class by name
class C(B[int]):
pass
c = C()
c.foo = 42
c.bar = 'abc'
@ -626,12 +662,12 @@ class GenericTests(TestCase):
assert C.__module__ == __name__
if not PY32:
assert C.__qualname__ == 'GenericTests.test_repr_2.<locals>.C'
assert repr(C).split('.')[-1] == 'C[~T]'
assert repr(C).split('.')[-1] == 'C<~T>'
X = C[int]
assert X.__module__ == __name__
if not PY32:
assert X.__qualname__ == 'C'
assert repr(X).split('.')[-1] == 'C[int]'
assert repr(X).split('.')[-1] == 'C<~T>[int]'
class Y(C[int]):
pass
@ -639,7 +675,7 @@ class GenericTests(TestCase):
assert Y.__module__ == __name__
if not PY32:
assert Y.__qualname__ == 'GenericTests.test_repr_2.<locals>.Y'
assert repr(Y).split('.')[-1] == 'Y[int]'
assert repr(Y).split('.')[-1] == 'Y'
def test_eq_1(self):
assert Generic == Generic
@ -667,15 +703,14 @@ class GenericTests(TestCase):
class B(Generic[KT, T]):
pass
class C(A, Generic[KT, VT], B):
class C(A[T, VT], Generic[VT, T, KT], B[KT, T]):
pass
assert C.__parameters__ == (T, VT, KT)
assert C.__parameters__ == (VT, T, KT)
def test_nested(self):
class G(Generic):
pass
G = Generic
class Visitor(G[T]):
@ -721,9 +756,30 @@ class GenericTests(TestCase):
assert type(a) is Node
assert type(b) is Node
assert type(c) is Node
assert a.label == x
assert b.label == x
assert c.label == x
foo(42)
def test_implicit_any(self):
T = TypeVar('T')
class C(Generic[T]):
pass
class D(C):
pass
assert D.__parameters__ == ()
with self.assertRaises(Exception):
D[int]
with self.assertRaises(Exception):
D[Any]
with self.assertRaises(Exception):
D[T]
class VarianceTests(TestCase):
@ -956,14 +1012,33 @@ class OverloadTests(TestCase):
from typing import overload
with self.assertRaises(RuntimeError):
@overload
def blah():
pass
blah()
def test_overload_succeeds(self):
from typing import overload
@overload
def blah():
pass
def blah():
pass
blah()
PY35 = sys.version_info[:2] >= (3, 5)
PY35_TESTS = """
import asyncio
T_a = TypeVar('T')
class AwaitableWrapper(typing.Awaitable[T_a]):
def __init__(self, value):
@ -973,7 +1048,6 @@ class AwaitableWrapper(typing.Awaitable[T_a]):
yield
return self.value
class AsyncIteratorWrapper(typing.AsyncIterator[T_a]):
def __init__(self, value: typing.Iterable[T_a]):
@ -989,6 +1063,10 @@ class AsyncIteratorWrapper(typing.AsyncIterator[T_a]):
return data
else:
raise StopAsyncIteration
"""
if PY35:
exec(PY35_TESTS)
class CollectionsAbcTests(TestCase):
@ -1015,9 +1093,14 @@ class CollectionsAbcTests(TestCase):
assert isinstance(it, typing.Iterator[int])
assert not isinstance(42, typing.Iterator)
@skipUnless(PY35, 'Python 3.5 required')
def test_awaitable(self):
async def foo() -> typing.Awaitable[int]:
return await AwaitableWrapper(42)
ns = {}
exec(
"async def foo() -> typing.Awaitable[int]:\n"
" return await AwaitableWrapper(42)\n",
globals(), ns)
foo = ns['foo']
g = foo()
assert issubclass(type(g), typing.Awaitable[int])
assert isinstance(g, typing.Awaitable)
@ -1028,6 +1111,7 @@ class CollectionsAbcTests(TestCase):
typing.Awaitable[Manager])
g.send(None) # Run foo() till completion, to avoid warning.
@skipUnless(PY35, 'Python 3.5 required')
def test_async_iterable(self):
base_it = range(10) # type: Iterator[int]
it = AsyncIteratorWrapper(base_it)
@ -1037,6 +1121,7 @@ class CollectionsAbcTests(TestCase):
typing.AsyncIterable[Employee])
assert not isinstance(42, typing.AsyncIterable)
@skipUnless(PY35, 'Python 3.5 required')
def test_async_iterator(self):
base_it = range(10) # type: Iterator[int]
it = AsyncIteratorWrapper(base_it)
@ -1127,6 +1212,22 @@ class CollectionsAbcTests(TestCase):
d = MyDict()
assert isinstance(d, MyDict)
def test_no_defaultdict_instantiation(self):
with self.assertRaises(TypeError):
typing.DefaultDict()
with self.assertRaises(TypeError):
typing.DefaultDict[KT, VT]()
with self.assertRaises(TypeError):
typing.DefaultDict[str, int]()
def test_defaultdict_subclass_instantiation(self):
class MyDefDict(typing.DefaultDict[str, int]):
pass
dd = MyDefDict()
assert isinstance(dd, MyDefDict)
def test_no_set_instantiation(self):
with self.assertRaises(TypeError):
typing.Set()
@ -1251,7 +1352,7 @@ class IOTests(TestCase):
return a.readline()
a = stuff.__annotations__['a']
assert a.__parameters__ == (str,)
assert a.__parameters__ == ()
def test_binaryio(self):
@ -1259,7 +1360,7 @@ class IOTests(TestCase):
return a.readline()
a = stuff.__annotations__['a']
assert a.__parameters__ == (bytes,)
assert a.__parameters__ == ()
def test_io_submodule(self):
from typing.io import IO, TextIO, BinaryIO, __all__, __name__
@ -1346,8 +1447,9 @@ class AllTests(TestCase):
assert 'ValuesView' in a
assert 'cast' in a
assert 'overload' in a
assert 'io' in a
assert 're' in a
# Check that io and re are not exported.
assert 'io' not in a
assert 're' not in a
# Spot-check that stdlib modules aren't exported.
assert 'os' not in a
assert 'sys' not in a

View File

@ -1,7 +1,3 @@
# TODO nits:
# Get rid of asserts that are the caller's fault.
# Docstrings (e.g. ABCs).
import abc
from abc import abstractmethod, abstractproperty
import collections
@ -56,6 +52,7 @@ __all__ = [
# Concrete collection types.
'Dict',
'DefaultDict',
'List',
'Set',
'NamedTuple', # Not really a type.
@ -68,12 +65,12 @@ __all__ = [
'no_type_check',
'no_type_check_decorator',
'overload',
# Submodules.
'io',
're',
]
# The pseudo-submodules 're' and 'io' are part of the public
# namespace, but excluded from __all__ because they might stomp on
# legitimate imports of those modules.
def _qualname(x):
if sys.version_info[:2] >= (3, 3):
@ -117,8 +114,8 @@ class TypingMeta(type):
"""
return self
def _has_type_var(self):
return False
def _get_type_vars(self, tvars):
pass
def __repr__(self):
return '%s.%s' % (self.__module__, _qualname(self))
@ -214,8 +211,8 @@ class _TypeAlias:
someone tries to subclass a type alias (not a good idea).
"""
if (len(args) == 3 and
isinstance(args[0], str) and
isinstance(args[1], tuple)):
isinstance(args[0], str) and
isinstance(args[1], tuple)):
# Close enough.
raise TypeError("A type alias cannot be subclassed")
return object.__new__(cls)
@ -271,8 +268,16 @@ class _TypeAlias:
return issubclass(cls, self.impl_type)
def _has_type_var(t):
return t is not None and isinstance(t, TypingMeta) and t._has_type_var()
def _get_type_vars(types, tvars):
for t in types:
if isinstance(t, TypingMeta):
t._get_type_vars(tvars)
def _type_vars(types):
tvars = []
_get_type_vars(types, tvars)
return tuple(tvars)
def _eval_type(t, globalns, localns):
@ -376,7 +381,7 @@ class TypeVar(TypingMeta, metaclass=TypingMeta, _root=True):
At runtime, isinstance(x, T) will raise TypeError. However,
issubclass(C, T) is true for any class C, and issubclass(str, A)
and issubclass(bytes, A) are true, and issubclass(int, A) is
false.
false. (TODO: Why is this needed? This may change. See #136.)
Type variables may be marked covariant or contravariant by passing
covariant=True or contravariant=True. See PEP 484 for more
@ -410,8 +415,9 @@ class TypeVar(TypingMeta, metaclass=TypingMeta, _root=True):
self.__bound__ = None
return self
def _has_type_var(self):
return True
def _get_type_vars(self, tvars):
if self not in tvars:
tvars.append(self)
def __repr__(self):
if self.__covariant__:
@ -448,7 +454,6 @@ VT_co = TypeVar('VT_co', covariant=True) # Value type covariant containers.
T_contra = TypeVar('T_contra', contravariant=True) # Ditto contravariant.
# A useful type variable with constraints. This represents string types.
# TODO: What about bytearray, memoryview?
AnyStr = TypeVar('AnyStr', bytes, str)
@ -514,12 +519,9 @@ class UnionMeta(TypingMeta):
return self.__class__(self.__name__, self.__bases__, {},
p, _root=True)
def _has_type_var(self):
def _get_type_vars(self, tvars):
if self.__union_params__:
for t in self.__union_params__:
if _has_type_var(t):
return True
return False
_get_type_vars(self.__union_params__, tvars)
def __repr__(self):
r = super().__repr__()
@ -656,12 +658,9 @@ class TupleMeta(TypingMeta):
self.__tuple_use_ellipsis__ = use_ellipsis
return self
def _has_type_var(self):
def _get_type_vars(self, tvars):
if self.__tuple_params__:
for t in self.__tuple_params__:
if _has_type_var(t):
return True
return False
_get_type_vars(self.__tuple_params__, tvars)
def _eval_type(self, globalns, localns):
tp = self.__tuple_params__
@ -769,12 +768,9 @@ class CallableMeta(TypingMeta):
self.__result__ = result
return self
def _has_type_var(self):
def _get_type_vars(self, tvars):
if self.__args__:
for t in self.__args__:
if _has_type_var(t):
return True
return _has_type_var(self.__result__)
_get_type_vars(self.__args__, tvars)
def _eval_type(self, globalns, localns):
if self.__args__ is None and self.__result__ is None:
@ -878,76 +874,106 @@ def _geqv(a, b):
return _gorg(a) is _gorg(b)
def _next_in_mro(cls):
"""Helper for Generic.__new__.
Returns the class after the last occurrence of Generic or
Generic[...] in cls.__mro__.
"""
next_in_mro = object
# Look for the last occurrence of Generic or Generic[...].
for i, c in enumerate(cls.__mro__[:-1]):
if isinstance(c, GenericMeta) and _gorg(c) is Generic:
next_in_mro = cls.__mro__[i+1]
return next_in_mro
class GenericMeta(TypingMeta, abc.ABCMeta):
"""Metaclass for generic types."""
# TODO: Constrain more how Generic is used; only a few
# standard patterns should be allowed.
# TODO: Use a more precise rule than matching __name__ to decide
# whether two classes are the same. Also, save the formal
# parameters. (These things are related! A solution lies in
# using origin.)
__extra__ = None
def __new__(cls, name, bases, namespace,
parameters=None, origin=None, extra=None):
if parameters is None:
# Extract parameters from direct base classes. Only
# direct bases are considered and only those that are
# themselves generic, and parameterized with type
# variables. Don't use bases like Any, Union, Tuple,
# Callable or type variables.
params = None
for base in bases:
if isinstance(base, TypingMeta):
if not isinstance(base, GenericMeta):
raise TypeError(
"You cannot inherit from magic class %s" %
repr(base))
if base.__parameters__ is None:
continue # The base is unparameterized.
for bp in base.__parameters__:
if _has_type_var(bp) and not isinstance(bp, TypeVar):
raise TypeError(
"Cannot inherit from a generic class "
"parameterized with "
"non-type-variable %s" % bp)
if params is None:
params = []
if bp not in params:
params.append(bp)
if params is not None:
parameters = tuple(params)
tvars=None, args=None, origin=None, extra=None):
self = super().__new__(cls, name, bases, namespace, _root=True)
self.__parameters__ = parameters
if tvars is not None:
# Called from __getitem__() below.
assert origin is not None
assert all(isinstance(t, TypeVar) for t in tvars), tvars
else:
# Called from class statement.
assert tvars is None, tvars
assert args is None, args
assert origin is None, origin
# Get the full set of tvars from the bases.
tvars = _type_vars(bases)
# Look for Generic[T1, ..., Tn].
# If found, tvars must be a subset of it.
# If not found, tvars is it.
# Also check for and reject plain Generic,
# and reject multiple Generic[...].
gvars = None
for base in bases:
if base is Generic:
raise TypeError("Cannot inherit from plain Generic")
if (isinstance(base, GenericMeta) and
base.__origin__ is Generic):
if gvars is not None:
raise TypeError(
"Cannot inherit from Generic[...] multiple types.")
gvars = base.__parameters__
if gvars is None:
gvars = tvars
else:
tvarset = set(tvars)
gvarset = set(gvars)
if not tvarset <= gvarset:
raise TypeError(
"Some type variables (%s) "
"are not listed in Generic[%s]" %
(", ".join(str(t) for t in tvars if t not in gvarset),
", ".join(str(g) for g in gvars)))
tvars = gvars
self.__parameters__ = tvars
self.__args__ = args
self.__origin__ = origin
if extra is not None:
self.__extra__ = extra
# Else __extra__ is inherited, eventually from the
# (meta-)class default above.
self.__origin__ = origin
# Speed hack (https://github.com/python/typing/issues/196).
self.__next_in_mro__ = _next_in_mro(self)
return self
def _has_type_var(self):
if self.__parameters__:
for t in self.__parameters__:
if _has_type_var(t):
return True
return False
def _get_type_vars(self, tvars):
if self.__origin__ and self.__parameters__:
_get_type_vars(self.__parameters__, tvars)
def __repr__(self):
r = super().__repr__()
if self.__parameters__ is not None:
if self.__origin__ is not None:
r = repr(self.__origin__)
else:
r = super().__repr__()
if self.__args__:
r += '[%s]' % (
', '.join(_type_repr(p) for p in self.__args__))
if self.__parameters__:
r += '<%s>' % (
', '.join(_type_repr(p) for p in self.__parameters__))
return r
def __eq__(self, other):
if not isinstance(other, GenericMeta):
return NotImplemented
return (_geqv(self, other) and
self.__parameters__ == other.__parameters__)
if self.__origin__ is not None:
return (self.__origin__ is other.__origin__ and
self.__args__ == other.__args__ and
self.__parameters__ == other.__parameters__)
else:
return self is other
def __hash__(self):
return hash((self.__name__, self.__parameters__))
@ -956,37 +982,45 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
if not isinstance(params, tuple):
params = (params,)
if not params:
raise TypeError("Cannot have empty parameter list")
raise TypeError(
"Parameter list to %s[...] cannot be empty" % _qualname(self))
msg = "Parameters to generic types must be types."
params = tuple(_type_check(p, msg) for p in params)
if self.__parameters__ is None:
for p in params:
if not isinstance(p, TypeVar):
raise TypeError("Initial parameters must be "
"type variables; got %s" % p)
if self is Generic:
# Generic can only be subscripted with unique type variables.
if not all(isinstance(p, TypeVar) for p in params):
raise TypeError(
"Parameters to Generic[...] must all be type variables")
if len(set(params)) != len(params):
raise TypeError(
"All type variables in Generic[...] must be distinct.")
"Parameters to Generic[...] must all be unique")
tvars = params
args = None
elif self is _Protocol:
# _Protocol is internal, don't check anything.
tvars = params
args = None
elif self.__origin__ in (Generic, _Protocol):
# Can't subscript Generic[...] or _Protocol[...].
raise TypeError("Cannot subscript already-subscripted %s" %
repr(self))
else:
if len(params) != len(self.__parameters__):
raise TypeError("Cannot change parameter count from %d to %d" %
(len(self.__parameters__), len(params)))
for new, old in zip(params, self.__parameters__):
if isinstance(old, TypeVar):
if not old.__constraints__:
# Substituting for an unconstrained TypeVar is OK.
continue
if issubclass(new, Union[old.__constraints__]):
# Specializing a constrained type variable is OK.
continue
if not issubclass(new, old):
raise TypeError(
"Cannot substitute %s for %s in %s" %
(_type_repr(new), _type_repr(old), self))
return self.__class__(self.__name__, (self,) + self.__bases__,
# Subscripting a regular Generic subclass.
if not self.__parameters__:
raise TypeError("%s is not a generic class" % repr(self))
alen = len(params)
elen = len(self.__parameters__)
if alen != elen:
raise TypeError(
"Too %s parameters for %s; actual %s, expected %s" %
("many" if alen > elen else "few", repr(self), alen, elen))
tvars = _type_vars(params)
args = params
return self.__class__(self.__name__,
(self,) + self.__bases__,
dict(self.__dict__),
parameters=params,
tvars=tvars,
args=args,
origin=self,
extra=self.__extra__)
@ -1006,10 +1040,10 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
# C[X] is a subclass of C[Y] iff X is a subclass of Y.
origin = self.__origin__
if origin is not None and origin is cls.__origin__:
assert len(self.__parameters__) == len(origin.__parameters__)
assert len(cls.__parameters__) == len(origin.__parameters__)
for p_self, p_cls, p_origin in zip(self.__parameters__,
cls.__parameters__,
assert len(self.__args__) == len(origin.__parameters__)
assert len(cls.__args__) == len(origin.__parameters__)
for p_self, p_cls, p_origin in zip(self.__args__,
cls.__args__,
origin.__parameters__):
if isinstance(p_origin, TypeVar):
if p_origin.__covariant__:
@ -1039,6 +1073,10 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
return issubclass(cls, self.__extra__)
# Prevent checks for Generic to crash when defining Generic.
Generic = None
class Generic(metaclass=GenericMeta):
"""Abstract base class for generic types.
@ -1053,29 +1091,23 @@ class Generic(metaclass=GenericMeta):
This class can then be used as follows::
def lookup_name(mapping: Mapping, key: KT, default: VT) -> VT:
def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:
try:
return mapping[key]
except KeyError:
return default
For clarity the type variables may be redefined, e.g.::
X = TypeVar('X')
Y = TypeVar('Y')
def lookup_name(mapping: Mapping[X, Y], key: X, default: Y) -> Y:
# Same body as above.
"""
__slots__ = ()
def __new__(cls, *args, **kwds):
next_in_mro = object
# Look for the last occurrence of Generic or Generic[...].
for i, c in enumerate(cls.__mro__[:-1]):
if isinstance(c, GenericMeta) and _gorg(c) is Generic:
next_in_mro = cls.__mro__[i+1]
return next_in_mro.__new__(_gorg(cls))
if cls.__origin__ is None:
return cls.__next_in_mro__.__new__(cls)
else:
origin = _gorg(cls)
obj = cls.__next_in_mro__.__new__(origin)
obj.__init__(*args, **kwds)
return obj
def cast(typ, val):
@ -1093,9 +1125,7 @@ def _get_defaults(func):
"""Internal helper to extract the default arguments, by name."""
code = func.__code__
pos_count = code.co_argcount
kw_count = code.co_kwonlyargcount
arg_names = code.co_varnames
kwarg_names = arg_names[pos_count:pos_count + kw_count]
arg_names = arg_names[:pos_count]
defaults = func.__defaults__ or ()
kwdefaults = func.__kwdefaults__
@ -1148,7 +1178,6 @@ def get_type_hints(obj, globalns=None, localns=None):
return hints
# TODO: Also support this as a class decorator.
def no_type_check(arg):
"""Decorator to indicate that annotations are not type hints.
@ -1183,8 +1212,42 @@ def no_type_check_decorator(decorator):
return wrapped_decorator
def _overload_dummy(*args, **kwds):
"""Helper for @overload to raise when called."""
raise NotImplementedError(
"You should not call an overloaded function. "
"A series of @overload-decorated functions "
"outside a stub module should always be followed "
"by an implementation that is not @overload-ed.")
def overload(func):
raise RuntimeError("Overloading is only supported in library stubs")
"""Decorator for overloaded functions/methods.
In a stub file, place two or more stub definitions for the same
function in a row, each decorated with @overload. For example:
@overload
def utf8(value: None) -> None: ...
@overload
def utf8(value: bytes) -> bytes: ...
@overload
def utf8(value: str) -> bytes: ...
In a non-stub file (i.e. a regular .py file), do the same but
follow it with an implementation. The implementation should *not*
be decorated with @overload. For example:
@overload
def utf8(value: None) -> None: ...
@overload
def utf8(value: bytes) -> bytes: ...
@overload
def utf8(value: str) -> bytes: ...
def utf8(value):
# implementation goes here
"""
return _overload_dummy
class _ProtocolMeta(GenericMeta):
@ -1232,14 +1295,16 @@ class _ProtocolMeta(GenericMeta):
break
else:
if (not attr.startswith('_abc_') and
attr != '__abstractmethods__' and
attr != '_is_protocol' and
attr != '__dict__' and
attr != '__slots__' and
attr != '_get_protocol_attrs' and
attr != '__parameters__' and
attr != '__origin__' and
attr != '__module__'):
attr != '__abstractmethods__' and
attr != '_is_protocol' and
attr != '__dict__' and
attr != '__args__' and
attr != '__slots__' and
attr != '_get_protocol_attrs' and
attr != '__next_in_mro__' and
attr != '__parameters__' and
attr != '__origin__' and
attr != '__module__'):
attrs.add(attr)
return attrs
@ -1264,16 +1329,25 @@ class _Protocol(metaclass=_ProtocolMeta):
Hashable = collections_abc.Hashable # Not generic.
class Awaitable(Generic[T_co], extra=collections_abc.Awaitable):
__slots__ = ()
if hasattr(collections_abc, 'Awaitable'):
class Awaitable(Generic[T_co], extra=collections_abc.Awaitable):
__slots__ = ()
else:
Awaitable = None
class AsyncIterable(Generic[T_co], extra=collections_abc.AsyncIterable):
__slots__ = ()
if hasattr(collections_abc, 'AsyncIterable'):
class AsyncIterable(Generic[T_co], extra=collections_abc.AsyncIterable):
__slots__ = ()
class AsyncIterator(AsyncIterable[T_co], extra=collections_abc.AsyncIterator):
__slots__ = ()
class AsyncIterator(AsyncIterable[T_co],
extra=collections_abc.AsyncIterator):
__slots__ = ()
else:
AsyncIterable = None
AsyncIterator = None
class Iterable(Generic[T_co], extra=collections_abc.Iterable):
@ -1332,12 +1406,16 @@ class SupportsRound(_Protocol[T_co]):
pass
class Reversible(_Protocol[T_co]):
__slots__ = ()
if hasattr(collections_abc, 'Reversible'):
class Reversible(Iterable[T_co], extra=collections_abc.Reversible):
__slots__ = ()
else:
class Reversible(_Protocol[T_co]):
__slots__ = ()
@abstractmethod
def __reversed__(self) -> 'Iterator[T_co]':
pass
@abstractmethod
def __reversed__(self) -> 'Iterator[T_co]':
pass
Sized = collections_abc.Sized # Not generic.
@ -1360,7 +1438,7 @@ class MutableSet(AbstractSet[T], extra=collections_abc.MutableSet):
# NOTE: Only the value type is covariant.
class Mapping(Sized, Iterable[KT], Container[KT], Generic[VT_co],
class Mapping(Sized, Iterable[KT], Container[KT], Generic[KT, VT_co],
extra=collections_abc.Mapping):
pass
@ -1368,10 +1446,14 @@ class Mapping(Sized, Iterable[KT], Container[KT], Generic[VT_co],
class MutableMapping(Mapping[KT, VT], extra=collections_abc.MutableMapping):
pass
class Sequence(Sized, Iterable[T_co], Container[T_co],
if hasattr(collections_abc, 'Reversible'):
class Sequence(Sized, Reversible[T_co], Container[T_co],
extra=collections_abc.Sequence):
pass
pass
else:
class Sequence(Sized, Iterable[T_co], Container[T_co],
extra=collections_abc.Sequence):
pass
class MutableSequence(Sequence[T], extra=collections_abc.MutableSequence):
@ -1436,8 +1518,9 @@ class KeysView(MappingView[KT], AbstractSet[KT],
pass
# TODO: Enable Set[Tuple[KT, VT_co]] instead of Generic[KT, VT_co].
class ItemsView(MappingView, Generic[KT, VT_co],
class ItemsView(MappingView[Tuple[KT, VT_co]],
Set[Tuple[KT, VT_co]],
Generic[KT, VT_co],
extra=collections_abc.ItemsView):
pass
@ -1454,6 +1537,13 @@ class Dict(dict, MutableMapping[KT, VT]):
"use dict() instead")
return dict.__new__(cls, *args, **kwds)
class DefaultDict(collections.defaultdict, MutableMapping[KT, VT]):
def __new__(cls, *args, **kwds):
if _geqv(cls, DefaultDict):
raise TypeError("Type DefaultDict cannot be instantiated; "
"use collections.defaultdict() instead")
return collections.defaultdict.__new__(cls, *args, **kwds)
# Determine what base class to use for Generator.
if hasattr(collections_abc, 'Generator'):