[Python-checkins] bpo-36933: Remove sys.set_coroutine_wrapper (marked for removal in 3.8) (GH-13577)

Miss Islington (bot) webhook-mailer at python.org
Tue May 28 03:11:06 EDT 2019


https://github.com/python/cpython/commit/3880f263d2994fb1eba25835dddccb0cf696fdf0
commit: 3880f263d2994fb1eba25835dddccb0cf696fdf0
branch: master
author: Matthias Bussonnier <bussonniermatthias at gmail.com>
committer: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
date: 2019-05-28T00:10:59-07:00
summary:

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

files:
A Misc/NEWS.d/next/Library/2019-05-26-10-16-55.bpo-36933.4w3eP9.rst
M Doc/library/sys.rst
M Doc/tools/susp-ignored.csv
M Doc/whatsnew/3.8.rst
M Include/ceval.h
M Include/cpython/pystate.h
M Lib/test/test_coroutines.py
M Python/ceval.c
M Python/clinic/sysmodule.c.h
M Python/pystate.c
M Python/sysmodule.c

diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
index 74aa2711dd01..5bde6870717c 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 a0e7868a037a..85263d47c8bb 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 125cefe11133..860d6cc18f11 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 8cdf353b05fd..6fb224b28850 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 6b7663fe3315..94b0809cd4f0 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 036f13fa50e9..0e7eb3a1af47 100644
--- a/Lib/test/test_coroutines.py
+++ b/Lib/test/test_coroutines.py
@@ -2146,99 +2146,6 @@ class CM:
         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 000000000000..dc2be7a140cf
--- /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 cb5a4beb2a66..9263df9b8fc4 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 5df8af1a1172..6f248ff18d9d 100644
--- a/Python/clinic/sysmodule.c.h
+++ b/Python/clinic/sysmodule.c.h
@@ -510,33 +510,6 @@ sys_get_coroutine_origin_tracking_depth(PyObject *module, PyObject *Py_UNUSED(ig
     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 d1a8d2472470..833e0fb30dcb 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 24018e25fa57..343601ec8596 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



More information about the Python-checkins mailing list