diff options
author | Nikita Sobolev <mail@sobolevn.me> | 2024-01-11 08:42:30 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-11 08:42:30 (GMT) |
commit | 2ac4cf4743a65ac54c7ac6a762bed636800598fe (patch) | |
tree | 9845713b4a3055f7c0d4df968f18c254ca591855 /Objects | |
parent | f653caa5a88d3b5027a8f286ff3a3ccd9e6fe4ed (diff) | |
download | cpython-2ac4cf4743a65ac54c7ac6a762bed636800598fe.zip cpython-2ac4cf4743a65ac54c7ac6a762bed636800598fe.tar.gz cpython-2ac4cf4743a65ac54c7ac6a762bed636800598fe.tar.bz2 |
gh-112640: Add `kwdefaults` parameter to `types.FunctionType.__new__` (#112641)
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/clinic/funcobject.c.h | 33 | ||||
-rw-r--r-- | Objects/funcobject.c | 15 |
2 files changed, 35 insertions, 13 deletions
diff --git a/Objects/clinic/funcobject.c.h b/Objects/clinic/funcobject.c.h index 138f877..8f20bda 100644 --- a/Objects/clinic/funcobject.c.h +++ b/Objects/clinic/funcobject.c.h @@ -9,7 +9,8 @@ preserve #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() PyDoc_STRVAR(func_new__doc__, -"function(code, globals, name=None, argdefs=None, closure=None)\n" +"function(code, globals, name=None, argdefs=None, closure=None,\n" +" kwdefaults=None)\n" "--\n" "\n" "Create a function object.\n" @@ -23,11 +24,14 @@ PyDoc_STRVAR(func_new__doc__, " argdefs\n" " a tuple that specifies the default argument values\n" " closure\n" -" a tuple that supplies the bindings for free variables"); +" a tuple that supplies the bindings for free variables\n" +" kwdefaults\n" +" a dictionary that specifies the default keyword argument values"); static PyObject * func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals, - PyObject *name, PyObject *defaults, PyObject *closure); + PyObject *name, PyObject *defaults, PyObject *closure, + PyObject *kwdefaults); static PyObject * func_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) @@ -35,14 +39,14 @@ func_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 5 + #define NUM_KEYWORDS 6 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD PyObject *ob_item[NUM_KEYWORDS]; } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_item = { &_Py_ID(code), &_Py_ID(globals), &_Py_ID(name), &_Py_ID(argdefs), &_Py_ID(closure), }, + .ob_item = { &_Py_ID(code), &_Py_ID(globals), &_Py_ID(name), &_Py_ID(argdefs), &_Py_ID(closure), &_Py_ID(kwdefaults), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -51,14 +55,14 @@ func_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"code", "globals", "name", "argdefs", "closure", NULL}; + static const char * const _keywords[] = {"code", "globals", "name", "argdefs", "closure", "kwdefaults", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "function", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[5]; + PyObject *argsbuf[6]; PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 2; @@ -67,8 +71,9 @@ func_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject *name = Py_None; PyObject *defaults = Py_None; PyObject *closure = Py_None; + PyObject *kwdefaults = Py_None; - fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 2, 5, 0, argsbuf); + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 2, 6, 0, argsbuf); if (!fastargs) { goto exit; } @@ -97,11 +102,17 @@ func_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) goto skip_optional_pos; } } - closure = fastargs[4]; + if (fastargs[4]) { + closure = fastargs[4]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + kwdefaults = fastargs[5]; skip_optional_pos: - return_value = func_new_impl(type, code, globals, name, defaults, closure); + return_value = func_new_impl(type, code, globals, name, defaults, closure, kwdefaults); exit: return return_value; } -/*[clinic end generated code: output=ff7b995500d2bee6 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=10947342188f38a9 input=a9049054013a1b77]*/ diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 4d88dd2..2620dc6 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -809,14 +809,17 @@ function.__new__ as func_new a tuple that specifies the default argument values closure: object = None a tuple that supplies the bindings for free variables + kwdefaults: object = None + a dictionary that specifies the default keyword argument values Create a function object. [clinic start generated code]*/ static PyObject * func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals, - PyObject *name, PyObject *defaults, PyObject *closure) -/*[clinic end generated code: output=99c6d9da3a24e3be input=93611752fc2daf11]*/ + PyObject *name, PyObject *defaults, PyObject *closure, + PyObject *kwdefaults) +/*[clinic end generated code: output=de72f4c22ac57144 input=20c9c9f04ad2d3f2]*/ { PyFunctionObject *newfunc; Py_ssize_t nclosure; @@ -843,6 +846,11 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals, return NULL; } } + if (kwdefaults != Py_None && !PyDict_Check(kwdefaults)) { + PyErr_SetString(PyExc_TypeError, + "arg 6 (kwdefaults) must be None or dict"); + return NULL; + } /* check that the closure is well-formed */ nclosure = closure == Py_None ? 0 : PyTuple_GET_SIZE(closure); @@ -879,6 +887,9 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals, if (closure != Py_None) { newfunc->func_closure = Py_NewRef(closure); } + if (kwdefaults != Py_None) { + newfunc->func_kwdefaults = Py_NewRef(kwdefaults); + } return (PyObject *)newfunc; } |