Files
adminandClaude Opus 5 79843aa2ae SolarManager unter Versionsverwaltung
Erster Stand der Hintergrundprozesse, die auf der Synology unter
/volume1/homes/wagner/SolarManager laufen: der Manager selbst, die Sammler
je Geraet, die MQTT-Bruecke, der Wecker und - neu hinzugezogen - der
AutoAction-Runner, der als Hintergrundprozess hierher gehoert und nicht ins
Web-Verzeichnis.

Zugangsdaten stehen nicht mehr im Quelltext, sondern in config.ini, die
nicht mit eingecheckt wird. Vorlage ist config.ini.example, gelesen wird sie
von konfig.py. Betroffen waren solarManager.py (Datenbank und Wattpilot),
zeit.py, gatherWaterData.py, wecker.py und skoda_testdaten.py, das sich das
Passwort bisher aus dem Quelltext eines anderen Moduls herausgesucht hat.

Die Kia-Anbindung ist mit dem Fahrzeug entfallen: kiaTest.py,
gatherCarData.py und hyundai_kia_connect_api sind nicht mehr dabei, ebenso
gatherInverterData.py, auf das nur noch eine auskommentierte Zeile zeigte.

Die mitgelieferten Bibliotheken bleiben im Repository - die NAS hat kein
pip, sie muessen neben den Skripten liegen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:46:59 +02:00

1825 lines
45 KiB
C

#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"
#ifndef _PyArg_UnpackKeywords
#define FASTCALL_OLD
#endif
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 *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *list = NULL,
*key = NULL,
*_default = NULL;
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:getall", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &_default)) {
return NULL;
}
#else
static _PyArg_Parser _parser = {NULL, _keywords, "getall", 0};
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
&_parser, 1, 2, 0, argsbuf);
if (!args) {
return NULL;
}
key = args[0];
if (!noptargs) {
goto skip_optional_pos;
}
_default = args[1];
skip_optional_pos:
#endif
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 *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*_default = NULL;
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:getone", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &_default)) {
return NULL;
}
#else
static _PyArg_Parser _parser = {NULL, _keywords, "getone", 0};
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
&_parser, 1, 2, 0, argsbuf);
if (!args) {
return NULL;
}
key = args[0];
if (!noptargs) {
goto skip_optional_pos;
}
_default = args[1];
skip_optional_pos:
#endif
return _multidict_getone(self, key, _default);
}
static inline PyObject *
multidict_get(MultiDictObject *self, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*_default = Py_None,
*ret;
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:get", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &_default)) {
return NULL;
}
#else
static _PyArg_Parser _parser = {NULL, _keywords, "get", 0};
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
&_parser, 1, 2, 0, argsbuf);
if (!args) {
return NULL;
}
key = args[0];
if (!noptargs) {
goto skip_optional_pos;
}
_default = args[1];
skip_optional_pos:
#endif
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 *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*val = NULL;
static const char * const _keywords[] = {"key", "value", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"OO:add", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &val)) {
return NULL;
}
#else
static _PyArg_Parser _parser = {NULL, _keywords, "add", 0};
PyObject *argsbuf[2];
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
&_parser, 2, 2, 0, argsbuf);
if (!args) {
return NULL;
}
key = args[0];
val = args[1];
#endif
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 *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*_default = NULL;
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:setdefault", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &_default)) {
return NULL;
}
#else
static _PyArg_Parser _parser = {NULL, _keywords, "setdefault", 0};
PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
&_parser, 1, 2, 0, argsbuf);
if (!args) {
return NULL;
}
key = args[0];
if (!noptargs) {
goto skip_optional_pos;
}
_default = args[1];
skip_optional_pos:
#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)
{
PyObject *key = NULL,
*_default = NULL,
*ret_val = NULL;
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:popone", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &_default)) {
return NULL;
}
#else
static _PyArg_Parser _parser = {NULL, _keywords, "popone", 0};
PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
&_parser, 1, 2, 0, argsbuf);
if (!args) {
return NULL;
}
key = args[0];
if (!noptargs) {
goto skip_optional_pos;
}
_default = args[1];
skip_optional_pos:
#endif
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_pop(MultiDictObject *self, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*_default = NULL,
*ret_val = NULL;
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:pop", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &_default)) {
return NULL;
}
#else
static _PyArg_Parser _parser = {NULL, _keywords, "pop", 0};
PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
&_parser, 1, 2, 0, argsbuf);
if (!args) {
return NULL;
}
key = args[0];
if (!noptargs) {
goto skip_optional_pos;
}
_default = args[1];
skip_optional_pos:
#endif
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 *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*_default = NULL,
*ret_val = NULL;
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:popall", _keywords, 0};
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&key, &_default)) {
return NULL;
}
#else
static _PyArg_Parser _parser = {NULL, _keywords, "popall", 0};
PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
&_parser, 1, 2, 0, argsbuf);
if (!args) {
return NULL;
}
key = args[0];
if (!noptargs) {
goto skip_optional_pos;
}
_default = args[1];
skip_optional_pos:
#endif
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_pop_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_FASTCALL | METH_KEYWORDS,
multidict_getall_doc
},
{
"getone",
(PyCFunction)multidict_getone,
METH_FASTCALL | METH_KEYWORDS,
multidict_getone_doc
},
{
"get",
(PyCFunction)multidict_get,
METH_FASTCALL | 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_FASTCALL | 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_FASTCALL | METH_KEYWORDS,
multidict_setdefault_doc
},
{
"popone",
(PyCFunction)multidict_popone,
METH_FASTCALL | METH_KEYWORDS,
multidict_popone_doc
},
{
"pop",
(PyCFunction)multidict_pop,
METH_FASTCALL | METH_KEYWORDS,
multidict_pop_doc
},
{
"popall",
(PyCFunction)multidict_popall,
METH_FASTCALL | 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 <class '%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 *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
return multidict_getall(self->md, args, nargs, kwnames);
}
static inline PyObject *
multidict_proxy_getone(MultiDictProxyObject *self, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
return multidict_getone(self->md, args, nargs, kwnames);
}
static inline PyObject *
multidict_proxy_get(MultiDictProxyObject *self, PyObject *const *args,
Py_ssize_t nargs, PyObject *kwnames)
{
return multidict_get(self->md, args, nargs, kwnames);
}
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_FASTCALL | METH_KEYWORDS,
multidict_getall_doc
},
{
"getone",
(PyCFunction)multidict_proxy_getone,
METH_FASTCALL | METH_KEYWORDS,
multidict_getone_doc
},
{
"get",
(PyCFunction)multidict_proxy_get,
METH_FASTCALL | 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
}