summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/typing.rst26
-rw-r--r--Lib/test/test_typing.py11
-rw-r--r--Lib/typing.py21
-rw-r--r--Misc/NEWS.d/next/Library/2024-05-06-08-23-01.gh-issue-118648.OVA3jJ.rst2
4 files changed, 51 insertions, 9 deletions
diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
index e062872..652a3f1 100644
--- a/Doc/library/typing.rst
+++ b/Doc/library/typing.rst
@@ -3648,8 +3648,14 @@ Aliases to asynchronous ABCs in :mod:`collections.abc`
is no ``ReturnType`` type parameter. As with :class:`Generator`, the
``SendType`` behaves contravariantly.
- If your generator will only yield values, set the ``SendType`` to
- ``None``::
+ The ``SendType`` defaults to :const:`!None`::
+
+ async def infinite_stream(start: int) -> AsyncGenerator[int]:
+ while True:
+ yield start
+ start = await increment(start)
+
+ It is also possible to set this type explicitly::
async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
while True:
@@ -3671,6 +3677,9 @@ Aliases to asynchronous ABCs in :mod:`collections.abc`
now supports subscripting (``[]``).
See :pep:`585` and :ref:`types-genericalias`.
+ .. versionchanged:: 3.13
+ The ``SendType`` parameter now has a default.
+
.. class:: AsyncIterable(Generic[T_co])
Deprecated alias to :class:`collections.abc.AsyncIterable`.
@@ -3754,8 +3763,14 @@ Aliases to other ABCs in :mod:`collections.abc`
of :class:`Generator` behaves contravariantly, not covariantly or
invariantly.
- If your generator will only yield values, set the ``SendType`` and
- ``ReturnType`` to ``None``::
+ The ``SendType`` and ``ReturnType`` parameters default to :const:`!None`::
+
+ def infinite_stream(start: int) -> Generator[int]:
+ while True:
+ yield start
+ start += 1
+
+ It is also possible to set these types explicitly::
def infinite_stream(start: int) -> Generator[int, None, None]:
while True:
@@ -3774,6 +3789,9 @@ Aliases to other ABCs in :mod:`collections.abc`
:class:`collections.abc.Generator` now supports subscripting (``[]``).
See :pep:`585` and :ref:`types-genericalias`.
+ .. versionchanged:: 3.13
+ Default values for the send and return types were added.
+
.. class:: Hashable
Deprecated alias to :class:`collections.abc.Hashable`.
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 112db03..8f0be1f 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -7289,6 +7289,17 @@ class CollectionsAbcTests(BaseTestCase):
g = foo()
self.assertIsSubclass(type(g), typing.Generator)
+ def test_generator_default(self):
+ g1 = typing.Generator[int]
+ g2 = typing.Generator[int, None, None]
+ self.assertEqual(get_args(g1), (int, type(None), type(None)))
+ self.assertEqual(get_args(g1), get_args(g2))
+
+ g3 = typing.Generator[int, float]
+ g4 = typing.Generator[int, float, None]
+ self.assertEqual(get_args(g3), (int, float, type(None)))
+ self.assertEqual(get_args(g3), get_args(g4))
+
def test_no_generator_instantiation(self):
with self.assertRaises(TypeError):
typing.Generator()
diff --git a/Lib/typing.py b/Lib/typing.py
index ff0e9b8..c159fcf 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -1328,7 +1328,7 @@ class _BaseGenericAlias(_Final, _root=True):
raise AttributeError(attr)
def __setattr__(self, attr, val):
- if _is_dunder(attr) or attr in {'_name', '_inst', '_nparams'}:
+ if _is_dunder(attr) or attr in {'_name', '_inst', '_nparams', '_defaults'}:
super().__setattr__(attr, val)
else:
setattr(self.__origin__, attr, val)
@@ -1578,11 +1578,12 @@ class _GenericAlias(_BaseGenericAlias, _root=True):
# parameters are accepted (needs custom __getitem__).
class _SpecialGenericAlias(_NotIterable, _BaseGenericAlias, _root=True):
- def __init__(self, origin, nparams, *, inst=True, name=None):
+ def __init__(self, origin, nparams, *, inst=True, name=None, defaults=()):
if name is None:
name = origin.__name__
super().__init__(origin, inst=inst, name=name)
self._nparams = nparams
+ self._defaults = defaults
if origin.__module__ == 'builtins':
self.__doc__ = f'A generic version of {origin.__qualname__}.'
else:
@@ -1594,12 +1595,22 @@ class _SpecialGenericAlias(_NotIterable, _BaseGenericAlias, _root=True):
params = (params,)
msg = "Parameters to generic types must be types."
params = tuple(_type_check(p, msg) for p in params)
+ if (self._defaults
+ and len(params) < self._nparams
+ and len(params) + len(self._defaults) >= self._nparams
+ ):
+ params = (*params, *self._defaults[len(params) - self._nparams:])
actual_len = len(params)
+
if actual_len != self._nparams:
+ if self._defaults:
+ expected = f"at least {self._nparams - len(self._defaults)}"
+ else:
+ expected = str(self._nparams)
if not self._nparams:
raise TypeError(f"{self} is not a generic class")
raise TypeError(f"Too {'many' if actual_len > self._nparams else 'few'} arguments for {self};"
- f" actual {actual_len}, expected {self._nparams}")
+ f" actual {actual_len}, expected {expected}")
return self.copy_with(params)
def copy_with(self, params):
@@ -2813,8 +2824,8 @@ 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)
+Generator = _alias(collections.abc.Generator, 3, defaults=(types.NoneType, types.NoneType))
+AsyncGenerator = _alias(collections.abc.AsyncGenerator, 2, defaults=(types.NoneType,))
Type = _alias(type, 1, inst=False, name='Type')
Type.__doc__ = \
"""Deprecated alias to builtins.type.
diff --git a/Misc/NEWS.d/next/Library/2024-05-06-08-23-01.gh-issue-118648.OVA3jJ.rst b/Misc/NEWS.d/next/Library/2024-05-06-08-23-01.gh-issue-118648.OVA3jJ.rst
new file mode 100644
index 0000000..7695fb0
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-05-06-08-23-01.gh-issue-118648.OVA3jJ.rst
@@ -0,0 +1,2 @@
+Add type parameter defaults to :class:`typing.Generator` and
+:class:`typing.AsyncGenerator`.