summaryrefslogtreecommitdiffstats
path: root/contrib/python
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2025-04-16 22:43:01 +0300
committerrobot-piglet <[email protected]>2025-04-16 22:54:05 +0300
commit475f6be41dd8364cd4726086ee21d6ad3215964d (patch)
treebecfcd2f7a176de8c197268398931f9235e1cbad /contrib/python
parente4792029dcd9ab8f79be717600a929507333d85a (diff)
Intermediate changes
commit_hash:c3dfa83d652d97bdc5a76419f4dc85da476da240
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/multidict/.dist-info/METADATA7
-rw-r--r--contrib/python/multidict/README.rst5
-rw-r--r--contrib/python/multidict/multidict/__init__.py2
-rw-r--r--contrib/python/multidict/multidict/_multidict.c683
-rw-r--r--contrib/python/multidict/multidict/_multidict_py.py19
-rw-r--r--contrib/python/multidict/multidict/_multilib/defs.h23
-rw-r--r--contrib/python/multidict/multidict/_multilib/dict.h12
-rw-r--r--contrib/python/multidict/multidict/_multilib/istr.h113
-rw-r--r--contrib/python/multidict/multidict/_multilib/iter.h125
-rw-r--r--contrib/python/multidict/multidict/_multilib/pair_list.h100
-rw-r--r--contrib/python/multidict/multidict/_multilib/parser.h1
-rw-r--r--contrib/python/multidict/multidict/_multilib/state.h132
-rw-r--r--contrib/python/multidict/multidict/_multilib/views.h378
-rw-r--r--contrib/python/multidict/tests/isolated/multidict_extend_dict.py27
-rw-r--r--contrib/python/multidict/tests/isolated/multidict_extend_multidict.py21
-rw-r--r--contrib/python/multidict/tests/isolated/multidict_extend_tuple.py27
-rw-r--r--contrib/python/multidict/tests/isolated/multidict_update_multidict.py21
-rw-r--r--contrib/python/multidict/tests/test_leaks.py31
-rw-r--r--contrib/python/multidict/tests/test_multidict.py138
-rw-r--r--contrib/python/multidict/tests/test_multidict_benchmarks.py19
-rw-r--r--contrib/python/multidict/tests/test_views_benchmarks.py100
-rw-r--r--contrib/python/multidict/ya.make2
22 files changed, 1323 insertions, 663 deletions
diff --git a/contrib/python/multidict/.dist-info/METADATA b/contrib/python/multidict/.dist-info/METADATA
index 3cd254428e2..9ee0987b9db 100644
--- a/contrib/python/multidict/.dist-info/METADATA
+++ b/contrib/python/multidict/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: multidict
-Version: 6.3.0
+Version: 6.4.3
Summary: multidict implementation
Home-page: https://github.com/aio-libs/multidict
Author: Andrew Svetlov
@@ -137,7 +137,12 @@ e.g.:
Please note, the pure Python (uncompiled) version is about 20-50 times slower depending on
the usage scenario!!!
+For extension development, set the ``MULTIDICT_DEBUG_BUILD`` environment variable to compile
+the extensions in debug mode:
+.. code-block:: console
+
+ $ MULTIDICT_DEBUG_BUILD=1 pip install multidict
Changelog
---------
diff --git a/contrib/python/multidict/README.rst b/contrib/python/multidict/README.rst
index fbab818a979..50a7f041b59 100644
--- a/contrib/python/multidict/README.rst
+++ b/contrib/python/multidict/README.rst
@@ -104,7 +104,12 @@ e.g.:
Please note, the pure Python (uncompiled) version is about 20-50 times slower depending on
the usage scenario!!!
+For extension development, set the ``MULTIDICT_DEBUG_BUILD`` environment variable to compile
+the extensions in debug mode:
+.. code-block:: console
+
+ $ MULTIDICT_DEBUG_BUILD=1 pip install multidict
Changelog
---------
diff --git a/contrib/python/multidict/multidict/__init__.py b/contrib/python/multidict/multidict/__init__.py
index 7159a2d6c0f..31b077f58c0 100644
--- a/contrib/python/multidict/multidict/__init__.py
+++ b/contrib/python/multidict/multidict/__init__.py
@@ -22,7 +22,7 @@ __all__ = (
"getversion",
)
-__version__ = "6.3.0"
+__version__ = "6.4.3"
if TYPE_CHECKING or not USE_EXTENSIONS:
diff --git a/contrib/python/multidict/multidict/_multidict.c b/contrib/python/multidict/multidict/_multidict.c
index 64d3c395e96..04af12cc416 100644
--- a/contrib/python/multidict/multidict/_multidict.c
+++ b/contrib/python/multidict/multidict/_multidict.c
@@ -3,38 +3,43 @@
#include "_multilib/pythoncapi_compat.h"
-// Include order important
-#include "_multilib/defs.h"
-#include "_multilib/istr.h"
-#include "_multilib/pair_list.h"
#include "_multilib/dict.h"
+#include "_multilib/istr.h"
#include "_multilib/iter.h"
+#include "_multilib/pair_list.h"
#include "_multilib/parser.h"
+#include "_multilib/state.h"
#include "_multilib/views.h"
-static PyTypeObject multidict_type;
-static PyTypeObject cimultidict_type;
-static PyTypeObject multidict_proxy_type;
-static PyTypeObject cimultidict_proxy_type;
-
-#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)))
+#define MultiDict_CheckExact(state, obj) Py_IS_TYPE(obj, state->MultiDictType)
+#define MultiDict_Check(state, obj) \
+ (MultiDict_CheckExact(state, obj) \
+ || PyObject_TypeCheck(obj, state->MultiDictType))
+#define CIMultiDict_CheckExact(state, obj) Py_IS_TYPE(obj, state->CIMultiDictType)
+#define CIMultiDict_Check(state, obj) \
+ (CIMultiDict_CheckExact(state, obj) \
+ || PyObject_TypeCheck(obj, state->CIMultiDictType))
+#define AnyMultiDict_Check(state, obj) \
+ (MultiDict_CheckExact(state, obj) \
+ || CIMultiDict_CheckExact(state, obj) \
+ || PyObject_TypeCheck(obj, state->MultiDictType))
+#define MultiDictProxy_CheckExact(state, obj) Py_IS_TYPE(obj, state->MultiDictProxyType)
+#define MultiDictProxy_Check(state, obj) \
+ (MultiDictProxy_CheckExact(state, obj) \
+ || PyObject_TypeCheck(obj, state->MultiDictProxyType))
+#define CIMultiDictProxy_CheckExact(state, obj) \
+ Py_IS_TYPE(obj, state->CIMultiDictProxyType)
+#define CIMultiDictProxy_Check(state, obj) \
+ (CIMultiDictProxy_CheckExact(state, obj) \
+ || PyObject_TypeCheck(obj, state->CIMultiDictProxyType))
+#define AnyMultiDictProxy_Check(state, obj) \
+ (MultiDictProxy_CheckExact(state, obj) \
+ || CIMultiDictProxy_CheckExact(state, obj) \
+ || PyObject_TypeCheck(obj, state->MultiDictProxyType))
/******************** Internal Methods ********************/
-/* Forward declaration */
-static PyObject *multidict_items(MultiDictObject *self);
-
static inline PyObject *
_multidict_getone(MultiDictObject *self, PyObject *key, PyObject *_default)
{
@@ -62,6 +67,7 @@ static inline int
_multidict_extend(MultiDictObject *self, PyObject *arg,
PyObject *kwds, const char *name, int do_add)
{
+ mod_state *state = self->pairs.state;
PyObject *used = NULL;
PyObject *seq = NULL;
pair_list_t *list;
@@ -78,12 +84,12 @@ _multidict_extend(MultiDictObject *self, PyObject *arg,
}
if (arg != NULL) {
- if (MultiDict_CheckExact(arg) || CIMultiDict_CheckExact(arg)) {
+ if (AnyMultiDict_Check(state, arg)) {
list = &((MultiDictObject*)arg)->pairs;
if (pair_list_update_from_pair_list(&self->pairs, used, list) < 0) {
goto fail;
}
- } else if (MultiDictProxy_CheckExact(arg) || CIMultiDictProxy_CheckExact(arg)) {
+ } else if (AnyMultiDictProxy_Check(state, arg)) {
list = &((MultiDictProxyObject*)arg)->md->pairs;
if (pair_list_update_from_pair_list(&self->pairs, used, list) < 0) {
goto fail;
@@ -219,12 +225,8 @@ fail:
/******************** Base Methods ********************/
static inline PyObject *
-multidict_getall(
- MultiDictObject *self,
- PyObject *const *args,
- Py_ssize_t nargs,
- PyObject *kwnames
-)
+multidict_getall(MultiDictObject *self, PyObject *const *args,
+ Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *list = NULL,
*key = NULL,
@@ -252,12 +254,8 @@ multidict_getall(
}
static inline PyObject *
-multidict_getone(
- MultiDictObject *self,
- PyObject *const *args,
- Py_ssize_t nargs,
- PyObject *kwnames
-)
+multidict_getone(MultiDictObject *self, PyObject *const *args,
+ Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*_default = NULL;
@@ -270,12 +268,8 @@ multidict_getone(
}
static inline PyObject *
-multidict_get(
- MultiDictObject *self,
- PyObject *const *args,
- Py_ssize_t nargs,
- PyObject *kwnames
-)
+multidict_get(MultiDictObject *self, PyObject *const *args,
+ Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*_default = NULL,
@@ -319,7 +313,7 @@ multidict_reduce(MultiDictObject *self)
*args = NULL,
*result = NULL;
- items = multidict_items(self);
+ items = multidict_itemsview_new(self);
if (items == NULL) {
goto ret;
}
@@ -335,7 +329,6 @@ multidict_reduce(MultiDictObject *self)
}
result = PyTuple_Pack(2, Py_TYPE(self), args);
-
ret:
Py_XDECREF(args);
Py_XDECREF(items_list);
@@ -347,10 +340,20 @@ ret:
static inline PyObject *
multidict_repr(MultiDictObject *self)
{
- PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__");
- if (name == NULL)
+ int tmp = Py_ReprEnter((PyObject *)self);
+ if (tmp < 0) {
+ return NULL;
+ }
+ if (tmp > 0) {
+ return PyUnicode_FromString("...");
+ }
+ PyObject *name = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "__name__");
+ if (name == NULL) {
+ Py_ReprLeave((PyObject *)self);
return NULL;
+ }
PyObject *ret = pair_list_repr(&self->pairs, name, true, true);
+ Py_ReprLeave((PyObject *)self);
Py_CLEAR(name);
return ret;
}
@@ -406,12 +409,13 @@ multidict_tp_richcompare(PyObject *self, PyObject *other, int op)
return PyBool_FromLong(cmp);
}
- if (MultiDict_CheckExact(other) || CIMultiDict_CheckExact(other)) {
+ mod_state *state = ((MultiDictObject*)self)->pairs.state;
+ if (AnyMultiDict_Check(state, other)) {
cmp = pair_list_eq(
&((MultiDictObject*)self)->pairs,
&((MultiDictObject*)other)->pairs
);
- } else if (MultiDictProxy_CheckExact(other) || CIMultiDictProxy_CheckExact(other)) {
+ } else if (AnyMultiDictProxy_Check(state, other)) {
cmp = pair_list_eq(
&((MultiDictObject*)self)->pairs,
&((MultiDictProxyObject*)other)->md->pairs
@@ -430,7 +434,8 @@ multidict_tp_richcompare(PyObject *self, PyObject *other, int op)
Py_CLEAR(keys);
}
if (fits) {
- cmp = pair_list_eq_to_mapping(&((MultiDictObject*)self)->pairs, other);
+ cmp = pair_list_eq_to_mapping(&((MultiDictObject*)self)->pairs,
+ other);
} else {
cmp = 0; // e.g., multidict is not equal to a list
}
@@ -449,9 +454,7 @@ multidict_tp_dealloc(MultiDictObject *self)
{
PyObject_GC_UnTrack(self);
Py_TRASHCAN_BEGIN(self, multidict_tp_dealloc)
- if (self->weaklist != NULL) {
- PyObject_ClearWeakRefs((PyObject *)self);
- };
+ PyObject_ClearWeakRefs((PyObject *)self);
pair_list_dealloc(&self->pairs);
Py_TYPE(self)->tp_free((PyObject *)self);
Py_TRASHCAN_END // there should be no code after this
@@ -460,6 +463,7 @@ multidict_tp_dealloc(MultiDictObject *self)
static inline int
multidict_tp_traverse(MultiDictObject *self, visitproc visit, void *arg)
{
+ Py_VISIT(Py_TYPE(self));
return pair_list_traverse(&self->pairs, visit, arg);
}
@@ -492,27 +496,28 @@ PyDoc_STRVAR(multidict_values_doc,
static inline int
multidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
+ mod_state *state = get_mod_state_by_def((PyObject *)self);
PyObject *arg = NULL;
Py_ssize_t size = _multidict_extend_parse_args(args, kwds, "MultiDict", &arg);
if (size < 0) {
- return -1;
+ goto fail;
}
- if (pair_list_init(&self->pairs, size) < 0) {
- return -1;
+ if (pair_list_init(&self->pairs, state, size) < 0) {
+ goto fail;
}
if (_multidict_extend(self, arg, kwds, "MultiDict", 1) < 0) {
- return -1;
+ goto fail;
}
+ Py_CLEAR(arg);
return 0;
+fail:
+ Py_CLEAR(arg);
+ return -1;
}
static inline PyObject *
-multidict_add(
- MultiDictObject *self,
- PyObject *const *args,
- Py_ssize_t nargs,
- PyObject *kwnames
-)
+multidict_add(MultiDictObject *self, PyObject *const *args,
+ Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*val = NULL;
@@ -534,14 +539,17 @@ multidict_extend(MultiDictObject *self, PyObject *args, PyObject *kwds)
PyObject *arg = NULL;
Py_ssize_t size = _multidict_extend_parse_args(args, kwds, "extend", &arg);
if (size < 0) {
- return NULL;
+ goto fail;
}
pair_list_grow(&self->pairs, size);
if (_multidict_extend(self, arg, kwds, "extend", 1) < 0) {
- return NULL;
+ goto fail;
}
-
+ Py_CLEAR(arg);
Py_RETURN_NONE;
+fail:
+ Py_CLEAR(arg);
+ return NULL;
}
static inline PyObject *
@@ -555,12 +563,8 @@ multidict_clear(MultiDictObject *self)
}
static inline PyObject *
-multidict_setdefault(
- MultiDictObject *self,
- PyObject *const *args,
- Py_ssize_t nargs,
- PyObject *kwnames
-)
+multidict_setdefault(MultiDictObject *self, PyObject *const *args,
+ Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*_default = NULL;
@@ -573,12 +577,8 @@ multidict_setdefault(
}
static inline PyObject *
-multidict_popone(
- MultiDictObject *self,
- PyObject *const *args,
- Py_ssize_t nargs,
- PyObject *kwnames
-)
+multidict_popone(MultiDictObject *self, PyObject *const *args,
+ Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*_default = NULL,
@@ -639,12 +639,8 @@ multidict_pop(
}
static inline PyObject *
-multidict_popall(
- MultiDictObject *self,
- PyObject *const *args,
- Py_ssize_t nargs,
- PyObject *kwnames
-)
+multidict_popall(MultiDictObject *self, PyObject *const *args,
+ Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *key = NULL,
*_default = NULL,
@@ -682,12 +678,16 @@ multidict_update(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
PyObject *arg = NULL;
if (_multidict_extend_parse_args(args, kwds, "update", &arg) < 0) {
- return NULL;
+ goto fail;
}
if (_multidict_extend(self, arg, kwds, "update", 0) < 0) {
- return NULL;
+ goto fail;
}
+ Py_CLEAR(arg);
Py_RETURN_NONE;
+fail:
+ Py_CLEAR(arg);
+ return NULL;
}
PyDoc_STRVAR(multidict_add_doc,
@@ -741,16 +741,6 @@ _multidict_sizeof(MultiDictObject *self)
}
-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",
@@ -876,70 +866,100 @@ static PyMethodDef multidict_methods[] = {
PyDoc_STRVAR(MultDict_doc,
"Dictionary with the support for duplicate keys.");
+#ifndef MANAGED_WEAKREFS
+static PyMemberDef multidict_members[] = {
+ {"__weaklistoffset__", Py_T_PYSSIZET,
+ offsetof(MultiDictObject, weaklist), Py_READONLY},
+ {NULL} /* Sentinel */
+};
+#endif
+
+static PyType_Slot multidict_slots[] = {
+ {Py_tp_dealloc, multidict_tp_dealloc},
+ {Py_tp_repr, multidict_repr},
+ {Py_tp_doc, (void *)MultDict_doc},
+
+ {Py_sq_contains, multidict_sq_contains},
+ {Py_mp_length, multidict_mp_len},
+ {Py_mp_subscript, multidict_mp_subscript},
+ {Py_mp_ass_subscript, multidict_mp_as_subscript},
+
+ {Py_tp_traverse, multidict_tp_traverse},
+ {Py_tp_clear, multidict_tp_clear},
+ {Py_tp_richcompare, multidict_tp_richcompare},
+ {Py_tp_iter, multidict_tp_iter},
+ {Py_tp_methods, multidict_methods},
+ {Py_tp_init, multidict_tp_init},
+ {Py_tp_alloc, PyType_GenericAlloc},
+ {Py_tp_new, PyType_GenericNew},
+ {Py_tp_free, PyObject_GC_Del},
+
+#ifndef MANAGED_WEAKREFS
+ {Py_tp_members, multidict_members},
+#endif
+ {0, NULL},
+};
-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,
+static PyType_Spec multidict_spec = {
+ .name = "multidict._multidict.MultiDict",
+ .basicsize = sizeof(MultiDictObject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
+#if PY_VERSION_HEX >= 0x030a00f0
+ | Py_TPFLAGS_IMMUTABLETYPE
+#endif
+#ifdef MANAGED_WEAKREFS
+ | Py_TPFLAGS_MANAGED_WEAKREF
+#endif
+ | Py_TPFLAGS_HAVE_GC),
+ .slots = multidict_slots,
};
+
/******************** CIMultiDict ********************/
static inline int
cimultidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds)
{
+ mod_state *state = get_mod_state_by_def((PyObject *)self);
PyObject *arg = NULL;
Py_ssize_t size = _multidict_extend_parse_args(args, kwds, "CIMultiDict", &arg);
if (size < 0) {
- return -1;
+ goto fail;
}
- if (ci_pair_list_init(&self->pairs, size) < 0) {
- return -1;
+ if (ci_pair_list_init(&self->pairs, state, size) < 0) {
+ goto fail;
}
if (_multidict_extend(self, arg, kwds, "CIMultiDict", 1) < 0) {
- return -1;
+ goto fail;
}
+ Py_CLEAR(arg);
return 0;
+fail:
+ Py_CLEAR(arg);
+ return -1;
}
PyDoc_STRVAR(CIMultDict_doc,
"Dictionary with the support for duplicate case-insensitive keys.");
+static PyType_Slot cimultidict_slots[] = {
+ {Py_tp_doc, (void *)CIMultDict_doc},
+ {Py_tp_init, cimultidict_tp_init},
+ {0, NULL},
+};
-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_base = &multidict_type,
- .tp_init = (initproc)cimultidict_tp_init,
- .tp_alloc = PyType_GenericAlloc,
- .tp_new = PyType_GenericNew,
- .tp_free = PyObject_GC_Del,
+static PyType_Spec cimultidict_spec = {
+ .name = "multidict._multidict.CIMultiDict",
+ .basicsize = sizeof(MultiDictObject),
+ .flags = (Py_TPFLAGS_DEFAULT
+#if PY_VERSION_HEX >= 0x030a00f0
+ | Py_TPFLAGS_IMMUTABLETYPE
+#endif
+ | Py_TPFLAGS_BASETYPE),
+ .slots = cimultidict_slots,
};
/******************** MultiDictProxy ********************/
@@ -948,6 +968,7 @@ static inline int
multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
PyObject *kwds)
{
+ mod_state *state = get_mod_state_by_def((PyObject *)self);
PyObject *arg = NULL;
MultiDictObject *md = NULL;
@@ -963,9 +984,8 @@ multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
);
return -1;
}
- if (!MultiDictProxy_CheckExact(arg) &&
- !CIMultiDict_CheckExact(arg) &&
- !MultiDict_CheckExact(arg))
+ if (!AnyMultiDictProxy_Check(state, arg) &&
+ !AnyMultiDict_Check(state, arg))
{
PyErr_Format(
PyExc_TypeError,
@@ -976,9 +996,10 @@ multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
return -1;
}
- md = (MultiDictObject*)arg;
- if (MultiDictProxy_CheckExact(arg)) {
+ if (AnyMultiDictProxy_Check(state, arg)) {
md = ((MultiDictProxyObject*)arg)->md;
+ } else {
+ md = (MultiDictObject*)arg;
}
Py_INCREF(md);
self->md = md;
@@ -987,49 +1008,24 @@ 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, PyObject *const *args,
+ Py_ssize_t nargs, PyObject *kwnames)
{
- return multidict_getall(
- self->md,
- args,
- nargs,
- 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
-)
+multidict_proxy_getone(MultiDictProxyObject *self, PyObject *const *args,
+ Py_ssize_t nargs, PyObject *kwnames)
{
- return multidict_getone(
- self->md, args,
- nargs, 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
-)
+multidict_proxy_get(MultiDictProxyObject *self, PyObject *const *args,
+ Py_ssize_t nargs, PyObject *kwnames)
{
- return multidict_get(
- self->md,
- args,
- nargs,
- kwnames
- );
+ return multidict_get(self->md, args, nargs, kwnames);
}
static inline PyObject *
@@ -1053,7 +1049,7 @@ multidict_proxy_values(MultiDictProxyObject *self)
static inline PyObject *
multidict_proxy_copy(MultiDictProxyObject *self)
{
- return _multidict_proxy_copy(self, &multidict_type);
+ return _multidict_proxy_copy(self, self->md->pairs.state->MultiDictType);
}
static inline PyObject *
@@ -1102,9 +1098,7 @@ static inline void
multidict_proxy_tp_dealloc(MultiDictProxyObject *self)
{
PyObject_GC_UnTrack(self);
- if (self->weaklist != NULL) {
- PyObject_ClearWeakRefs((PyObject *)self);
- };
+ PyObject_ClearWeakRefs((PyObject *)self);
Py_XDECREF(self->md);
Py_TYPE(self)->tp_free((PyObject *)self);
}
@@ -1113,6 +1107,7 @@ static inline int
multidict_proxy_tp_traverse(MultiDictProxyObject *self, visitproc visit,
void *arg)
{
+ Py_VISIT(Py_TYPE(self));
Py_VISIT(self->md);
return 0;
}
@@ -1136,15 +1131,6 @@ multidict_proxy_repr(MultiDictProxyObject *self)
}
-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",
@@ -1210,27 +1196,51 @@ static PyMethodDef multidict_proxy_methods[] = {
PyDoc_STRVAR(MultDictProxy_doc,
"Read-only proxy for MultiDict instance.");
+#ifndef MANAGED_WEAKREFS
+static PyMemberDef multidict_proxy_members[] = {
+ {"__weaklistoffset__", Py_T_PYSSIZET,
+ offsetof(MultiDictProxyObject, weaklist), Py_READONLY},
+ {NULL} /* Sentinel */
+};
+#endif
+
+static PyType_Slot multidict_proxy_slots[] = {
+ {Py_tp_dealloc, multidict_proxy_tp_dealloc},
+ {Py_tp_repr, multidict_proxy_repr},
+ {Py_tp_doc, (void *)MultDictProxy_doc},
+
+ {Py_sq_contains, multidict_proxy_sq_contains},
+ {Py_mp_length, multidict_proxy_mp_len},
+ {Py_mp_subscript, multidict_proxy_mp_subscript},
+
+ {Py_tp_traverse, multidict_proxy_tp_traverse},
+ {Py_tp_clear, multidict_proxy_tp_clear},
+ {Py_tp_richcompare, multidict_proxy_tp_richcompare},
+ {Py_tp_iter, multidict_proxy_tp_iter},
+ {Py_tp_methods, multidict_proxy_methods},
+ {Py_tp_init, multidict_proxy_tp_init},
+ {Py_tp_alloc, PyType_GenericAlloc},
+ {Py_tp_new, PyType_GenericNew},
+ {Py_tp_free, PyObject_GC_Del},
+
+#ifndef MANAGED_WEAKREFS
+ {Py_tp_members, multidict_proxy_members},
+#endif
+ {0, NULL},
+};
-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_proxy_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,
+static PyType_Spec multidict_proxy_spec = {
+ .name = "multidict._multidict.MultiDictProxy",
+ .basicsize = sizeof(MultiDictProxyObject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
+#if PY_VERSION_HEX >= 0x030a00f0
+ | Py_TPFLAGS_IMMUTABLETYPE
+#endif
+#ifdef MANAGED_WEAKREFS
+ | Py_TPFLAGS_MANAGED_WEAKREF
+#endif
+ | Py_TPFLAGS_HAVE_GC),
+ .slots = multidict_proxy_slots,
};
/******************** CIMultiDictProxy ********************/
@@ -1239,6 +1249,7 @@ static inline int
cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
PyObject *kwds)
{
+ mod_state *state = get_mod_state_by_def((PyObject *)self);
PyObject *arg = NULL;
MultiDictObject *md = NULL;
@@ -1254,7 +1265,8 @@ cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
);
return -1;
}
- if (!CIMultiDictProxy_CheckExact(arg) && !CIMultiDict_CheckExact(arg)) {
+ if (!CIMultiDictProxy_Check(state, arg)
+ && !CIMultiDict_Check(state, arg)) {
PyErr_Format(
PyExc_TypeError,
"ctor requires CIMultiDict or CIMultiDictProxy instance, "
@@ -1264,9 +1276,10 @@ cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
return -1;
}
- md = (MultiDictObject*)arg;
- if (CIMultiDictProxy_CheckExact(arg)) {
+ if (CIMultiDictProxy_Check(state, arg)) {
md = ((MultiDictProxyObject*)arg)->md;
+ } else {
+ md = (MultiDictObject*)arg;
}
Py_INCREF(md);
self->md = md;
@@ -1277,7 +1290,7 @@ cimultidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
static inline PyObject *
cimultidict_proxy_copy(MultiDictProxyObject *self)
{
- return _multidict_proxy_copy(self, &cimultidict_type);
+ return _multidict_proxy_copy(self, self->md->pairs.state->CIMultiDictType);
}
@@ -1300,23 +1313,22 @@ static PyMethodDef cimultidict_proxy_methods[] = {
} /* 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,
+static PyType_Slot cimultidict_proxy_slots[] = {
+ {Py_tp_doc, (void *)CIMultDictProxy_doc},
+ {Py_tp_methods, cimultidict_proxy_methods},
+ {Py_tp_init, cimultidict_proxy_tp_init},
+ {0, NULL},
+};
+
+static PyType_Spec cimultidict_proxy_spec = {
+ .name = "multidict._multidict.CIMultiDictProxy",
+ .basicsize = sizeof(MultiDictProxyObject),
+ .flags = (Py_TPFLAGS_DEFAULT
+#if PY_VERSION_HEX >= 0x030a00f0
+ | Py_TPFLAGS_IMMUTABLETYPE
+#endif
+ | Py_TPFLAGS_BASETYPE),
+ .slots = cimultidict_proxy_slots,
};
/******************** Other functions ********************/
@@ -1324,10 +1336,11 @@ static PyTypeObject cimultidict_proxy_type = {
static inline PyObject *
getversion(PyObject *self, PyObject *md)
{
+ mod_state *state = get_mod_state(self);
pair_list_t *pairs = NULL;
- if (MultiDict_CheckExact(md) || CIMultiDict_CheckExact(md)) {
+ if (AnyMultiDict_Check(state, md)) {
pairs = &((MultiDictObject*)md)->pairs;
- } else if (MultiDictProxy_CheckExact(md) || CIMultiDictProxy_CheckExact(md)) {
+ } else if (AnyMultiDictProxy_Check(state, md)) {
pairs = &((MultiDictProxyObject*)md)->md->pairs;
} else {
PyErr_Format(PyExc_TypeError, "unexpected type");
@@ -1338,131 +1351,189 @@ getversion(PyObject *self, PyObject *md)
/******************** Module ********************/
+static int
+module_traverse(PyObject *mod, visitproc visit, void *arg)
+{
+ mod_state *state = get_mod_state(mod);
+
+ Py_VISIT(state->IStrType);
+
+ Py_VISIT(state->MultiDictType);
+ Py_VISIT(state->CIMultiDictType);
+ Py_VISIT(state->MultiDictProxyType);
+ Py_VISIT(state->CIMultiDictProxyType);
+
+ Py_VISIT(state->KeysViewType);
+ Py_VISIT(state->ItemsViewType);
+ Py_VISIT(state->ValuesViewType);
+
+ Py_VISIT(state->KeysIterType);
+ Py_VISIT(state->ItemsIterType);
+ Py_VISIT(state->ValuesIterType);
+
+ Py_VISIT(state->str_lower);
+ Py_VISIT(state->str_canonical);
+
+ return 0;
+}
+
+static int
+module_clear(PyObject *mod)
+{
+ mod_state *state = get_mod_state(mod);
+
+ Py_CLEAR(state->IStrType);
+
+ Py_CLEAR(state->MultiDictType);
+ Py_CLEAR(state->CIMultiDictType);
+ Py_CLEAR(state->MultiDictProxyType);
+ Py_CLEAR(state->CIMultiDictProxyType);
+
+ Py_CLEAR(state->KeysViewType);
+ Py_CLEAR(state->ItemsViewType);
+ Py_CLEAR(state->ValuesViewType);
+
+ Py_CLEAR(state->KeysIterType);
+ Py_CLEAR(state->ItemsIterType);
+ Py_CLEAR(state->ValuesIterType);
+
+ Py_CLEAR(state->str_lower);
+ Py_CLEAR(state->str_canonical);
+
+ return 0;
+}
+
static inline void
-module_free(void *m)
+module_free(void *mod)
{
- Py_CLEAR(multidict_str_lower);
- Py_CLEAR(multidict_str_canonical);
+ (void)module_clear((PyObject *)mod);
}
-static PyMethodDef multidict_module_methods[] = {
+static PyMethodDef 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(void)
+static int
+module_exec(PyObject *mod)
{
- multidict_str_lower = PyUnicode_InternFromString("lower");
- if (multidict_str_lower == NULL) {
+ mod_state *state = get_mod_state(mod);
+ PyObject *tmp;
+ PyObject *tpl = NULL;
+
+ state->str_lower = PyUnicode_InternFromString("lower");
+ if (state->str_lower == NULL) {
goto fail;
}
- multidict_str_canonical = PyUnicode_InternFromString("_canonical");
- if (multidict_str_canonical == NULL) {
+ state->str_canonical = PyUnicode_InternFromString("_canonical");
+ if (state->str_canonical == NULL) {
goto fail;
}
- PyObject *module = NULL;
-
- if (multidict_views_init() < 0) {
+ if (multidict_views_init(mod, state) < 0) {
goto fail;
}
- if (multidict_iter_init() < 0) {
+ if (multidict_iter_init(mod, state) < 0) {
goto fail;
}
- if (istr_init() < 0) {
+ if (istr_init(mod, state) < 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)
- {
+ tmp = PyType_FromModuleAndSpec(mod, &multidict_spec, NULL);
+ if (tmp == NULL) {
goto fail;
}
+ state->MultiDictType = (PyTypeObject *)tmp;
- /* Instantiate this module */
- module = PyModule_Create(&multidict_module);
- if (module == NULL) {
+ tpl = PyTuple_Pack(1, (PyObject *)state->MultiDictType);
+ if (tpl == NULL) {
goto fail;
}
-
-#ifdef Py_GIL_DISABLED
- PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED);
-#endif
-
- Py_INCREF(&istr_type);
- if (PyModule_AddObject(
- module, "istr", (PyObject*)&istr_type) < 0)
- {
+ tmp = PyType_FromModuleAndSpec(mod, &cimultidict_spec, tpl);
+ if (tmp == NULL) {
goto fail;
}
+ state->CIMultiDictType = (PyTypeObject *)tmp;
+ Py_CLEAR(tpl);
- Py_INCREF(&multidict_type);
- if (PyModule_AddObject(
- module, "MultiDict", (PyObject*)&multidict_type) < 0)
- {
+ tmp = PyType_FromModuleAndSpec(mod, &multidict_proxy_spec, NULL);
+ if (tmp == NULL) {
goto fail;
}
+ state->MultiDictProxyType = (PyTypeObject *)tmp;
- Py_INCREF(&cimultidict_type);
- if (PyModule_AddObject(
- module, "CIMultiDict", (PyObject*)&cimultidict_type) < 0)
- {
+ tpl = PyTuple_Pack(1, (PyObject *)state->MultiDictProxyType);
+ if (tpl == NULL) {
goto fail;
}
-
- Py_INCREF(&multidict_proxy_type);
- if (PyModule_AddObject(
- module, "MultiDictProxy", (PyObject*)&multidict_proxy_type) < 0)
- {
+ tmp = PyType_FromModuleAndSpec(mod, &cimultidict_proxy_spec, tpl);
+ if (tmp == NULL) {
goto fail;
}
+ state->CIMultiDictProxyType = (PyTypeObject *)tmp;
+ Py_CLEAR(tpl);
- Py_INCREF(&cimultidict_proxy_type);
- if (PyModule_AddObject(
- module, "CIMultiDictProxy", (PyObject*)&cimultidict_proxy_type) < 0)
- {
+ if (PyModule_AddType(mod, state->IStrType) < 0) {
goto fail;
}
-
- Py_INCREF(&multidict_keysview_type);
- if (PyModule_AddObject(
- module, "_KeysView", (PyObject*)&multidict_keysview_type) < 0)
- {
+ if (PyModule_AddType(mod, state->MultiDictType) < 0) {
goto fail;
}
-
- Py_INCREF(&multidict_itemsview_type);
- if (PyModule_AddObject(
- module, "_ItemsView", (PyObject*)&multidict_itemsview_type) < 0)
- {
+ if (PyModule_AddType(mod, state->CIMultiDictType) < 0) {
goto fail;
}
-
- Py_INCREF(&multidict_valuesview_type);
- if (PyModule_AddObject(
- module, "_ValuesView", (PyObject*)&multidict_valuesview_type) < 0)
- {
+ if (PyModule_AddType(mod, state->MultiDictProxyType) < 0) {
+ goto fail;
+ }
+ if (PyModule_AddType(mod, state->CIMultiDictProxyType) < 0) {
+ goto fail;
+ }
+ if (PyModule_AddType(mod, state->ItemsViewType) < 0) {
+ goto fail;
+ }
+ if (PyModule_AddType(mod, state->KeysViewType) < 0) {
+ goto fail;
+ }
+ if (PyModule_AddType(mod, state->ValuesViewType) < 0) {
goto fail;
}
- return module;
-
+ return 0;
fail:
- Py_XDECREF(multidict_str_lower);
- Py_XDECREF(multidict_str_canonical);
+ Py_CLEAR(tpl);
+ return -1;
+}
- return NULL;
+
+static struct PyModuleDef_Slot module_slots[] = {
+ {Py_mod_exec, module_exec},
+#if PY_VERSION_HEX >= 0x030c00f0
+ {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
+#endif
+#if PY_VERSION_HEX >= 0x030d00f0
+ {Py_mod_gil, Py_MOD_GIL_NOT_USED},
+#endif
+ {0, NULL},
+};
+
+
+static PyModuleDef multidict_module = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "_multidict",
+ .m_size = sizeof(mod_state),
+ .m_methods = module_methods,
+ .m_slots = module_slots,
+ .m_traverse = module_traverse,
+ .m_clear = module_clear,
+ .m_free = (freefunc)module_free,
+};
+
+PyMODINIT_FUNC
+PyInit__multidict(void)
+{
+ return PyModuleDef_Init(&multidict_module);
}
diff --git a/contrib/python/multidict/multidict/_multidict_py.py b/contrib/python/multidict/multidict/_multidict_py.py
index 7babdd5e6ef..3176861e787 100644
--- a/contrib/python/multidict/multidict/_multidict_py.py
+++ b/contrib/python/multidict/multidict/_multidict_py.py
@@ -1,4 +1,5 @@
import enum
+import reprlib
import sys
from abc import abstractmethod
from array import array
@@ -55,7 +56,6 @@ class _Impl(Generic[_V]):
self.incr_version()
def incr_version(self) -> None:
- global _version
v = _version
v[0] += 1
self._version = v[0]
@@ -121,6 +121,7 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
raise RuntimeError("Dictionary changed during iteration")
yield self._keyfunc(k), v
+ @reprlib.recursive_repr()
def __repr__(self) -> str:
lst = []
for i, k, v in self._impl._items:
@@ -254,7 +255,7 @@ class _ItemsView(_ViewBase[_V], ItemsView[str, _V]):
except TypeError:
return NotImplemented
ret: set[Union[tuple[str, _V], _T]] = self - rgt
- ret |= (rgt - self)
+ ret |= rgt - self
return ret
__rxor__ = __xor__
@@ -288,6 +289,7 @@ class _ValuesView(_ViewBase[_V], ValuesView[_V]):
raise RuntimeError("Dictionary changed during iteration")
yield v
+ @reprlib.recursive_repr()
def __repr__(self) -> str:
lst = []
for i, k, v in self._impl._items:
@@ -425,7 +427,7 @@ class _KeysView(_ViewBase[_V], KeysView[str]):
except TypeError:
return NotImplemented
ret: set[Union[str, _T]] = self - rgt # type: ignore[assignment]
- ret |= (rgt - self)
+ ret |= rgt - self
return ret
__rxor__ = __xor__
@@ -453,6 +455,8 @@ class _CSMixin:
class _CIMixin:
+ _ci: bool = True
+
def _key(self, key: str) -> str:
if type(key) is istr:
return key
@@ -474,6 +478,7 @@ class _CIMixin:
class _Base(MultiMapping[_V]):
_impl: _Impl[_V]
+ _ci: bool = False
@abstractmethod
def _key(self, key: str) -> str: ...
@@ -579,6 +584,7 @@ class _Base(MultiMapping[_V]):
return True
return False
+ @reprlib.recursive_repr()
def __repr__(self) -> str:
body = ", ".join(f"'{k}': {v!r}" for i, k, v in self._impl._items)
return f"<{self.__class__.__name__}({body})>"
@@ -628,7 +634,12 @@ class MultiDict(_CSMixin, _Base[_V], MutableMultiMapping[_V]):
) -> None:
if arg:
if isinstance(arg, (MultiDict, MultiDictProxy)):
- items = arg._impl._items
+ if self._ci is not arg._ci:
+ items = [(self._title(k), k, v) for _, k, v in arg._impl._items]
+ else:
+ items = arg._impl._items
+ if kwargs:
+ items = items.copy()
if kwargs:
for key, value in kwargs.items():
items.append((self._title(key), key, value))
diff --git a/contrib/python/multidict/multidict/_multilib/defs.h b/contrib/python/multidict/multidict/_multilib/defs.h
deleted file mode 100644
index 9e1cd724122..00000000000
--- a/contrib/python/multidict/multidict/_multilib/defs.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _MULTIDICT_DEFS_H
-#define _MULTIDICT_DEFS_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-static PyObject *multidict_str_lower = NULL;
-static PyObject *multidict_str_canonical = NULL;
-
-/* We link this module statically for convenience. If compiled as a shared
- library instead, some compilers don't allow addresses of Python objects
- defined in other libraries to be used in static initializers here. The
- DEFERRED_ADDRESS macro is used to tag the slots where such addresses
- appear; the module init function must fill in the tagged slots at runtime.
- The argument is for documentation -- the macro ignores it.
-*/
-#define DEFERRED_ADDRESS(ADDR) 0
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/contrib/python/multidict/multidict/_multilib/dict.h b/contrib/python/multidict/multidict/_multilib/dict.h
index 064101d47ea..fa07fdf4ac3 100644
--- a/contrib/python/multidict/multidict/_multilib/dict.h
+++ b/contrib/python/multidict/multidict/_multilib/dict.h
@@ -5,15 +5,27 @@
extern "C" {
#endif
+#include "pythoncapi_compat.h"
+#include "pair_list.h"
+
+#if PY_VERSION_HEX >= 0x030c00f0
+#define MANAGED_WEAKREFS
+#endif
+
+
typedef struct { // 16 or 24 for GC prefix
PyObject_HEAD // 16
+#ifndef MANAGED_WEAKREFS
PyObject *weaklist;
+#endif
pair_list_t pairs;
} MultiDictObject;
typedef struct {
PyObject_HEAD
+#ifndef MANAGED_WEAKREFS
PyObject *weaklist;
+#endif
MultiDictObject *md;
} MultiDictProxyObject;
diff --git a/contrib/python/multidict/multidict/_multilib/istr.h b/contrib/python/multidict/multidict/_multilib/istr.h
index 68328054528..156b0dc04a3 100644
--- a/contrib/python/multidict/multidict/_multilib/istr.h
+++ b/contrib/python/multidict/multidict/_multilib/istr.h
@@ -5,14 +5,19 @@
extern "C" {
#endif
+#include "state.h"
+
typedef struct {
PyUnicodeObject str;
PyObject * canonical;
+ mod_state *state;
} istrobject;
-PyDoc_STRVAR(istr__doc__, "istr class implementation");
+#define IStr_CheckExact(state, obj) Py_IS_TYPE(obj, state->IStrType)
+#define IStr_Check(state, obj) \
+ (IStr_CheckExact(state, obj) || PyObject_TypeCheck(obj, state->IStrType))
-static PyTypeObject istr_type;
+PyDoc_STRVAR(istr__doc__, "istr class implementation");
static inline void
istr_dealloc(istrobject *self)
@@ -24,26 +29,24 @@ istr_dealloc(istrobject *self)
static inline PyObject *
istr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
+ PyObject *mod = PyType_GetModuleByDef(type, &multidict_module);
+ if (mod == NULL) {
+ return NULL;
+ }
+ mod_state *state = get_mod_state(mod);
+
PyObject *x = NULL;
static char *kwlist[] = {"object", "encoding", "errors", 0};
PyObject *encoding = NULL;
PyObject *errors = NULL;
PyObject *canonical = NULL;
- PyObject * ret = NULL;
- if (kwds != NULL) {
- int cmp = PyDict_Pop(kwds, multidict_str_canonical, &canonical);
- if (cmp < 0) {
- return NULL;
- } else if (cmp > 0) {
- Py_INCREF(canonical);
- }
- }
+ PyObject *ret = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO:str",
kwlist, &x, &encoding, &errors)) {
return NULL;
}
- if (x != NULL && Py_TYPE(x) == &istr_type) {
+ if (x != NULL && IStr_Check(state, x)) {
Py_INCREF(x);
return x;
}
@@ -51,29 +54,18 @@ istr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (!ret) {
goto fail;
}
-
- if (canonical == NULL) {
- canonical = PyObject_CallMethodNoArgs(ret, multidict_str_lower);
- if (!canonical) {
- goto fail;
- }
- }
- if (!PyUnicode_CheckExact(canonical)) {
- PyObject *tmp = PyUnicode_FromObject(canonical);
- Py_CLEAR(canonical);
- if (tmp == NULL) {
- goto fail;
- }
- canonical = tmp;
+ canonical = PyObject_CallMethodNoArgs(ret, state->str_lower);
+ if (!canonical) {
+ goto fail;
}
((istrobject*)ret)->canonical = canonical;
+ ((istrobject*)ret)->state = state;
return ret;
fail:
Py_XDECREF(ret);
return NULL;
}
-
static inline PyObject *
istr_reduce(PyObject *self)
{
@@ -102,62 +94,61 @@ static PyMethodDef istr_methods[] = {
{NULL, NULL} /* sentinel */
};
-static PyTypeObject istr_type = {
- PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
- "multidict._multidict.istr",
- sizeof(istrobject),
- .tp_dealloc = (destructor)istr_dealloc,
- .tp_flags = Py_TPFLAGS_DEFAULT
+static PyType_Slot istr_slots[] = {
+ {Py_tp_dealloc, istr_dealloc},
+ {Py_tp_doc, (void *)istr__doc__},
+ {Py_tp_methods, istr_methods},
+ {Py_tp_new, istr_new},
+ {0, NULL},
+};
+
+static PyType_Spec istr_spec = {
+ .name = "multidict._multidict.istr",
+ .basicsize = sizeof(istrobject),
+ .flags = (Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
- | Py_TPFLAGS_UNICODE_SUBCLASS,
- .tp_doc = istr__doc__,
- .tp_base = DEFERRED_ADDRESS(&PyUnicode_Type),
- .tp_methods = istr_methods,
- .tp_new = (newfunc)istr_new,
+#if PY_VERSION_HEX >= 0x030a00f0
+ | Py_TPFLAGS_IMMUTABLETYPE
+#endif
+ | Py_TPFLAGS_UNICODE_SUBCLASS),
+ .slots = istr_slots,
};
static inline PyObject *
-IStr_New(PyObject *str, PyObject *canonical)
+IStr_New(mod_state *state, PyObject *str, PyObject *canonical)
{
PyObject *args = NULL;
- PyObject *kwds = NULL;
PyObject *res = NULL;
-
args = PyTuple_Pack(1, str);
if (args == NULL) {
goto ret;
}
-
- if (canonical != NULL) {
- kwds = PyDict_New();
- if (kwds == NULL) {
- goto ret;
- }
- if (!PyUnicode_CheckExact(canonical)) {
- PyErr_SetString(PyExc_TypeError,
- "'canonical' argument should be exactly str");
- goto ret;
- }
- if (PyDict_SetItem(kwds, multidict_str_canonical, canonical) < 0) {
- goto ret;
- }
+ res = PyUnicode_Type.tp_new(state->IStrType, args, NULL);
+ if (!res) {
+ goto ret;
}
-
- res = istr_new(&istr_type, args, kwds);
+ Py_INCREF(canonical);
+ ((istrobject*)res)->canonical = canonical;
+ ((istrobject*)res)->state = state;
ret:
Py_CLEAR(args);
- Py_CLEAR(kwds);
return res;
}
static inline int
-istr_init(void)
+istr_init(PyObject *module, mod_state *state)
{
- istr_type.tp_base = &PyUnicode_Type;
- if (PyType_Ready(&istr_type) < 0) {
+ PyObject *tpl = PyTuple_Pack(1, (PyObject *)&PyUnicode_Type);
+ if (tpl == NULL) {
+ return -1;
+ }
+ PyObject *tmp = PyType_FromModuleAndSpec(module, &istr_spec, tpl);
+ Py_DECREF(tpl);
+ if (tmp == NULL) {
return -1;
}
+ state->IStrType = (PyTypeObject *)tmp;
return 0;
}
diff --git a/contrib/python/multidict/multidict/_multilib/iter.h b/contrib/python/multidict/multidict/_multilib/iter.h
index 3fd34e2ca4b..2f3ca9de84c 100644
--- a/contrib/python/multidict/multidict/_multilib/iter.h
+++ b/contrib/python/multidict/multidict/_multilib/iter.h
@@ -5,9 +5,9 @@
extern "C" {
#endif
-static PyTypeObject multidict_items_iter_type;
-static PyTypeObject multidict_values_iter_type;
-static PyTypeObject multidict_keys_iter_type;
+#include "dict.h"
+#include "pair_list.h"
+#include "state.h"
typedef struct multidict_iter {
PyObject_HEAD
@@ -28,7 +28,7 @@ static inline PyObject *
multidict_items_iter_new(MultiDictObject *md)
{
MultidictIter *it = PyObject_GC_New(
- MultidictIter, &multidict_items_iter_type);
+ MultidictIter, md->pairs.state->ItemsIterType);
if (it == NULL) {
return NULL;
}
@@ -43,7 +43,7 @@ static inline PyObject *
multidict_keys_iter_new(MultiDictObject *md)
{
MultidictIter *it = PyObject_GC_New(
- MultidictIter, &multidict_keys_iter_type);
+ MultidictIter, md->pairs.state->KeysIterType);
if (it == NULL) {
return NULL;
}
@@ -58,7 +58,7 @@ static inline PyObject *
multidict_values_iter_new(MultiDictObject *md)
{
MultidictIter *it = PyObject_GC_New(
- MultidictIter, &multidict_values_iter_type);
+ MultidictIter, md->pairs.state->ValuesIterType);
if (it == NULL) {
return NULL;
}
@@ -180,53 +180,92 @@ static PyMethodDef multidict_iter_methods[] = {
/***********************************************************************/
-static PyTypeObject multidict_items_iter_type = {
- PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
- "multidict._multidict._itemsiter", /* tp_name */
- sizeof(MultidictIter), /* tp_basicsize */
- .tp_dealloc = (destructor)multidict_iter_dealloc,
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
- .tp_traverse = (traverseproc)multidict_iter_traverse,
- .tp_clear = (inquiry)multidict_iter_clear,
- .tp_iter = PyObject_SelfIter,
- .tp_iternext = (iternextfunc)multidict_items_iter_iternext,
- .tp_methods = multidict_iter_methods,
+static PyType_Slot multidict_items_iter_slots[] = {
+ {Py_tp_dealloc, multidict_iter_dealloc},
+ {Py_tp_methods, multidict_iter_methods},
+ {Py_tp_traverse, multidict_iter_traverse},
+ {Py_tp_clear, multidict_iter_clear},
+ {Py_tp_iter, PyObject_SelfIter},
+ {Py_tp_iternext, multidict_items_iter_iternext},
+ {0, NULL},
};
-static PyTypeObject multidict_values_iter_type = {
- PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
- "multidict._multidict._valuesiter", /* tp_name */
- sizeof(MultidictIter), /* tp_basicsize */
- .tp_dealloc = (destructor)multidict_iter_dealloc,
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
- .tp_traverse = (traverseproc)multidict_iter_traverse,
- .tp_clear = (inquiry)multidict_iter_clear,
- .tp_iter = PyObject_SelfIter,
- .tp_iternext = (iternextfunc)multidict_values_iter_iternext,
- .tp_methods = multidict_iter_methods,
+static PyType_Spec multidict_items_iter_spec = {
+ .name = "multidict._multidict._itemsiter",
+ .basicsize = sizeof(MultidictIter),
+ .flags = (Py_TPFLAGS_DEFAULT
+#if PY_VERSION_HEX >= 0x030a00f0
+ | Py_TPFLAGS_IMMUTABLETYPE
+#endif
+ | Py_TPFLAGS_HAVE_GC),
+ .slots = multidict_items_iter_slots,
};
-static PyTypeObject multidict_keys_iter_type = {
- PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
- "multidict._multidict._keysiter", /* tp_name */
- sizeof(MultidictIter), /* tp_basicsize */
- .tp_dealloc = (destructor)multidict_iter_dealloc,
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
- .tp_traverse = (traverseproc)multidict_iter_traverse,
- .tp_clear = (inquiry)multidict_iter_clear,
- .tp_iter = PyObject_SelfIter,
- .tp_iternext = (iternextfunc)multidict_keys_iter_iternext,
- .tp_methods = multidict_iter_methods,
+static PyType_Slot multidict_values_iter_slots[] = {
+ {Py_tp_dealloc, multidict_iter_dealloc},
+ {Py_tp_methods, multidict_iter_methods},
+ {Py_tp_traverse, multidict_iter_traverse},
+ {Py_tp_clear, multidict_iter_clear},
+ {Py_tp_iter, PyObject_SelfIter},
+ {Py_tp_iternext, multidict_values_iter_iternext},
+ {0, NULL},
+};
+
+static PyType_Spec multidict_values_iter_spec = {
+ .name = "multidict._multidict._valuesiter",
+ .basicsize = sizeof(MultidictIter),
+ .flags = (Py_TPFLAGS_DEFAULT
+#if PY_VERSION_HEX >= 0x030a00f0
+ | Py_TPFLAGS_IMMUTABLETYPE
+#endif
+ | Py_TPFLAGS_HAVE_GC),
+ .slots = multidict_values_iter_slots,
+};
+
+
+static PyType_Slot multidict_keys_iter_slots[] = {
+ {Py_tp_dealloc, multidict_iter_dealloc},
+ {Py_tp_methods, multidict_iter_methods},
+ {Py_tp_traverse, multidict_iter_traverse},
+ {Py_tp_clear, multidict_iter_clear},
+ {Py_tp_iter, PyObject_SelfIter},
+ {Py_tp_iternext, multidict_keys_iter_iternext},
+ {0, NULL},
+};
+
+static PyType_Spec multidict_keys_iter_spec = {
+ .name = "multidict._multidict._keysiter",
+ .basicsize = sizeof(MultidictIter),
+ .flags = (Py_TPFLAGS_DEFAULT
+#if PY_VERSION_HEX >= 0x030a00f0
+ | Py_TPFLAGS_IMMUTABLETYPE
+#endif
+ | Py_TPFLAGS_HAVE_GC),
+ .slots = multidict_keys_iter_slots,
};
static inline int
-multidict_iter_init(void)
+multidict_iter_init(PyObject *module, mod_state *state)
{
- if (PyType_Ready(&multidict_items_iter_type) < 0 ||
- PyType_Ready(&multidict_values_iter_type) < 0 ||
- PyType_Ready(&multidict_keys_iter_type) < 0) {
+ PyObject * tmp;
+ tmp = PyType_FromModuleAndSpec(module, &multidict_items_iter_spec, NULL);
+ if (tmp == NULL) {
+ return -1;
+ }
+ state->ItemsIterType = (PyTypeObject *)tmp;
+
+ tmp = PyType_FromModuleAndSpec(module, &multidict_values_iter_spec, NULL);
+ if (tmp == NULL) {
return -1;
}
+ state->ValuesIterType = (PyTypeObject *)tmp;
+
+ tmp = PyType_FromModuleAndSpec(module, &multidict_keys_iter_spec, NULL);
+ if (tmp == NULL) {
+ return -1;
+ }
+ state->KeysIterType = (PyTypeObject *)tmp;
+
return 0;
}
diff --git a/contrib/python/multidict/multidict/_multilib/pair_list.h b/contrib/python/multidict/multidict/_multilib/pair_list.h
index c5080743339..6c45673b73f 100644
--- a/contrib/python/multidict/multidict/_multilib/pair_list.h
+++ b/contrib/python/multidict/multidict/_multilib/pair_list.h
@@ -12,6 +12,9 @@ extern "C" {
#include <stdint.h>
#include <stdbool.h>
+#include "istr.h"
+#include "state.h"
+
/* Implementation note.
identity always has exact PyUnicode_Type type, not a subclass.
It guarantees that identity hashing and comparison never calls
@@ -32,10 +35,7 @@ typedef struct pair {
} pair_t;
/* Note about the structure size
-With 29 pairs the MultiDict object size is slightly less than 1KiB
-(1000-1008 bytes depending on Python version,
-plus extra 12 bytes for memory allocator internal structures).
-As the result the max reserved size is 1020 bytes at most.
+With 28 pairs the MultiDict object size is slightly less than 1KiB
To fit into 512 bytes, the structure can contain only 13 pairs
which is too small, e.g. https://www.python.org returns 16 headers
@@ -45,9 +45,10 @@ The embedded buffer intention is to fit the vast majority of possible
HTTP headers into the buffer without allocating an extra memory block.
*/
-#define EMBEDDED_CAPACITY 29
+#define EMBEDDED_CAPACITY 28
typedef struct pair_list {
+ mod_state *state;
Py_ssize_t capacity;
Py_ssize_t size;
uint64_t version;
@@ -92,10 +93,9 @@ str_cmp(PyObject *s1, PyObject *s2)
static inline PyObject *
-_key_to_ident(PyObject *key)
+_key_to_ident(mod_state *state, PyObject *key)
{
- PyTypeObject *type = Py_TYPE(key);
- if (type == &istr_type) {
+ if (IStr_Check(state, key)) {
return Py_NewRef(((istrobject*)key)->canonical);
}
if (PyUnicode_CheckExact(key)) {
@@ -112,14 +112,13 @@ _key_to_ident(PyObject *key)
static inline PyObject *
-_ci_key_to_ident(PyObject *key)
+_ci_key_to_ident(mod_state *state, PyObject *key)
{
- PyTypeObject *type = Py_TYPE(key);
- if (type == &istr_type) {
+ if (IStr_Check(state, key)) {
return Py_NewRef(((istrobject*)key)->canonical);
}
if (PyUnicode_Check(key)) {
- PyObject *ret = PyObject_CallMethodNoArgs(key, multidict_str_lower);
+ PyObject *ret = PyObject_CallMethodNoArgs(key, state->str_lower);
if (!PyUnicode_CheckExact(ret)) {
PyObject *tmp = PyUnicode_FromObject(ret);
Py_CLEAR(ret);
@@ -138,7 +137,7 @@ _ci_key_to_ident(PyObject *key)
static inline PyObject *
-_arg_to_key(PyObject *key, PyObject *ident)
+_arg_to_key(mod_state *state, PyObject *key, PyObject *ident)
{
if (PyUnicode_Check(key)) {
return Py_NewRef(key);
@@ -151,14 +150,13 @@ _arg_to_key(PyObject *key, PyObject *ident)
static inline PyObject *
-_ci_arg_to_key(PyObject *key, PyObject *ident)
+_ci_arg_to_key(mod_state *state, PyObject *key, PyObject *ident)
{
- PyTypeObject *type = Py_TYPE(key);
- if (type == &istr_type) {
+ if (IStr_Check(state, key)) {
return Py_NewRef(key);
}
if (PyUnicode_Check(key)) {
- return IStr_New(key, ident);
+ return IStr_New(state, key, ident);
}
PyErr_SetString(PyExc_TypeError,
"CIMultiDict keys should be either str "
@@ -240,8 +238,10 @@ pair_list_shrink(pair_list_t *list)
static inline int
-_pair_list_init(pair_list_t *list, bool calc_ci_identity, Py_ssize_t preallocate)
+_pair_list_init(pair_list_t *list, mod_state *state,
+ bool calc_ci_identity, Py_ssize_t preallocate)
{
+ list->state = state;
list->calc_ci_indentity = calc_ci_identity;
Py_ssize_t capacity = EMBEDDED_CAPACITY;
if (preallocate >= capacity) {
@@ -257,16 +257,16 @@ _pair_list_init(pair_list_t *list, bool calc_ci_identity, Py_ssize_t preallocate
}
static inline int
-pair_list_init(pair_list_t *list, Py_ssize_t size)
+pair_list_init(pair_list_t *list, mod_state *state, Py_ssize_t size)
{
- return _pair_list_init(list, /* calc_ci_identity = */ false, size);
+ return _pair_list_init(list, state, /* calc_ci_identity = */ false, size);
}
static inline int
-ci_pair_list_init(pair_list_t *list, Py_ssize_t size)
+ci_pair_list_init(pair_list_t *list, mod_state *state, Py_ssize_t size)
{
- return _pair_list_init(list, /* calc_ci_identity = */ true, size);
+ return _pair_list_init(list, state, /* calc_ci_identity = */ true, size);
}
@@ -274,16 +274,16 @@ static inline PyObject *
pair_list_calc_identity(pair_list_t *list, PyObject *key)
{
if (list->calc_ci_indentity)
- return _ci_key_to_ident(key);
- return _key_to_ident(key);
+ return _ci_key_to_ident(list->state, key);
+ return _key_to_ident(list->state, key);
}
static inline PyObject *
pair_list_calc_key(pair_list_t *list, PyObject *key, PyObject *ident)
{
if (list->calc_ci_indentity)
- return _ci_arg_to_key(key, ident);
- return _arg_to_key(key, ident);
+ return _ci_arg_to_key(list->state, key, ident);
+ return _arg_to_key(list->state, key, ident);
}
static inline void
@@ -363,9 +363,7 @@ _pair_list_add_with_hash(pair_list_t *list,
static inline int
-pair_list_add(pair_list_t *list,
- PyObject *key,
- PyObject *value)
+pair_list_add(pair_list_t *list, PyObject *key, PyObject *value)
{
PyObject *identity = pair_list_calc_identity(list, key);
if (identity == NULL) {
@@ -1017,6 +1015,7 @@ _dict_set_number(PyObject *dict, PyObject *key, Py_ssize_t num)
return -1;
}
+ Py_DECREF(tmp);
return 0;
}
@@ -1129,26 +1128,58 @@ _pair_list_update(pair_list_t *list, PyObject *key,
static inline int
-pair_list_update_from_pair_list(pair_list_t *list, PyObject* used, pair_list_t *other)
+pair_list_update_from_pair_list(pair_list_t *list,
+ PyObject* used, pair_list_t *other)
{
Py_ssize_t pos;
+ Py_hash_t hash;
+ PyObject *identity = NULL;
+ PyObject *key = NULL;
+ bool recalc_identity = list->calc_ci_indentity != other->calc_ci_indentity;
for (pos = 0; pos < other->size; pos++) {
pair_t *pair = other->pairs + pos;
+ if (recalc_identity) {
+ identity = pair_list_calc_identity(list, pair->key);
+ if (identity == NULL) {
+ goto fail;
+ }
+ hash = PyObject_Hash(identity);
+ if (hash == -1) {
+ goto fail;
+ }
+ /* materialize key */
+ key = pair_list_calc_key(other, pair->key, identity);
+ if (key == NULL) {
+ goto fail;
+ }
+ } else {
+ identity = pair->identity;
+ hash = pair->hash;
+ key = pair->key;
+ }
if (used != NULL) {
- if (_pair_list_update(list, pair->key, pair->value, used,
- pair->identity, pair->hash) < 0) {
+ if (_pair_list_update(list, key, pair->value, used,
+ identity, hash) < 0) {
goto fail;
}
} else {
- if (_pair_list_add_with_hash(list, pair->identity, pair->key,
- pair->value, pair->hash) < 0) {
+ if (_pair_list_add_with_hash(list, identity, key,
+ pair->value, hash) < 0) {
goto fail;
}
}
+ if (recalc_identity) {
+ Py_CLEAR(identity);
+ Py_CLEAR(key);
+ }
}
return 0;
fail:
+ if (recalc_identity) {
+ Py_CLEAR(identity);
+ Py_CLEAR(key);
+ }
return -1;
}
@@ -1545,6 +1576,7 @@ fail:
Py_CLEAR(key);
Py_CLEAR(value);
PyUnicodeWriter_Discard(writer);
+ return NULL;
}
diff --git a/contrib/python/multidict/multidict/_multilib/parser.h b/contrib/python/multidict/multidict/_multilib/parser.h
index a804018cf1d..074f6fa7d9e 100644
--- a/contrib/python/multidict/multidict/_multilib/parser.h
+++ b/contrib/python/multidict/multidict/_multilib/parser.h
@@ -22,7 +22,6 @@ static int raise_missing_posarg(const char *fname, const char* argname)
}
-
/* Parse FASTCALL|METH_KEYWORDS arguments as two args,
the first arg is mandatory and the second one is optional.
If the second arg is not passed it remains NULL pointer.
diff --git a/contrib/python/multidict/multidict/_multilib/state.h b/contrib/python/multidict/multidict/_multilib/state.h
new file mode 100644
index 00000000000..58110d973a7
--- /dev/null
+++ b/contrib/python/multidict/multidict/_multilib/state.h
@@ -0,0 +1,132 @@
+#ifndef _MULTIDICT_STATE_H
+#define _MULTIDICT_STATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* State of the _multidict module */
+typedef struct {
+ PyTypeObject *IStrType;
+
+ PyTypeObject *MultiDictType;
+ PyTypeObject *CIMultiDictType;
+ PyTypeObject *MultiDictProxyType;
+ PyTypeObject *CIMultiDictProxyType;
+
+ PyTypeObject *KeysViewType;
+ PyTypeObject *ItemsViewType;
+ PyTypeObject *ValuesViewType;
+
+ PyTypeObject *KeysIterType;
+ PyTypeObject *ItemsIterType;
+ PyTypeObject *ValuesIterType;
+
+ PyObject *str_lower;
+ PyObject *str_canonical;
+} mod_state;
+
+static inline mod_state *
+get_mod_state(PyObject *mod)
+{
+ mod_state *state = (mod_state *)PyModule_GetState(mod);
+ assert(state != NULL);
+ return state;
+}
+
+static inline mod_state *
+get_mod_state_by_cls(PyTypeObject *cls)
+{
+ mod_state *state = (mod_state *)PyType_GetModuleState(cls);
+ assert(state != NULL);
+ return state;
+}
+
+
+#if PY_VERSION_HEX < 0x030b0000
+PyObject *
+PyType_GetModuleByDef(PyTypeObject *tp, PyModuleDef *def)
+{
+ PyModuleDef * mod_def;
+ if (!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
+ goto err;
+ }
+ PyObject *mod = NULL;
+
+ mod = PyType_GetModule(tp);
+ if (mod == NULL) {
+ PyErr_Clear();
+ } else {
+ mod_def = PyModule_GetDef(mod);
+ if (mod_def == def) {
+ return mod;
+ }
+ }
+
+ PyObject *mro = tp->tp_mro;
+ assert(mro != NULL);
+ assert(PyTuple_Check(mro));
+ assert(PyTuple_GET_SIZE(mro) >= 1);
+ assert(PyTuple_GET_ITEM(mro, 0) == (PyObject *)tp);
+
+ Py_ssize_t n = PyTuple_GET_SIZE(mro);
+ for (Py_ssize_t i = 1; i < n; i++) {
+ PyObject *super = PyTuple_GET_ITEM(mro, i);
+ if (!PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) {
+ continue;
+ }
+ mod = PyType_GetModule((PyTypeObject*)super);
+ if (mod == NULL) {
+ PyErr_Clear();
+ } else {
+ mod_def = PyModule_GetDef(mod);
+ if (mod_def == def) {
+ return mod;
+ }
+ }
+ }
+
+err:
+ PyErr_Format(
+ PyExc_TypeError,
+ "PyType_GetModuleByDef: No superclass of '%s' has the given module",
+ tp->tp_name);
+ return NULL;
+
+}
+#endif
+
+static PyModuleDef multidict_module;
+
+static inline int
+get_mod_state_by_def_checked(PyObject *self, mod_state **ret)
+{
+ PyTypeObject *tp = Py_TYPE(self);
+ PyObject *mod = PyType_GetModuleByDef(tp, &multidict_module);
+ if (mod == NULL) {
+ *ret = NULL;
+ if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+ PyErr_Clear();
+ return 0;
+ }
+ return -1;
+ }
+ *ret = get_mod_state(mod);
+ return 1;
+}
+
+
+static inline mod_state *
+get_mod_state_by_def(PyObject *self)
+{
+ PyTypeObject *tp = Py_TYPE(self);
+ PyObject *mod = PyType_GetModuleByDef(tp, &multidict_module);
+ assert(mod != NULL);
+ return get_mod_state(mod);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/contrib/python/multidict/multidict/_multilib/views.h b/contrib/python/multidict/multidict/_multilib/views.h
index 9cf002f803b..3e195f4d5b2 100644
--- a/contrib/python/multidict/multidict/_multilib/views.h
+++ b/contrib/python/multidict/multidict/_multilib/views.h
@@ -5,9 +5,9 @@
extern "C" {
#endif
-static PyTypeObject multidict_itemsview_type;
-static PyTypeObject multidict_valuesview_type;
-static PyTypeObject multidict_keysview_type;
+#include "dict.h"
+#include "pair_list.h"
+#include "state.h"
typedef struct {
PyObject_HEAD
@@ -15,6 +15,11 @@ typedef struct {
} _Multidict_ViewObject;
+#define Items_CheckExact(state, obj) Py_IS_TYPE(obj, state->ItemsViewType)
+#define Keys_CheckExact(state, obj) Py_IS_TYPE(obj, state->KeysViewType)
+#define Values_CheckExact(state, obj) Py_IS_TYPE(obj, state->ValuesViewType)
+
+
/********** Base **********/
static inline void
@@ -63,7 +68,7 @@ multidict_view_richcompare(PyObject *self, PyObject *other, int op)
Py_ssize_t size = PyObject_Length(other);
if (size < 0) {
PyErr_Clear();
- Py_RETURN_NOTIMPLEMENTED;;
+ Py_RETURN_NOTIMPLEMENTED;
}
PyObject *iter = NULL;
PyObject *item = NULL;
@@ -147,7 +152,7 @@ static inline PyObject *
multidict_itemsview_new(MultiDictObject *md)
{
_Multidict_ViewObject *mv = PyObject_GC_New(
- _Multidict_ViewObject, &multidict_itemsview_type);
+ _Multidict_ViewObject, md->pairs.state->ItemsViewType);
if (mv == NULL) {
return NULL;
}
@@ -167,10 +172,20 @@ multidict_itemsview_iter(_Multidict_ViewObject *self)
static inline PyObject *
multidict_itemsview_repr(_Multidict_ViewObject *self)
{
+ int tmp = Py_ReprEnter((PyObject *)self);
+ if (tmp < 0) {
+ return NULL;
+ }
+ if (tmp > 0) {
+ return PyUnicode_FromString("...");
+ }
PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__");
- if (name == NULL)
+ if (name == NULL) {
+ Py_ReprLeave((PyObject *)self);
return NULL;
+ }
PyObject *ret = pair_list_repr(&self->md->pairs, name, true, true);
+ Py_ReprLeave((PyObject *)self);
Py_CLEAR(name);
return ret;
}
@@ -390,22 +405,25 @@ fail:
static inline PyObject *
multidict_itemsview_and(PyObject *lft, PyObject *rht)
{
- int tmp = PyObject_IsInstance(lft, (PyObject *)&multidict_itemsview_type);
+ mod_state * state;
+ int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp > 0) {
- return multidict_itemsview_and1((_Multidict_ViewObject *)lft, rht);
- } else {
- tmp = PyObject_IsInstance(rht, (PyObject *)&multidict_itemsview_type);
+ } else if (tmp == 0) {
+ tmp = get_mod_state_by_def_checked(rht, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp == 0) {
+ } else if (tmp == 0) {
Py_RETURN_NOTIMPLEMENTED;
}
+ }
+ assert(state != NULL);
+ if (Items_CheckExact(state, lft)) {
+ return multidict_itemsview_and1((_Multidict_ViewObject *)lft, rht);
+ } else if (Items_CheckExact(state, rht)) {
return multidict_itemsview_and2((_Multidict_ViewObject *)rht, lft);
}
+ Py_RETURN_NOTIMPLEMENTED;
}
static inline PyObject *
@@ -579,22 +597,25 @@ fail:
static inline PyObject *
multidict_itemsview_or(PyObject *lft, PyObject *rht)
{
- int tmp = PyObject_IsInstance(lft, (PyObject *)&multidict_itemsview_type);
+ mod_state * state;
+ int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp > 0) {
- return multidict_itemsview_or1((_Multidict_ViewObject *)lft, rht);
- } else {
- tmp = PyObject_IsInstance(rht, (PyObject *)&multidict_itemsview_type);
+ } else if (tmp == 0) {
+ tmp = get_mod_state_by_def_checked(rht, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp == 0) {
+ } else if (tmp == 0) {
Py_RETURN_NOTIMPLEMENTED;
}
+ }
+ assert(state != NULL);
+ if (Items_CheckExact(state, lft)) {
+ return multidict_itemsview_or1((_Multidict_ViewObject *)lft, rht);
+ } else if (Items_CheckExact(state, rht)) {
return multidict_itemsview_or2((_Multidict_ViewObject *)rht, lft);
}
+ Py_RETURN_NOTIMPLEMENTED;
}
@@ -769,42 +790,50 @@ fail:
static inline PyObject *
multidict_itemsview_sub(PyObject *lft, PyObject *rht)
{
- int tmp = PyObject_IsInstance(lft, (PyObject *)&multidict_itemsview_type);
+ mod_state * state;
+ int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp > 0) {
- return multidict_itemsview_sub1((_Multidict_ViewObject *)lft, rht);
- } else {
- tmp = PyObject_IsInstance(rht, (PyObject *)&multidict_itemsview_type);
+ } else if (tmp == 0) {
+ tmp = get_mod_state_by_def_checked(rht, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp == 0) {
+ } else if (tmp == 0) {
Py_RETURN_NOTIMPLEMENTED;
}
+ }
+ assert(state != NULL);
+ if (Items_CheckExact(state, lft)) {
+ return multidict_itemsview_sub1((_Multidict_ViewObject *)lft, rht);
+ } else if (Items_CheckExact(state, rht)) {
return multidict_itemsview_sub2((_Multidict_ViewObject *)rht, lft);
}
+ Py_RETURN_NOTIMPLEMENTED;
}
static inline PyObject *
multidict_itemsview_xor(_Multidict_ViewObject *self, PyObject *other)
{
- int tmp = PyObject_IsInstance((PyObject *)self,
- (PyObject *)&multidict_itemsview_type);
+ mod_state * state;
+ int tmp = get_mod_state_by_def_checked((PyObject *)self, &state);
if (tmp < 0) {
- goto fail;
- }
- if (tmp == 0) {
- tmp = PyObject_IsInstance(other, (PyObject *)&multidict_itemsview_type);
+ return NULL;
+ } else if (tmp == 0) {
+ tmp = get_mod_state_by_def_checked(other, &state);
if (tmp < 0) {
- goto fail;
+ return NULL;
+ } else if (tmp == 0) {
+ Py_RETURN_NOTIMPLEMENTED;
}
- if (tmp == 0) {
+ }
+ assert(state != NULL);
+ if (!Items_CheckExact(state, self)) {
+ if (Items_CheckExact(state, other)) {
+ return multidict_itemsview_xor((_Multidict_ViewObject *)other,
+ (PyObject *)self);
+ } else {
Py_RETURN_NOTIMPLEMENTED;
}
- return multidict_itemsview_xor((_Multidict_ViewObject *)other,
- (PyObject *)self);
}
PyObject *ret = NULL;
@@ -842,13 +871,6 @@ fail:
return NULL;
}
-static PyNumberMethods multidict_itemsview_as_number = {
- .nb_subtract = (binaryfunc)multidict_itemsview_sub,
- .nb_and = (binaryfunc)multidict_itemsview_and,
- .nb_xor = (binaryfunc)multidict_itemsview_xor,
- .nb_or = (binaryfunc)multidict_itemsview_or,
-};
-
static inline int
multidict_itemsview_contains(_Multidict_ViewObject *self, PyObject *obj)
{
@@ -907,11 +929,6 @@ multidict_itemsview_contains(_Multidict_ViewObject *self, PyObject *obj)
return 0;
}
-static PySequenceMethods multidict_itemsview_as_sequence = {
- .sq_length = (lenfunc)multidict_view_len,
- .sq_contains = (objobjproc)multidict_itemsview_contains,
-};
-
static inline PyObject *
multidict_itemsview_isdisjoint(_Multidict_ViewObject *self, PyObject *other)
{
@@ -989,21 +1006,34 @@ static PyMethodDef multidict_itemsview_methods[] = {
{NULL, NULL} /* sentinel */
};
-static PyTypeObject multidict_itemsview_type = {
- PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
- "multidict._multidict._ItemsView", /* tp_name */
- sizeof(_Multidict_ViewObject), /* tp_basicsize */
- .tp_dealloc = (destructor)multidict_view_dealloc,
- .tp_repr = (reprfunc)multidict_itemsview_repr,
- .tp_as_number = &multidict_itemsview_as_number,
- .tp_as_sequence = &multidict_itemsview_as_sequence,
- .tp_getattro = PyObject_GenericGetAttr,
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
- .tp_traverse = (traverseproc)multidict_view_traverse,
- .tp_clear = (inquiry)multidict_view_clear,
- .tp_richcompare = multidict_view_richcompare,
- .tp_iter = (getiterfunc)multidict_itemsview_iter,
- .tp_methods = multidict_itemsview_methods,
+static PyType_Slot multidict_itemsview_slots[] = {
+ {Py_tp_dealloc, multidict_view_dealloc},
+ {Py_tp_repr, multidict_itemsview_repr},
+
+ {Py_nb_subtract, multidict_itemsview_sub},
+ {Py_nb_and, multidict_itemsview_and},
+ {Py_nb_xor, multidict_itemsview_xor},
+ {Py_nb_or, multidict_itemsview_or},
+ {Py_sq_length, multidict_view_len},
+ {Py_sq_contains, multidict_itemsview_contains},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_traverse, multidict_view_traverse},
+ {Py_tp_clear, multidict_view_clear},
+ {Py_tp_richcompare, multidict_view_richcompare},
+ {Py_tp_iter, multidict_itemsview_iter},
+ {Py_tp_methods, multidict_itemsview_methods},
+ {0, NULL},
+};
+
+static PyType_Spec multidict_itemsview_spec = {
+ .name = "multidict._multidict._ItemsView",
+ .basicsize = sizeof(_Multidict_ViewObject),
+ .flags = (Py_TPFLAGS_DEFAULT
+#if PY_VERSION_HEX >= 0x030a0000
+ | Py_TPFLAGS_IMMUTABLETYPE
+#endif
+ | Py_TPFLAGS_HAVE_GC),
+ .slots = multidict_itemsview_slots,
};
@@ -1013,7 +1043,7 @@ static inline PyObject *
multidict_keysview_new(MultiDictObject *md)
{
_Multidict_ViewObject *mv = PyObject_GC_New(
- _Multidict_ViewObject, &multidict_keysview_type);
+ _Multidict_ViewObject, md->pairs.state->KeysViewType);
if (mv == NULL) {
return NULL;
}
@@ -1034,8 +1064,9 @@ static inline PyObject *
multidict_keysview_repr(_Multidict_ViewObject *self)
{
PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__");
- if (name == NULL)
+ if (name == NULL) {
return NULL;
+ }
PyObject *ret = pair_list_repr(&self->md->pairs, name, true, false);
Py_CLEAR(name);
return ret;
@@ -1137,22 +1168,25 @@ fail:
static inline PyObject *
multidict_keysview_and(PyObject *lft, PyObject *rht)
{
- int tmp = PyObject_IsInstance(lft, (PyObject *)&multidict_keysview_type);
+ mod_state * state;
+ int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp > 0) {
- return multidict_keysview_and1((_Multidict_ViewObject *)lft, rht);
- } else {
- tmp = PyObject_IsInstance(rht, (PyObject *)&multidict_keysview_type);
+ } else if (tmp == 0) {
+ tmp = get_mod_state_by_def_checked(rht, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp == 0) {
+ } else if (tmp == 0) {
Py_RETURN_NOTIMPLEMENTED;
}
+ }
+ assert(state != NULL);
+ if (Keys_CheckExact(state, lft)) {
+ return multidict_keysview_and1((_Multidict_ViewObject *)lft, rht);
+ } else if (Keys_CheckExact(state, rht)) {
return multidict_keysview_and2((_Multidict_ViewObject *)rht, lft);
}
+ Py_RETURN_NOTIMPLEMENTED;
}
static inline PyObject *
@@ -1283,22 +1317,25 @@ fail:
static inline PyObject *
multidict_keysview_or(PyObject *lft, PyObject *rht)
{
- int tmp = PyObject_IsInstance(lft, (PyObject *)&multidict_keysview_type);
+ mod_state * state;
+ int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp > 0) {
- return multidict_keysview_or1((_Multidict_ViewObject *)lft, rht);
- } else {
- tmp = PyObject_IsInstance(rht, (PyObject *)&multidict_keysview_type);
+ } else if (tmp == 0) {
+ tmp = get_mod_state_by_def_checked(rht, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp == 0) {
+ } else if (tmp == 0) {
Py_RETURN_NOTIMPLEMENTED;
}
+ }
+ assert(state != NULL);
+ if (Keys_CheckExact(state, lft)) {
+ return multidict_keysview_or1((_Multidict_ViewObject *)lft, rht);
+ } else if (Keys_CheckExact(state, rht)) {
return multidict_keysview_or2((_Multidict_ViewObject *)rht, lft);
}
+ Py_RETURN_NOTIMPLEMENTED;
}
static inline PyObject *
@@ -1399,42 +1436,50 @@ fail:
static inline PyObject *
multidict_keysview_sub(PyObject *lft, PyObject *rht)
{
- int tmp = PyObject_IsInstance(lft, (PyObject *)&multidict_keysview_type);
+ mod_state * state;
+ int tmp = get_mod_state_by_def_checked(lft, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp > 0) {
- return multidict_keysview_sub1((_Multidict_ViewObject *)lft, rht);
- } else {
- tmp = PyObject_IsInstance(rht, (PyObject *)&multidict_keysview_type);
+ } else if (tmp == 0) {
+ tmp = get_mod_state_by_def_checked(rht, &state);
if (tmp < 0) {
return NULL;
- }
- if (tmp == 0) {
+ } else if (tmp == 0) {
Py_RETURN_NOTIMPLEMENTED;
}
+ }
+ assert(state != NULL);
+ if (Keys_CheckExact(state, lft)) {
+ return multidict_keysview_sub1((_Multidict_ViewObject *)lft, rht);
+ } else if (Keys_CheckExact(state, rht)) {
return multidict_keysview_sub2((_Multidict_ViewObject *)rht, lft);
}
+ Py_RETURN_NOTIMPLEMENTED;
}
static inline PyObject *
multidict_keysview_xor(_Multidict_ViewObject *self, PyObject *other)
{
- int tmp = PyObject_IsInstance((PyObject *)self,
- (PyObject *)&multidict_keysview_type);
+ mod_state * state;
+ int tmp = get_mod_state_by_def_checked((PyObject *)self, &state);
if (tmp < 0) {
- goto fail;
- }
- if (tmp == 0) {
- tmp = PyObject_IsInstance(other, (PyObject *)&multidict_keysview_type);
+ return NULL;
+ } else if (tmp == 0) {
+ tmp = get_mod_state_by_def_checked(other, &state);
if (tmp < 0) {
- goto fail;
+ return NULL;
+ } else if (tmp == 0) {
+ Py_RETURN_NOTIMPLEMENTED;
}
- if (tmp == 0) {
+ }
+ assert(state != NULL);
+ if (!Keys_CheckExact(state, self)) {
+ if (Keys_CheckExact(state, other)) {
+ return multidict_keysview_xor((_Multidict_ViewObject *)other,
+ (PyObject *)self);
+ } else {
Py_RETURN_NOTIMPLEMENTED;
}
- return multidict_keysview_xor((_Multidict_ViewObject *)other,
- (PyObject *)self);
}
PyObject *ret = NULL;
@@ -1472,24 +1517,12 @@ fail:
return NULL;
}
-static PyNumberMethods multidict_keysview_as_number = {
- .nb_subtract = (binaryfunc)multidict_keysview_sub,
- .nb_and = (binaryfunc)multidict_keysview_and,
- .nb_xor = (binaryfunc)multidict_keysview_xor,
- .nb_or = (binaryfunc)multidict_keysview_or,
-};
-
static inline int
multidict_keysview_contains(_Multidict_ViewObject *self, PyObject *key)
{
return pair_list_contains(&self->md->pairs, key, NULL);
}
-static PySequenceMethods multidict_keysview_as_sequence = {
- .sq_length = (lenfunc)multidict_view_len,
- .sq_contains = (objobjproc)multidict_keysview_contains,
-};
-
static inline PyObject *
multidict_keysview_isdisjoint(_Multidict_ViewObject *self, PyObject *other)
{
@@ -1527,23 +1560,35 @@ static PyMethodDef multidict_keysview_methods[] = {
{NULL, NULL} /* sentinel */
};
-static PyTypeObject multidict_keysview_type = {
- PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
- "multidict._multidict._KeysView", /* tp_name */
- sizeof(_Multidict_ViewObject), /* tp_basicsize */
- .tp_dealloc = (destructor)multidict_view_dealloc,
- .tp_repr = (reprfunc)multidict_keysview_repr,
- .tp_as_number = &multidict_keysview_as_number,
- .tp_as_sequence = &multidict_keysview_as_sequence,
- .tp_getattro = PyObject_GenericGetAttr,
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
- .tp_traverse = (traverseproc)multidict_view_traverse,
- .tp_clear = (inquiry)multidict_view_clear,
- .tp_richcompare = multidict_view_richcompare,
- .tp_iter = (getiterfunc)multidict_keysview_iter,
- .tp_methods = multidict_keysview_methods,
+static PyType_Slot multidict_keysview_slots[] = {
+ {Py_tp_dealloc, multidict_view_dealloc},
+ {Py_tp_repr, multidict_keysview_repr},
+
+ {Py_nb_subtract, multidict_keysview_sub},
+ {Py_nb_and, multidict_keysview_and},
+ {Py_nb_xor, multidict_keysview_xor},
+ {Py_nb_or, multidict_keysview_or},
+ {Py_sq_length, multidict_view_len},
+ {Py_sq_contains, multidict_keysview_contains},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_traverse, multidict_view_traverse},
+ {Py_tp_clear, multidict_view_clear},
+ {Py_tp_richcompare, multidict_view_richcompare},
+ {Py_tp_iter, multidict_keysview_iter},
+ {Py_tp_methods, multidict_keysview_methods},
+ {0, NULL},
};
+static PyType_Spec multidict_keysview_spec = {
+ .name = "multidict._multidict._KeysView",
+ .basicsize = sizeof(_Multidict_ViewObject),
+ .flags = (Py_TPFLAGS_DEFAULT
+#if PY_VERSION_HEX >= 0x030a0000
+ | Py_TPFLAGS_IMMUTABLETYPE
+#endif
+ | Py_TPFLAGS_HAVE_GC),
+ .slots = multidict_keysview_slots,
+};
/********** Values **********/
@@ -1551,7 +1596,7 @@ static inline PyObject *
multidict_valuesview_new(MultiDictObject *md)
{
_Multidict_ViewObject *mv = PyObject_GC_New(
- _Multidict_ViewObject, &multidict_valuesview_type);
+ _Multidict_ViewObject, md->pairs.state->ValuesViewType);
if (mv == NULL) {
return NULL;
}
@@ -1571,46 +1616,71 @@ multidict_valuesview_iter(_Multidict_ViewObject *self)
static inline PyObject *
multidict_valuesview_repr(_Multidict_ViewObject *self)
{
+ int tmp = Py_ReprEnter((PyObject *)self);
+ if (tmp < 0) {
+ return NULL;
+ }
+ if (tmp > 0) {
+ return PyUnicode_FromString("...");
+ }
PyObject *name = PyObject_GetAttrString((PyObject*)Py_TYPE(self), "__name__");
- if (name == NULL)
+ if (name == NULL) {
+ Py_ReprLeave((PyObject *)self);
return NULL;
+ }
PyObject *ret = pair_list_repr(&self->md->pairs, name, false, true);
+ Py_ReprLeave((PyObject *)self);
Py_CLEAR(name);
return ret;
}
-static PySequenceMethods multidict_valuesview_as_sequence = {
- .sq_length = (lenfunc)multidict_view_len,
+static PyType_Slot multidict_valuesview_slots[] = {
+ {Py_tp_dealloc, multidict_view_dealloc},
+ {Py_tp_repr, multidict_valuesview_repr},
+
+ {Py_sq_length, multidict_view_len},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_traverse, multidict_view_traverse},
+ {Py_tp_clear, multidict_view_clear},
+ {Py_tp_iter, multidict_valuesview_iter},
+ {0, NULL},
};
-static PyTypeObject multidict_valuesview_type = {
- PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
- "multidict._multidict._ValuesView", /* tp_name */
- sizeof(_Multidict_ViewObject), /* tp_basicsize */
- .tp_dealloc = (destructor)multidict_view_dealloc,
- .tp_repr = (reprfunc)multidict_valuesview_repr,
- .tp_as_sequence = &multidict_valuesview_as_sequence,
- .tp_getattro = PyObject_GenericGetAttr,
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
- .tp_traverse = (traverseproc)multidict_view_traverse,
- .tp_clear = (inquiry)multidict_view_clear,
- .tp_iter = (getiterfunc)multidict_valuesview_iter,
+static PyType_Spec multidict_valuesview_spec = {
+ .name = "multidict._multidict._ValuesView",
+ .basicsize = sizeof(_Multidict_ViewObject),
+ .flags = (Py_TPFLAGS_DEFAULT
+#if PY_VERSION_HEX >= 0x030a0000
+ | Py_TPFLAGS_IMMUTABLETYPE
+#endif
+ | Py_TPFLAGS_HAVE_GC),
+ .slots = multidict_valuesview_slots,
};
static inline int
-multidict_views_init(void)
+multidict_views_init(PyObject *module, mod_state *state)
{
- if (PyType_Ready(&multidict_itemsview_type) < 0 ||
- PyType_Ready(&multidict_valuesview_type) < 0 ||
- PyType_Ready(&multidict_keysview_type) < 0)
- {
- goto fail;
+ PyObject * tmp;
+ tmp = PyType_FromModuleAndSpec(module, &multidict_itemsview_spec, NULL);
+ if (tmp == NULL) {
+ return -1;
}
+ state->ItemsViewType = (PyTypeObject *)tmp;
+
+ tmp = PyType_FromModuleAndSpec(module, &multidict_valuesview_spec, NULL);
+ if (tmp == NULL) {
+ return -1;
+ }
+ state->ValuesViewType = (PyTypeObject *)tmp;
+
+ tmp = PyType_FromModuleAndSpec(module, &multidict_keysview_spec, NULL);
+ if (tmp == NULL) {
+ return -1;
+ }
+ state->KeysViewType = (PyTypeObject *)tmp;
return 0;
-fail:
- return -1;
}
#ifdef __cplusplus
diff --git a/contrib/python/multidict/tests/isolated/multidict_extend_dict.py b/contrib/python/multidict/tests/isolated/multidict_extend_dict.py
new file mode 100644
index 00000000000..c7fc86d237f
--- /dev/null
+++ b/contrib/python/multidict/tests/isolated/multidict_extend_dict.py
@@ -0,0 +1,27 @@
+import gc
+import sys
+from typing import Any
+
+import objgraph # type: ignore[import-untyped]
+
+from multidict import MultiDict
+
+
+class NoLeakDict(dict[str, Any]):
+ """A subclassed dict to make it easier to test for leaks."""
+
+
+def _run_isolated_case() -> None:
+ md: MultiDict[str] = MultiDict()
+ for _ in range(100):
+ md.update(NoLeakDict())
+ del md
+ gc.collect()
+
+ leaked = len(objgraph.by_type("NoLeakDict"))
+ print(f"{leaked} instances of NoLeakDict not collected by GC")
+ sys.exit(1 if leaked else 0)
+
+
+if __name__ == "__main__":
+ _run_isolated_case()
diff --git a/contrib/python/multidict/tests/isolated/multidict_extend_multidict.py b/contrib/python/multidict/tests/isolated/multidict_extend_multidict.py
new file mode 100644
index 00000000000..4c98972bf42
--- /dev/null
+++ b/contrib/python/multidict/tests/isolated/multidict_extend_multidict.py
@@ -0,0 +1,21 @@
+import gc
+import sys
+
+import objgraph # type: ignore[import-untyped]
+
+from multidict import MultiDict
+
+
+def _run_isolated_case() -> None:
+ md: MultiDict[str] = MultiDict()
+ for _ in range(100):
+ md.extend(MultiDict())
+ del md
+ gc.collect()
+ leaked = len(objgraph.by_type("MultiDict"))
+ print(f"{leaked} instances of MultiDict not collected by GC")
+ sys.exit(1 if leaked else 0)
+
+
+if __name__ == "__main__":
+ _run_isolated_case()
diff --git a/contrib/python/multidict/tests/isolated/multidict_extend_tuple.py b/contrib/python/multidict/tests/isolated/multidict_extend_tuple.py
new file mode 100644
index 00000000000..d96e922c316
--- /dev/null
+++ b/contrib/python/multidict/tests/isolated/multidict_extend_tuple.py
@@ -0,0 +1,27 @@
+import gc
+import sys
+from typing import Any
+
+import objgraph # type: ignore[import-untyped]
+
+from multidict import MultiDict
+
+
+class NotLeakTuple(tuple[Any, ...]):
+ """A subclassed tuple to make it easier to test for leaks."""
+
+
+def _run_isolated_case() -> None:
+ md: MultiDict[str] = MultiDict()
+ for _ in range(100):
+ md.extend(NotLeakTuple())
+ del md
+ gc.collect()
+
+ leaked = len(objgraph.by_type("NotLeakTuple"))
+ print(f"{leaked} instances of NotLeakTuple not collected by GC")
+ sys.exit(1 if leaked else 0)
+
+
+if __name__ == "__main__":
+ _run_isolated_case()
diff --git a/contrib/python/multidict/tests/isolated/multidict_update_multidict.py b/contrib/python/multidict/tests/isolated/multidict_update_multidict.py
new file mode 100644
index 00000000000..4c98972bf42
--- /dev/null
+++ b/contrib/python/multidict/tests/isolated/multidict_update_multidict.py
@@ -0,0 +1,21 @@
+import gc
+import sys
+
+import objgraph # type: ignore[import-untyped]
+
+from multidict import MultiDict
+
+
+def _run_isolated_case() -> None:
+ md: MultiDict[str] = MultiDict()
+ for _ in range(100):
+ md.extend(MultiDict())
+ del md
+ gc.collect()
+ leaked = len(objgraph.by_type("MultiDict"))
+ print(f"{leaked} instances of MultiDict not collected by GC")
+ sys.exit(1 if leaked else 0)
+
+
+if __name__ == "__main__":
+ _run_isolated_case()
diff --git a/contrib/python/multidict/tests/test_leaks.py b/contrib/python/multidict/tests/test_leaks.py
new file mode 100644
index 00000000000..ded7cf065b0
--- /dev/null
+++ b/contrib/python/multidict/tests/test_leaks.py
@@ -0,0 +1,31 @@
+import pathlib
+import platform
+import subprocess
+import sys
+
+import pytest
+
+IS_PYPY = platform.python_implementation() == "PyPy"
+
+
+ ("script"),
+ (
+ "multidict_extend_dict.py",
+ "multidict_extend_multidict.py",
+ "multidict_extend_tuple.py",
+ "multidict_update_multidict.py",
+ ),
+)
[email protected](IS_PYPY, reason="leak testing is not supported on PyPy")
+def test_leak(script: str) -> None:
+ """Run isolated leak test script and check for leaks."""
+ leak_test_script = pathlib.Path(__file__).parent.joinpath("isolated", script)
+
+ subprocess.run(
+ [sys.executable, "-u", str(leak_test_script)],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ check=True,
+ )
diff --git a/contrib/python/multidict/tests/test_multidict.py b/contrib/python/multidict/tests/test_multidict.py
index 48ad479deac..aa59d6adef4 100644
--- a/contrib/python/multidict/tests/test_multidict.py
+++ b/contrib/python/multidict/tests/test_multidict.py
@@ -2,6 +2,7 @@ from __future__ import annotations
import gc
import operator
+import platform
import sys
import weakref
from collections import deque
@@ -18,9 +19,11 @@ from multidict import (
MultiDictProxy,
MultiMapping,
MutableMultiMapping,
+ istr,
)
_T = TypeVar("_T")
+IS_PYPY = platform.python_implementation() == "PyPy"
def chained_callable(
@@ -36,8 +39,6 @@ def chained_callable(
*args: object,
**kwargs: object,
) -> MultiMapping[int | str] | MutableMultiMapping[int | str]:
- nonlocal callables
-
callable_chain = (getattr(module, name) for name in callables)
first_callable = next(callable_chain)
@@ -725,6 +726,17 @@ class TestMultiDict(BaseMultiDictTest):
assert str(d) == "<%s('key': 'one', 'key': 'two')>" % _cls.__name__
+ def test__repr___recursive(
+ self, any_multidict_class: type[MultiDict[object]]
+ ) -> None:
+ d = any_multidict_class()
+ _cls = type(d)
+
+ d = any_multidict_class()
+ d["key"] = d
+
+ assert str(d) == "<%s('key': ...)>" % _cls.__name__
+
def test_getall(self, cls: type[MultiDict[str]]) -> None:
d = cls([("key", "value1")], key="value2")
@@ -757,6 +769,14 @@ class TestMultiDict(BaseMultiDictTest):
expected = "<_ItemsView('key': 'value1', 'key': 'value2')>"
assert repr(d.items()) == expected
+ def test_items__repr__recursive(
+ self, any_multidict_class: type[MultiDict[object]]
+ ) -> None:
+ d = any_multidict_class()
+ d["key"] = d.items()
+ expected = "<_ItemsView('key': <_ItemsView('key': ...)>)>"
+ assert repr(d.items()) == expected
+
def test_keys__repr__(self, cls: type[MultiDict[str]]) -> None:
d = cls([("key", "value1")], key="value2")
assert repr(d.keys()) == "<_KeysView('key', 'key')>"
@@ -765,6 +785,13 @@ class TestMultiDict(BaseMultiDictTest):
d = cls([("key", "value1")], key="value2")
assert repr(d.values()) == "<_ValuesView('value1', 'value2')>"
+ def test_values__repr__recursive(
+ self, any_multidict_class: type[MultiDict[object]]
+ ) -> None:
+ d = any_multidict_class()
+ d["key"] = d.values()
+ assert repr(d.values()) == "<_ValuesView(<_ValuesView(...)>)>"
+
class TestCIMultiDict(BaseMultiDictTest):
@pytest.fixture(
@@ -1189,3 +1216,110 @@ class TestCIMultiDict(BaseMultiDictTest):
) -> None:
d = cls([("KEY", "one")])
assert d.items().isdisjoint(arg) == expected
+
+
+def test_create_multidict_from_existing_multidict_new_pairs() -> None:
+ """Test creating a MultiDict from an existing one does not mutate the original."""
+ original = MultiDict([("h1", "header1"), ("h2", "header2"), ("h3", "header3")])
+ new = MultiDict(original, h4="header4")
+ assert "h4" in new
+ assert "h4" not in original
+
+
+def test_convert_multidict_to_cimultidict_and_back(
+ case_sensitive_multidict_class: type[MultiDict[str]],
+ case_insensitive_multidict_class: type[CIMultiDict[str]],
+ case_insensitive_str_class: type[istr],
+) -> None:
+ """Test conversion from MultiDict to CIMultiDict."""
+ start_as_md = case_sensitive_multidict_class(
+ [("KEY", "value1"), ("key2", "value2")]
+ )
+ assert start_as_md.get("KEY") == "value1"
+ assert start_as_md["KEY"] == "value1"
+ assert start_as_md.get("key2") == "value2"
+ assert start_as_md["key2"] == "value2"
+ start_as_cimd = case_insensitive_multidict_class(
+ [("KEY", "value1"), ("key2", "value2")]
+ )
+ assert start_as_cimd.get("key") == "value1"
+ assert start_as_cimd["key"] == "value1"
+ assert start_as_cimd.get("key2") == "value2"
+ assert start_as_cimd["key2"] == "value2"
+ converted_to_ci = case_insensitive_multidict_class(start_as_md)
+ assert converted_to_ci.get("key") == "value1"
+ assert converted_to_ci["key"] == "value1"
+ assert converted_to_ci.get("key2") == "value2"
+ assert converted_to_ci["key2"] == "value2"
+ converted_to_md = case_sensitive_multidict_class(converted_to_ci)
+ assert all(type(k) is case_insensitive_str_class for k in converted_to_ci.keys())
+ assert converted_to_md.get("KEY") == "value1"
+ assert converted_to_md["KEY"] == "value1"
+ assert converted_to_md.get("key2") == "value2"
+ assert converted_to_md["key2"] == "value2"
+
+
+def test_convert_multidict_to_cimultidict_eq(
+ case_sensitive_multidict_class: type[MultiDict[str]],
+ case_insensitive_multidict_class: type[CIMultiDict[str]],
+) -> None:
+ """Test compare after conversion from MultiDict to CIMultiDict."""
+ original = case_sensitive_multidict_class(
+ [("h1", "header1"), ("h2", "header2"), ("h3", "header3")]
+ )
+ assert case_insensitive_multidict_class(
+ original
+ ) == case_insensitive_multidict_class(
+ [("H1", "header1"), ("H2", "header2"), ("H3", "header3")]
+ )
+
+
[email protected](IS_PYPY, reason="getrefcount is not supported on PyPy")
+def test_extend_does_not_alter_refcount(
+ case_sensitive_multidict_class: type[MultiDict[str]],
+) -> None:
+ """Test that extending a MultiDict with a MultiDict does not alter the refcount of the original."""
+ original = case_sensitive_multidict_class([("h1", "header1")])
+ new = case_sensitive_multidict_class([("h2", "header2")])
+ original_refcount = sys.getrefcount(original)
+ new.extend(original)
+ assert sys.getrefcount(original) == original_refcount
+
+
[email protected](IS_PYPY, reason="getrefcount is not supported on PyPy")
+def test_update_does_not_alter_refcount(
+ case_sensitive_multidict_class: type[MultiDict[str]],
+) -> None:
+ """Test that updating a MultiDict with a MultiDict does not alter the refcount of the original."""
+ original = case_sensitive_multidict_class([("h1", "header1")])
+ new = case_sensitive_multidict_class([("h2", "header2")])
+ original_refcount = sys.getrefcount(original)
+ new.update(original)
+ assert sys.getrefcount(original) == original_refcount
+
+
[email protected](IS_PYPY, reason="getrefcount is not supported on PyPy")
+def test_init_does_not_alter_refcount(
+ case_sensitive_multidict_class: type[MultiDict[str]],
+) -> None:
+ """Test that initializing a MultiDict with a MultiDict does not alter the refcount of the original."""
+ original = case_sensitive_multidict_class([("h1", "header1")])
+ original_refcount = sys.getrefcount(original)
+ case_sensitive_multidict_class(original)
+ assert sys.getrefcount(original) == original_refcount
+
+
+def test_subclassed_multidict(
+ any_multidict_class: type[MultiDict[str]],
+) -> None:
+ """Test that subclassed MultiDicts work as expected."""
+ class SubclassedMultiDict(any_multidict_class): # type: ignore[valid-type, misc]
+ """Subclassed MultiDict."""
+
+ d1 = SubclassedMultiDict([("key", "value1")])
+ d2 = SubclassedMultiDict([("key", "value2")])
+ d3 = SubclassedMultiDict([("key", "value1")])
+ assert d1 != d2
+ assert d1 == d3
+ assert d1 == SubclassedMultiDict([("key", "value1")])
+ assert d1 != SubclassedMultiDict([("key", "value2")])
diff --git a/contrib/python/multidict/tests/test_multidict_benchmarks.py b/contrib/python/multidict/tests/test_multidict_benchmarks.py
index bed9faa4038..a7a6a76e728 100644
--- a/contrib/python/multidict/tests/test_multidict_benchmarks.py
+++ b/contrib/python/multidict/tests/test_multidict_benchmarks.py
@@ -255,17 +255,19 @@ def test_cimultidict_delitem_istr(
def test_multidict_getall_str_hit(
benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
) -> None:
- md = any_multidict_class(("all", str(i)) for i in range(100))
+ md = any_multidict_class((f"key{j}", str(f"{i}-{j}"))
+ for i in range(20) for j in range(5))
@benchmark
def _run() -> None:
- md.getall("all")
+ md.getall("key0")
def test_multidict_getall_str_miss(
benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
) -> None:
- md = any_multidict_class(("all", str(i)) for i in range(100))
+ md = any_multidict_class((f"key{j}", str(f"{i}-{j}"))
+ for i in range(20) for j in range(5))
@benchmark
def _run() -> None:
@@ -276,8 +278,9 @@ def test_cimultidict_getall_istr_hit(
benchmark: BenchmarkFixture,
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
) -> None:
- all_istr = istr("all")
- md = case_insensitive_multidict_class((all_istr, istr(i)) for i in range(100))
+ all_istr = istr("key0")
+ md = case_insensitive_multidict_class((f"key{j}", istr(f"{i}-{j}"))
+ for i in range(20) for j in range(5))
@benchmark
def _run() -> None:
@@ -288,9 +291,9 @@ def test_cimultidict_getall_istr_miss(
benchmark: BenchmarkFixture,
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
) -> None:
- all_istr = istr("all")
miss_istr = istr("miss")
- md = case_insensitive_multidict_class((all_istr, istr(i)) for i in range(100))
+ md = case_insensitive_multidict_class((istr(f"key{j}"), istr(f"{i}-{j}"))
+ for i in range(20) for j in range(5))
@benchmark
def _run() -> None:
@@ -565,6 +568,7 @@ def test_iterate_multidict(
for _ in md:
pass
+
def test_iterate_multidict_keys(
benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
) -> None:
@@ -588,6 +592,7 @@ def test_iterate_multidict_values(
for _ in md.values():
pass
+
def test_iterate_multidict_items(
benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
) -> None:
diff --git a/contrib/python/multidict/tests/test_views_benchmarks.py b/contrib/python/multidict/tests/test_views_benchmarks.py
index 6290b31f445..7f1b9fff995 100644
--- a/contrib/python/multidict/tests/test_views_benchmarks.py
+++ b/contrib/python/multidict/tests/test_views_benchmarks.py
@@ -7,7 +7,9 @@ from pytest_codspeed import BenchmarkFixture
from multidict import MultiDict
-def test_keys_view_equals(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_equals(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
@@ -16,7 +18,9 @@ def test_keys_view_equals(benchmark: BenchmarkFixture, any_multidict_class: Type
assert md1.keys() == md2.keys()
-def test_keys_view_not_equals(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_not_equals(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(20, 120)})
@@ -25,7 +29,9 @@ def test_keys_view_not_equals(benchmark: BenchmarkFixture, any_multidict_class:
assert md1.keys() != md2.keys()
-def test_keys_view_more(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_more(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
s = {str(i) for i in range(50)}
@@ -34,7 +40,9 @@ def test_keys_view_more(benchmark: BenchmarkFixture, any_multidict_class: Type[M
assert md.keys() > s
-def test_keys_view_more_or_equal(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_more_or_equal(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
s = {str(i) for i in range(100)}
@@ -43,7 +51,9 @@ def test_keys_view_more_or_equal(benchmark: BenchmarkFixture, any_multidict_clas
assert md.keys() >= s
-def test_keys_view_less(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_less(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
s = {str(i) for i in range(150)}
@@ -52,7 +62,9 @@ def test_keys_view_less(benchmark: BenchmarkFixture, any_multidict_class: Type[M
assert md.keys() < s
-def test_keys_view_less_or_equal(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_less_or_equal(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
s = {str(i) for i in range(100)}
@@ -61,7 +73,9 @@ def test_keys_view_less_or_equal(benchmark: BenchmarkFixture, any_multidict_clas
assert md.keys() <= s
-def test_keys_view_and(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_and(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)})
@@ -70,7 +84,9 @@ def test_keys_view_and(benchmark: BenchmarkFixture, any_multidict_class: Type[Mu
assert len(md1.keys() & md2.keys()) == 50
-def test_keys_view_or(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_or(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)})
@@ -79,7 +95,9 @@ def test_keys_view_or(benchmark: BenchmarkFixture, any_multidict_class: Type[Mul
assert len(md1.keys() | md2.keys()) == 150
-def test_keys_view_sub(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_sub(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)})
@@ -88,7 +106,9 @@ def test_keys_view_sub(benchmark: BenchmarkFixture, any_multidict_class: Type[Mu
assert len(md1.keys() - md2.keys()) == 50
-def test_keys_view_xor(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_xor(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)})
@@ -97,7 +117,9 @@ def test_keys_view_xor(benchmark: BenchmarkFixture, any_multidict_class: Type[Mu
assert len(md1.keys() ^ md2.keys()) == 100
-def test_keys_view_is_disjoint(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_is_disjoint(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100, 200)})
@@ -106,7 +128,9 @@ def test_keys_view_is_disjoint(benchmark: BenchmarkFixture, any_multidict_class:
assert md1.keys().isdisjoint(md2.keys())
-def test_keys_view_repr(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_keys_view_repr(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
@benchmark
@@ -114,7 +138,9 @@ def test_keys_view_repr(benchmark: BenchmarkFixture, any_multidict_class: Type[M
repr(md.keys())
-def test_items_view_equals(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_equals(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
@@ -123,7 +149,9 @@ def test_items_view_equals(benchmark: BenchmarkFixture, any_multidict_class: Typ
assert md1.items() == md2.items()
-def test_items_view_not_equals(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_not_equals(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(20, 120)})
@@ -132,7 +160,9 @@ def test_items_view_not_equals(benchmark: BenchmarkFixture, any_multidict_class:
assert md1.items() != md2.items()
-def test_items_view_more(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_more(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
s = {(str(i), str(i)) for i in range(50)}
@@ -141,7 +171,9 @@ def test_items_view_more(benchmark: BenchmarkFixture, any_multidict_class: Type[
assert md.items() > s
-def test_items_view_more_or_equal(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_more_or_equal(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
s = {(str(i), str(i)) for i in range(100)}
@@ -150,7 +182,9 @@ def test_items_view_more_or_equal(benchmark: BenchmarkFixture, any_multidict_cla
assert md.items() >= s
-def test_items_view_less(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_less(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
s = {(str(i), str(i)) for i in range(150)}
@@ -159,7 +193,9 @@ def test_items_view_less(benchmark: BenchmarkFixture, any_multidict_class: Type[
assert md.items() < s
-def test_items_view_less_or_equal(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_less_or_equal(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
s = {(str(i), str(i)) for i in range(100)}
@@ -168,7 +204,9 @@ def test_items_view_less_or_equal(benchmark: BenchmarkFixture, any_multidict_cla
assert md.items() <= s
-def test_items_view_and(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_and(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)})
@@ -177,7 +215,9 @@ def test_items_view_and(benchmark: BenchmarkFixture, any_multidict_class: Type[M
assert len(md1.items() & md2.items()) == 50
-def test_items_view_or(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_or(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)})
@@ -186,7 +226,9 @@ def test_items_view_or(benchmark: BenchmarkFixture, any_multidict_class: Type[Mu
assert len(md1.items() | md2.items()) == 150
-def test_items_view_sub(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_sub(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)})
@@ -195,7 +237,9 @@ def test_items_view_sub(benchmark: BenchmarkFixture, any_multidict_class: Type[M
assert len(md1.items() - md2.items()) == 50
-def test_items_view_xor(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_xor(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(50, 150)})
@@ -204,7 +248,9 @@ def test_items_view_xor(benchmark: BenchmarkFixture, any_multidict_class: Type[M
assert len(md1.items() ^ md2.items()) == 100
-def test_items_view_is_disjoint(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_is_disjoint(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md1: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
md2: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100, 200)})
@@ -213,7 +259,9 @@ def test_items_view_is_disjoint(benchmark: BenchmarkFixture, any_multidict_class
assert md1.items().isdisjoint(md2.items())
-def test_items_view_repr(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_items_view_repr(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
@benchmark
@@ -221,7 +269,9 @@ def test_items_view_repr(benchmark: BenchmarkFixture, any_multidict_class: Type[
repr(md.items())
-def test_values_view_repr(benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]) -> None:
+def test_values_view_repr(
+ benchmark: BenchmarkFixture, any_multidict_class: Type[MultiDict[str]]
+) -> None:
md: MultiDict[str] = any_multidict_class({str(i): str(i) for i in range(100)})
@benchmark
diff --git a/contrib/python/multidict/ya.make b/contrib/python/multidict/ya.make
index ed3eec6faaf..ad0d3d0777c 100644
--- a/contrib/python/multidict/ya.make
+++ b/contrib/python/multidict/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(6.3.0)
+VERSION(6.4.3)
LICENSE(Apache-2.0)