diff options
author | Matthieu Dartiailh <m.dartiailh@gmail.com> | 2023-02-07 09:34:21 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-07 09:34:21 (GMT) |
commit | ae62bddaf81176a7e55f95f18d55621c9c46c23d (patch) | |
tree | 0c7a661b7abd64546ebe0b8a495f3004ab30a6f0 /Modules | |
parent | c4de6b1d52304a0a9cdfafc1dad5098993710404 (diff) | |
download | cpython-ae62bddaf81176a7e55f95f18d55621c9c46c23d.zip cpython-ae62bddaf81176a7e55f95f18d55621c9c46c23d.tar.gz cpython-ae62bddaf81176a7e55f95f18d55621c9c46c23d.tar.bz2 |
gh-101072: support default and kw default in PyEval_EvalCodeEx for 3.11+ (#101127)
Co-authored-by: Ćukasz Langa <lukasz@langa.pl>
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_testcapimodule.c | 141 |
1 files changed, 140 insertions, 1 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 5e47f49..5a6097e 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2237,7 +2237,7 @@ dict_get_version(PyObject *self, PyObject *args) return NULL; _Py_COMP_DIAG_PUSH - _Py_COMP_DIAG_IGNORE_DEPR_DECLS + _Py_COMP_DIAG_IGNORE_DEPR_DECLS version = dict->ma_version_tag; _Py_COMP_DIAG_POP @@ -3065,6 +3065,144 @@ eval_get_func_desc(PyObject *self, PyObject *func) } static PyObject * +eval_eval_code_ex(PyObject *mod, PyObject *pos_args) +{ + PyObject *result = NULL; + PyObject *code; + PyObject *globals; + PyObject *locals = NULL; + PyObject *args = NULL; + PyObject *kwargs = NULL; + PyObject *defaults = NULL; + PyObject *kw_defaults = NULL; + PyObject *closure = NULL; + + PyObject **c_kwargs = NULL; + + if (!PyArg_UnpackTuple(pos_args, + "eval_code_ex", + 2, + 8, + &code, + &globals, + &locals, + &args, + &kwargs, + &defaults, + &kw_defaults, + &closure)) + { + goto exit; + } + + if (!PyCode_Check(code)) { + PyErr_SetString(PyExc_TypeError, + "code must be a Python code object"); + goto exit; + } + + if (!PyDict_Check(globals)) { + PyErr_SetString(PyExc_TypeError, "globals must be a dict"); + goto exit; + } + + if (locals && !PyMapping_Check(locals)) { + PyErr_SetString(PyExc_TypeError, "locals must be a mapping"); + goto exit; + } + if (locals == Py_None) { + locals = NULL; + } + + PyObject **c_args = NULL; + Py_ssize_t c_args_len = 0; + + if (args) + { + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, "args must be a tuple"); + goto exit; + } else { + c_args = &PyTuple_GET_ITEM(args, 0); + c_args_len = PyTuple_Size(args); + } + } + + Py_ssize_t c_kwargs_len = 0; + + if (kwargs) + { + if (!PyDict_Check(kwargs)) { + PyErr_SetString(PyExc_TypeError, "keywords must be a dict"); + goto exit; + } else { + c_kwargs_len = PyDict_Size(kwargs); + if (c_kwargs_len > 0) { + c_kwargs = PyMem_NEW(PyObject*, 2 * c_kwargs_len); + if (!c_kwargs) { + PyErr_NoMemory(); + goto exit; + } + + Py_ssize_t i = 0; + Py_ssize_t pos = 0; + + while (PyDict_Next(kwargs, + &pos, + &c_kwargs[i], + &c_kwargs[i + 1])) + { + i += 2; + } + c_kwargs_len = i / 2; + /* XXX This is broken if the caller deletes dict items! */ + } + } + } + + + PyObject **c_defaults = NULL; + Py_ssize_t c_defaults_len = 0; + + if (defaults && PyTuple_Check(defaults)) { + c_defaults = &PyTuple_GET_ITEM(defaults, 0); + c_defaults_len = PyTuple_Size(defaults); + } + + if (kw_defaults && !PyDict_Check(kw_defaults)) { + PyErr_SetString(PyExc_TypeError, "kw_defaults must be a dict"); + goto exit; + } + + if (closure && !PyTuple_Check(closure)) { + PyErr_SetString(PyExc_TypeError, "closure must be a tuple of cells"); + goto exit; + } + + + result = PyEval_EvalCodeEx( + code, + globals, + locals, + c_args, + c_args_len, + c_kwargs, + c_kwargs_len, + c_defaults, + c_defaults_len, + kw_defaults, + closure + ); + +exit: + if (c_kwargs) { + PyMem_DEL(c_kwargs); + } + + return result; +} + +static PyObject * get_feature_macros(PyObject *self, PyObject *Py_UNUSED(args)) { PyObject *result = PyDict_New(); @@ -3385,6 +3523,7 @@ static PyMethodDef TestMethods[] = { {"set_exc_info", test_set_exc_info, METH_VARARGS}, {"argparsing", argparsing, METH_VARARGS}, {"code_newempty", code_newempty, METH_VARARGS}, + {"eval_code_ex", eval_eval_code_ex, METH_VARARGS}, {"make_exception_with_doc", _PyCFunction_CAST(make_exception_with_doc), METH_VARARGS | METH_KEYWORDS}, {"make_memoryview_from_NULL_pointer", make_memoryview_from_NULL_pointer, |