(as has always been the case for an executing frame).
(Contributed by Irit Katriel in :gh:`79932`.)
+* Assignment to a function's ``__code__`` attribute where the new code
+ object's type does not match the function's type, is deprecated. The
+ different types are: plain function, generator, async generator and
+ coroutine.
+ (Contributed by Irit Katriel in :gh:`81137`.)
+
Pending Removal in Python 3.14
------------------------------
import types
import typing
import unittest
+import warnings
def global_function():
test.__code__ = self.b.__code__
self.assertEqual(test(), 3) # self.b always returns 3, arbitrarily
+ def test_invalid___code___assignment(self):
+ def A(): pass
+ def B(): yield
+ async def C(): yield
+ async def D(x): await x
+
+ for src in [A, B, C, D]:
+ for dst in [A, B, C, D]:
+ if src == dst:
+ continue
+
+ assert src.__code__.co_flags != dst.__code__.co_flags
+ prev = dst.__code__
+ try:
+ with self.assertWarnsRegex(DeprecationWarning, 'code object of non-matching type'):
+ dst.__code__ = src.__code__
+ finally:
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', '', DeprecationWarning)
+ dst.__code__ = prev
+
def test___globals__(self):
self.assertIs(self.b.__globals__, globals())
self.cannot_set_attr(self.b, '__globals__', 2,
--- /dev/null
+Deprecate assignment to a function's ``__code__`` field when the new code
+object is of a mismatched type (e.g., from a generator to a plain function).
nclosure, nfree);
return -1;
}
+
+ PyObject *func_code = PyFunction_GET_CODE(op);
+ int old_flags = ((PyCodeObject *)func_code)->co_flags;
+ int new_flags = ((PyCodeObject *)value)->co_flags;
+ int mask = CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR;
+ if ((old_flags & mask) != (new_flags & mask)) {
+ if (PyErr_Warn(PyExc_DeprecationWarning,
+ "Assigning a code object of non-matching type is deprecated "
+ "(e.g., from a generator to a plain function)") < 0)
+ {
+ return -1;
+ }
+ }
+
handle_func_event(PyFunction_EVENT_MODIFY_CODE, op, value);
_PyFunction_SetVersion(op, 0);
Py_XSETREF(op->func_code, Py_NewRef(value));