Skip to content

Commit 8419f01

Browse files
JelleZijlstraAlexWaygoodsobolevn
authored
gh-118647: Add defaults to typing.Generator and typing.AsyncGenerator (#118648)
Co-authored-by: Alex Waygood <[email protected]> Co-authored-by: Nikita Sobolev <[email protected]>
1 parent 9fd33af commit 8419f01

File tree

4 files changed

+51
-9
lines changed

4 files changed

+51
-9
lines changed

Doc/library/typing.rst

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3648,8 +3648,14 @@ Aliases to asynchronous ABCs in :mod:`collections.abc`
36483648
is no ``ReturnType`` type parameter. As with :class:`Generator`, the
36493649
``SendType`` behaves contravariantly.
36503650

3651-
If your generator will only yield values, set the ``SendType`` to
3652-
``None``::
3651+
The ``SendType`` defaults to :const:`!None`::
3652+
3653+
async def infinite_stream(start: int) -> AsyncGenerator[int]:
3654+
while True:
3655+
yield start
3656+
start = await increment(start)
3657+
3658+
It is also possible to set this type explicitly::
36533659

36543660
async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
36553661
while True:
@@ -3671,6 +3677,9 @@ Aliases to asynchronous ABCs in :mod:`collections.abc`
36713677
now supports subscripting (``[]``).
36723678
See :pep:`585` and :ref:`types-genericalias`.
36733679

3680+
.. versionchanged:: 3.13
3681+
The ``SendType`` parameter now has a default.
3682+
36743683
.. class:: AsyncIterable(Generic[T_co])
36753684

36763685
Deprecated alias to :class:`collections.abc.AsyncIterable`.
@@ -3754,8 +3763,14 @@ Aliases to other ABCs in :mod:`collections.abc`
37543763
of :class:`Generator` behaves contravariantly, not covariantly or
37553764
invariantly.
37563765

3757-
If your generator will only yield values, set the ``SendType`` and
3758-
``ReturnType`` to ``None``::
3766+
The ``SendType`` and ``ReturnType`` parameters default to :const:`!None`::
3767+
3768+
def infinite_stream(start: int) -> Generator[int]:
3769+
while True:
3770+
yield start
3771+
start += 1
3772+
3773+
It is also possible to set these types explicitly::
37593774

37603775
def infinite_stream(start: int) -> Generator[int, None, None]:
37613776
while True:
@@ -3774,6 +3789,9 @@ Aliases to other ABCs in :mod:`collections.abc`
37743789
:class:`collections.abc.Generator` now supports subscripting (``[]``).
37753790
See :pep:`585` and :ref:`types-genericalias`.
37763791

3792+
.. versionchanged:: 3.13
3793+
Default values for the send and return types were added.
3794+
37773795
.. class:: Hashable
37783796

37793797
Deprecated alias to :class:`collections.abc.Hashable`.

Lib/test/test_typing.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7289,6 +7289,17 @@ def foo():
72897289
g = foo()
72907290
self.assertIsSubclass(type(g), typing.Generator)
72917291

7292+
def test_generator_default(self):
7293+
g1 = typing.Generator[int]
7294+
g2 = typing.Generator[int, None, None]
7295+
self.assertEqual(get_args(g1), (int, type(None), type(None)))
7296+
self.assertEqual(get_args(g1), get_args(g2))
7297+
7298+
g3 = typing.Generator[int, float]
7299+
g4 = typing.Generator[int, float, None]
7300+
self.assertEqual(get_args(g3), (int, float, type(None)))
7301+
self.assertEqual(get_args(g3), get_args(g4))
7302+
72927303
def test_no_generator_instantiation(self):
72937304
with self.assertRaises(TypeError):
72947305
typing.Generator()

Lib/typing.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,7 +1328,7 @@ def __getattr__(self, attr):
13281328
raise AttributeError(attr)
13291329

13301330
def __setattr__(self, attr, val):
1331-
if _is_dunder(attr) or attr in {'_name', '_inst', '_nparams'}:
1331+
if _is_dunder(attr) or attr in {'_name', '_inst', '_nparams', '_defaults'}:
13321332
super().__setattr__(attr, val)
13331333
else:
13341334
setattr(self.__origin__, attr, val)
@@ -1578,11 +1578,12 @@ def __iter__(self):
15781578
# parameters are accepted (needs custom __getitem__).
15791579

15801580
class _SpecialGenericAlias(_NotIterable, _BaseGenericAlias, _root=True):
1581-
def __init__(self, origin, nparams, *, inst=True, name=None):
1581+
def __init__(self, origin, nparams, *, inst=True, name=None, defaults=()):
15821582
if name is None:
15831583
name = origin.__name__
15841584
super().__init__(origin, inst=inst, name=name)
15851585
self._nparams = nparams
1586+
self._defaults = defaults
15861587
if origin.__module__ == 'builtins':
15871588
self.__doc__ = f'A generic version of {origin.__qualname__}.'
15881589
else:
@@ -1594,12 +1595,22 @@ def __getitem__(self, params):
15941595
params = (params,)
15951596
msg = "Parameters to generic types must be types."
15961597
params = tuple(_type_check(p, msg) for p in params)
1598+
if (self._defaults
1599+
and len(params) < self._nparams
1600+
and len(params) + len(self._defaults) >= self._nparams
1601+
):
1602+
params = (*params, *self._defaults[len(params) - self._nparams:])
15971603
actual_len = len(params)
1604+
15981605
if actual_len != self._nparams:
1606+
if self._defaults:
1607+
expected = f"at least {self._nparams - len(self._defaults)}"
1608+
else:
1609+
expected = str(self._nparams)
15991610
if not self._nparams:
16001611
raise TypeError(f"{self} is not a generic class")
16011612
raise TypeError(f"Too {'many' if actual_len > self._nparams else 'few'} arguments for {self};"
1602-
f" actual {actual_len}, expected {self._nparams}")
1613+
f" actual {actual_len}, expected {expected}")
16031614
return self.copy_with(params)
16041615

16051616
def copy_with(self, params):
@@ -2813,8 +2824,8 @@ class Other(Leaf): # Error reported by type checker
28132824
OrderedDict = _alias(collections.OrderedDict, 2)
28142825
Counter = _alias(collections.Counter, 1)
28152826
ChainMap = _alias(collections.ChainMap, 2)
2816-
Generator = _alias(collections.abc.Generator, 3)
2817-
AsyncGenerator = _alias(collections.abc.AsyncGenerator, 2)
2827+
Generator = _alias(collections.abc.Generator, 3, defaults=(types.NoneType, types.NoneType))
2828+
AsyncGenerator = _alias(collections.abc.AsyncGenerator, 2, defaults=(types.NoneType,))
28182829
Type = _alias(type, 1, inst=False, name='Type')
28192830
Type.__doc__ = \
28202831
"""Deprecated alias to builtins.type.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add type parameter defaults to :class:`typing.Generator` and
2+
:class:`typing.AsyncGenerator`.

0 commit comments

Comments
 (0)