Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e5ebb8d
gh-74696: Pass root_dir to custom archivers which support it
serhiy-storchaka Jun 22, 2022
563b0f5
Update Doc/library/shutil.rst
serhiy-storchaka Jun 25, 2022
2190304
Merge branch 'main' into shutil-register_archive_format-supports_root…
Sep 29, 2022
7dc8fb3
closes gh-97650: correct sphinx executable (gh-97651)
NoSuck Sep 29, 2022
679cf96
gh-96397: Document that attributes need not be identifiers (#96454)
jeff5 Sep 29, 2022
3c84af2
gh-96348: Deprecate the 3-arg signature of coroutine.throw and genera…
ofey404 Sep 30, 2022
8a0ad46
Use SyntaxError invalid range in tutorial introduction example (GH-93…
ehebert Sep 30, 2022
182755f
gh-97649: The Tools directory is no longer installed on Windows (GH-9…
zooba Sep 30, 2022
b1a9de0
gh-90989: Install Windows launcher per-user, and clarify some install…
zooba Sep 30, 2022
cc1e8e0
gh-94526: getpath_dirname() no longer encodes the path (#97645)
vstinner Sep 30, 2022
8fd0e86
bpo-35675: IDLE - separate config_key window and frame (#11427)
csabella Sep 30, 2022
d1d6b31
gh-87597: Document TimeoutExpired.stdout & .stderr types (#97685)
gpshead Sep 30, 2022
c6203f8
GH-96827: Don't touch closed loops from executor threads (#96837)
gvanrossum Sep 30, 2022
67851dc
GH-97592: Fix crash in C remove_done_callback due to evil code (#97660)
gvanrossum Sep 30, 2022
4c95e50
gh-90110: Update the c-analyzer Tool (gh-97695)
ericsnowcurrently Oct 1, 2022
fb39e7f
gh-90908: Document asyncio.Task.cancelling() and asyncio.Task.uncance…
ambv Oct 1, 2022
0bb7e71
Fix capitalization of Unix in documentation (#96913)
hawkinsw Oct 1, 2022
5ffc011
gh-95588: Drop the safety claim from `ast.literal_eval` docs. (#95919)
gpshead Oct 2, 2022
e401b65
gh-97591: In `Exception.__setstate__()` acquire strong references bef…
ofey404 Oct 2, 2022
879e866
gh-95975: Move except/*/finally ref labels to more precise locations …
CAM-Gerlach Oct 2, 2022
299dd41
gh-97607: Fix content parsing in the impl-detail reST directive (#97652)
CAM-Gerlach Oct 2, 2022
551b707
[docs] Update logging cookbook with recipe for using a logger like an…
vsajip Oct 2, 2022
b37f2cd
Refactor tests.
serhiy-storchaka Oct 2, 2022
bf58b11
Merge branch 'main' into shutil-register_archive_format-supports_root…
serhiy-storchaka Oct 2, 2022
9980c8c
Apply suggestions from code review
serhiy-storchaka Oct 4, 2022
5160cb7
fix markup
merwok Oct 4, 2022
701f896
Update Doc/whatsnew/3.12.rst
serhiy-storchaka Oct 5, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
gh-96348: Deprecate the 3-arg signature of coroutine.throw and genera…
…tor.throw (GH-96428)
  • Loading branch information
ofey404 authored and serhiy-storchaka committed Oct 2, 2022
commit 3c84af2d0ce28999004254a18c472a98ebee25e2
5 changes: 5 additions & 0 deletions Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2996,6 +2996,11 @@ generators, coroutines do not directly support iteration.
above. If the exception is not caught in the coroutine, it propagates
back to the caller.

.. versionchanged:: 3.12

The second signature \(type\[, value\[, traceback\]\]\) is deprecated and
may be removed in a future version of Python.

.. method:: coroutine.close()

Causes the coroutine to clean itself up and exit. If the coroutine
Expand Down
13 changes: 12 additions & 1 deletion Doc/reference/expressions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,11 @@ is already executing raises a :exc:`ValueError` exception.
:attr:`~BaseException.__traceback__` attribute stored in *value* may
be cleared.

.. versionchanged:: 3.12

The second signature \(type\[, value\[, traceback\]\]\) is deprecated and
may be removed in a future version of Python.

.. index:: exception: GeneratorExit


Expand Down Expand Up @@ -738,7 +743,8 @@ which are used to control the execution of a generator function.
because there is no yield expression that could receive the value.


.. coroutinemethod:: agen.athrow(type[, value[, traceback]])
.. coroutinemethod:: agen.athrow(value)
agen.athrow(type[, value[, traceback]])

Returns an awaitable that raises an exception of type ``type`` at the point
where the asynchronous generator was paused, and returns the next value
Expand All @@ -750,6 +756,11 @@ which are used to control the execution of a generator function.
raises a different exception, then when the awaitable is run that exception
propagates to the caller of the awaitable.

.. versionchanged:: 3.12

The second signature \(type\[, value\[, traceback\]\]\) is deprecated and
may be removed in a future version of Python.

.. index:: exception: GeneratorExit


Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.12.rst
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ Deprecated
and tailor them to your needs.
(Contributed by Erlend E. Aasland in :gh:`90016`.)

* The 3-arg signatures (type, value, traceback) of :meth:`~coroutine.throw`,
:meth:`~generator.throw` and :meth:`~agen.athrow` are deprecated and
may be removed in a future version of Python. Use the single-arg versions
of these functions instead. (Contributed by Ofey Chan in :gh:`89874`.)


Pending Removal in Python 3.13
------------------------------
Expand Down
4 changes: 2 additions & 2 deletions Lib/contextlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def __exit__(self, typ, value, traceback):
# tell if we get the same exception back
value = typ()
try:
self.gen.throw(typ, value, traceback)
self.gen.throw(value)
except StopIteration as exc:
# Suppress StopIteration *unless* it's the same exception that
# was passed to throw(). This prevents a StopIteration
Expand Down Expand Up @@ -219,7 +219,7 @@ async def __aexit__(self, typ, value, traceback):
# tell if we get the same exception back
value = typ()
try:
await self.gen.athrow(typ, value, traceback)
await self.gen.athrow(value)
except StopAsyncIteration as exc:
# Suppress StopIteration *unless* it's the same exception that
# was passed to throw(). This prevents a StopIteration
Expand Down
22 changes: 15 additions & 7 deletions Lib/test/test_asyncgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import types
import unittest
import contextlib
import warnings

from test.support.import_helper import import_module
from test.support import gc_collect, requires_working_socket
Expand Down Expand Up @@ -377,6 +378,13 @@ async def async_gen_wrapper():

self.compare_generators(sync_gen_wrapper(), async_gen_wrapper())

def test_async_gen_3_arg_deprecation_warning(self):
async def gen():
yield 123

with self.assertWarns(DeprecationWarning):
gen().athrow(GeneratorExit, GeneratorExit(), None)

def test_async_gen_api_01(self):
async def gen():
yield 123
Expand Down Expand Up @@ -650,7 +658,7 @@ def test1(anext):
agen = agenfn()
with contextlib.closing(anext(agen, "default").__await__()) as g:
self.assertEqual(g.send(None), 1)
self.assertEqual(g.throw(MyError, MyError(), None), 2)
self.assertEqual(g.throw(MyError()), 2)
try:
g.send(None)
except StopIteration as e:
Expand All @@ -663,9 +671,9 @@ def test2(anext):
agen = agenfn()
with contextlib.closing(anext(agen, "default").__await__()) as g:
self.assertEqual(g.send(None), 1)
self.assertEqual(g.throw(MyError, MyError(), None), 2)
self.assertEqual(g.throw(MyError()), 2)
with self.assertRaises(MyError):
g.throw(MyError, MyError(), None)
g.throw(MyError())

def test3(anext):
agen = agenfn()
Expand All @@ -692,9 +700,9 @@ async def agenfn():
agen = agenfn()
with contextlib.closing(anext(agen, "default").__await__()) as g:
self.assertEqual(g.send(None), 10)
self.assertEqual(g.throw(MyError, MyError(), None), 20)
self.assertEqual(g.throw(MyError()), 20)
with self.assertRaisesRegex(MyError, 'val'):
g.throw(MyError, MyError('val'), None)
g.throw(MyError('val'))

def test5(anext):
@types.coroutine
Expand All @@ -713,7 +721,7 @@ async def agenfn():
with contextlib.closing(anext(agen, "default").__await__()) as g:
self.assertEqual(g.send(None), 10)
with self.assertRaisesRegex(StopIteration, 'default'):
g.throw(MyError, MyError(), None)
g.throw(MyError())

def test6(anext):
@types.coroutine
Expand All @@ -728,7 +736,7 @@ async def agenfn():
agen = agenfn()
with contextlib.closing(anext(agen, "default").__await__()) as g:
with self.assertRaises(MyError):
g.throw(MyError, MyError(), None)
g.throw(MyError())

def run_test(test):
with self.subTest('pure-Python anext()'):
Expand Down
13 changes: 9 additions & 4 deletions Lib/test/test_asyncio/test_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from types import GenericAlias
import asyncio
from asyncio import futures
import warnings
from test.test_asyncio import utils as test_utils
from test import support

Expand Down Expand Up @@ -619,10 +620,14 @@ def test_future_stop_iteration_args(self):
def test_future_iter_throw(self):
fut = self._new_future(loop=self.loop)
fi = iter(fut)
self.assertRaises(TypeError, fi.throw,
Exception, Exception("elephant"), 32)
self.assertRaises(TypeError, fi.throw,
Exception("elephant"), Exception("elephant"))
with self.assertWarns(DeprecationWarning):
self.assertRaises(Exception, fi.throw, Exception, Exception("zebra"), None)
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
self.assertRaises(TypeError, fi.throw,
Exception, Exception("elephant"), 32)
self.assertRaises(TypeError, fi.throw,
Exception("elephant"), Exception("elephant"))
self.assertRaises(TypeError, fi.throw, list)

def test_future_del_collect(self):
Expand Down
9 changes: 8 additions & 1 deletion Lib/test/test_coroutines.py
Original file line number Diff line number Diff line change
Expand Up @@ -709,9 +709,16 @@ async def foo():
aw = coro.__await__()
next(aw)
with self.assertRaises(ZeroDivisionError):
aw.throw(ZeroDivisionError, None, None)
aw.throw(ZeroDivisionError())
self.assertEqual(N, 102)

coro = foo()
aw = coro.__await__()
next(aw)
with self.assertRaises(ZeroDivisionError):
with self.assertWarns(DeprecationWarning):
aw.throw(ZeroDivisionError, ZeroDivisionError(), None)

def test_func_11(self):
async def func(): pass
coro = func()
Expand Down
21 changes: 21 additions & 0 deletions Lib/test/test_generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,15 @@ def generator():
with self.assertRaises(StopIteration):
gen.throw(E)

def test_gen_3_arg_deprecation_warning(self):
def g():
yield 42

gen = g()
with self.assertWarns(DeprecationWarning):
with self.assertRaises(TypeError):
gen.throw(TypeError, TypeError(24), None)

def test_stopiteration_error(self):
# See also PEP 479.

Expand Down Expand Up @@ -2113,6 +2122,12 @@ def printsolution(self, x):
>>> g.throw(ValueError("xyz")) # value only
caught ValueError (xyz)

>>> import warnings
>>> warnings.filterwarnings("ignore", category=DeprecationWarning)

# Filter DeprecationWarning: regarding the (type, val, tb) signature of throw().
# Deprecation warnings are re-enabled below.

>>> g.throw(ValueError, ValueError(1)) # value+matching type
caught ValueError (1)

Expand Down Expand Up @@ -2181,6 +2196,12 @@ def printsolution(self, x):
...
ValueError: 7

>>> warnings.filters.pop(0)
('ignore', None, <class 'DeprecationWarning'>, None, 0)

# Re-enable DeprecationWarning: the (type, val, tb) exception representation is deprecated,
# and may be removed in a future version of Python.

Plain "raise" inside a generator should preserve the traceback (#13188).
The traceback should have 3 levels:
- g.throw()
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2072,7 +2072,7 @@ def foo(): return gen
wrapper = foo()
wrapper.send(None)
with self.assertRaisesRegex(Exception, 'ham'):
wrapper.throw(Exception, Exception('ham'))
wrapper.throw(Exception('ham'))

# decorate foo second time
foo = types.coroutine(foo)
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ Michael Cetrulo
Dave Chambers
Pascal Chambon
Nicholas Chammas
Ofey Chan
John Chandler
Hye-Shik Chang
Jeffrey Chang
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Emit a DeprecationWarning when :meth:`~generator.throw`, :meth:`~coroutine.throw` or :meth:`~agen.athrow`
are called with more than one argument.
8 changes: 8 additions & 0 deletions Modules/_asynciomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1668,6 +1668,14 @@ FutureIter_throw(futureiterobject *self, PyObject *const *args, Py_ssize_t nargs
if (!_PyArg_CheckPositional("throw", nargs, 1, 3)) {
return NULL;
}
if (nargs > 1) {
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"the (type, exc, tb) signature of throw() is deprecated, "
"use the single-arg signature instead.",
1) < 0) {
return NULL;
}
}

type = args[0];
if (nargs == 3) {
Expand Down
32 changes: 29 additions & 3 deletions Objects/genobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,9 @@ PyDoc_STRVAR(throw_doc,
throw(type[,value[,tb]])\n\
\n\
Raise exception in generator, return next yielded value or raise\n\
StopIteration.");
StopIteration.\n\
the (type, val, tb) signature is deprecated, \n\
and may be removed in a future version of Python.");

static PyObject *
_gen_throw(PyGenObject *gen, int close_on_genexit,
Expand Down Expand Up @@ -559,6 +561,14 @@ gen_throw(PyGenObject *gen, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("throw", nargs, 1, 3)) {
return NULL;
}
if (nargs > 1) {
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"the (type, exc, tb) signature of throw() is deprecated, "
"use the single-arg signature instead.",
1) < 0) {
return NULL;
}
}
typ = args[0];
if (nargs == 3) {
val = args[1];
Expand Down Expand Up @@ -1147,7 +1157,10 @@ PyDoc_STRVAR(coro_throw_doc,
throw(type[,value[,traceback]])\n\
\n\
Raise exception in coroutine, return next iterated value or raise\n\
StopIteration.");
StopIteration.\n\
the (type, val, tb) signature is deprecated, \n\
and may be removed in a future version of Python.");


PyDoc_STRVAR(coro_close_doc,
"close() -> raise GeneratorExit inside coroutine.");
Expand Down Expand Up @@ -1500,6 +1513,14 @@ async_gen_aclose(PyAsyncGenObject *o, PyObject *arg)
static PyObject *
async_gen_athrow(PyAsyncGenObject *o, PyObject *args)
{
if (PyTuple_GET_SIZE(args) > 1) {
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"the (type, exc, tb) signature of athrow() is deprecated, "
"use the single-arg signature instead.",
1) < 0) {
return NULL;
}
}
if (async_gen_init_hooks(o)) {
return NULL;
}
Expand Down Expand Up @@ -1537,7 +1558,12 @@ PyDoc_STRVAR(async_asend_doc,
"asend(v) -> send 'v' in generator.");

PyDoc_STRVAR(async_athrow_doc,
"athrow(typ[,val[,tb]]) -> raise exception in generator.");
"athrow(value)\n\
athrow(type[,value[,tb]])\n\
\n\
raise exception in generator.\n\
the (type, val, tb) signature is deprecated, \n\
and may be removed in a future version of Python.");

static PyMethodDef async_gen_methods[] = {
{"asend", (PyCFunction)async_gen_asend, METH_O, async_asend_doc},
Expand Down
9 changes: 7 additions & 2 deletions Objects/iterobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,13 @@ return next yielded value or raise StopIteration.");


PyDoc_STRVAR(throw_doc,
"throw(typ[,val[,tb]]) -> raise exception in the wrapped iterator,\n\
return next yielded value or raise StopIteration.");
"throw(value)\n\
throw(typ[,val[,tb]])\n\
\n\
raise exception in the wrapped iterator, return next yielded value\n\
or raise StopIteration.\n\
the (type, val, tb) signature is deprecated, \n\
and may be removed in a future version of Python.");


PyDoc_STRVAR(close_doc,
Expand Down