summaryrefslogtreecommitdiffstats
path: root/third_party/python/multidict/multidict/_multidict.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/python/multidict/multidict/_multidict.c')
-rw-r--r--third_party/python/multidict/multidict/_multidict.c1646
1 files changed, 1646 insertions, 0 deletions
diff --git a/third_party/python/multidict/multidict/_multidict.c b/third_party/python/multidict/multidict/_multidict.c
new file mode 100644
index 0000000000..5bdcc898de
--- /dev/null
+++ b/third_party/python/multidict/multidict/_multidict.c
@@ -0,0 +1,1646 @@
+#include "Python.h"
+#include "structmember.h"
+
+// Include order important
+#include "_multilib/defs.h"
+#include "_multilib/istr.h"
+#include "_multilib/pair_list.h"
+#include "_multilib/dict.h"
+#include "_multilib/iter.h"
+#include "_multilib/views.h"
+
+static PyObject *collections_abc_mapping;
+static PyObject *collections_abc_mut_mapping;
+static PyObject *collections_abc_mut_multi_mapping;
+
+static PyTypeObject multidict_type;
+static PyTypeObject cimultidict_type;
+static PyTypeObject multidict_proxy_type;
+static PyTypeObject cimultidict_proxy_type;
+
+static PyObject *repr_func;
+
+#define MultiDict_CheckExact(o) (Py_TYPE(o) == &multidict_type)
+#define CIMultiDict_CheckExact(o) (Py_TYPE(o) == &cimultidict_type)
+#define MultiDictProxy_CheckExact(o) (Py_TYPE(o) == &multidict_proxy_type)
+#define CIMultiDictProxy_CheckExact(o) (Py_TYPE(o) == &cimultidict_proxy_type)
+
+/* Helper macro for something like isinstance(obj, Base) */
+#define _MultiDict_Check(o) \
+ ((MultiDict_CheckExact(o)) || \
+ (CIMultiDict_CheckExact(o)) || \
+ (MultiDictProxy_CheckExact(o)) || \
+ (CIMultiDictProxy_CheckExact(o)))
+
+/******************** Internal Methods ********************/
+
+/* Forward declaration */
+static PyObject *multidict_items(MultiDictObject *self);
+
+static inline PyObject *
+_multidict_getone(MultiDictObject *self, PyObject *key, PyObject *_default)
+{
+ PyObject *val = pair_list_get_one(&self->pairs, key);
+
+ if (val == NULL &&
+ PyErr_ExceptionMatches(PyExc_KeyError) &&
+ _default != NULL)
+ {
+ PyErr_Clear();
+ Py_INCREF(_default);
+ return _default;
+ }
+
+ return val;
+}
+
+static inline int
+_multidict_eq(MultiDictObject *self, MultiDictObject *other)
+{
+ Py_ssize_t pos1 = 0,
+ pos2 = 0;
+
+ Py_hash_t h1 = 0,
+ h2 = 0;
+
+ PyObject *identity1 = NULL,
+ *identity2 = NULL,
+ *value1 = NULL,
+ *value2 = NULL;
+
+ int cmp_identity = 0,
+ cmp_value = 0;
+
+ if (self == other) {
+ return 1;
+ }
+
+ if (pair_list_len(&self->pairs) != pair_list_len(&other->pairs)) {
+ return 0;
+ }
+
+ while (_pair_list_next(&self->pairs, &pos1, &identity1, NULL, &value1, &h1) &&
+ _pair_list_next(&other->pairs, &pos2, &identity2, NULL, &value2, &h2))
+ {
+ if (h1 != h2) {
+ return 0;
+ }
+ cmp_identity = PyObject_RichCompareBool(identity1, identity2, Py_NE);
+ if (cmp_identity < 0) {
+ return -1;
+ }
+ cmp_value = PyObject_RichCompareBool(value1, value2, Py_NE);
+ if (cmp_value < 0) {
+ return -1;
+ }
+ if (cmp_identity || cmp_value) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static inline int
+_multidict_update_items(MultiDictObject *self, pair_list_t *pairs)
+{
+ return pair_list_update(&self->pairs, pairs);
+}
+
+static inline int
+_multidict_append_items(MultiDictObject *self, pair_list_t *pairs)
+{
+ PyObject *key = NULL,
+ *value = NULL;
+
+ Py_ssize_t pos = 0;
+
+ while (_pair_list_next(pairs, &pos, NULL, &key, &value, NULL)) {
+ if (pair_list_add(&self->pairs, key, value) < 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static inline int
+_multidict_append_items_seq(MultiDictObject *self, PyObject *arg,
+ const char *name)
+{
+ PyObject *key = NULL,
+ *value = NULL,
+ *item = NULL,
+ *iter = PyObject_GetIter(arg);
+
+ if (iter == NULL) {
+ return -1;
+ }
+
+ while ((item = PyIter_Next(iter)) != NULL) {
+ if (PyTuple_CheckExact(item)) {
+ if (PyTuple_GET_SIZE(item) != 2) {
+ goto invalid_type;
+ }
+ key = PyTuple_GET_ITEM(item, 0);
+ Py_INCREF(key);
+ value = PyTuple_GET_ITEM(item, 1);
+ Py_INCREF(value);
+ }
+ else if (PyList_CheckExact(item)) {
+ if (PyList_GET_SIZE(item) != 2) {
+ goto invalid_type;
+ }
+ key = PyList_GET_ITEM(item, 0);
+ Py_INCREF(key);
+ value = PyList_GET_ITEM(item, 1);
+ Py_INCREF(value);
+ }
+ else if (PySequence_Check(item)) {
+ if (PySequence_Size(item) != 2) {
+ goto invalid_type;
+ }
+ key = PySequence_GetItem(item, 0);
+ value = PySequence_GetItem(item, 1);
+ } else {
+ goto invalid_type;
+ }
+
+ if (pair_list_add(&self->pairs, key, value) < 0) {
+ goto fail;
+ }
+ Py_CLEAR(key);
+ Py_CLEAR(value);
+ Py_CLEAR(item);
+ }
+
+ Py_DECREF(iter);
+
+ if (PyErr_Occurred()) {
+ return -1;
+ }
+
+ return 0;
+invalid_type:
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s takes either dict or list of (key, value) pairs",
+ name,
+ NULL
+ );
+ goto fail;
+fail:
+ Py_XDECREF(key);
+ Py_XDECREF(value);
+ Py_XDECREF(item);
+ Py_DECREF(iter);
+ return -1;
+}
+
+static inline int
+_multidict_list_extend(PyObject *list, PyObject *target_list)
+{
+ PyObject *item = NULL,
+ *iter = PyObject_GetIter(target_list);
+
+ if (iter == NULL) {
+ return -1;
+ }
+
+ while ((item = PyIter_Next(iter)) != NULL) {
+ if (PyList_Append(list, item) < 0) {
+ Py_DECREF(item);
+ Py_DECREF(iter);
+ return -1;
+ }
+ Py_DECREF(item);
+ }
+
+ Py_DECREF(iter);
+
+ if (PyErr_Occurred()) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static inline int
+_multidict_extend_with_args(MultiDictObject *self, PyObject *arg,
+ PyObject *kwds, const char *name, int do_add)
+{
+ PyObject *arg_items = NULL, /* tracked by GC */
+ *kwds_items = NULL; /* new reference */
+ pair_list_t *pairs = NULL;
+
+ int err = 0;
+
+ if (kwds && !PyArg_ValidateKeywordArguments(kwds)) {
+ return -1;
+ }
+
+ // TODO: mb can be refactored more clear
+ if (_MultiDict_Check(arg) && kwds == NULL) {
+ if (MultiDict_CheckExact(arg) || CIMultiDict_CheckExact(arg)) {
+ pairs = &((MultiDictObject*)arg)->pairs;
+ } else if (MultiDictProxy_CheckExact(arg) || CIMultiDictProxy_CheckExact(arg)) {
+ pairs = &((MultiDictProxyObject*)arg)->md->pairs;
+ }
+
+ if (do_add) {
+ return _multidict_append_items(self, pairs);
+ }
+
+ return _multidict_update_items(self, pairs);
+ }
+
+ if (PyObject_HasAttrString(arg, "items")) {
+ if (_MultiDict_Check(arg)) {
+ arg_items = multidict_items((MultiDictObject*)arg);
+ } else {
+ arg_items = PyMapping_Items(arg);
+ }
+ if (arg_items == NULL) {
+ return -1;
+ }
+ } else {
+ arg_items = arg;
+ Py_INCREF(arg_items);
+ }
+
+ if (kwds) {
+ PyObject *tmp = PySequence_List(arg_items);
+ Py_DECREF(arg_items);
+ arg_items = tmp;
+ if (arg_items == NULL) {
+ return -1;
+ }
+
+ kwds_items = PyDict_Items(kwds);
+ if (kwds_items == NULL) {
+ Py_DECREF(arg_items);
+ return -1;
+ }
+ err = _multidict_list_extend(arg_items, kwds_items);
+ Py_DECREF(kwds_items);
+ if (err < 0) {
+ Py_DECREF(arg_items);
+ return -1;
+ }
+ }
+
+ if (do_add) {
+ err = _multidict_append_items_seq(self, arg_items, name);
+ } else {
+ err = pair_list_update_from_seq(&self->pairs, arg_items);
+ }
+
+ Py_DECREF(arg_items);
+
+ return err;
+}
+
+static inline int
+_multidict_extend_with_kwds(MultiDictObject *self, PyObject *kwds,
+ const char *name, int do_add)
+{
+ PyObject *arg = NULL;
+
+ int err = 0;
+
+ if (!PyArg_ValidateKeywordArguments(kwds)) {
+ return -1;
+ }
+
+ arg = PyDict_Items(kwds);
+ if (do_add) {
+ err = _multidict_append_items_seq(self, arg, name);
+ } else {
+ err = pair_list_update_from_seq(&self->pairs, arg);
+ }
+
+ Py_DECREF(arg);
+ return err;
+}
+
+static inline int
+_multidict_extend(MultiDictObject *self, PyObject *args, PyObject *kwds,
+ const char *name, int do_add)
+{
+ PyObject *arg = NULL;
+
+ if (args && PyObject_Length(args) > 1) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "%s takes at most 1 positional argument (%zd given)",
+ name, PyObject_Length(args), NULL
+ );
+ return -1;
+ }
+
+ if (args && PyObject_Length(args) > 0) {
+ if (!PyArg_UnpackTuple(args, name, 0, 1, &arg)) {
+ return -1;
+ }
+ if (_multidict_extend_with_args(self, arg, kwds, name, do_add) < 0) {
+ return -1;
+ }
+ } else if (kwds && PyObject_Length(kwds) > 0) {
+ if (_multidict_extend_with_kwds(self, kwds, name, do_add) < 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static inline PyObject *
+_multidict_copy(MultiDictObject *self, PyTypeObject *multidict_tp_object)
+{
+ MultiDictObject *new_multidict = NULL;
+
+ PyObject *arg_items = NULL,
+ *items = NULL;
+
+ new_multidict = (MultiDictObject*)PyType_GenericNew(
+ multidict_tp_object, NULL, NULL);
+ if (new_multidict == NULL) {
+ return NULL;
+ }
+
+ if (multidict_tp_object->tp_init(
+ (PyObject*)new_multidict, NULL, NULL) < 0)
+ {
+ return NULL;
+ }
+
+ items = multidict_items(self);
+ if (items == NULL) {
+ goto fail;
+ }
+
+ // TODO: "Implementation looks as slow as possible ..."
+ arg_items = PyTuple_New(1);
+ if (arg_items == NULL) {
+ goto fail;
+ }
+
+ Py_INCREF(items);
+ PyTuple_SET_ITEM(arg_items, 0, items);
+
+ if (_multidict_extend(
+ new_multidict, arg_items, NULL, "copy", 1) < 0)
+ {
+ goto fail;
+ }
+
+ Py_DECREF(items);
+ Py_DECREF(arg_items);
+
+ return (PyObject*)new_multidict;
+
+fail:
+ Py_XDECREF(items);
+ Py_XDECREF(arg_items);
+
+ Py_DECREF(new_multidict);
+
+ return NULL;
+}
+
+static inline PyObject *
+_multidict_proxy_copy(MultiDictProxyObject *self, PyTypeObject *type)
+{
+ PyObject *new_multidict = PyType_GenericNew(type, NULL, NULL);
+ if (new_multidict == NULL) {
+ goto fail;
+ }
+ if (type->tp_init(new_multidict, NULL, NULL) < 0) {
+ goto fail;
+ }
+ if (_multidict_extend_with_args(
+ (MultiDictObject*)new_multidict, (PyObject*)self, NULL, "copy", 1) < 0)
+ {
+ goto fail;
+ }
+
+ return new_multidict;
+
+fail:
+ Py_XDECREF(new_multidict);
+ return NULL;
+}
+
+
+/******************** Base Methods ********************/
+
+static inline PyObject *
+multidict_getall(MultiDictObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *list = NULL,
+ *key = NULL,
+ *_default = NULL;
+
+ static char *getall_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getall",
+ getall_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+
+ list = pair_list_get_all(&self->pairs, key);
+
+ if (list == NULL &&
+ PyErr_ExceptionMatches(PyExc_KeyError) &&
+ _default != NULL)
+ {
+ PyErr_Clear();
+ Py_INCREF(_default);
+ return _default;
+ }
+
+ return list;
+}
+
+static inline PyObject *
+multidict_getone(MultiDictObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *key = NULL,
+ *_default = NULL;
+
+ static char *getone_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getone",
+ getone_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+
+ return _multidict_getone(self, key, _default);
+}
+
+static inline PyObject *
+multidict_get(MultiDictObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *key = NULL,
+ *_default = Py_None,
+ *ret;
+
+ static char *getone_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getone",
+ getone_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+ ret = _multidict_getone(self, key, _default);
+ return ret;
+}
+
+static inline PyObject *
+multidict_keys(MultiDictObject *self)
+{
+ return multidict_keysview_new((PyObject*)self);
+}
+
+static inline PyObject *
+multidict_items(MultiDictObject *self)
+{
+ return multidict_itemsview_new((PyObject*)self);
+}
+
+static inline PyObject *
+multidict_values(MultiDictObject *self)
+{
+ return multidict_valuesview_new((PyObject*)self);
+}
+
+static inline PyObject *
+multidict_reduce(MultiDictObject *self)
+{
+ PyObject *items = NULL,
+ *items_list = NULL,
+ *args = NULL,
+ *result = NULL;
+
+ items = multidict_items(self);
+ if (items == NULL) {
+ goto ret;
+ }
+
+ items_list = PySequence_List(items);
+ if (items_list == NULL) {
+ goto ret;
+ }
+
+ args = PyTuple_Pack(1, items_list);
+ if (args == NULL) {
+ goto ret;
+ }
+
+ result = PyTuple_Pack(2, Py_TYPE(self), args);
+
+ret:
+ Py_XDECREF(args);
+ Py_XDECREF(items_list);
+ Py_XDECREF(items);
+
+ return result;
+}
+
+static inline PyObject *
+multidict_repr(PyObject *self)
+{
+ return PyObject_CallFunctionObjArgs(
+ repr_func, self, NULL);
+}
+
+static inline Py_ssize_t
+multidict_mp_len(MultiDictObject *self)
+{
+ return pair_list_len(&self->pairs);
+}
+
+static inline PyObject *
+multidict_mp_subscript(MultiDictObject *self, PyObject *key)
+{
+ return _multidict_getone(self, key, NULL);
+}
+
+static inline int
+multidict_mp_as_subscript(MultiDictObject *self, PyObject *key, PyObject *val)
+{
+ if (val == NULL) {
+ return pair_list_del(&self->pairs, key);
+ } else {
+ return pair_list_replace(&self->pairs, key, val);
+ }
+}
+
+static inline int
+multidict_sq_contains(MultiDictObject *self, PyObject *key)
+{
+ return pair_list_contains(&self->pairs, key);
+}
+
+static inline PyObject *
+multidict_tp_iter(MultiDictObject *self)
+{
+ return multidict_keys_iter_new(self);
+}
+
+static inline PyObject *
+multidict_tp_richcompare(PyObject *self, PyObject *other, int op)
+{
+ // TODO: refactoring me with love
+
+ int cmp = 0;
+
+ if (op != Py_EQ && op != Py_NE) {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+
+ if (MultiDict_CheckExact(other) || CIMultiDict_CheckExact(other)) {
+ cmp = _multidict_eq(
+ (MultiDictObject*)self,
+ (MultiDictObject*)other
+ );
+ if (cmp < 0) {
+ return NULL;
+ }
+ if (op == Py_NE) {
+ cmp = !cmp;
+ }
+ return PyBool_FromLong(cmp);
+ }
+
+ if (MultiDictProxy_CheckExact(other) || CIMultiDictProxy_CheckExact(other)) {
+ cmp = _multidict_eq(
+ (MultiDictObject*)self,
+ ((MultiDictProxyObject*)other)->md
+ );
+ if (cmp < 0) {
+ return NULL;
+ }
+ if (op == Py_NE) {
+ cmp = !cmp;
+ }
+ return PyBool_FromLong(cmp);
+ }
+
+ cmp = PyObject_IsInstance(other, (PyObject*)collections_abc_mapping);
+ if (cmp < 0) {
+ return NULL;
+ }
+
+ if (cmp) {
+ cmp = pair_list_eq_to_mapping(&((MultiDictObject*)self)->pairs, other);
+ if (cmp < 0) {
+ return NULL;
+ }
+ if (op == Py_NE) {
+ cmp = !cmp;
+ }
+ return PyBool_FromLong(cmp);
+ }
+
+ Py_RETURN_NOTIMPLEMENTED;
+}
+
+static inline void
+multidict_tp_dealloc(MultiDictObject *self)
+{
+ PyObject_GC_UnTrack(self);
+ Py_TRASHCAN_SAFE_BEGIN(self);
+ if (self->weaklist != NULL) {
+ PyObject_ClearWeakRefs((PyObject *)self);
+ };
+ pair_list_dealloc(&self->pairs);
+ Py_TYPE(self)->tp_free((PyObject *)self);
+ Py_TRASHCAN_SAFE_END(self);
+}
+
+static inline int
+multidict_tp_traverse(MultiDictObject *self, visitproc visit, void *arg)
+{
+ return pair_list_traverse(&self->pairs, visit, arg);
+}
+
+static inline int
+multidict_tp_clear(MultiDictObject *self)
+{
+ return pair_list_clear(&self->pairs);
+}
+
+PyDoc_STRVAR(multidict_getall_doc,
+"Return a list of all values matching the key.");
+
+PyDoc_STRVAR(multidict_getone_doc,
+"Get first value matching the key.");
+
+PyDoc_STRVAR(multidict_get_doc,
+"Get first value matching the key.\n\nThe method is alias for .getone().");
+
+PyDoc_STRVAR(multidict_keys_doc,
+"Return a new view of the dictionary's keys.");
+
+PyDoc_STRVAR(multidict_items_doc,
+"Return a new view of the dictionary's items *(key, value) pairs).");
+
+PyDoc_STRVAR(multidict_values_doc,
+"Return a new view of the dictionary's values.");
+
+/******************** MultiDict ********************/
+
+static inline int
+multidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds)
+{
+ if (pair_list_init(&self->pairs) < 0) {
+ return -1;
+ }
+ if (_multidict_extend(self, args, kwds, "MultiDict", 1) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static inline PyObject *
+multidict_add(MultiDictObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *key = NULL,
+ *val = NULL;
+
+ static char *kwlist[] = {"key", "value", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:add",
+ kwlist, &key, &val))
+ {
+ return NULL;
+ }
+
+ if (pair_list_add(&self->pairs, key, val) < 0) {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static inline PyObject *
+multidict_copy(MultiDictObject *self)
+{
+ return _multidict_copy(self, &multidict_type);
+}
+
+static inline PyObject *
+multidict_extend(MultiDictObject *self, PyObject *args, PyObject *kwds)
+{
+ if (_multidict_extend(self, args, kwds, "extend", 1) < 0) {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static inline PyObject *
+multidict_clear(MultiDictObject *self)
+{
+ if (pair_list_clear(&self->pairs) < 0) {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static inline PyObject *
+multidict_setdefault(MultiDictObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *key = NULL,
+ *_default = NULL;
+
+ static char *setdefault_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:setdefault",
+ setdefault_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+ return pair_list_set_default(&self->pairs, key, _default);
+}
+
+static inline PyObject *
+multidict_popone(MultiDictObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *key = NULL,
+ *_default = NULL,
+ *ret_val = NULL;
+
+ 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;
+}
+
+static inline PyObject *
+multidict_popall(MultiDictObject *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *key = NULL,
+ *_default = NULL,
+ *ret_val = NULL;
+
+ static char *popall_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popall",
+ popall_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+
+ ret_val = pair_list_pop_all(&self->pairs, key);
+
+ if (ret_val == NULL &&
+ PyErr_ExceptionMatches(PyExc_KeyError) &&
+ _default != NULL)
+ {
+ PyErr_Clear();
+ Py_INCREF(_default);
+ return _default;
+ }
+
+ return ret_val;
+}
+
+static inline PyObject *
+multidict_popitem(MultiDictObject *self)
+{
+ return pair_list_pop_item(&self->pairs);
+}
+
+static inline PyObject *
+multidict_update(MultiDictObject *self, PyObject *args, PyObject *kwds)
+{
+ if (_multidict_extend(self, args, kwds, "update", 0) < 0) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(multidict_add_doc,
+"Add the key and value, not overwriting any previous value.");
+
+PyDoc_STRVAR(multidict_copy_doc,
+"Return a copy of itself.");
+
+PyDoc_STRVAR(multdicit_method_extend_doc,
+"Extend current MultiDict with more values.\n\
+This method must be used instead of update.");
+
+PyDoc_STRVAR(multidict_clear_doc,
+"Remove all items from MultiDict");
+
+PyDoc_STRVAR(multidict_setdefault_doc,
+"Return value for key, set value to default if key is not present.");
+
+PyDoc_STRVAR(multidict_popone_doc,
+"Remove the last occurrence of key and return the corresponding value.\n\n\
+If key is not found, default is returned if given, otherwise KeyError is \
+raised.\n");
+
+PyDoc_STRVAR(multidict_popall_doc,
+"Remove all occurrences of key and return the list of corresponding values.\n\n\
+If key is not found, default is returned if given, otherwise KeyError is \
+raised.\n");
+
+PyDoc_STRVAR(multidict_popitem_doc,
+"Remove and return an arbitrary (key, value) pair.");
+
+PyDoc_STRVAR(multidict_update_doc,
+"Update the dictionary from *other*, overwriting existing keys.");
+
+
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9
+#define multidict_class_getitem Py_GenericAlias
+#else
+static inline PyObject *
+multidict_class_getitem(PyObject *self, PyObject *arg)
+{
+ Py_INCREF(self);
+ return self;
+}
+#endif
+
+
+PyDoc_STRVAR(sizeof__doc__,
+"D.__sizeof__() -> size of D in memory, in bytes");
+
+static inline PyObject *
+_multidict_sizeof(MultiDictObject *self)
+{
+ Py_ssize_t size = sizeof(MultiDictObject);
+ if (self->pairs.pairs != self->pairs.buffer) {
+ size += (Py_ssize_t)sizeof(pair_t) * self->pairs.capacity;
+ }
+ return PyLong_FromSsize_t(size);
+}
+
+
+static PySequenceMethods multidict_sequence = {
+ .sq_contains = (objobjproc)multidict_sq_contains,
+};
+
+static PyMappingMethods multidict_mapping = {
+ .mp_length = (lenfunc)multidict_mp_len,
+ .mp_subscript = (binaryfunc)multidict_mp_subscript,
+ .mp_ass_subscript = (objobjargproc)multidict_mp_as_subscript,
+};
+
+static PyMethodDef multidict_methods[] = {
+ {
+ "getall",
+ (PyCFunction)multidict_getall,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_getall_doc
+ },
+ {
+ "getone",
+ (PyCFunction)multidict_getone,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_getone_doc
+ },
+ {
+ "get",
+ (PyCFunction)multidict_get,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_get_doc
+ },
+ {
+ "keys",
+ (PyCFunction)multidict_keys,
+ METH_NOARGS,
+ multidict_keys_doc
+ },
+ {
+ "items",
+ (PyCFunction)multidict_items,
+ METH_NOARGS,
+ multidict_items_doc
+ },
+ {
+ "values",
+ (PyCFunction)multidict_values,
+ METH_NOARGS,
+ multidict_values_doc
+ },
+ {
+ "add",
+ (PyCFunction)multidict_add,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_add_doc
+ },
+ {
+ "copy",
+ (PyCFunction)multidict_copy,
+ METH_NOARGS,
+ multidict_copy_doc
+ },
+ {
+ "extend",
+ (PyCFunction)multidict_extend,
+ METH_VARARGS | METH_KEYWORDS,
+ multdicit_method_extend_doc
+ },
+ {
+ "clear",
+ (PyCFunction)multidict_clear,
+ METH_NOARGS,
+ multidict_clear_doc
+ },
+ {
+ "setdefault",
+ (PyCFunction)multidict_setdefault,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_setdefault_doc
+ },
+ {
+ "popone",
+ (PyCFunction)multidict_popone,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_popone_doc
+ },
+ {
+ "pop",
+ (PyCFunction)multidict_popone,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_popone_doc
+ },
+ {
+ "popall",
+ (PyCFunction)multidict_popall,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_popall_doc
+ },
+ {
+ "popitem",
+ (PyCFunction)multidict_popitem,
+ METH_NOARGS,
+ multidict_popitem_doc
+ },
+ {
+ "update",
+ (PyCFunction)multidict_update,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_update_doc
+ },
+ {
+ "__reduce__",
+ (PyCFunction)multidict_reduce,
+ METH_NOARGS,
+ NULL,
+ },
+ {
+ "__class_getitem__",
+ (PyCFunction)multidict_class_getitem,
+ METH_O | METH_CLASS,
+ NULL
+ },
+ {
+ "__sizeof__",
+ (PyCFunction)_multidict_sizeof,
+ METH_NOARGS,
+ sizeof__doc__,
+ },
+ {
+ NULL,
+ NULL
+ } /* sentinel */
+};
+
+
+PyDoc_STRVAR(MultDict_doc,
+"Dictionary with the support for duplicate keys.");
+
+
+static PyTypeObject multidict_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "multidict._multidict.MultiDict", /* tp_name */
+ sizeof(MultiDictObject), /* tp_basicsize */
+ .tp_dealloc = (destructor)multidict_tp_dealloc,
+ .tp_repr = (reprfunc)multidict_repr,
+ .tp_as_sequence = &multidict_sequence,
+ .tp_as_mapping = &multidict_mapping,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
+ .tp_doc = MultDict_doc,
+ .tp_traverse = (traverseproc)multidict_tp_traverse,
+ .tp_clear = (inquiry)multidict_tp_clear,
+ .tp_richcompare = (richcmpfunc)multidict_tp_richcompare,
+ .tp_weaklistoffset = offsetof(MultiDictObject, weaklist),
+ .tp_iter = (getiterfunc)multidict_tp_iter,
+ .tp_methods = multidict_methods,
+ .tp_init = (initproc)multidict_tp_init,
+ .tp_alloc = PyType_GenericAlloc,
+ .tp_new = PyType_GenericNew,
+ .tp_free = PyObject_GC_Del,
+};
+
+/******************** CIMultiDict ********************/
+
+static inline int
+cimultidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds)
+{
+ if (ci_pair_list_init(&self->pairs) < 0) {
+ return -1;
+ }
+ if (_multidict_extend(self, args, kwds, "CIMultiDict", 1) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static inline PyObject *
+cimultidict_copy(MultiDictObject *self)
+{
+ return _multidict_copy(self, &cimultidict_type);
+}
+
+PyDoc_STRVAR(cimultidict_copy_doc,
+"Return a copy of itself.");
+
+static PyMethodDef cimultidict_methods[] = {
+ {
+ "copy",
+ (PyCFunction)cimultidict_copy,
+ METH_NOARGS,
+ cimultidict_copy_doc
+ },
+ {
+ NULL,
+ NULL
+ } /* sentinel */
+};
+
+PyDoc_STRVAR(CIMultDict_doc,
+"Dictionary with the support for duplicate case-insensitive keys.");
+
+
+static PyTypeObject cimultidict_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "multidict._multidict.CIMultiDict", /* tp_name */
+ sizeof(MultiDictObject), /* tp_basicsize */
+ .tp_dealloc = (destructor)multidict_tp_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
+ .tp_doc = CIMultDict_doc,
+ .tp_traverse = (traverseproc)multidict_tp_traverse,
+ .tp_clear = (inquiry)multidict_tp_clear,
+ .tp_weaklistoffset = offsetof(MultiDictObject, weaklist),
+ .tp_methods = cimultidict_methods,
+ .tp_base = &multidict_type,
+ .tp_init = (initproc)cimultidict_tp_init,
+ .tp_alloc = PyType_GenericAlloc,
+ .tp_new = PyType_GenericNew,
+ .tp_free = PyObject_GC_Del,
+};
+
+/******************** MultiDictProxy ********************/
+
+static inline int
+multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ PyObject *arg = NULL;
+ MultiDictObject *md = NULL;
+
+ if (!PyArg_UnpackTuple(args, "multidict._multidict.MultiDictProxy",
+ 0, 1, &arg))
+ {
+ return -1;
+ }
+ if (arg == NULL) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "__init__() missing 1 required positional argument: 'arg'"
+ );
+ return -1;
+ }
+ if (!MultiDictProxy_CheckExact(arg) &&
+ !CIMultiDict_CheckExact(arg) &&
+ !MultiDict_CheckExact(arg))
+ {
+ PyErr_Format(
+ PyExc_TypeError,
+ "ctor requires MultiDict or MultiDictProxy instance, "
+ "not <classs '%s'>",
+ Py_TYPE(arg)->tp_name
+ );
+ return -1;
+ }
+
+ md = (MultiDictObject*)arg;
+ if (MultiDictProxy_CheckExact(arg)) {
+ md = ((MultiDictProxyObject*)arg)->md;
+ }
+ Py_INCREF(md);
+ self->md = md;
+
+ return 0;
+}
+
+static inline PyObject *
+multidict_proxy_getall(MultiDictProxyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ return multidict_getall(self->md, args, kwds);
+}
+
+static inline PyObject *
+multidict_proxy_getone(MultiDictProxyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ return multidict_getone(self->md, args, kwds);
+}
+
+static inline PyObject *
+multidict_proxy_get(MultiDictProxyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ return multidict_get(self->md, args, kwds);
+}
+
+static inline PyObject *
+multidict_proxy_keys(MultiDictProxyObject *self)
+{
+ return multidict_keys(self->md);
+}
+
+static inline PyObject *
+multidict_proxy_items(MultiDictProxyObject *self)
+{
+ return multidict_items(self->md);
+}
+
+static inline PyObject *
+multidict_proxy_values(MultiDictProxyObject *self)
+{
+ return multidict_values(self->md);
+}
+
+static inline PyObject *
+multidict_proxy_copy(MultiDictProxyObject *self)
+{
+ return _multidict_proxy_copy(self, &multidict_type);
+}
+
+static inline PyObject *
+multidict_proxy_reduce(MultiDictProxyObject *self)
+{
+ PyErr_Format(
+ PyExc_TypeError,
+ "can't pickle %s objects", Py_TYPE(self)->tp_name
+ );
+
+ return NULL;
+}
+
+static inline Py_ssize_t
+multidict_proxy_mp_len(MultiDictProxyObject *self)
+{
+ return multidict_mp_len(self->md);
+}
+
+static inline PyObject *
+multidict_proxy_mp_subscript(MultiDictProxyObject *self, PyObject *key)
+{
+ return multidict_mp_subscript(self->md, key);
+}
+
+static inline int
+multidict_proxy_sq_contains(MultiDictProxyObject *self, PyObject *key)
+{
+ return multidict_sq_contains(self->md, key);
+}
+
+static inline PyObject *
+multidict_proxy_tp_iter(MultiDictProxyObject *self)
+{
+ return multidict_tp_iter(self->md);
+}
+
+static inline PyObject *
+multidict_proxy_tp_richcompare(MultiDictProxyObject *self, PyObject *other,
+ int op)
+{
+ return multidict_tp_richcompare((PyObject*)self->md, other, op);
+}
+
+static inline void
+multidict_proxy_tp_dealloc(MultiDictProxyObject *self)
+{
+ PyObject_GC_UnTrack(self);
+ if (self->weaklist != NULL) {
+ PyObject_ClearWeakRefs((PyObject *)self);
+ };
+ Py_XDECREF(self->md);
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static inline int
+multidict_proxy_tp_traverse(MultiDictProxyObject *self, visitproc visit,
+ void *arg)
+{
+ Py_VISIT(self->md);
+ return 0;
+}
+
+static inline int
+multidict_proxy_tp_clear(MultiDictProxyObject *self)
+{
+ Py_CLEAR(self->md);
+ return 0;
+}
+
+static PySequenceMethods multidict_proxy_sequence = {
+ .sq_contains = (objobjproc)multidict_proxy_sq_contains,
+};
+
+static PyMappingMethods multidict_proxy_mapping = {
+ .mp_length = (lenfunc)multidict_proxy_mp_len,
+ .mp_subscript = (binaryfunc)multidict_proxy_mp_subscript,
+};
+
+static PyMethodDef multidict_proxy_methods[] = {
+ {
+ "getall",
+ (PyCFunction)multidict_proxy_getall,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_getall_doc
+ },
+ {
+ "getone",
+ (PyCFunction)multidict_proxy_getone,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_getone_doc
+ },
+ {
+ "get",
+ (PyCFunction)multidict_proxy_get,
+ METH_VARARGS | METH_KEYWORDS,
+ multidict_get_doc
+ },
+ {
+ "keys",
+ (PyCFunction)multidict_proxy_keys,
+ METH_NOARGS,
+ multidict_keys_doc
+ },
+ {
+ "items",
+ (PyCFunction)multidict_proxy_items,
+ METH_NOARGS,
+ multidict_items_doc
+ },
+ {
+ "values",
+ (PyCFunction)multidict_proxy_values,
+ METH_NOARGS,
+ multidict_values_doc
+ },
+ {
+ "copy",
+ (PyCFunction)multidict_proxy_copy,
+ METH_NOARGS,
+ multidict_copy_doc
+ },
+ {
+ "__reduce__",
+ (PyCFunction)multidict_proxy_reduce,
+ METH_NOARGS,
+ NULL
+ },
+ {
+ "__class_getitem__",
+ (PyCFunction)multidict_class_getitem,
+ METH_O | METH_CLASS,
+ NULL
+ },
+ {
+ NULL,
+ NULL
+ } /* sentinel */
+};
+
+
+PyDoc_STRVAR(MultDictProxy_doc,
+"Read-only proxy for MultiDict instance.");
+
+
+static PyTypeObject multidict_proxy_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "multidict._multidict.MultiDictProxy", /* tp_name */
+ sizeof(MultiDictProxyObject), /* tp_basicsize */
+ .tp_dealloc = (destructor)multidict_proxy_tp_dealloc,
+ .tp_repr = (reprfunc)multidict_repr,
+ .tp_as_sequence = &multidict_proxy_sequence,
+ .tp_as_mapping = &multidict_proxy_mapping,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
+ .tp_doc = MultDictProxy_doc,
+ .tp_traverse = (traverseproc)multidict_proxy_tp_traverse,
+ .tp_clear = (inquiry)multidict_proxy_tp_clear,
+ .tp_richcompare = (richcmpfunc)multidict_proxy_tp_richcompare,
+ .tp_weaklistoffset = offsetof(MultiDictProxyObject, weaklist),
+ .tp_iter = (getiterfunc)multidict_proxy_tp_iter,
+ .tp_methods = multidict_proxy_methods,
+ .tp_init = (initproc)multidict_proxy_tp_init,
+ .tp_alloc = PyType_GenericAlloc,
+ .tp_new = PyType_GenericNew,
+ .tp_free = PyObject_GC_Del,
+};
+
+/******************** CIMultiDictProxy ********************/
+
+static inline int
+cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ PyObject *arg = NULL;
+ MultiDictObject *md = NULL;
+
+ if (!PyArg_UnpackTuple(args, "multidict._multidict.CIMultiDictProxy",
+ 1, 1, &arg))
+ {
+ return -1;
+ }
+ if (arg == NULL) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "__init__() missing 1 required positional argument: 'arg'"
+ );
+ return -1;
+ }
+ if (!CIMultiDictProxy_CheckExact(arg) && !CIMultiDict_CheckExact(arg)) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "ctor requires CIMultiDict or CIMultiDictProxy instance, "
+ "not <class '%s'>",
+ Py_TYPE(arg)->tp_name
+ );
+ return -1;
+ }
+
+ md = (MultiDictObject*)arg;
+ if (CIMultiDictProxy_CheckExact(arg)) {
+ md = ((MultiDictProxyObject*)arg)->md;
+ }
+ Py_INCREF(md);
+ self->md = md;
+
+ return 0;
+}
+
+static inline PyObject *
+cimultidict_proxy_copy(MultiDictProxyObject *self)
+{
+ return _multidict_proxy_copy(self, &cimultidict_type);
+}
+
+
+PyDoc_STRVAR(CIMultDictProxy_doc,
+"Read-only proxy for CIMultiDict instance.");
+
+PyDoc_STRVAR(cimultidict_proxy_copy_doc,
+"Return copy of itself");
+
+static PyMethodDef cimultidict_proxy_methods[] = {
+ {
+ "copy",
+ (PyCFunction)cimultidict_proxy_copy,
+ METH_NOARGS,
+ cimultidict_proxy_copy_doc
+ },
+ {
+ NULL,
+ NULL
+ } /* sentinel */
+};
+
+static PyTypeObject cimultidict_proxy_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "multidict._multidict.CIMultiDictProxy", /* tp_name */
+ sizeof(MultiDictProxyObject), /* tp_basicsize */
+ .tp_dealloc = (destructor)multidict_proxy_tp_dealloc,
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
+ .tp_doc = CIMultDictProxy_doc,
+ .tp_traverse = (traverseproc)multidict_proxy_tp_traverse,
+ .tp_clear = (inquiry)multidict_proxy_tp_clear,
+ .tp_richcompare = (richcmpfunc)multidict_proxy_tp_richcompare,
+ .tp_weaklistoffset = offsetof(MultiDictProxyObject, weaklist),
+ .tp_methods = cimultidict_proxy_methods,
+ .tp_base = &multidict_proxy_type,
+ .tp_init = (initproc)cimultidict_proxy_tp_init,
+ .tp_alloc = PyType_GenericAlloc,
+ .tp_new = PyType_GenericNew,
+ .tp_free = PyObject_GC_Del,
+};
+
+/******************** Other functions ********************/
+
+static inline PyObject *
+getversion(PyObject *self, PyObject *md)
+{
+ pair_list_t *pairs = NULL;
+ if (MultiDict_CheckExact(md) || CIMultiDict_CheckExact(md)) {
+ pairs = &((MultiDictObject*)md)->pairs;
+ } else if (MultiDictProxy_CheckExact(md) || CIMultiDictProxy_CheckExact(md)) {
+ pairs = &((MultiDictProxyObject*)md)->md->pairs;
+ } else {
+ PyErr_Format(PyExc_TypeError, "unexpected type");
+ return NULL;
+ }
+ return PyLong_FromUnsignedLong(pair_list_version(pairs));
+}
+
+/******************** Module ********************/
+
+static inline void
+module_free(void *m)
+{
+ Py_CLEAR(collections_abc_mapping);
+ Py_CLEAR(collections_abc_mut_mapping);
+ Py_CLEAR(collections_abc_mut_multi_mapping);
+}
+
+static PyMethodDef multidict_module_methods[] = {
+ {
+ "getversion",
+ (PyCFunction)getversion,
+ METH_O
+ },
+ {
+ NULL,
+ NULL
+ } /* sentinel */
+};
+
+static PyModuleDef multidict_module = {
+ PyModuleDef_HEAD_INIT, /* m_base */
+ "_multidict", /* m_name */
+ .m_size = -1,
+ .m_methods = multidict_module_methods,
+ .m_free = (freefunc)module_free,
+};
+
+PyMODINIT_FUNC
+PyInit__multidict()
+{
+ PyObject *module = NULL,
+ *reg_func_call_result = NULL;
+
+#define WITH_MOD(NAME) \
+ Py_CLEAR(module); \
+ module = PyImport_ImportModule(NAME); \
+ if (module == NULL) { \
+ goto fail; \
+ }
+
+#define GET_MOD_ATTR(VAR, NAME) \
+ VAR = PyObject_GetAttrString(module, NAME); \
+ if (VAR == NULL) { \
+ goto fail; \
+ }
+
+ if (multidict_views_init() < 0) {
+ goto fail;
+ }
+
+ if (multidict_iter_init() < 0) {
+ goto fail;
+ }
+
+ if (istr_init() < 0) {
+ goto fail;
+ }
+
+ if (PyType_Ready(&multidict_type) < 0 ||
+ PyType_Ready(&cimultidict_type) < 0 ||
+ PyType_Ready(&multidict_proxy_type) < 0 ||
+ PyType_Ready(&cimultidict_proxy_type) < 0)
+ {
+ goto fail;
+ }
+
+ WITH_MOD("collections.abc");
+ GET_MOD_ATTR(collections_abc_mapping, "Mapping");
+
+ WITH_MOD("multidict._abc");
+ GET_MOD_ATTR(collections_abc_mut_mapping, "MultiMapping");
+
+ WITH_MOD("multidict._abc");
+ GET_MOD_ATTR(collections_abc_mut_multi_mapping, "MutableMultiMapping");
+
+ WITH_MOD("multidict._multidict_base");
+ GET_MOD_ATTR(repr_func, "_mdrepr");
+
+ /* Register in _abc mappings (CI)MultiDict and (CI)MultiDictProxy */
+ reg_func_call_result = PyObject_CallMethod(
+ collections_abc_mut_mapping,
+ "register", "O",
+ (PyObject*)&multidict_proxy_type
+ );
+ if (reg_func_call_result == NULL) {
+ goto fail;
+ }
+ Py_DECREF(reg_func_call_result);
+
+ reg_func_call_result = PyObject_CallMethod(
+ collections_abc_mut_mapping,
+ "register", "O",
+ (PyObject*)&cimultidict_proxy_type
+ );
+ if (reg_func_call_result == NULL) {
+ goto fail;
+ }
+ Py_DECREF(reg_func_call_result);
+
+ reg_func_call_result = PyObject_CallMethod(
+ collections_abc_mut_multi_mapping,
+ "register", "O",
+ (PyObject*)&multidict_type
+ );
+ if (reg_func_call_result == NULL) {
+ goto fail;
+ }
+ Py_DECREF(reg_func_call_result);
+
+ reg_func_call_result = PyObject_CallMethod(
+ collections_abc_mut_multi_mapping,
+ "register", "O",
+ (PyObject*)&cimultidict_type
+ );
+ if (reg_func_call_result == NULL) {
+ goto fail;
+ }
+ Py_DECREF(reg_func_call_result);
+
+ /* Instantiate this module */
+ module = PyModule_Create(&multidict_module);
+
+ Py_INCREF(&istr_type);
+ if (PyModule_AddObject(
+ module, "istr", (PyObject*)&istr_type) < 0)
+ {
+ goto fail;
+ }
+
+ Py_INCREF(&multidict_type);
+ if (PyModule_AddObject(
+ module, "MultiDict", (PyObject*)&multidict_type) < 0)
+ {
+ goto fail;
+ }
+
+ Py_INCREF(&cimultidict_type);
+ if (PyModule_AddObject(
+ module, "CIMultiDict", (PyObject*)&cimultidict_type) < 0)
+ {
+ goto fail;
+ }
+
+ Py_INCREF(&multidict_proxy_type);
+ if (PyModule_AddObject(
+ module, "MultiDictProxy", (PyObject*)&multidict_proxy_type) < 0)
+ {
+ goto fail;
+ }
+
+ Py_INCREF(&cimultidict_proxy_type);
+ if (PyModule_AddObject(
+ module, "CIMultiDictProxy", (PyObject*)&cimultidict_proxy_type) < 0)
+ {
+ goto fail;
+ }
+
+ return module;
+
+fail:
+ Py_XDECREF(collections_abc_mapping);
+ Py_XDECREF(collections_abc_mut_mapping);
+ Py_XDECREF(collections_abc_mut_multi_mapping);
+
+ return NULL;
+
+#undef WITH_MOD
+#undef GET_MOD_ATTR
+}