diff options
Diffstat (limited to 'Python')
-rw-r--r-- | Python/bltinmodule.c | 60 | ||||
-rw-r--r-- | Python/clinic/bltinmodule.c.h | 37 |
2 files changed, 78 insertions, 19 deletions
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 84ebb68..072bf75 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -977,6 +977,8 @@ exec as builtin_exec globals: object = None locals: object = None / + * + closure: object(c_default="NULL") = None Execute the given source in the context of globals and locals. @@ -985,12 +987,14 @@ or a code object as returned by compile(). The globals must be a dictionary and locals can be any mapping, defaulting to the current globals and locals. If only globals is given, locals defaults to it. +The closure must be a tuple of cellvars, and can only be used +when source is a code object requiring exactly that many cellvars. [clinic start generated code]*/ static PyObject * builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, - PyObject *locals) -/*[clinic end generated code: output=3c90efc6ab68ef5d input=01ca3e1c01692829]*/ + PyObject *locals, PyObject *closure) +/*[clinic end generated code: output=7579eb4e7646743d input=f13a7e2b503d1d9a]*/ { PyObject *v; @@ -1029,20 +1033,60 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, return NULL; } + if (closure == Py_None) { + closure = NULL; + } + if (PyCode_Check(source)) { + Py_ssize_t num_free = PyCode_GetNumFree((PyCodeObject *)source); + if (num_free == 0) { + if (closure) { + PyErr_SetString(PyExc_TypeError, + "cannot use a closure with this code object"); + return NULL; + } + } else { + int closure_is_ok = + closure + && PyTuple_CheckExact(closure) + && (PyTuple_GET_SIZE(closure) == num_free); + if (closure_is_ok) { + for (Py_ssize_t i = 0; i < num_free; i++) { + PyObject *cell = PyTuple_GET_ITEM(closure, i); + if (!PyCell_Check(cell)) { + closure_is_ok = 0; + break; + } + } + } + if (!closure_is_ok) { + PyErr_Format(PyExc_TypeError, + "code object requires a closure of exactly length %zd", + num_free); + return NULL; + } + } + if (PySys_Audit("exec", "O", source) < 0) { return NULL; } - if (PyCode_GetNumFree((PyCodeObject *)source) > 0) { - PyErr_SetString(PyExc_TypeError, - "code object passed to exec() may not " - "contain free variables"); - return NULL; + if (!closure) { + v = PyEval_EvalCode(source, globals, locals); + } else { + v = PyEval_EvalCodeEx(source, globals, locals, + NULL, 0, + NULL, 0, + NULL, 0, + NULL, + closure); } - v = PyEval_EvalCode(source, globals, locals); } else { + if (closure != NULL) { + PyErr_SetString(PyExc_TypeError, + "closure can only be used when source is a code object"); + } PyObject *source_copy; const char *str; PyCompilerFlags cf = _PyCompilerFlags_INIT; diff --git a/Python/clinic/bltinmodule.c.h b/Python/clinic/bltinmodule.c.h index f69b006..48f6509 100644 --- a/Python/clinic/bltinmodule.c.h +++ b/Python/clinic/bltinmodule.c.h @@ -408,7 +408,7 @@ exit: } PyDoc_STRVAR(builtin_exec__doc__, -"exec($module, source, globals=None, locals=None, /)\n" +"exec($module, source, globals=None, locals=None, /, *, closure=None)\n" "--\n" "\n" "Execute the given source in the context of globals and locals.\n" @@ -417,37 +417,52 @@ PyDoc_STRVAR(builtin_exec__doc__, "or a code object as returned by compile().\n" "The globals must be a dictionary and locals can be any mapping,\n" "defaulting to the current globals and locals.\n" -"If only globals is given, locals defaults to it."); +"If only globals is given, locals defaults to it.\n" +"The closure must be a tuple of cellvars, and can only be used\n" +"when source is a code object requiring exactly that many cellvars."); #define BUILTIN_EXEC_METHODDEF \ - {"exec", _PyCFunction_CAST(builtin_exec), METH_FASTCALL, builtin_exec__doc__}, + {"exec", _PyCFunction_CAST(builtin_exec), METH_FASTCALL|METH_KEYWORDS, builtin_exec__doc__}, static PyObject * builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals, - PyObject *locals); + PyObject *locals, PyObject *closure); static PyObject * -builtin_exec(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +builtin_exec(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + static const char * const _keywords[] = {"", "", "", "closure", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "exec", 0}; + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; PyObject *source; PyObject *globals = Py_None; PyObject *locals = Py_None; + PyObject *closure = NULL; - if (!_PyArg_CheckPositional("exec", nargs, 1, 3)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 3, 0, argsbuf); + if (!args) { goto exit; } source = args[0]; if (nargs < 2) { - goto skip_optional; + goto skip_optional_posonly; } + noptargs--; globals = args[1]; if (nargs < 3) { - goto skip_optional; + goto skip_optional_posonly; } + noptargs--; locals = args[2]; -skip_optional: - return_value = builtin_exec_impl(module, source, globals, locals); +skip_optional_posonly: + if (!noptargs) { + goto skip_optional_kwonly; + } + closure = args[3]; +skip_optional_kwonly: + return_value = builtin_exec_impl(module, source, globals, locals, closure); exit: return return_value; @@ -1030,4 +1045,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=6a2b78ef82bc5155 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a2c5c53e8aead7c3 input=a9049054013a1b77]*/ |