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
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
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')
: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
=====================
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 *);
int coroutine_origin_tracking_depth;
- PyObject *coroutine_wrapper;
- int in_coroutine_wrapper;
-
PyObject *async_gen_firstiter;
PyObject *async_gen_finalizer;
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)
--- /dev/null
+The functions ``sys.set_coroutine_wrapper`` and ``sys.get_coroutine_wrapper``
+that were deprecated and marked for removal in 3.8 have been removed.
/* 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);
_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;
}
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)
{
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"
#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]*/
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;
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);
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,
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