diff --git a/CHANGES/862.bugfix.1.rst b/CHANGES/862.bugfix.1.rst new file mode 120000 index 000000000..1dad3117f --- /dev/null +++ b/CHANGES/862.bugfix.1.rst @@ -0,0 +1 @@ +909.bugfix.rst \ No newline at end of file diff --git a/CHANGES/909.bugfix.rst b/CHANGES/909.bugfix.rst new file mode 100644 index 000000000..98966ab0b --- /dev/null +++ b/CHANGES/909.bugfix.rst @@ -0,0 +1,3 @@ +Revert to using the public argument parsing API +:c:func:`PyArg_ParseTupleAndKeywords` under Python 3.13 +-- :user:`webknjaz`. diff --git a/multidict/_multidict.c b/multidict/_multidict.c index 5121862c7..228d4df1b 100644 --- a/multidict/_multidict.c +++ b/multidict/_multidict.c @@ -9,9 +9,11 @@ #include "_multilib/iter.h" #include "_multilib/views.h" +#if PY_MAJOR_VERSION < 3 || PY_MINOR_VERSION < 13 #ifndef _PyArg_UnpackKeywords #define FASTCALL_OLD #endif +#endif static PyObject *collections_abc_mapping; @@ -440,13 +442,31 @@ _multidict_proxy_copy(MultiDictProxyObject *self, PyTypeObject *type) /******************** Base Methods ********************/ static inline PyObject * -multidict_getall(MultiDictObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) +multidict_getall( + MultiDictObject *self, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + PyObject *args, + PyObject *kwds +#else + PyObject *const *args, + Py_ssize_t nargs, + PyObject *kwnames +#endif +) { PyObject *list = NULL, *key = NULL, *_default = NULL; +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + static char *getall_keywords[] = {"key", "default", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getall", + getall_keywords, &key, &_default)) + { + return NULL; + } +#else static const char * const _keywords[] = {"key", "default", NULL}; #ifdef FASTCALL_OLD static _PyArg_Parser _parser = {"O|O:getall", _keywords, 0}; @@ -470,6 +490,7 @@ multidict_getall(MultiDictObject *self, PyObject *const *args, _default = args[1]; skip_optional_pos: +#endif #endif list = pair_list_get_all(&self->pairs, key); @@ -486,12 +507,31 @@ multidict_getall(MultiDictObject *self, PyObject *const *args, } static inline PyObject * -multidict_getone(MultiDictObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) +multidict_getone( + MultiDictObject *self, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + PyObject *args, + PyObject *kwds +#else + PyObject *const *args, + Py_ssize_t nargs, + PyObject *kwnames +#endif +) { PyObject *key = NULL, *_default = NULL; +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + static char *getone_keywords[] = {"key", "default", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getone", + getone_keywords, &key, &_default)) + { + return NULL; + } + +#else static const char * const _keywords[] = {"key", "default", NULL}; #ifdef FASTCALL_OLD static _PyArg_Parser _parser = {"O|O:getone", _keywords, 0}; @@ -515,18 +555,37 @@ multidict_getone(MultiDictObject *self, PyObject *const *args, _default = args[1]; skip_optional_pos: +#endif #endif return _multidict_getone(self, key, _default); } static inline PyObject * -multidict_get(MultiDictObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) +multidict_get( + MultiDictObject *self, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + PyObject *args, + PyObject *kwds +#else + PyObject *const *args, + Py_ssize_t nargs, + PyObject *kwnames +#endif +) { PyObject *key = NULL, *_default = Py_None, *ret; +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + static char *getone_keywords[] = {"key", "default", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getone", + getone_keywords, &key, &_default)) + { + return NULL; + } +#else static const char * const _keywords[] = {"key", "default", NULL}; #ifdef FASTCALL_OLD static _PyArg_Parser _parser = {"O|O:get", _keywords, 0}; @@ -550,6 +609,7 @@ multidict_get(MultiDictObject *self, PyObject *const *args, _default = args[1]; skip_optional_pos: +#endif #endif ret = _multidict_getone(self, key, _default); return ret; @@ -771,12 +831,29 @@ multidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds) } static inline PyObject * -multidict_add(MultiDictObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) +multidict_add( + MultiDictObject *self, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + PyObject *args, + PyObject *kwds +#else + PyObject *const *args, + Py_ssize_t nargs, + PyObject *kwnames +#endif +) { PyObject *key = NULL, *val = NULL; +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + static char *kwlist[] = {"key", "value", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:add", + kwlist, &key, &val)) + { + return NULL; + } +#else static const char * const _keywords[] = {"key", "value", NULL}; #ifdef FASTCALL_OLD static _PyArg_Parser _parser = {"OO:add", _keywords, 0}; @@ -798,6 +875,7 @@ multidict_add(MultiDictObject *self, PyObject *const *args, } key = args[0]; val = args[1]; +#endif #endif if (pair_list_add(&self->pairs, key, val) < 0) { return NULL; @@ -833,12 +911,30 @@ multidict_clear(MultiDictObject *self) } static inline PyObject * -multidict_setdefault(MultiDictObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) +multidict_setdefault( + MultiDictObject *self, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + PyObject *args, + PyObject *kwds +#else + PyObject *const *args, + Py_ssize_t nargs, + PyObject *kwnames +#endif +) { PyObject *key = NULL, *_default = NULL; +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + static char *setdefault_keywords[] = {"key", "default", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:setdefault", + setdefault_keywords, &key, &_default)) + { + return NULL; + } +#else static const char * const _keywords[] = {"key", "default", NULL}; #ifdef FASTCALL_OLD static _PyArg_Parser _parser = {"O|O:setdefault", _keywords, 0}; @@ -863,18 +959,50 @@ multidict_setdefault(MultiDictObject *self, PyObject *const *args, _default = args[1]; skip_optional_pos: +#endif #endif return pair_list_set_default(&self->pairs, key, _default); } static inline PyObject * -multidict_popone(MultiDictObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) +multidict_popone( + MultiDictObject *self, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + PyObject *args, + PyObject *kwds +#else + PyObject *const *args, + Py_ssize_t nargs, + PyObject *kwnames +#endif +) { PyObject *key = NULL, *_default = NULL, *ret_val = NULL; +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + static char *popone_keywords[] = {"key", "default", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popone", + popone_keywords, &key, &_default)) + { + return NULL; + } + + ret_val = pair_list_pop_one(&self->pairs, key); + + if (ret_val == NULL && + PyErr_ExceptionMatches(PyExc_KeyError) && + _default != NULL) + { + PyErr_Clear(); + Py_INCREF(_default); + return _default; + } + + return ret_val; +#else static const char * const _keywords[] = {"key", "default", NULL}; #ifdef FASTCALL_OLD static _PyArg_Parser _parser = {"O|O:popone", _keywords, 0}; @@ -912,16 +1040,36 @@ multidict_popone(MultiDictObject *self, PyObject *const *args, } return ret_val; +#endif } static inline PyObject * -multidict_pop(MultiDictObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) +multidict_pop( + MultiDictObject *self, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + PyObject *args, + PyObject *kwds +#else + PyObject *const *args, + Py_ssize_t nargs, + PyObject *kwnames +#endif +) { PyObject *key = NULL, *_default = NULL, *ret_val = NULL; +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + static char *pop_keywords[] = {"key", "default", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popone", + pop_keywords, &key, &_default)) + { + return NULL; + } + +#else static const char * const _keywords[] = {"key", "default", NULL}; #ifdef FASTCALL_OLD static _PyArg_Parser _parser = {"O|O:pop", _keywords, 0}; @@ -946,6 +1094,7 @@ multidict_pop(MultiDictObject *self, PyObject *const *args, _default = args[1]; skip_optional_pos: +#endif #endif ret_val = pair_list_pop_one(&self->pairs, key); @@ -962,14 +1111,32 @@ multidict_pop(MultiDictObject *self, PyObject *const *args, } static inline PyObject * -multidict_popall(MultiDictObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) +multidict_popall( + MultiDictObject *self, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + PyObject *args, + PyObject *kwds +#else + PyObject *const *args, + Py_ssize_t nargs, + PyObject *kwnames +#endif +) { PyObject *key = NULL, *_default = NULL, *ret_val = NULL; +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + static char *popall_keywords[] = {"key", "default", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popall", + popall_keywords, &key, &_default)) + { + return NULL; + } +#else static const char * const _keywords[] = {"key", "default", NULL}; #ifdef FASTCALL_OLD static _PyArg_Parser _parser = {"O|O:popall", _keywords, 0}; @@ -994,6 +1161,7 @@ multidict_popall(MultiDictObject *self, PyObject *const *args, _default = args[1]; skip_optional_pos: +#endif #endif ret_val = pair_list_pop_all(&self->pairs, key); @@ -1102,19 +1270,34 @@ static PyMethodDef multidict_methods[] = { { "getall", (PyCFunction)multidict_getall, - METH_FASTCALL | METH_KEYWORDS, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + METH_VARARGS +#else + METH_FASTCALL +#endif + | METH_KEYWORDS, multidict_getall_doc }, { "getone", (PyCFunction)multidict_getone, - METH_FASTCALL | METH_KEYWORDS, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + METH_VARARGS +#else + METH_FASTCALL +#endif + | METH_KEYWORDS, multidict_getone_doc }, { "get", (PyCFunction)multidict_get, - METH_FASTCALL | METH_KEYWORDS, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + METH_VARARGS +#else + METH_FASTCALL +#endif + | METH_KEYWORDS, multidict_get_doc }, { @@ -1138,7 +1321,12 @@ static PyMethodDef multidict_methods[] = { { "add", (PyCFunction)multidict_add, - METH_FASTCALL | METH_KEYWORDS, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + METH_VARARGS +#else + METH_FASTCALL +#endif + | METH_KEYWORDS, multidict_add_doc }, { @@ -1162,25 +1350,45 @@ static PyMethodDef multidict_methods[] = { { "setdefault", (PyCFunction)multidict_setdefault, - METH_FASTCALL | METH_KEYWORDS, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + METH_VARARGS +#else + METH_FASTCALL +#endif + | METH_KEYWORDS, multidict_setdefault_doc }, { "popone", (PyCFunction)multidict_popone, - METH_FASTCALL | METH_KEYWORDS, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + METH_VARARGS +#else + METH_FASTCALL +#endif + | METH_KEYWORDS, multidict_popone_doc }, { "pop", (PyCFunction)multidict_pop, - METH_FASTCALL | METH_KEYWORDS, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + METH_VARARGS +#else + METH_FASTCALL +#endif + | METH_KEYWORDS, multidict_pop_doc }, { "popall", (PyCFunction)multidict_popall, - METH_FASTCALL | METH_KEYWORDS, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + METH_VARARGS +#else + METH_FASTCALL +#endif + | METH_KEYWORDS, multidict_popall_doc }, { @@ -1349,24 +1557,76 @@ multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args, } static inline PyObject * -multidict_proxy_getall(MultiDictProxyObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) +multidict_proxy_getall( + MultiDictProxyObject *self, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + PyObject *args, + PyObject *kwds +#else + PyObject *const *args, + Py_ssize_t nargs, + PyObject *kwnames +#endif +) { - return multidict_getall(self->md, args, nargs, kwnames); + return multidict_getall( + self->md, + args, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + kwds +#else + nargs, + kwnames +#endif + ); } static inline PyObject * -multidict_proxy_getone(MultiDictProxyObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) +multidict_proxy_getone( + MultiDictProxyObject *self, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + PyObject *args, + PyObject *kwds +#else + PyObject *const *args, + Py_ssize_t nargs, + PyObject *kwnames +#endif +) { - return multidict_getone(self->md, args, nargs, kwnames); + return multidict_getone( + self->md, args, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + kwds +#else + nargs, kwnames +#endif + ); } static inline PyObject * -multidict_proxy_get(MultiDictProxyObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames) +multidict_proxy_get( + MultiDictProxyObject *self, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + PyObject *args, + PyObject *kwds +#else + PyObject *const *args, + Py_ssize_t nargs, + PyObject *kwnames +#endif +) { - return multidict_get(self->md, args, nargs, kwnames); + return multidict_get( + self->md, + args, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + kwds +#else + nargs, + kwnames +#endif + ); } static inline PyObject * @@ -1474,19 +1734,34 @@ static PyMethodDef multidict_proxy_methods[] = { { "getall", (PyCFunction)multidict_proxy_getall, - METH_FASTCALL | METH_KEYWORDS, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + METH_VARARGS +#else + METH_FASTCALL +#endif + | METH_KEYWORDS, multidict_getall_doc }, { "getone", (PyCFunction)multidict_proxy_getone, - METH_FASTCALL | METH_KEYWORDS, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + METH_VARARGS +#else + METH_FASTCALL +#endif + | METH_KEYWORDS, multidict_getone_doc }, { "get", (PyCFunction)multidict_proxy_get, - METH_FASTCALL | METH_KEYWORDS, +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 13 + METH_VARARGS +#else + METH_FASTCALL +#endif + | METH_KEYWORDS, multidict_get_doc }, {