From: Matthias Bussonnier Date: Tue, 28 May 2019 07:10:59 +0000 (-0700) Subject: bpo-36933: Remove sys.set_coroutine_wrapper (marked for removal in 3.8) (GH-13577) X-Git-Tag: v3.8.0b1~177 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3880f263d2994fb1eba25835dddccb0cf696fdf0;p=python bpo-36933: Remove sys.set_coroutine_wrapper (marked for removal in 3.8) (GH-13577) It has been documented as deprecated and to be removed in 3.8; From a comment on another thread – which I can't find ; leave get_coro_wrapper() for now, but always return `None`. https://bugs.python.org/issue36933 --- diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 74aa2711dd..5bde687071 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -781,22 +781,6 @@ always available. for details.) Use it only for debugging purposes. -.. function:: get_coroutine_wrapper() - - Returns ``None``, or a wrapper set by :func:`set_coroutine_wrapper`. - - .. versionadded:: 3.5 - See :pep:`492` for more details. - - .. note:: - This function has been added on a provisional basis (see :pep:`411` - for details.) Use it only for debugging purposes. - - .. deprecated:: 3.7 - The coroutine wrapper functionality has been deprecated, and - will be removed in 3.8. See :issue:`32591` for details. - - .. data:: hash_info A :term:`struct sequence` giving parameters of the numeric hash @@ -1384,49 +1368,6 @@ always available. This function has been added on a provisional basis (see :pep:`411` for details.) Use it only for debugging purposes. -.. function:: set_coroutine_wrapper(wrapper) - - Allows intercepting creation of :term:`coroutine` objects (only ones that - are created by an :keyword:`async def` function; generators decorated with - :func:`types.coroutine` or :func:`asyncio.coroutine` will not be - intercepted). - - The *wrapper* argument must be either: - - * a callable that accepts one argument (a coroutine object); - * ``None``, to reset the wrapper. - - If called twice, the new wrapper replaces the previous one. The function - is thread-specific. - - The *wrapper* callable cannot define new coroutines directly or indirectly:: - - def wrapper(coro): - async def wrap(coro): - return await coro - return wrap(coro) - sys.set_coroutine_wrapper(wrapper) - - async def foo(): - pass - - # The following line will fail with a RuntimeError, because - # ``wrapper`` creates a ``wrap(coro)`` coroutine: - foo() - - See also :func:`get_coroutine_wrapper`. - - .. versionadded:: 3.5 - See :pep:`492` for more details. - - .. note:: - This function has been added on a provisional basis (see :pep:`411` - for details.) Use it only for debugging purposes. - - .. deprecated-removed:: 3.7 3.8 - The coroutine wrapper functionality has been deprecated, and - will be removed in 3.8. See :issue:`32591` for details. - .. function:: _enablelegacywindowsfsencoding() Changes the default filesystem encoding and errors mode to 'mbcs' and diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv index a0e7868a03..85263d47c8 100644 --- a/Doc/tools/susp-ignored.csv +++ b/Doc/tools/susp-ignored.csv @@ -337,7 +337,6 @@ library/zipapp,,:main,"$ python -m zipapp myapp -m ""myapp:main""" library/zipapp,,:fn,"pkg.mod:fn" library/zipapp,,:callable,"pkg.module:callable" library/stdtypes,,::,>>> m[::2].tolist() -library/sys,,`,# ``wrapper`` creates a ``wrap(coro)`` coroutine: whatsnew/3.5,,:root,'WARNING:root:warning\n' whatsnew/3.5,,:warning,'WARNING:root:warning\n' whatsnew/3.5,,::,>>> addr6 = ipaddress.IPv6Address('::1') diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 125cefe111..860d6cc18f 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -973,6 +973,10 @@ The following features and APIs have been removed from Python 3.8: :func:`fileinput.FileInput` which was ignored and deprecated since Python 3.6 has been removed. :issue:`36952` (Contributed by Matthias Bussonnier) +* The function :func:`sys.set_coroutine_wrapper` deprecated in Python 3.7 has + been removed; :func:`sys.get_coroutine_wrapper` now always return ``None``. + :issue:`36933` (Contributed by Matthias Bussonnier) + Porting to Python 3.8 ===================== diff --git a/Include/ceval.h b/Include/ceval.h index 8cdf353b05..6fb224b288 100644 --- a/Include/ceval.h +++ b/Include/ceval.h @@ -33,8 +33,6 @@ PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *); PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *); PyAPI_FUNC(void) _PyEval_SetCoroutineOriginTrackingDepth(int new_depth); PyAPI_FUNC(int) _PyEval_GetCoroutineOriginTrackingDepth(void); -PyAPI_FUNC(void) _PyEval_SetCoroutineWrapper(PyObject *); -PyAPI_FUNC(PyObject *) _PyEval_GetCoroutineWrapper(void); PyAPI_FUNC(void) _PyEval_SetAsyncGenFirstiter(PyObject *); PyAPI_FUNC(PyObject *) _PyEval_GetAsyncGenFirstiter(void); PyAPI_FUNC(void) _PyEval_SetAsyncGenFinalizer(PyObject *); diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 6b7663fe33..94b0809cd4 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -126,9 +126,6 @@ struct _ts { int coroutine_origin_tracking_depth; - PyObject *coroutine_wrapper; - int in_coroutine_wrapper; - PyObject *async_gen_firstiter; PyObject *async_gen_finalizer; diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 036f13fa50..0e7eb3a1af 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -2146,99 +2146,6 @@ class CoroAsyncIOCompatTest(unittest.TestCase): self.assertEqual(buffer, [1, 2, 'MyException']) -class SysSetCoroWrapperTest(unittest.TestCase): - - def test_set_wrapper_1(self): - async def foo(): - return 'spam' - - wrapped = None - def wrap(gen): - nonlocal wrapped - wrapped = gen - return gen - - with self.assertWarns(DeprecationWarning): - self.assertIsNone(sys.get_coroutine_wrapper()) - - with self.assertWarns(DeprecationWarning): - sys.set_coroutine_wrapper(wrap) - with self.assertWarns(DeprecationWarning): - self.assertIs(sys.get_coroutine_wrapper(), wrap) - try: - f = foo() - self.assertTrue(wrapped) - - self.assertEqual(run_async(f), ([], 'spam')) - finally: - with self.assertWarns(DeprecationWarning): - sys.set_coroutine_wrapper(None) - f.close() - - with self.assertWarns(DeprecationWarning): - self.assertIsNone(sys.get_coroutine_wrapper()) - - wrapped = None - coro = foo() - self.assertFalse(wrapped) - coro.close() - - def test_set_wrapper_2(self): - with self.assertWarns(DeprecationWarning): - self.assertIsNone(sys.get_coroutine_wrapper()) - with self.assertRaisesRegex(TypeError, "callable expected, got int"): - with self.assertWarns(DeprecationWarning): - sys.set_coroutine_wrapper(1) - with self.assertWarns(DeprecationWarning): - self.assertIsNone(sys.get_coroutine_wrapper()) - - def test_set_wrapper_3(self): - async def foo(): - return 'spam' - - def wrapper(coro): - async def wrap(coro): - return await coro - return wrap(coro) - - with self.assertWarns(DeprecationWarning): - sys.set_coroutine_wrapper(wrapper) - try: - with silence_coro_gc(), self.assertRaisesRegex( - RuntimeError, - r"coroutine wrapper.*\.wrapper at 0x.*attempted to " - r"recursively wrap .* wrap .*"): - - foo() - - finally: - with self.assertWarns(DeprecationWarning): - sys.set_coroutine_wrapper(None) - - def test_set_wrapper_4(self): - @types.coroutine - def foo(): - return 'spam' - - wrapped = None - def wrap(gen): - nonlocal wrapped - wrapped = gen - return gen - - with self.assertWarns(DeprecationWarning): - sys.set_coroutine_wrapper(wrap) - try: - foo() - self.assertIs( - wrapped, None, - "generator-based coroutine was wrapped via " - "sys.set_coroutine_wrapper") - finally: - with self.assertWarns(DeprecationWarning): - sys.set_coroutine_wrapper(None) - - class OriginTrackingTest(unittest.TestCase): def here(self): info = inspect.getframeinfo(inspect.currentframe().f_back) diff --git a/Misc/NEWS.d/next/Library/2019-05-26-10-16-55.bpo-36933.4w3eP9.rst b/Misc/NEWS.d/next/Library/2019-05-26-10-16-55.bpo-36933.4w3eP9.rst new file mode 100644 index 0000000000..dc2be7a140 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-05-26-10-16-55.bpo-36933.4w3eP9.rst @@ -0,0 +1,2 @@ +The functions ``sys.set_coroutine_wrapper`` and ``sys.get_coroutine_wrapper`` +that were deprecated and marked for removal in 3.8 have been removed. diff --git a/Python/ceval.c b/Python/ceval.c index cb5a4beb2a..9263df9b8f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4143,19 +4143,8 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals, /* Handle generator/coroutine/asynchronous generator */ if (co->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { PyObject *gen; - PyObject *coro_wrapper = tstate->coroutine_wrapper; int is_coro = co->co_flags & CO_COROUTINE; - if (is_coro && tstate->in_coroutine_wrapper) { - assert(coro_wrapper != NULL); - _PyErr_Format(tstate, PyExc_RuntimeError, - "coroutine wrapper %.200R attempted " - "to recursively wrap %.200R", - coro_wrapper, - co); - goto fail; - } - /* Don't need to keep the reference to f_back, it will be set * when the generator is resumed. */ Py_CLEAR(f->f_back); @@ -4175,14 +4164,6 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals, _PyObject_GC_TRACK(f); - if (is_coro && coro_wrapper != NULL) { - PyObject *wrapped; - tstate->in_coroutine_wrapper = 1; - wrapped = PyObject_CallFunction(coro_wrapper, "N", gen); - tstate->in_coroutine_wrapper = 0; - return wrapped; - } - return gen; } @@ -4633,26 +4614,6 @@ _PyEval_GetCoroutineOriginTrackingDepth(void) return tstate->coroutine_origin_tracking_depth; } -void -_PyEval_SetCoroutineWrapper(PyObject *wrapper) -{ - PyThreadState *tstate = _PyThreadState_GET(); - - if (PySys_Audit("sys.set_coroutine_wrapper", NULL) < 0) { - return; - } - - Py_XINCREF(wrapper); - Py_XSETREF(tstate->coroutine_wrapper, wrapper); -} - -PyObject * -_PyEval_GetCoroutineWrapper(void) -{ - PyThreadState *tstate = _PyThreadState_GET(); - return tstate->coroutine_wrapper; -} - void _PyEval_SetAsyncGenFirstiter(PyObject *firstiter) { diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index 5df8af1a11..6f248ff18d 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -510,33 +510,6 @@ exit: return return_value; } -PyDoc_STRVAR(sys_set_coroutine_wrapper__doc__, -"set_coroutine_wrapper($module, wrapper, /)\n" -"--\n" -"\n" -"Set a wrapper for coroutine objects."); - -#define SYS_SET_COROUTINE_WRAPPER_METHODDEF \ - {"set_coroutine_wrapper", (PyCFunction)sys_set_coroutine_wrapper, METH_O, sys_set_coroutine_wrapper__doc__}, - -PyDoc_STRVAR(sys_get_coroutine_wrapper__doc__, -"get_coroutine_wrapper($module, /)\n" -"--\n" -"\n" -"Return the wrapper for coroutines set by sys.set_coroutine_wrapper."); - -#define SYS_GET_COROUTINE_WRAPPER_METHODDEF \ - {"get_coroutine_wrapper", (PyCFunction)sys_get_coroutine_wrapper, METH_NOARGS, sys_get_coroutine_wrapper__doc__}, - -static PyObject * -sys_get_coroutine_wrapper_impl(PyObject *module); - -static PyObject * -sys_get_coroutine_wrapper(PyObject *module, PyObject *Py_UNUSED(ignored)) -{ - return sys_get_coroutine_wrapper_impl(module); -} - PyDoc_STRVAR(sys_get_asyncgen_hooks__doc__, "get_asyncgen_hooks($module, /)\n" "--\n" @@ -1109,4 +1082,4 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=03da2eb03135d9f2 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=43c4fde7b5783d8d input=a9049054013a1b77]*/ diff --git a/Python/pystate.c b/Python/pystate.c index d1a8d24724..833e0fb30d 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -606,9 +606,6 @@ new_threadstate(PyInterpreterState *interp, int init) tstate->coroutine_origin_tracking_depth = 0; - tstate->coroutine_wrapper = NULL; - tstate->in_coroutine_wrapper = 0; - tstate->async_gen_firstiter = NULL; tstate->async_gen_finalizer = NULL; @@ -802,7 +799,6 @@ PyThreadState_Clear(PyThreadState *tstate) Py_CLEAR(tstate->c_profileobj); Py_CLEAR(tstate->c_traceobj); - Py_CLEAR(tstate->coroutine_wrapper); Py_CLEAR(tstate->async_gen_firstiter); Py_CLEAR(tstate->async_gen_finalizer); diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 24018e25fa..343601ec85 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1158,62 +1158,6 @@ sys_get_coroutine_origin_tracking_depth_impl(PyObject *module) return _PyEval_GetCoroutineOriginTrackingDepth(); } -/*[clinic input] -sys.set_coroutine_wrapper - - wrapper: object - / - -Set a wrapper for coroutine objects. -[clinic start generated code]*/ - -static PyObject * -sys_set_coroutine_wrapper(PyObject *module, PyObject *wrapper) -/*[clinic end generated code: output=9c7db52d65f6b188 input=df6ac09a06afef34]*/ -{ - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "set_coroutine_wrapper is deprecated", 1) < 0) { - return NULL; - } - - if (wrapper != Py_None) { - if (!PyCallable_Check(wrapper)) { - PyErr_Format(PyExc_TypeError, - "callable expected, got %.50s", - Py_TYPE(wrapper)->tp_name); - return NULL; - } - _PyEval_SetCoroutineWrapper(wrapper); - } - else { - _PyEval_SetCoroutineWrapper(NULL); - } - Py_RETURN_NONE; -} - -/*[clinic input] -sys.get_coroutine_wrapper - -Return the wrapper for coroutines set by sys.set_coroutine_wrapper. -[clinic start generated code]*/ - -static PyObject * -sys_get_coroutine_wrapper_impl(PyObject *module) -/*[clinic end generated code: output=b74a7e4b14fe898e input=ef0351fb9ece0bb4]*/ -{ - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "get_coroutine_wrapper is deprecated", 1) < 0) { - return NULL; - } - PyObject *wrapper = _PyEval_GetCoroutineWrapper(); - if (wrapper == NULL) { - wrapper = Py_None; - } - Py_INCREF(wrapper); - return wrapper; -} - - static PyTypeObject AsyncGenHooksType; PyDoc_STRVAR(asyncgen_hooks_doc, @@ -2002,8 +1946,6 @@ static PyMethodDef sys_methods[] = { SYS__DEBUGMALLOCSTATS_METHODDEF SYS_SET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF SYS_GET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF - SYS_SET_COROUTINE_WRAPPER_METHODDEF - SYS_GET_COROUTINE_WRAPPER_METHODDEF {"set_asyncgen_hooks", (PyCFunction)(void(*)(void))sys_set_asyncgen_hooks, METH_VARARGS | METH_KEYWORDS, set_asyncgen_hooks_doc}, SYS_GET_ASYNCGEN_HOOKS_METHODDEF