aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2024-02-16 10:13:56 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2024-02-16 10:26:57 +0300
commitfc37cddc9194c7f32912cebb50cbf8bbb5ab6bea (patch)
tree971f549f8e560730b13d779d63054d8e9f6f9e9d
parenta2797b8125bd000483873cf2c0b2b520aed8304b (diff)
downloadydb-fc37cddc9194c7f32912cebb50cbf8bbb5ab6bea.tar.gz
Intermediate changes
-rw-r--r--contrib/python/multidict/.dist-info/METADATA16
-rw-r--r--contrib/python/multidict/LICENSE2
-rw-r--r--contrib/python/multidict/README.rst6
-rw-r--r--contrib/python/multidict/multidict/__init__.py2
-rw-r--r--contrib/python/multidict/multidict/_multidict.c413
-rw-r--r--contrib/python/multidict/multidict/_multidict_py.py1
-rw-r--r--contrib/python/multidict/multidict/_multilib/defs.h4
-rw-r--r--contrib/python/multidict/multidict/_multilib/istr.h4
-rw-r--r--contrib/python/multidict/multidict/_multilib/iter.h2
-rw-r--r--contrib/python/multidict/multidict/_multilib/pair_list.h55
-rw-r--r--contrib/python/multidict/multidict/_multilib/views.h4
-rw-r--r--contrib/python/multidict/tests/__init__.py0
-rw-r--r--contrib/python/multidict/tests/cimultidict-c-extension.pickle.0 (renamed from contrib/python/multidict/tests/cimultidict.pickle.0)0
-rw-r--r--contrib/python/multidict/tests/cimultidict-c-extension.pickle.1 (renamed from contrib/python/multidict/tests/cimultidict.pickle.1)bin71 -> 71 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-c-extension.pickle.2 (renamed from contrib/python/multidict/tests/cimultidict.pickle.2)bin70 -> 70 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-c-extension.pickle.3 (renamed from contrib/python/multidict/tests/cimultidict.pickle.3)bin70 -> 70 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-c-extension.pickle.4 (renamed from contrib/python/multidict/tests/cimultidict.pickle.4)bin73 -> 73 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-c-extension.pickle.5 (renamed from contrib/python/multidict/tests/cimultidict.pickle.5)bin73 -> 73 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-pure-python.pickle.0 (renamed from contrib/python/multidict/tests/pycimultidict.pickle.0)0
-rw-r--r--contrib/python/multidict/tests/cimultidict-pure-python.pickle.1 (renamed from contrib/python/multidict/tests/pycimultidict.pickle.1)bin74 -> 74 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-pure-python.pickle.2 (renamed from contrib/python/multidict/tests/pycimultidict.pickle.2)bin73 -> 73 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-pure-python.pickle.3 (renamed from contrib/python/multidict/tests/pycimultidict.pickle.3)bin73 -> 73 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-pure-python.pickle.4 (renamed from contrib/python/multidict/tests/pycimultidict.pickle.4)bin76 -> 76 bytes
-rw-r--r--contrib/python/multidict/tests/cimultidict-pure-python.pickle.5 (renamed from contrib/python/multidict/tests/pycimultidict.pickle.5)bin76 -> 76 bytes
-rw-r--r--contrib/python/multidict/tests/conftest.py220
-rw-r--r--contrib/python/multidict/tests/gen_pickles.py32
-rw-r--r--contrib/python/multidict/tests/multidict-c-extension.pickle.0 (renamed from contrib/python/multidict/tests/multidict.pickle.0)0
-rw-r--r--contrib/python/multidict/tests/multidict-c-extension.pickle.1 (renamed from contrib/python/multidict/tests/multidict.pickle.1)bin69 -> 69 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-c-extension.pickle.2 (renamed from contrib/python/multidict/tests/multidict.pickle.2)bin68 -> 68 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-c-extension.pickle.3 (renamed from contrib/python/multidict/tests/multidict.pickle.3)bin68 -> 68 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-c-extension.pickle.4 (renamed from contrib/python/multidict/tests/multidict.pickle.4)bin71 -> 71 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-c-extension.pickle.5 (renamed from contrib/python/multidict/tests/multidict.pickle.5)bin71 -> 71 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-pure-python.pickle.0 (renamed from contrib/python/multidict/tests/pymultidict.pickle.0)0
-rw-r--r--contrib/python/multidict/tests/multidict-pure-python.pickle.1 (renamed from contrib/python/multidict/tests/pymultidict.pickle.1)bin72 -> 72 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-pure-python.pickle.2 (renamed from contrib/python/multidict/tests/pymultidict.pickle.2)bin71 -> 71 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-pure-python.pickle.3 (renamed from contrib/python/multidict/tests/pymultidict.pickle.3)bin71 -> 71 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-pure-python.pickle.4 (renamed from contrib/python/multidict/tests/pymultidict.pickle.4)bin74 -> 74 bytes
-rw-r--r--contrib/python/multidict/tests/multidict-pure-python.pickle.5 (renamed from contrib/python/multidict/tests/pymultidict.pickle.5)bin74 -> 74 bytes
-rw-r--r--contrib/python/multidict/tests/test_abc.py50
-rw-r--r--contrib/python/multidict/tests/test_circular_imports.py112
-rw-r--r--contrib/python/multidict/tests/test_copy.py61
-rw-r--r--contrib/python/multidict/tests/test_guard.py34
-rw-r--r--contrib/python/multidict/tests/test_istr.py105
-rw-r--r--contrib/python/multidict/tests/test_multidict.py399
-rw-r--r--contrib/python/multidict/tests/test_mutable_multidict.py451
-rw-r--r--contrib/python/multidict/tests/test_mypy.py2
-rw-r--r--contrib/python/multidict/tests/test_pickle.py81
-rw-r--r--contrib/python/multidict/tests/test_types.py100
-rw-r--r--contrib/python/multidict/tests/test_update.py110
-rw-r--r--contrib/python/multidict/tests/test_version.py411
-rw-r--r--contrib/python/multidict/ya.make2
-rw-r--r--yt/yt/core/rpc/config.cpp3
-rw-r--r--yt/yt/core/rpc/config.h1
-rw-r--r--yt/yt/core/rpc/service_detail.cpp58
-rw-r--r--yt/yt/core/rpc/service_detail.h14
55 files changed, 1777 insertions, 978 deletions
diff --git a/contrib/python/multidict/.dist-info/METADATA b/contrib/python/multidict/.dist-info/METADATA
index 55377fcd85..9d9b4a7212 100644
--- a/contrib/python/multidict/.dist-info/METADATA
+++ b/contrib/python/multidict/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: multidict
-Version: 6.0.4
+Version: 6.0.5
Summary: multidict implementation
Home-page: https://github.com/aio-libs/multidict
Author: Andrew Svetlov
@@ -9,11 +9,12 @@ License: Apache 2
Project-URL: Chat: Gitter, https://gitter.im/aio-libs/Lobby
Project-URL: CI: GitHub, https://github.com/aio-libs/multidict/actions
Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/multidict
-Project-URL: Docs: RTD, https://multidict.readthedocs.io
+Project-URL: Docs: RTD, https://multidict.aio-libs.org
Project-URL: GitHub: issues, https://github.com/aio-libs/multidict/issues
Project-URL: GitHub: repo, https://github.com/aio-libs/multidict
-Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
@@ -21,8 +22,9 @@ Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
-Classifier: Development Status :: 5 - Production/Stable
+Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.7
+Description-Content-Type: text/x-rst
License-File: LICENSE
=========
@@ -42,8 +44,8 @@ multidict
:alt: PyPI
.. image:: https://readthedocs.org/projects/multidict/badge/?version=latest
- :target: http://multidict.readthedocs.org/en/latest/?badge=latest
- :alt: Documentationb
+ :target: http://multidict.aio-libs.org/en/latest/?badge=latest
+ :alt: Documentation
.. image:: https://img.shields.io/pypi/pyversions/multidict.svg
:target: https://pypi.org/project/multidict
@@ -127,4 +129,4 @@ the usage scenario!!!
Changelog
---------
-See `RTD page <http://multidict.readthedocs.org/en/latest/changes.html>`_.
+See `RTD page <http://multidict.aio-libs.org/en/latest/changes>`_.
diff --git a/contrib/python/multidict/LICENSE b/contrib/python/multidict/LICENSE
index 305eef6003..8727172ae0 100644
--- a/contrib/python/multidict/LICENSE
+++ b/contrib/python/multidict/LICENSE
@@ -1,4 +1,4 @@
- Copyright 2016-2021 Andrew Svetlov and aio-libs team
+ Copyright 2016 Andrew Svetlov and aio-libs contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/contrib/python/multidict/README.rst b/contrib/python/multidict/README.rst
index 0fb146c446..df20596979 100644
--- a/contrib/python/multidict/README.rst
+++ b/contrib/python/multidict/README.rst
@@ -15,8 +15,8 @@ multidict
:alt: PyPI
.. image:: https://readthedocs.org/projects/multidict/badge/?version=latest
- :target: http://multidict.readthedocs.org/en/latest/?badge=latest
- :alt: Documentationb
+ :target: http://multidict.aio-libs.org/en/latest/?badge=latest
+ :alt: Documentation
.. image:: https://img.shields.io/pypi/pyversions/multidict.svg
:target: https://pypi.org/project/multidict
@@ -100,4 +100,4 @@ the usage scenario!!!
Changelog
---------
-See `RTD page <http://multidict.readthedocs.org/en/latest/changes.html>`_.
+See `RTD page <http://multidict.aio-libs.org/en/latest/changes>`_.
diff --git a/contrib/python/multidict/multidict/__init__.py b/contrib/python/multidict/multidict/__init__.py
index d9ea722167..23142eeafd 100644
--- a/contrib/python/multidict/multidict/__init__.py
+++ b/contrib/python/multidict/multidict/__init__.py
@@ -20,7 +20,7 @@ __all__ = (
"getversion",
)
-__version__ = "6.0.4"
+__version__ = "6.0.5"
try:
diff --git a/contrib/python/multidict/multidict/_multidict.c b/contrib/python/multidict/multidict/_multidict.c
index cbc6179932..60864953b1 100644
--- a/contrib/python/multidict/multidict/_multidict.c
+++ b/contrib/python/multidict/multidict/_multidict.c
@@ -9,9 +9,11 @@
#include "_multilib/iter.h"
#include "_multilib/views.h"
+#if PY_MAJOR_VERSION < 3 || PY_MINOR_VERSION < 12
#ifndef _PyArg_UnpackKeywords
#define FASTCALL_OLD
#endif
+#endif
static PyObject *collections_abc_mapping;
@@ -440,13 +442,31 @@ fail:
/******************** Base Methods ********************/
static inline PyObject *
-multidict_getall(MultiDictObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_getall(
+ MultiDictObject *self,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ PyObject *args,
+ PyObject *kwds
+#else
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames
+#endif
+)
{
PyObject *list = NULL,
*key = NULL,
*_default = NULL;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ static char *getall_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getall",
+ getall_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+#else
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:getall", _keywords, 0};
@@ -455,11 +475,7 @@ multidict_getall(MultiDictObject *self, PyObject *const *args,
return NULL;
}
#else
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "getall",
- .kwtuple = NULL,
- };
+ static _PyArg_Parser _parser = {NULL, _keywords, "getall", 0};
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
@@ -475,6 +491,7 @@ multidict_getall(MultiDictObject *self, PyObject *const *args,
_default = args[1];
skip_optional_pos:
#endif
+#endif
list = pair_list_get_all(&self->pairs, key);
if (list == NULL &&
@@ -490,12 +507,31 @@ skip_optional_pos:
}
static inline PyObject *
-multidict_getone(MultiDictObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_getone(
+ MultiDictObject *self,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ PyObject *args,
+ PyObject *kwds
+#else
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames
+#endif
+)
{
PyObject *key = NULL,
*_default = NULL;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ static char *getone_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getone",
+ getone_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+
+#else
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:getone", _keywords, 0};
@@ -504,11 +540,7 @@ multidict_getone(MultiDictObject *self, PyObject *const *args,
return NULL;
}
#else
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "getone",
- .kwtuple = NULL,
- };
+ static _PyArg_Parser _parser = {NULL, _keywords, "getone", 0};
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
@@ -524,17 +556,36 @@ multidict_getone(MultiDictObject *self, PyObject *const *args,
_default = args[1];
skip_optional_pos:
#endif
+#endif
return _multidict_getone(self, key, _default);
}
static inline PyObject *
-multidict_get(MultiDictObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_get(
+ MultiDictObject *self,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ PyObject *args,
+ PyObject *kwds
+#else
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames
+#endif
+)
{
PyObject *key = NULL,
*_default = Py_None,
*ret;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ static char *getone_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getone",
+ getone_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+#else
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:get", _keywords, 0};
@@ -543,11 +594,7 @@ multidict_get(MultiDictObject *self, PyObject *const *args,
return NULL;
}
#else
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "get",
- .kwtuple = NULL,
- };
+ static _PyArg_Parser _parser = {NULL, _keywords, "get", 0};
PyObject *argsbuf[2];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
@@ -563,6 +610,7 @@ multidict_get(MultiDictObject *self, PyObject *const *args,
_default = args[1];
skip_optional_pos:
#endif
+#endif
ret = _multidict_getone(self, key, _default);
return ret;
}
@@ -721,13 +769,21 @@ static inline void
multidict_tp_dealloc(MultiDictObject *self)
{
PyObject_GC_UnTrack(self);
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9
+ Py_TRASHCAN_BEGIN(self, multidict_tp_dealloc)
+#else
Py_TRASHCAN_SAFE_BEGIN(self);
+#endif
if (self->weaklist != NULL) {
PyObject_ClearWeakRefs((PyObject *)self);
};
pair_list_dealloc(&self->pairs);
Py_TYPE(self)->tp_free((PyObject *)self);
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9
+ Py_TRASHCAN_END // there should be no code after this
+#else
Py_TRASHCAN_SAFE_END(self);
+#endif
}
static inline int
@@ -775,12 +831,29 @@ multidict_tp_init(MultiDictObject *self, PyObject *args, PyObject *kwds)
}
static inline PyObject *
-multidict_add(MultiDictObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_add(
+ MultiDictObject *self,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ PyObject *args,
+ PyObject *kwds
+#else
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames
+#endif
+)
{
PyObject *key = NULL,
*val = NULL;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ static char *kwlist[] = {"key", "value", NULL};
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:add",
+ kwlist, &key, &val))
+ {
+ return NULL;
+ }
+#else
static const char * const _keywords[] = {"key", "value", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"OO:add", _keywords, 0};
@@ -795,7 +868,6 @@ multidict_add(MultiDictObject *self, PyObject *const *args,
.kwtuple = NULL,
};
PyObject *argsbuf[2];
-
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames,
&_parser, 2, 2, 0, argsbuf);
if (!args) {
@@ -804,6 +876,7 @@ multidict_add(MultiDictObject *self, PyObject *const *args,
key = args[0];
val = args[1];
#endif
+#endif
if (pair_list_add(&self->pairs, key, val) < 0) {
return NULL;
}
@@ -838,12 +911,30 @@ multidict_clear(MultiDictObject *self)
}
static inline PyObject *
-multidict_setdefault(MultiDictObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_setdefault(
+ MultiDictObject *self,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ PyObject *args,
+ PyObject *kwds
+#else
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames
+#endif
+)
{
PyObject *key = NULL,
*_default = NULL;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ static char *setdefault_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:setdefault",
+ setdefault_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+#else
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:setdefault", _keywords, 0};
@@ -852,11 +943,7 @@ multidict_setdefault(MultiDictObject *self, PyObject *const *args,
return NULL;
}
#else
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "setdefault",
- .kwtuple = NULL,
- };
+ static _PyArg_Parser _parser = {NULL, _keywords, "setdefault", 0};
PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
@@ -873,17 +960,49 @@ multidict_setdefault(MultiDictObject *self, PyObject *const *args,
skip_optional_pos:
#endif
+#endif
return pair_list_set_default(&self->pairs, key, _default);
}
static inline PyObject *
-multidict_popone(MultiDictObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_popone(
+ MultiDictObject *self,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ PyObject *args,
+ PyObject *kwds
+#else
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames
+#endif
+)
{
PyObject *key = NULL,
*_default = NULL,
*ret_val = NULL;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ static char *popone_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popone",
+ popone_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+
+ ret_val = pair_list_pop_one(&self->pairs, key);
+
+ if (ret_val == NULL &&
+ PyErr_ExceptionMatches(PyExc_KeyError) &&
+ _default != NULL)
+ {
+ PyErr_Clear();
+ Py_INCREF(_default);
+ return _default;
+ }
+
+ return ret_val;
+#else
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:popone", _keywords, 0};
@@ -892,11 +1011,7 @@ multidict_popone(MultiDictObject *self, PyObject *const *args,
return NULL;
}
#else
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "popone",
- .kwtuple = NULL,
- };
+ static _PyArg_Parser _parser = {NULL, _keywords, "popone", 0};
PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
@@ -925,16 +1040,36 @@ skip_optional_pos:
}
return ret_val;
+#endif
}
static inline PyObject *
-multidict_pop(MultiDictObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_pop(
+ MultiDictObject *self,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ PyObject *args,
+ PyObject *kwds
+#else
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames
+#endif
+)
{
PyObject *key = NULL,
*_default = NULL,
*ret_val = NULL;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ static char *pop_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popone",
+ pop_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+
+#else
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:pop", _keywords, 0};
@@ -943,11 +1078,7 @@ multidict_pop(MultiDictObject *self, PyObject *const *args,
return NULL;
}
#else
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "pop",
- .kwtuple = NULL,
- };
+ static _PyArg_Parser _parser = {NULL, _keywords, "pop", 0};
PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
@@ -964,6 +1095,7 @@ multidict_pop(MultiDictObject *self, PyObject *const *args,
skip_optional_pos:
#endif
+#endif
ret_val = pair_list_pop_one(&self->pairs, key);
if (ret_val == NULL &&
@@ -979,14 +1111,32 @@ skip_optional_pos:
}
static inline PyObject *
-multidict_popall(MultiDictObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_popall(
+ MultiDictObject *self,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ PyObject *args,
+ PyObject *kwds
+#else
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames
+#endif
+)
{
PyObject *key = NULL,
*_default = NULL,
*ret_val = NULL;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ static char *popall_keywords[] = {"key", "default", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:popall",
+ popall_keywords, &key, &_default))
+ {
+ return NULL;
+ }
+#else
static const char * const _keywords[] = {"key", "default", NULL};
#ifdef FASTCALL_OLD
static _PyArg_Parser _parser = {"O|O:popall", _keywords, 0};
@@ -995,11 +1145,7 @@ multidict_popall(MultiDictObject *self, PyObject *const *args,
return NULL;
}
#else
- static _PyArg_Parser _parser = {
- .keywords = _keywords,
- .fname = "popall",
- .kwtuple = NULL,
- };
+ static _PyArg_Parser _parser = {NULL, _keywords, "popall", 0};
PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
@@ -1016,6 +1162,7 @@ multidict_popall(MultiDictObject *self, PyObject *const *args,
skip_optional_pos:
#endif
+#endif
ret_val = pair_list_pop_all(&self->pairs, key);
if (ret_val == NULL &&
@@ -1123,19 +1270,34 @@ static PyMethodDef multidict_methods[] = {
{
"getall",
(PyCFunction)multidict_getall,
- METH_FASTCALL | METH_KEYWORDS,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ METH_VARARGS
+#else
+ METH_FASTCALL
+#endif
+ | METH_KEYWORDS,
multidict_getall_doc
},
{
"getone",
(PyCFunction)multidict_getone,
- METH_FASTCALL | METH_KEYWORDS,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ METH_VARARGS
+#else
+ METH_FASTCALL
+#endif
+ | METH_KEYWORDS,
multidict_getone_doc
},
{
"get",
(PyCFunction)multidict_get,
- METH_FASTCALL | METH_KEYWORDS,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ METH_VARARGS
+#else
+ METH_FASTCALL
+#endif
+ | METH_KEYWORDS,
multidict_get_doc
},
{
@@ -1159,7 +1321,12 @@ static PyMethodDef multidict_methods[] = {
{
"add",
(PyCFunction)multidict_add,
- METH_FASTCALL | METH_KEYWORDS,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ METH_VARARGS
+#else
+ METH_FASTCALL
+#endif
+ | METH_KEYWORDS,
multidict_add_doc
},
{
@@ -1183,25 +1350,45 @@ static PyMethodDef multidict_methods[] = {
{
"setdefault",
(PyCFunction)multidict_setdefault,
- METH_FASTCALL | METH_KEYWORDS,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ METH_VARARGS
+#else
+ METH_FASTCALL
+#endif
+ | METH_KEYWORDS,
multidict_setdefault_doc
},
{
"popone",
(PyCFunction)multidict_popone,
- METH_FASTCALL | METH_KEYWORDS,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ METH_VARARGS
+#else
+ METH_FASTCALL
+#endif
+ | METH_KEYWORDS,
multidict_popone_doc
},
{
"pop",
(PyCFunction)multidict_pop,
- METH_FASTCALL | METH_KEYWORDS,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ METH_VARARGS
+#else
+ METH_FASTCALL
+#endif
+ | METH_KEYWORDS,
multidict_pop_doc
},
{
"popall",
(PyCFunction)multidict_popall,
- METH_FASTCALL | METH_KEYWORDS,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ METH_VARARGS
+#else
+ METH_FASTCALL
+#endif
+ | METH_KEYWORDS,
multidict_popall_doc
},
{
@@ -1370,24 +1557,76 @@ multidict_proxy_tp_init(MultiDictProxyObject *self, PyObject *args,
}
static inline PyObject *
-multidict_proxy_getall(MultiDictProxyObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_proxy_getall(
+ MultiDictProxyObject *self,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ PyObject *args,
+ PyObject *kwds
+#else
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames
+#endif
+)
{
- return multidict_getall(self->md, args, nargs, kwnames);
+ return multidict_getall(
+ self->md,
+ args,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ kwds
+#else
+ nargs,
+ kwnames
+#endif
+ );
}
static inline PyObject *
-multidict_proxy_getone(MultiDictProxyObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_proxy_getone(
+ MultiDictProxyObject *self,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ PyObject *args,
+ PyObject *kwds
+#else
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames
+#endif
+)
{
- return multidict_getone(self->md, args, nargs, kwnames);
+ return multidict_getone(
+ self->md, args,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ kwds
+#else
+ nargs, kwnames
+#endif
+ );
}
static inline PyObject *
-multidict_proxy_get(MultiDictProxyObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames)
+multidict_proxy_get(
+ MultiDictProxyObject *self,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ PyObject *args,
+ PyObject *kwds
+#else
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames
+#endif
+)
{
- return multidict_get(self->md, args, nargs, kwnames);
+ return multidict_get(
+ self->md,
+ args,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ kwds
+#else
+ nargs,
+ kwnames
+#endif
+ );
}
static inline PyObject *
@@ -1495,19 +1734,34 @@ static PyMethodDef multidict_proxy_methods[] = {
{
"getall",
(PyCFunction)multidict_proxy_getall,
- METH_FASTCALL | METH_KEYWORDS,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ METH_VARARGS
+#else
+ METH_FASTCALL
+#endif
+ | METH_KEYWORDS,
multidict_getall_doc
},
{
"getone",
(PyCFunction)multidict_proxy_getone,
- METH_FASTCALL | METH_KEYWORDS,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ METH_VARARGS
+#else
+ METH_FASTCALL
+#endif
+ | METH_KEYWORDS,
multidict_getone_doc
},
{
"get",
(PyCFunction)multidict_proxy_get,
- METH_FASTCALL | METH_KEYWORDS,
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 12
+ METH_VARARGS
+#else
+ METH_FASTCALL
+#endif
+ | METH_KEYWORDS,
multidict_get_doc
},
{
@@ -1687,6 +1941,9 @@ getversion(PyObject *self, PyObject *md)
static inline void
module_free(void *m)
{
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9
+ Py_CLEAR(multidict_str_lower);
+#endif
Py_CLEAR(collections_abc_mapping);
Py_CLEAR(collections_abc_mut_mapping);
Py_CLEAR(collections_abc_mut_multi_mapping);
@@ -1713,8 +1970,15 @@ static PyModuleDef multidict_module = {
};
PyMODINIT_FUNC
-PyInit__multidict()
+PyInit__multidict(void)
{
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9
+ multidict_str_lower = PyUnicode_InternFromString("lower");
+ if (multidict_str_lower == NULL) {
+ goto fail;
+ }
+#endif
+
PyObject *module = NULL,
*reg_func_call_result = NULL;
@@ -1845,6 +2109,9 @@ PyInit__multidict()
return module;
fail:
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9
+ Py_XDECREF(multidict_str_lower);
+#endif
Py_XDECREF(collections_abc_mapping);
Py_XDECREF(collections_abc_mut_mapping);
Py_XDECREF(collections_abc_mut_multi_mapping);
diff --git a/contrib/python/multidict/multidict/_multidict_py.py b/contrib/python/multidict/multidict/_multidict_py.py
index cdbc328903..79c45aa19c 100644
--- a/contrib/python/multidict/multidict/_multidict_py.py
+++ b/contrib/python/multidict/multidict/_multidict_py.py
@@ -10,6 +10,7 @@ _marker = object()
if sys.version_info >= (3, 9):
GenericAlias = types.GenericAlias
else:
+
def GenericAlias(cls):
return cls
diff --git a/contrib/python/multidict/multidict/_multilib/defs.h b/contrib/python/multidict/multidict/_multilib/defs.h
index c7027c817e..55c21074dd 100644
--- a/contrib/python/multidict/multidict/_multilib/defs.h
+++ b/contrib/python/multidict/multidict/_multilib/defs.h
@@ -5,7 +5,11 @@
extern "C" {
#endif
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9
+static PyObject *multidict_str_lower = NULL;
+#else
_Py_IDENTIFIER(lower);
+#endif
/* We link this module statically for convenience. If compiled as a shared
library instead, some compilers don't allow addresses of Python objects
diff --git a/contrib/python/multidict/multidict/_multilib/istr.h b/contrib/python/multidict/multidict/_multilib/istr.h
index 2688f48914..61dc61aec6 100644
--- a/contrib/python/multidict/multidict/_multilib/istr.h
+++ b/contrib/python/multidict/multidict/_multilib/istr.h
@@ -43,7 +43,11 @@ istr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (!ret) {
goto fail;
}
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 9
+ s = PyObject_CallMethodNoArgs(ret, multidict_str_lower);
+#else
s =_PyObject_CallMethodId(ret, &PyId_lower, NULL);
+#endif
if (!s) {
goto fail;
}
diff --git a/contrib/python/multidict/multidict/_multilib/iter.h b/contrib/python/multidict/multidict/_multilib/iter.h
index 4e2e32b387..9ee3375382 100644
--- a/contrib/python/multidict/multidict/_multilib/iter.h
+++ b/contrib/python/multidict/multidict/_multilib/iter.h
@@ -222,7 +222,7 @@ static PyTypeObject multidict_keys_iter_type = {
};
static inline int
-multidict_iter_init()
+multidict_iter_init(void)
{
if (PyType_Ready(&multidict_items_iter_type) < 0 ||
PyType_Ready(&multidict_values_iter_type) < 0 ||
diff --git a/contrib/python/multidict/multidict/_multilib/pair_list.h b/contrib/python/multidict/multidict/_multilib/pair_list.h
index 7eafd215b5..15291d46a8 100644
--- a/contrib/python/multidict/multidict/_multilib/pair_list.h
+++ b/contrib/python/multidict/multidict/_multilib/pair_list.h
@@ -8,8 +8,7 @@ extern "C" {
#include <string.h>
#include <stddef.h>
#include <stdint.h>
-
-typedef PyObject * (*calc_identity_func)(PyObject *key);
+#include <stdbool.h>
typedef struct pair {
PyObject *identity; // 8
@@ -38,12 +37,12 @@ HTTP headers into the buffer without allocating an extra memory block.
#define EMBEDDED_CAPACITY 29
#endif
-typedef struct pair_list { // 40
- Py_ssize_t capacity; // 8
- Py_ssize_t size; // 8
- uint64_t version; // 8
- calc_identity_func calc_identity; // 8
- pair_t *pairs; // 8
+typedef struct pair_list {
+ Py_ssize_t capacity;
+ Py_ssize_t size;
+ uint64_t version;
+ bool calc_ci_indentity;
+ pair_t *pairs;
pair_t buffer[EMBEDDED_CAPACITY];
} pair_list_t;
@@ -111,7 +110,11 @@ ci_key_to_str(PyObject *key)
return ret;
}
if (PyUnicode_Check(key)) {
+#if PY_VERSION_HEX < 0x03090000
return _PyObject_CallMethodId(key, &PyId_lower, NULL);
+#else
+ return PyObject_CallMethodNoArgs(key, multidict_str_lower);
+#endif
}
PyErr_SetString(PyExc_TypeError,
"CIMultiDict keys should be either str "
@@ -199,30 +202,38 @@ pair_list_shrink(pair_list_t *list)
static inline int
-_pair_list_init(pair_list_t *list, calc_identity_func calc_identity)
+_pair_list_init(pair_list_t *list, bool calc_ci_identity)
{
+ list->calc_ci_indentity = calc_ci_identity;
list->pairs = list->buffer;
list->capacity = EMBEDDED_CAPACITY;
list->size = 0;
list->version = NEXT_VERSION();
- list->calc_identity = calc_identity;
return 0;
}
static inline int
pair_list_init(pair_list_t *list)
{
- return _pair_list_init(list, key_to_str);
+ return _pair_list_init(list, /* calc_ci_identity = */ false);
}
static inline int
ci_pair_list_init(pair_list_t *list)
{
- return _pair_list_init(list, ci_key_to_str);
+ return _pair_list_init(list, /* calc_ci_identity = */ true);
}
+static inline PyObject *
+pair_list_calc_identity(pair_list_t *list, PyObject *key)
+{
+ if (list->calc_ci_indentity)
+ return ci_key_to_str(key);
+ return key_to_str(key);
+}
+
static inline void
pair_list_dealloc(pair_list_t *list)
{
@@ -304,7 +315,7 @@ pair_list_add(pair_list_t *list,
PyObject *identity = NULL;
int ret;
- identity = list->calc_identity(key);
+ identity = pair_list_calc_identity(list, key);
if (identity == NULL) {
goto fail;
}
@@ -412,7 +423,7 @@ pair_list_del(pair_list_t *list, PyObject *key)
Py_hash_t hash;
int ret;
- identity = list->calc_identity(key);
+ identity = pair_list_calc_identity(list, key);
if (identity == NULL) {
goto fail;
}
@@ -486,7 +497,7 @@ pair_list_contains(pair_list_t *list, PyObject *key)
PyObject *identity = NULL;
int tmp;
- ident = list->calc_identity(key);
+ ident = pair_list_calc_identity(list, key);
if (ident == NULL) {
goto fail;
}
@@ -528,7 +539,7 @@ pair_list_get_one(pair_list_t *list, PyObject *key)
PyObject *value = NULL;
int tmp;
- ident = list->calc_identity(key);
+ ident = pair_list_calc_identity(list, key);
if (ident == NULL) {
goto fail;
}
@@ -573,7 +584,7 @@ pair_list_get_all(pair_list_t *list, PyObject *key)
PyObject *res = NULL;
int tmp;
- ident = list->calc_identity(key);
+ ident = pair_list_calc_identity(list, key);
if (ident == NULL) {
goto fail;
}
@@ -631,7 +642,7 @@ pair_list_set_default(pair_list_t *list, PyObject *key, PyObject *value)
PyObject *value2 = NULL;
int tmp;
- ident = list->calc_identity(key);
+ ident = pair_list_calc_identity(list, key);
if (ident == NULL) {
goto fail;
}
@@ -680,7 +691,7 @@ pair_list_pop_one(pair_list_t *list, PyObject *key)
int tmp;
PyObject *ident = NULL;
- ident = list->calc_identity(key);
+ ident = pair_list_calc_identity(list, key);
if (ident == NULL) {
goto fail;
}
@@ -730,7 +741,7 @@ pair_list_pop_all(pair_list_t *list, PyObject *key)
PyObject *res = NULL;
PyObject *ident = NULL;
- ident = list->calc_identity(key);
+ ident = pair_list_calc_identity(list, key);
if (ident == NULL) {
goto fail;
}
@@ -826,7 +837,7 @@ pair_list_replace(pair_list_t *list, PyObject * key, PyObject *value)
PyObject *identity = NULL;
Py_hash_t hash;
- identity = list->calc_identity(key);
+ identity = pair_list_calc_identity(list, key);
if (identity == NULL) {
goto fail;
}
@@ -1101,7 +1112,7 @@ pair_list_update_from_seq(pair_list_t *list, PyObject *seq)
Py_INCREF(key);
Py_INCREF(value);
- identity = list->calc_identity(key);
+ identity = pair_list_calc_identity(list, key);
if (identity == NULL) {
goto fail_1;
}
diff --git a/contrib/python/multidict/multidict/_multilib/views.h b/contrib/python/multidict/multidict/_multilib/views.h
index 5b1ebfe77c..ec80e07aeb 100644
--- a/contrib/python/multidict/multidict/_multilib/views.h
+++ b/contrib/python/multidict/multidict/_multilib/views.h
@@ -385,7 +385,7 @@ static PyTypeObject multidict_valuesview_type = {
static inline int
-multidict_views_init()
+multidict_views_init(void)
{
PyObject *reg_func_call_result = NULL;
PyObject *module = PyImport_ImportModule("multidict._multidict_base");
@@ -409,7 +409,7 @@ multidict_views_init()
GET_MOD_ATTR(abc_keysview_register_func, "_abc_keysview_register");
GET_MOD_ATTR(abc_valuesview_register_func, "_abc_valuesview_register");
- GET_MOD_ATTR(itemsview_repr_func, "_itemsview_isdisjoint");
+ GET_MOD_ATTR(itemsview_isdisjoint_func, "_itemsview_isdisjoint");
GET_MOD_ATTR(itemsview_repr_func, "_itemsview_repr");
GET_MOD_ATTR(keysview_repr_func, "_keysview_repr");
diff --git a/contrib/python/multidict/tests/__init__.py b/contrib/python/multidict/tests/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
--- a/contrib/python/multidict/tests/__init__.py
+++ /dev/null
diff --git a/contrib/python/multidict/tests/cimultidict.pickle.0 b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.0
index 7b2ed00845..7b2ed00845 100644
--- a/contrib/python/multidict/tests/cimultidict.pickle.0
+++ b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.0
diff --git a/contrib/python/multidict/tests/cimultidict.pickle.1 b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.1
index 225458ba29..225458ba29 100644
--- a/contrib/python/multidict/tests/cimultidict.pickle.1
+++ b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.1
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict.pickle.2 b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.2
index d33600e615..d33600e615 100644
--- a/contrib/python/multidict/tests/cimultidict.pickle.2
+++ b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.2
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict.pickle.3 b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.3
index cbb8624db0..cbb8624db0 100644
--- a/contrib/python/multidict/tests/cimultidict.pickle.3
+++ b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.3
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict.pickle.4 b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.4
index 1f5164ca37..1f5164ca37 100644
--- a/contrib/python/multidict/tests/cimultidict.pickle.4
+++ b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.4
Binary files differ
diff --git a/contrib/python/multidict/tests/cimultidict.pickle.5 b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.5
index 11bf552c43..11bf552c43 100644
--- a/contrib/python/multidict/tests/cimultidict.pickle.5
+++ b/contrib/python/multidict/tests/cimultidict-c-extension.pickle.5
Binary files differ
diff --git a/contrib/python/multidict/tests/pycimultidict.pickle.0 b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.0
index bd39b6db20..bd39b6db20 100644
--- a/contrib/python/multidict/tests/pycimultidict.pickle.0
+++ b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.0
diff --git a/contrib/python/multidict/tests/pycimultidict.pickle.1 b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.1
index 866003d26c..866003d26c 100644
--- a/contrib/python/multidict/tests/pycimultidict.pickle.1
+++ b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.1
Binary files differ
diff --git a/contrib/python/multidict/tests/pycimultidict.pickle.2 b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.2
index c9e43fef9c..c9e43fef9c 100644
--- a/contrib/python/multidict/tests/pycimultidict.pickle.2
+++ b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.2
Binary files differ
diff --git a/contrib/python/multidict/tests/pycimultidict.pickle.3 b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.3
index 821659fe0c..821659fe0c 100644
--- a/contrib/python/multidict/tests/pycimultidict.pickle.3
+++ b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.3
Binary files differ
diff --git a/contrib/python/multidict/tests/pycimultidict.pickle.4 b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.4
index a17c6e9b73..a17c6e9b73 100644
--- a/contrib/python/multidict/tests/pycimultidict.pickle.4
+++ b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.4
Binary files differ
diff --git a/contrib/python/multidict/tests/pycimultidict.pickle.5 b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.5
index 479bfe3a5d..479bfe3a5d 100644
--- a/contrib/python/multidict/tests/pycimultidict.pickle.5
+++ b/contrib/python/multidict/tests/cimultidict-pure-python.pickle.5
Binary files differ
diff --git a/contrib/python/multidict/tests/conftest.py b/contrib/python/multidict/tests/conftest.py
index bd3b4de027..0d003950cd 100644
--- a/contrib/python/multidict/tests/conftest.py
+++ b/contrib/python/multidict/tests/conftest.py
@@ -1,25 +1,221 @@
+from __future__ import annotations
+
+import argparse
import pickle
+from dataclasses import dataclass
+from importlib import import_module
+from sys import version_info as _version_info
+from types import ModuleType
+from typing import Callable, Type
+
+try:
+ from functools import cached_property # Python 3.8+
+except ImportError:
+ from functools import lru_cache as _lru_cache
+
+ def cached_property(func):
+ return property(_lru_cache()(func))
+
import pytest
-from multidict._compat import USE_EXTENSIONS
+from multidict import MultiMapping, MutableMultiMapping
+
+C_EXT_MARK = pytest.mark.c_extension
+PY_38_AND_BELOW = _version_info < (3, 9)
+
+
+@dataclass(frozen=True)
+class MultidictImplementation:
+ """A facade for accessing importable multidict module variants.
+
+ An instance essentially represents a c-extension or a pure-python module.
+ The actual underlying module is accessed dynamically through a property and
+ is cached.
+
+ It also has a text tag depending on what variant it is, and a string
+ representation suitable for use in Pytest's test IDs via parametrization.
+ """
+
+ is_pure_python: bool
+ """A flag showing whether this is a pure-python module or a C-extension."""
+
+ @cached_property
+ def tag(self) -> str:
+ """Return a text representation of the pure-python attribute."""
+ return "pure-python" if self.is_pure_python else "c-extension"
+
+ @cached_property
+ def imported_module(self) -> ModuleType:
+ """Return a loaded importable containing a multidict variant."""
+ importable_module = "_multidict_py" if self.is_pure_python else "_multidict"
+ return import_module(f"multidict.{importable_module}")
+
+ def __str__(self):
+ """Render the implementation facade instance as a string."""
+ return f"{self.tag}-module"
-OPTIONAL_CYTHON = (
- ()
- if USE_EXTENSIONS
- else pytest.mark.skip(reason="No extensions available")
+
+@pytest.fixture(
+ scope="session",
+ params=(
+ pytest.param(
+ MultidictImplementation(is_pure_python=False),
+ marks=C_EXT_MARK,
+ ),
+ MultidictImplementation(is_pure_python=True),
+ ),
+ ids=str,
)
+def multidict_implementation(request: pytest.FixtureRequest) -> MultidictImplementation:
+ """Return a multidict variant facade."""
+ return request.param
+
+@pytest.fixture(scope="session")
+def multidict_module(
+ multidict_implementation: MultidictImplementation,
+) -> ModuleType:
+ """Return a pre-imported module containing a multidict variant."""
+ return multidict_implementation.imported_module
-@pytest.fixture( # type: ignore[call-overload]
+
+@pytest.fixture(
scope="session",
- params=[
- pytest.param("multidict._multidict", marks=OPTIONAL_CYTHON), # type: ignore
- "multidict._multidict_py",
- ],
+ params=("MultiDict", "CIMultiDict"),
+ ids=("case-sensitive", "case-insensitive"),
)
-def _multidict(request):
- return pytest.importorskip(request.param)
+def any_multidict_class_name(request: pytest.FixtureRequest) -> str:
+ """Return a class name of a mutable multidict implementation."""
+ return request.param
+
+
+@pytest.fixture(scope="session")
+def any_multidict_class(
+ any_multidict_class_name: str,
+ multidict_module: ModuleType,
+) -> Type[MutableMultiMapping[str]]:
+ """Return a class object of a mutable multidict implementation."""
+ return getattr(multidict_module, any_multidict_class_name)
+
+
+@pytest.fixture(scope="session")
+def case_sensitive_multidict_class(
+ multidict_module: ModuleType,
+) -> Type[MutableMultiMapping[str]]:
+ """Return a case-sensitive mutable multidict class."""
+ return multidict_module.MultiDict
+
+
+@pytest.fixture(scope="session")
+def case_insensitive_multidict_class(
+ multidict_module: ModuleType,
+) -> Type[MutableMultiMapping[str]]:
+ """Return a case-insensitive mutable multidict class."""
+ return multidict_module.CIMultiDict
+
+
+@pytest.fixture(scope="session")
+def case_insensitive_str_class(multidict_module: ModuleType) -> Type[str]:
+ """Return a case-insensitive string class."""
+ return multidict_module.istr
+
+
+@pytest.fixture(scope="session")
+def any_multidict_proxy_class_name(any_multidict_class_name: str) -> str:
+ """Return a class name of an immutable multidict implementation."""
+ return f"{any_multidict_class_name}Proxy"
+
+
+@pytest.fixture(scope="session")
+def any_multidict_proxy_class(
+ any_multidict_proxy_class_name: str,
+ multidict_module: ModuleType,
+) -> Type[MultiMapping[str]]:
+ """Return an immutable multidict implementation class object."""
+ return getattr(multidict_module, any_multidict_proxy_class_name)
+
+
+@pytest.fixture(scope="session")
+def case_sensitive_multidict_proxy_class(
+ multidict_module: ModuleType,
+) -> Type[MutableMultiMapping[str]]:
+ """Return a case-sensitive immutable multidict class."""
+ return multidict_module.MultiDictProxy
+
+
+@pytest.fixture(scope="session")
+def case_insensitive_multidict_proxy_class(
+ multidict_module: ModuleType,
+) -> Type[MutableMultiMapping[str]]:
+ """Return a case-insensitive immutable multidict class."""
+ return multidict_module.CIMultiDictProxy
+
+
+@pytest.fixture(scope="session")
+def multidict_getversion_callable(multidict_module: ModuleType) -> Callable:
+ """Return a ``getversion()`` function for current implementation."""
+ return multidict_module.getversion
+
+
+def pytest_addoption(
+ parser: pytest.Parser,
+ pluginmanager: pytest.PytestPluginManager,
+) -> None:
+ """Define a new ``--c-extensions`` flag.
+
+ This lets the callers deselect tests executed against the C-extension
+ version of the ``multidict`` implementation.
+ """
+ del pluginmanager
+
+ parser.addoption(
+ "--c-extensions", # disabled with `--no-c-extensions`
+ action="store_true" if PY_38_AND_BELOW else argparse.BooleanOptionalAction,
+ default=True,
+ dest="c_extensions",
+ help="Test C-extensions (on by default)",
+ )
+
+ if PY_38_AND_BELOW:
+ parser.addoption(
+ "--no-c-extensions",
+ action="store_false",
+ dest="c_extensions",
+ help="Skip testing C-extensions (on by default)",
+ )
+
+
+def pytest_collection_modifyitems(
+ session: pytest.Session,
+ config: pytest.Config,
+ items: list[pytest.Item],
+) -> None:
+ """Deselect tests against C-extensions when requested via CLI."""
+ test_c_extensions = config.getoption("--c-extensions") is True
+
+ if test_c_extensions:
+ return
+
+ selected_tests = []
+ deselected_tests = []
+
+ for item in items:
+ c_ext = item.get_closest_marker(C_EXT_MARK.name) is not None
+
+ target_items_list = deselected_tests if c_ext else selected_tests
+ target_items_list.append(item)
+
+ config.hook.pytest_deselected(items=deselected_tests)
+ items[:] = selected_tests
+
+
+def pytest_configure(config: pytest.Config) -> None:
+ """Declare the C-extension marker in config."""
+ config.addinivalue_line(
+ "markers",
+ f"{C_EXT_MARK.name}: tests running against the C-extension implementation.",
+ )
def pytest_generate_tests(metafunc):
diff --git a/contrib/python/multidict/tests/gen_pickles.py b/contrib/python/multidict/tests/gen_pickles.py
index 028a01f8cc..4e0d268bed 100644
--- a/contrib/python/multidict/tests/gen_pickles.py
+++ b/contrib/python/multidict/tests/gen_pickles.py
@@ -1,31 +1,27 @@
import pickle
+from importlib import import_module
+from pathlib import Path
-from multidict._compat import USE_EXTENSIONS
-from multidict._multidict_py import CIMultiDict as PyCIMultiDict # noqa
-from multidict._multidict_py import MultiDict as PyMultiDict # noqa
+TESTS_DIR = Path(__file__).parent.resolve()
-try:
- from multidict._multidict import ( # type: ignore # noqa
- CIMultiDict,
- MultiDict,
- )
-except ImportError:
- pass
-
-def write(name, proto):
- cls = globals()[name]
+def write(tag, cls, proto):
d = cls([("a", 1), ("a", 2)])
- with open("{}.pickle.{}".format(name.lower(), proto), "wb") as f:
+ file_basename = f"{cls.__name__.lower()}-{tag}"
+ with (TESTS_DIR / f"{file_basename}.pickle.{proto}").open("wb") as f:
pickle.dump(d, f, proto)
def generate():
- if not USE_EXTENSIONS:
- raise RuntimeError("C Extension is required")
+ _impl_map = {
+ "c-extension": "_multidict",
+ "pure-python": "_multidict_py",
+ }
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
- for name in ("MultiDict", "CIMultiDict", "PyMultiDict", "PyCIMultiDict"):
- write(name, proto)
+ for tag, impl_name in _impl_map.items():
+ impl = import_module(f"multidict.{impl_name}")
+ for cls in impl.CIMultiDict, impl.MultiDict:
+ write(tag, cls, proto)
if __name__ == "__main__":
diff --git a/contrib/python/multidict/tests/multidict.pickle.0 b/contrib/python/multidict/tests/multidict-c-extension.pickle.0
index eb979fcf72..eb979fcf72 100644
--- a/contrib/python/multidict/tests/multidict.pickle.0
+++ b/contrib/python/multidict/tests/multidict-c-extension.pickle.0
diff --git a/contrib/python/multidict/tests/multidict.pickle.1 b/contrib/python/multidict/tests/multidict-c-extension.pickle.1
index a4f211d7b1..a4f211d7b1 100644
--- a/contrib/python/multidict/tests/multidict.pickle.1
+++ b/contrib/python/multidict/tests/multidict-c-extension.pickle.1
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict.pickle.2 b/contrib/python/multidict/tests/multidict-c-extension.pickle.2
index b4563f879d..b4563f879d 100644
--- a/contrib/python/multidict/tests/multidict.pickle.2
+++ b/contrib/python/multidict/tests/multidict-c-extension.pickle.2
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict.pickle.3 b/contrib/python/multidict/tests/multidict-c-extension.pickle.3
index 415960a3ee..415960a3ee 100644
--- a/contrib/python/multidict/tests/multidict.pickle.3
+++ b/contrib/python/multidict/tests/multidict-c-extension.pickle.3
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict.pickle.4 b/contrib/python/multidict/tests/multidict-c-extension.pickle.4
index 00ef17c3f7..00ef17c3f7 100644
--- a/contrib/python/multidict/tests/multidict.pickle.4
+++ b/contrib/python/multidict/tests/multidict-c-extension.pickle.4
Binary files differ
diff --git a/contrib/python/multidict/tests/multidict.pickle.5 b/contrib/python/multidict/tests/multidict-c-extension.pickle.5
index 2c4ae0a0d3..2c4ae0a0d3 100644
--- a/contrib/python/multidict/tests/multidict.pickle.5
+++ b/contrib/python/multidict/tests/multidict-c-extension.pickle.5
Binary files differ
diff --git a/contrib/python/multidict/tests/pymultidict.pickle.0 b/contrib/python/multidict/tests/multidict-pure-python.pickle.0
index e91023ecf9..e91023ecf9 100644
--- a/contrib/python/multidict/tests/pymultidict.pickle.0
+++ b/contrib/python/multidict/tests/multidict-pure-python.pickle.0
diff --git a/contrib/python/multidict/tests/pymultidict.pickle.1 b/contrib/python/multidict/tests/multidict-pure-python.pickle.1
index acce9bf793..acce9bf793 100644
--- a/contrib/python/multidict/tests/pymultidict.pickle.1
+++ b/contrib/python/multidict/tests/multidict-pure-python.pickle.1
Binary files differ
diff --git a/contrib/python/multidict/tests/pymultidict.pickle.2 b/contrib/python/multidict/tests/multidict-pure-python.pickle.2
index 900446ad8d..900446ad8d 100644
--- a/contrib/python/multidict/tests/pymultidict.pickle.2
+++ b/contrib/python/multidict/tests/multidict-pure-python.pickle.2
Binary files differ
diff --git a/contrib/python/multidict/tests/pymultidict.pickle.3 b/contrib/python/multidict/tests/multidict-pure-python.pickle.3
index 9b9073515a..9b9073515a 100644
--- a/contrib/python/multidict/tests/pymultidict.pickle.3
+++ b/contrib/python/multidict/tests/multidict-pure-python.pickle.3
Binary files differ
diff --git a/contrib/python/multidict/tests/pymultidict.pickle.4 b/contrib/python/multidict/tests/multidict-pure-python.pickle.4
index db363f8d3c..db363f8d3c 100644
--- a/contrib/python/multidict/tests/pymultidict.pickle.4
+++ b/contrib/python/multidict/tests/multidict-pure-python.pickle.4
Binary files differ
diff --git a/contrib/python/multidict/tests/pymultidict.pickle.5 b/contrib/python/multidict/tests/multidict-pure-python.pickle.5
index 7dc772d58f..7dc772d58f 100644
--- a/contrib/python/multidict/tests/pymultidict.pickle.5
+++ b/contrib/python/multidict/tests/multidict-pure-python.pickle.5
Binary files differ
diff --git a/contrib/python/multidict/tests/test_abc.py b/contrib/python/multidict/tests/test_abc.py
index 4636b3bc1a..e18ad83f82 100644
--- a/contrib/python/multidict/tests/test_abc.py
+++ b/contrib/python/multidict/tests/test_abc.py
@@ -3,43 +3,6 @@ from collections.abc import Mapping, MutableMapping
import pytest
from multidict import MultiMapping, MutableMultiMapping
-from multidict._compat import USE_EXTENSIONS
-from multidict._multidict_py import CIMultiDict as PyCIMultiDict
-from multidict._multidict_py import CIMultiDictProxy as PyCIMultiDictProxy
-from multidict._multidict_py import MultiDict as PyMultiDict # noqa: E402
-from multidict._multidict_py import MultiDictProxy as PyMultiDictProxy
-
-if USE_EXTENSIONS:
- from multidict._multidict import ( # type: ignore
- CIMultiDict,
- CIMultiDictProxy,
- MultiDict,
- MultiDictProxy,
- )
-
-
-@pytest.fixture(
- params=([MultiDict, CIMultiDict] if USE_EXTENSIONS else [])
- + [PyMultiDict, PyCIMultiDict],
- ids=(["MultiDict", "CIMultiDict"] if USE_EXTENSIONS else [])
- + ["PyMultiDict", "PyCIMultiDict"],
-)
-def cls(request):
- return request.param
-
-
-@pytest.fixture(
- params=(
- [(MultiDictProxy, MultiDict), (CIMultiDictProxy, CIMultiDict)]
- if USE_EXTENSIONS
- else []
- )
- + [(PyMultiDictProxy, PyMultiDict), (PyCIMultiDictProxy, PyCIMultiDict)],
- ids=(["MultiDictProxy", "CIMultiDictProxy"] if USE_EXTENSIONS else [])
- + ["PyMultiDictProxy", "PyCIMultiDictProxy"],
-)
-def proxy_classes(request):
- return request.param
def test_abc_inheritance():
@@ -116,15 +79,14 @@ def test_abc_popall():
B().popall("key")
-def test_multidict_inheritance(cls):
- assert issubclass(cls, MultiMapping)
- assert issubclass(cls, MutableMultiMapping)
+def test_multidict_inheritance(any_multidict_class):
+ assert issubclass(any_multidict_class, MultiMapping)
+ assert issubclass(any_multidict_class, MutableMultiMapping)
-def test_proxy_inheritance(proxy_classes):
- proxy, _ = proxy_classes
- assert issubclass(proxy, MultiMapping)
- assert not issubclass(proxy, MutableMultiMapping)
+def test_proxy_inheritance(any_multidict_proxy_class):
+ assert issubclass(any_multidict_proxy_class, MultiMapping)
+ assert not issubclass(any_multidict_proxy_class, MutableMultiMapping)
def test_generic_type_in_runtime():
diff --git a/contrib/python/multidict/tests/test_circular_imports.py b/contrib/python/multidict/tests/test_circular_imports.py
new file mode 100644
index 0000000000..00f6ae4f58
--- /dev/null
+++ b/contrib/python/multidict/tests/test_circular_imports.py
@@ -0,0 +1,112 @@
+"""Tests for circular imports in all local packages and modules.
+
+This ensures all internal packages can be imported right away without
+any need to import some other module before doing so.
+
+This module is based on the idea that pytest uses for self-testing:
+* https://github.com/sanitizers/octomachinery/blob/be18b54/tests/circular_imports_test.py # noqa: E501
+* https://github.com/pytest-dev/pytest/blob/d18c75b/testing/test_meta.py
+* https://twitter.com/codewithanthony/status/1229445110510735361
+"""
+
+from __future__ import annotations
+
+import os
+import pkgutil
+import subprocess
+import sys
+from itertools import chain
+from pathlib import Path
+from types import ModuleType
+from typing import Generator
+
+import pytest
+
+import multidict
+
+
+def _find_all_importables(pkg: ModuleType) -> list[str]:
+ """Find all importables in the project.
+
+ Return them in order.
+ """
+ return sorted(
+ set(
+ chain.from_iterable(
+ _discover_path_importables(Path(p), pkg.__name__) for p in pkg.__path__
+ ),
+ ),
+ )
+
+
+def _discover_path_importables(
+ pkg_pth: Path,
+ pkg_name: str,
+) -> Generator[str, None, None]:
+ """Yield all importables under a given path and package."""
+ yield pkg_name
+ for dir_path, _d, file_names in os.walk(pkg_pth):
+ pkg_dir_path = Path(dir_path)
+
+ if pkg_dir_path.parts[-1] == "__pycache__":
+ continue
+
+ if all(Path(_).suffix != ".py" for _ in file_names):
+ continue
+
+ rel_pt = pkg_dir_path.relative_to(pkg_pth)
+ pkg_pref = ".".join((pkg_name,) + rel_pt.parts)
+ yield from (
+ pkg_path
+ for _, pkg_path, _ in pkgutil.walk_packages(
+ (str(pkg_dir_path),),
+ prefix=f"{pkg_pref}.",
+ )
+ )
+
+
+@pytest.fixture(params=_find_all_importables(multidict))
+def import_path(request: pytest.FixtureRequest) -> str:
+ """Return an importable from the multidict package."""
+ importable_module: str = request.param
+ if importable_module == "multidict._multidict":
+ request.applymarker(pytest.mark.c_extension)
+
+ return importable_module
+
+
+def test_no_warnings(import_path: str) -> None:
+ """Verify that importing modules and packages doesn't explode.
+
+ This is seeking for any import errors including ones caused
+ by circular imports.
+ """
+ imp_cmd = (
+ # fmt: off
+ sys.executable,
+ "-I",
+ "-W", "error",
+ "-c", f"import {import_path!s}",
+ # fmt: on
+ )
+
+ subprocess.check_call(imp_cmd)
+
+
+@pytest.mark.c_extension
+def test_c_extension_preferred_by_default(monkeypatch: pytest.MonkeyPatch) -> None:
+ """Verify that the C-extension is exposed by default."""
+ monkeypatch.delenv("MULTIDICT_NO_EXTENSIONS", raising=False)
+
+ imp_cmd = (
+ # fmt: off
+ sys.executable,
+ "-I",
+ "-W", "error",
+ "-c", "import multidict; raise SystemExit(int("
+ "multidict.istr.__module__ != 'multidict._multidict' "
+ "or multidict.USE_EXTENSIONS is not True))",
+ # fmt: on
+ )
+
+ subprocess.check_call(imp_cmd)
diff --git a/contrib/python/multidict/tests/test_copy.py b/contrib/python/multidict/tests/test_copy.py
index 564cdde597..cd926cdc1d 100644
--- a/contrib/python/multidict/tests/test_copy.py
+++ b/contrib/python/multidict/tests/test_copy.py
@@ -1,48 +1,8 @@
import copy
-import pytest
-from multidict._compat import USE_EXTENSIONS
-from multidict._multidict_py import CIMultiDict as PyCIMultiDict
-from multidict._multidict_py import CIMultiDictProxy as PyCIMultiDictProxy
-from multidict._multidict_py import MultiDict as PyMultiDict # noqa: E402
-from multidict._multidict_py import MultiDictProxy as PyMultiDictProxy
-
-if USE_EXTENSIONS:
- from multidict._multidict import ( # type: ignore
- CIMultiDict,
- CIMultiDictProxy,
- MultiDict,
- MultiDictProxy,
- )
-
-
-@pytest.fixture(
- params=([MultiDict, CIMultiDict] if USE_EXTENSIONS else [])
- + [PyMultiDict, PyCIMultiDict],
- ids=(["MultiDict", "CIMultiDict"] if USE_EXTENSIONS else [])
- + ["PyMultiDict", "PyCIMultiDict"],
-)
-def cls(request):
- return request.param
-
-
-@pytest.fixture(
- params=(
- [(MultiDictProxy, MultiDict), (CIMultiDictProxy, CIMultiDict)]
- if USE_EXTENSIONS
- else []
- )
- + [(PyMultiDictProxy, PyMultiDict), (PyCIMultiDictProxy, PyCIMultiDict)],
- ids=(["MultiDictProxy", "CIMultiDictProxy"] if USE_EXTENSIONS else [])
- + ["PyMultiDictProxy", "PyCIMultiDictProxy"],
-)
-def proxy_classes(request):
- return request.param
-
-
-def test_copy(cls):
- d = cls()
+def test_copy(any_multidict_class):
+ d = any_multidict_class()
d["foo"] = 6
d2 = d.copy()
d2["foo"] = 7
@@ -50,11 +10,10 @@ def test_copy(cls):
assert d2["foo"] == 7
-def test_copy_proxy(proxy_classes):
- proxy_cls, dict_cls = proxy_classes
- d = dict_cls()
+def test_copy_proxy(any_multidict_class, any_multidict_proxy_class):
+ d = any_multidict_class()
d["foo"] = 6
- p = proxy_cls(d)
+ p = any_multidict_proxy_class(d)
d2 = p.copy()
d2["foo"] = 7
assert d["foo"] == 6
@@ -62,8 +21,8 @@ def test_copy_proxy(proxy_classes):
assert d2["foo"] == 7
-def test_copy_std_copy(cls):
- d = cls()
+def test_copy_std_copy(any_multidict_class):
+ d = any_multidict_class()
d["foo"] = 6
d2 = copy.copy(d)
d2["foo"] = 7
@@ -71,9 +30,9 @@ def test_copy_std_copy(cls):
assert d2["foo"] == 7
-def test_ci_multidict_clone(cls):
- d = cls(foo=6)
- d2 = cls(d)
+def test_ci_multidict_clone(any_multidict_class):
+ d = any_multidict_class(foo=6)
+ d2 = any_multidict_class(d)
d2["foo"] = 7
assert d["foo"] == 6
assert d2["foo"] == 7
diff --git a/contrib/python/multidict/tests/test_guard.py b/contrib/python/multidict/tests/test_guard.py
index 823cc1afb8..225da67c8d 100644
--- a/contrib/python/multidict/tests/test_guard.py
+++ b/contrib/python/multidict/tests/test_guard.py
@@ -1,38 +1,34 @@
-import pytest
-
-from multidict._compat import USE_EXTENSIONS
-from multidict._multidict_py import MultiDict as PyMultiDict # noqa: E402
-
-if USE_EXTENSIONS:
- from multidict._multidict import MultiDict # type: ignore
+from typing import Type
+import pytest
-@pytest.fixture(
- params=([MultiDict] if USE_EXTENSIONS else []) + [PyMultiDict],
- ids=(["MultiDict"] if USE_EXTENSIONS else []) + ["PyMultiDict"],
-)
-def cls(request):
- return request.param
+from multidict import MultiMapping
-def test_guard_items(cls):
- md = cls({"a": "b"})
+def test_guard_items(
+ case_sensitive_multidict_class: Type[MultiMapping[str]],
+) -> None:
+ md = case_sensitive_multidict_class({"a": "b"})
it = iter(md.items())
md["a"] = "c"
with pytest.raises(RuntimeError):
next(it)
-def test_guard_keys(cls):
- md = cls({"a": "b"})
+def test_guard_keys(
+ case_sensitive_multidict_class: Type[MultiMapping[str]],
+) -> None:
+ md = case_sensitive_multidict_class({"a": "b"})
it = iter(md.keys())
md["a"] = "c"
with pytest.raises(RuntimeError):
next(it)
-def test_guard_values(cls):
- md = cls({"a": "b"})
+def test_guard_values(
+ case_sensitive_multidict_class: Type[MultiMapping[str]],
+) -> None:
+ md = case_sensitive_multidict_class({"a": "b"})
it = iter(md.values())
md["a"] = "c"
with pytest.raises(RuntimeError):
diff --git a/contrib/python/multidict/tests/test_istr.py b/contrib/python/multidict/tests/test_istr.py
index caae397f2d..1918153532 100644
--- a/contrib/python/multidict/tests/test_istr.py
+++ b/contrib/python/multidict/tests/test_istr.py
@@ -1,83 +1,74 @@
import gc
import sys
-from typing import Type
+from typing import Callable, Type
import pytest
-from multidict._compat import USE_EXTENSIONS
-from multidict._multidict_py import istr as _istr # noqa: E402
+IMPLEMENTATION = getattr(sys, "implementation") # to suppress mypy error
-if USE_EXTENSIONS:
- from multidict._multidict import istr # type: ignore
-else:
- from multidict import istr
+def test_ctor(case_insensitive_str_class: Type[str]) -> None:
+ s = case_insensitive_str_class()
+ assert "" == s
-IMPLEMENTATION = getattr(sys, "implementation") # to suppress mypy error
+def test_ctor_str(case_insensitive_str_class: Type[str]) -> None:
+ s = case_insensitive_str_class("aBcD")
+ assert "aBcD" == s
-class IStrMixin:
- cls = Type[istr]
+def test_ctor_istr(case_insensitive_str_class: Type[str]) -> None:
+ s = case_insensitive_str_class("A")
+ s2 = case_insensitive_str_class(s)
+ assert "A" == s
+ assert s == s2
- def test_ctor(self):
- s = self.cls()
- assert "" == s
- def test_ctor_str(self):
- s = self.cls("aBcD")
- assert "aBcD" == s
+def test_ctor_buffer(case_insensitive_str_class: Type[str]) -> None:
+ s = case_insensitive_str_class(b"aBc")
+ assert "b'aBc'" == s
- def test_ctor_istr(self):
- s = self.cls("A")
- s2 = self.cls(s)
- assert "A" == s
- assert s == s2
- def test_ctor_buffer(self):
- s = self.cls(b"aBc")
- assert "b'aBc'" == s
+def test_ctor_repr(case_insensitive_str_class: Type[str]) -> None:
+ s = case_insensitive_str_class(None)
+ assert "None" == s
- def test_ctor_repr(self):
- s = self.cls(None)
- assert "None" == s
- def test_str(self):
- s = self.cls("aBcD")
- s1 = str(s)
- assert s1 == "aBcD"
- assert type(s1) is str
+def test_str(case_insensitive_str_class: Type[str]) -> None:
+ s = case_insensitive_str_class("aBcD")
+ s1 = str(s)
+ assert s1 == "aBcD"
+ assert type(s1) is str
- def test_eq(self):
- s1 = "Abc"
- s2 = self.cls(s1)
- assert s1 == s2
+def test_eq(case_insensitive_str_class: Type[str]) -> None:
+ s1 = "Abc"
+ s2 = case_insensitive_str_class(s1)
+ assert s1 == s2
-class TestPyIStr(IStrMixin):
- cls = _istr
- @staticmethod
- def _create_strs():
- _istr("foobarbaz")
- istr2 = _istr()
- _istr(istr2)
+@pytest.fixture
+def create_istrs(case_insensitive_str_class: Type[str]) -> Callable[[], None]:
+ """Make a callable populating memory with a few ``istr`` objects."""
- @pytest.mark.skipif(
- IMPLEMENTATION.name != "cpython", reason="PyPy has different GC implementation"
- )
- def test_leak(self):
- gc.collect()
- cnt = len(gc.get_objects())
- for _ in range(10000):
- self._create_strs()
+ def _create_strs() -> None:
+ case_insensitive_str_class("foobarbaz")
+ istr2 = case_insensitive_str_class()
+ case_insensitive_str_class(istr2)
- gc.collect()
- cnt2 = len(gc.get_objects())
- assert abs(cnt - cnt2) < 10 # on PyPy these numbers are not equal
+ return _create_strs
-if USE_EXTENSIONS:
+@pytest.mark.skipif(
+ IMPLEMENTATION.name != "cpython",
+ reason="PyPy has different GC implementation",
+)
+def test_leak(create_istrs: Callable[[], None]) -> None:
+ gc.collect()
+ cnt = len(gc.get_objects())
+ for _ in range(10000):
+ create_istrs()
- class TestIStr(IStrMixin):
- cls = istr
+ gc.collect()
+ cnt2 = len(gc.get_objects())
+ assert abs(cnt - cnt2) < 10 # on PyPy these numbers are not equal
diff --git a/contrib/python/multidict/tests/test_multidict.py b/contrib/python/multidict/tests/test_multidict.py
index e2ad71ee34..3173fe24c7 100644
--- a/contrib/python/multidict/tests/test_multidict.py
+++ b/contrib/python/multidict/tests/test_multidict.py
@@ -1,121 +1,129 @@
+from __future__ import annotations
+
import gc
import operator
import sys
import weakref
from collections import deque
from collections.abc import Mapping
-from functools import reduce
+from types import ModuleType
from typing import (
- Any,
Callable,
Dict,
Iterable,
Iterator,
+ KeysView,
List,
Mapping,
Set,
Tuple,
Type,
- TypeVar,
Union,
+ cast,
)
import pytest
import multidict
-from multidict import CIMultiDict, CIMultiDictProxy, MultiDict, MultiDictProxy
-
-_MultiDictClasses = Union[Type[MultiDict[str]], Type[CIMultiDict[str]]]
+from multidict import CIMultiDict, MultiDict, MultiMapping, MutableMultiMapping
def chained_callable(
- module: object, callables: Union[str, Iterable[str]]
-) -> Callable[..., Any]:
+ module: ModuleType,
+ callables: Iterable[str],
+) -> Callable[..., MultiMapping[int | str] | MutableMultiMapping[int | str]]:
"""
- Returns callable that will get and call all given objects in module in
- exact order. If `names` is a single object's name function will return
- object itself.
-
- Will treat `names` of type `str` as a list of single element.
+ Return callable that will get and call all given objects in module in
+ exact order.
"""
- callables = (callables,) if isinstance(callables, str) else callables
- _callable, *rest = (getattr(module, name) for name in callables)
- def chained_call(*args: object, **kwargs: object) -> Any:
- return reduce(lambda res, c: c(res), rest, _callable(*args, **kwargs))
+ def chained_call(
+ *args: object,
+ **kwargs: object,
+ ) -> MultiMapping[int | str] | MutableMultiMapping[int | str]:
+ nonlocal callables
- return chained_call if len(rest) > 0 else _callable # type: ignore[no-any-return]
+ callable_chain = (getattr(module, name) for name in callables)
+ first_callable = next(callable_chain)
+ value = first_callable(*args, **kwargs)
+ for element in callable_chain:
+ value = element(value)
-@pytest.fixture(scope="function")
-def cls(request: Any, _multidict: Any) -> Any:
- return chained_callable(_multidict, request.param)
+ return cast(
+ Union[
+ MultiMapping[Union[int, str]],
+ MutableMultiMapping[Union[int, str]],
+ ],
+ value,
+ )
+ return chained_call
-@pytest.fixture(scope="function")
-def classes(request: Any, _multidict: Any) -> Any:
- return tuple(chained_callable(_multidict, n) for n in request.param)
+@pytest.fixture
+def cls( # type: ignore[misc]
+ request: pytest.FixtureRequest,
+ multidict_module: ModuleType,
+) -> Callable[..., MultiMapping[int | str] | MutableMultiMapping[int | str]]:
+ """Make a callable from multidict module, requested by name."""
+ return chained_callable(multidict_module, request.param)
-@pytest.mark.parametrize("cls", ["MultiDict", "CIMultiDict"], indirect=True)
-def test_exposed_names(
- cls: Union[Type[MultiDict[object]], Type[CIMultiDict[object]]]
-) -> None:
- name = cls.__name__
-
- while name.startswith("_"):
- name = name[1:]
- assert name in multidict.__all__ # type: ignore[attr-defined]
+def test_exposed_names(any_multidict_class_name: str) -> None:
+ assert any_multidict_class_name in multidict.__all__ # type: ignore[attr-defined]
@pytest.mark.parametrize(
- "cls, key_cls",
- [("MultiDict", str), (("MultiDict", "MultiDictProxy"), str)],
+ ("cls", "key_cls"),
+ (
+ (("MultiDict",), str),
+ (
+ ("MultiDict", "MultiDictProxy"),
+ str,
+ ),
+ ),
indirect=["cls"],
)
def test__iter__types(
- cls: Type[MultiDict[Union[str, int]]], key_cls: Type[object]
+ cls: Type[MultiDict[Union[str, int]]],
+ key_cls: Type[object],
) -> None:
d = cls([("key", "one"), ("key2", "two"), ("key", 3)])
for i in d:
assert type(i) is key_cls, (type(i), key_cls)
-_ClsPair = TypeVar(
- "_ClsPair",
- Tuple[Type[MultiDict[str]], Type[MultiDictProxy[str]]],
- Tuple[Type[CIMultiDict[str]], Type[CIMultiDictProxy[str]]],
-)
-
-
-@pytest.mark.parametrize(
- "classes",
- [("MultiDict", "MultiDictProxy"), ("CIMultiDict", "CIMultiDictProxy")],
- indirect=True,
-)
-def test_proxy_copy(classes: _ClsPair) -> None:
- dict_cls, proxy_cls = classes
- d1 = dict_cls(key="value", a="b")
- p1 = proxy_cls(d1)
+def test_proxy_copy(
+ any_multidict_class: Type[MutableMultiMapping[str]],
+ any_multidict_proxy_class: Type[MultiMapping[str]],
+) -> None:
+ d1 = any_multidict_class(key="value", a="b")
+ p1 = any_multidict_proxy_class(d1)
- d2 = p1.copy()
+ d2 = p1.copy() # type: ignore[attr-defined]
assert d1 == d2
assert d1 is not d2
-@pytest.mark.parametrize(
- "cls",
- ["MultiDict", "CIMultiDict", "MultiDictProxy", "CIMultiDictProxy"],
- indirect=True,
-)
-def test_subclassing(cls: Any) -> None:
- class MyClass(cls): # type: ignore[valid-type,misc]
+def test_multidict_subclassing(
+ any_multidict_class: Type[MutableMultiMapping[str]],
+) -> None:
+ class DummyMultidict(any_multidict_class): # type: ignore[valid-type,misc]
+ pass
+
+
+def test_multidict_proxy_subclassing(
+ any_multidict_proxy_class: Type[MultiMapping[str]],
+) -> None:
+ class DummyMultidictProxy(
+ any_multidict_proxy_class, # type: ignore[valid-type,misc]
+ ):
pass
class BaseMultiDictTest:
- def test_instantiate__empty(self, cls: _MultiDictClasses) -> None:
+ def test_instantiate__empty(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls()
empty: Mapping[str, str] = {}
assert d == empty
@@ -126,12 +134,12 @@ class BaseMultiDictTest:
assert cls() != list() # type: ignore[comparison-overlap]
with pytest.raises(TypeError, match=r"(2 given)"):
- cls(("key1", "value1"), ("key2", "value2")) # type: ignore[arg-type,call-arg] # noqa: E501
+ cls(("key1", "value1"), ("key2", "value2")) # type: ignore[call-arg] # noqa: E501
- @pytest.mark.parametrize("arg0", [[("key", "value1")], {"key": "value1"}])
+ @pytest.mark.parametrize("arg0", ([("key", "value1")], {"key": "value1"}))
def test_instantiate__from_arg0(
self,
- cls: _MultiDictClasses,
+ cls: Type[MutableMultiMapping[str]],
arg0: Union[List[Tuple[str, str]], Dict[str, str]],
) -> None:
d = cls(arg0)
@@ -142,7 +150,10 @@ class BaseMultiDictTest:
assert list(d.values()) == ["value1"]
assert list(d.items()) == [("key", "value1")]
- def test_instantiate__with_kwargs(self, cls: _MultiDictClasses) -> None:
+ def test_instantiate__with_kwargs(
+ self,
+ cls: Type[MutableMultiMapping[str]],
+ ) -> None:
d = cls([("key", "value1")], key2="value2")
assert d == {"key": "value1", "key2": "value2"}
@@ -162,31 +173,30 @@ class BaseMultiDictTest:
assert sorted(d.values()) == [0, 1]
assert sorted(d.items()) == [("0", 0), ("1", 1)]
- def test_instantiate__from_list_of_lists(self, cls: _MultiDictClasses) -> None:
+ def test_instantiate__from_list_of_lists(
+ self,
+ cls: Type[MutableMultiMapping[str]],
+ ) -> None:
# Should work at runtime, but won't type check.
- d = cls([["key", "value1"]]) # type: ignore[list-item]
+ d = cls([["key", "value1"]]) # type: ignore[call-arg]
assert d == {"key": "value1"}
def test_instantiate__from_list_of_custom_pairs(
- self, cls: _MultiDictClasses
+ self,
+ cls: Type[MutableMultiMapping[str]],
) -> None:
class Pair:
def __len__(self) -> int:
return 2
def __getitem__(self, pos: int) -> str:
- if pos == 0:
- return "key"
- elif pos == 1:
- return "value1"
- else:
- raise IndexError
+ return ("key", "value1")[pos]
# Works at runtime, but won't type check.
- d = cls([Pair()]) # type: ignore[list-item]
+ d = cls([Pair()])
assert d == {"key": "value1"}
- def test_getone(self, cls: _MultiDictClasses) -> None:
+ def test_getone(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")], key="value2")
assert d.getone("key") == "value1"
@@ -199,18 +209,27 @@ class BaseMultiDictTest:
d.getone("key2")
assert d.getone("key2", "default") == "default"
- assert d.getone(key="key2", default="default") == "default"
+
+ def test_call_with_kwargs(self, cls: Type[MultiDict[str]]) -> None:
+ d = cls([("present", "value")])
+ assert d.getall(default="missing", key="notfound") == "missing"
def test__iter__(
self,
- cls: Union[Type[MultiDict[Union[str, int]]], Type[CIMultiDict[Union[str, int]]]]
+ cls: Union[
+ Type[MultiDict[Union[str, int]]],
+ Type[CIMultiDict[Union[str, int]]],
+ ],
) -> None:
d = cls([("key", "one"), ("key2", "two"), ("key", 3)])
assert list(d) == ["key", "key2", "key"]
def test_keys__contains(
self,
- cls: Union[Type[MultiDict[Union[str, int]]], Type[CIMultiDict[Union[str, int]]]]
+ cls: Union[
+ Type[MultiDict[Union[str, int]]],
+ Type[CIMultiDict[Union[str, int]]],
+ ],
) -> None:
d = cls([("key", "one"), ("key2", "two"), ("key", 3)])
@@ -223,7 +242,10 @@ class BaseMultiDictTest:
def test_values__contains(
self,
- cls: Union[Type[MultiDict[Union[str, int]]], Type[CIMultiDict[Union[str, int]]]]
+ cls: Union[
+ Type[MultiDict[Union[str, int]]],
+ Type[CIMultiDict[Union[str, int]]],
+ ],
) -> None:
d = cls([("key", "one"), ("key", "two"), ("key", 3)])
@@ -237,7 +259,10 @@ class BaseMultiDictTest:
def test_items__contains(
self,
- cls: Union[Type[MultiDict[Union[str, int]]], Type[CIMultiDict[Union[str, int]]]]
+ cls: Union[
+ Type[MultiDict[Union[str, int]]],
+ Type[CIMultiDict[Union[str, int]]],
+ ],
) -> None:
d = cls([("key", "one"), ("key", "two"), ("key", 3)])
@@ -249,58 +274,67 @@ class BaseMultiDictTest:
assert ("foo", "bar") not in d.items()
- def test_cannot_create_from_unaccepted(self, cls: _MultiDictClasses) -> None:
+ def test_cannot_create_from_unaccepted(
+ self,
+ cls: Type[MutableMultiMapping[str]],
+ ) -> None:
with pytest.raises(TypeError):
- cls([(1, 2, 3)]) # type: ignore[list-item]
+ cls([(1, 2, 3)]) # type: ignore[call-arg]
- def test_keys_is_set_less(self, cls: _MultiDictClasses) -> None:
+ def test_keys_is_set_less(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")])
assert d.keys() < {"key", "key2"}
- def test_keys_is_set_less_equal(self, cls: _MultiDictClasses) -> None:
+ def test_keys_is_set_less_equal(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")])
assert d.keys() <= {"key"}
- def test_keys_is_set_equal(self, cls: _MultiDictClasses) -> None:
+ def test_keys_is_set_equal(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")])
assert d.keys() == {"key"}
- def test_keys_is_set_greater(self, cls: _MultiDictClasses) -> None:
+ def test_keys_is_set_greater(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")])
assert {"key", "key2"} > d.keys()
- def test_keys_is_set_greater_equal(self, cls: _MultiDictClasses) -> None:
+ def test_keys_is_set_greater_equal(
+ self,
+ cls: Type[MutableMultiMapping[str]],
+ ) -> None:
d = cls([("key", "value1")])
assert {"key"} >= d.keys()
- def test_keys_is_set_not_equal(self, cls: _MultiDictClasses) -> None:
+ def test_keys_is_set_not_equal(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")])
assert d.keys() != {"key2"}
- def test_eq(self, cls: _MultiDictClasses) -> None:
+ def test_eq(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")])
assert {"key": "value1"} == d
- def test_eq2(self, cls: _MultiDictClasses) -> None:
+ def test_eq2(self, cls: Type[MutableMultiMapping[str]]) -> None:
d1 = cls([("key", "value1")])
d2 = cls([("key2", "value1")])
assert d1 != d2
- def test_eq3(self, cls: _MultiDictClasses) -> None:
+ def test_eq3(self, cls: Type[MutableMultiMapping[str]]) -> None:
d1 = cls([("key", "value1")])
d2 = cls()
assert d1 != d2
- def test_eq_other_mapping_contains_more_keys(self, cls: _MultiDictClasses) -> None:
+ def test_eq_other_mapping_contains_more_keys(
+ self,
+ cls: Type[MutableMultiMapping[str]],
+ ) -> None:
d1 = cls(foo="bar")
d2 = dict(foo="bar", bar="baz")
@@ -311,10 +345,10 @@ class BaseMultiDictTest:
) -> None:
class BadMapping(Mapping[str, int]):
def __getitem__(self, key: str) -> int:
- return 1
+ return 1 # pragma: no cover # `len()` fails earlier
def __iter__(self) -> Iterator[str]:
- yield "a"
+ yield "a" # pragma: no cover # `len()` fails earlier
def __len__(self) -> int: # type: ignore[return]
1 / 0
@@ -326,14 +360,14 @@ class BaseMultiDictTest:
def test_eq_bad_mapping_getitem(
self,
- cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]]
+ cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]],
) -> None:
class BadMapping(Mapping[str, int]):
def __getitem__(self, key: str) -> int: # type: ignore[return]
1 / 0
def __iter__(self) -> Iterator[str]:
- yield "a"
+ yield "a" # pragma: no cover # foreign objects no iterated
def __len__(self) -> int:
return 1
@@ -343,60 +377,139 @@ class BaseMultiDictTest:
with pytest.raises(ZeroDivisionError):
d1 == d2
- def test_ne(self, cls: _MultiDictClasses) -> None:
+ def test_ne(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")])
assert d != {"key": "another_value"}
- def test_and(self, cls: _MultiDictClasses) -> None:
+ def test_and(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")])
assert {"key"} == d.keys() & {"key", "key2"}
- def test_and2(self, cls: _MultiDictClasses) -> None:
+ def test_and2(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")])
assert {"key"} == {"key", "key2"} & d.keys()
- def test_or(self, cls: _MultiDictClasses) -> None:
+ def test_bitwise_and_not_implemented(
+ self, cls: Type[MutableMultiMapping[str]]
+ ) -> None:
+ d = cls([("key", "value1")])
+
+ sentinel_operation_result = object()
+
+ class RightOperand:
+ def __rand__(self, other: KeysView[str]) -> object:
+ assert isinstance(other, KeysView)
+ return sentinel_operation_result
+
+ assert d.keys() & RightOperand() is sentinel_operation_result
+
+ def test_bitwise_and_iterable_not_set(
+ self, cls: Type[MutableMultiMapping[str]]
+ ) -> None:
+ d = cls([("key", "value1")])
+
+ assert {"key"} == d.keys() & ["key", "key2"]
+
+ def test_or(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")])
assert {"key", "key2"} == d.keys() | {"key2"}
- def test_or2(self, cls: _MultiDictClasses) -> None:
+ def test_or2(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1")])
assert {"key", "key2"} == {"key2"} | d.keys()
- def test_sub(self, cls: _MultiDictClasses) -> None:
+ def test_bitwise_or_not_implemented(
+ self, cls: Type[MutableMultiMapping[str]]
+ ) -> None:
+ d = cls([("key", "value1")])
+
+ sentinel_operation_result = object()
+
+ class RightOperand:
+ def __ror__(self, other: KeysView[str]) -> object:
+ assert isinstance(other, KeysView)
+ return sentinel_operation_result
+
+ assert d.keys() | RightOperand() is sentinel_operation_result
+
+ def test_bitwise_or_iterable_not_set(
+ self, cls: Type[MutableMultiMapping[str]]
+ ) -> None:
+ d = cls([("key", "value1")])
+
+ assert {"key", "key2"} == d.keys() | ["key2"]
+
+ def test_sub(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1"), ("key2", "value2")])
assert {"key"} == d.keys() - {"key2"}
- def test_sub2(self, cls: _MultiDictClasses) -> None:
+ def test_sub2(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1"), ("key2", "value2")])
assert {"key3"} == {"key", "key2", "key3"} - d.keys()
- def test_xor(self, cls: _MultiDictClasses) -> None:
+ def test_sub_not_implemented(self, cls: Type[MutableMultiMapping[str]]) -> None:
+ d = cls([("key", "value1"), ("key2", "value2")])
+
+ sentinel_operation_result = object()
+
+ class RightOperand:
+ def __rsub__(self, other: KeysView[str]) -> object:
+ assert isinstance(other, KeysView)
+ return sentinel_operation_result
+
+ assert d.keys() - RightOperand() is sentinel_operation_result
+
+ def test_sub_iterable_not_set(self, cls: Type[MutableMultiMapping[str]]) -> None:
+ d = cls([("key", "value1"), ("key2", "value2")])
+
+ assert {"key"} == d.keys() - ["key2"]
+
+ def test_xor(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1"), ("key2", "value2")])
assert {"key", "key3"} == d.keys() ^ {"key2", "key3"}
- def test_xor2(self, cls: _MultiDictClasses) -> None:
+ def test_xor2(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls([("key", "value1"), ("key2", "value2")])
assert {"key", "key3"} == {"key2", "key3"} ^ d.keys()
- @pytest.mark.parametrize("_set, expected", [({"key2"}, True), ({"key"}, False)])
+ def test_xor_not_implemented(self, cls: Type[MutableMultiMapping[str]]) -> None:
+ d = cls([("key", "value1"), ("key2", "value2")])
+
+ sentinel_operation_result = object()
+
+ class RightOperand:
+ def __rxor__(self, other: KeysView[str]) -> object:
+ assert isinstance(other, KeysView)
+ return sentinel_operation_result
+
+ assert d.keys() ^ RightOperand() is sentinel_operation_result
+
+ def test_xor_iterable_not_set(self, cls: Type[MutableMultiMapping[str]]) -> None:
+ d = cls([("key", "value1"), ("key2", "value2")])
+
+ assert {"key", "key3"} == d.keys() ^ ["key2", "key3"]
+
+ @pytest.mark.parametrize(
+ ("key", "value", "expected"),
+ (("key2", "v", True), ("key", "value1", False)),
+ )
def test_isdisjoint(
- self, cls: _MultiDictClasses, _set: Set[str], expected: bool
+ self, cls: Type[MutableMultiMapping[str]], key: str, value: str, expected: bool
) -> None:
d = cls([("key", "value1")])
+ assert d.items().isdisjoint({(key, value)}) is expected
+ assert d.keys().isdisjoint({key}) is expected
- assert d.keys().isdisjoint(_set) == expected
-
- def test_repr_issue_410(self, cls: _MultiDictClasses) -> None:
+ def test_repr_aiohttp_issue_410(self, cls: Type[MutableMultiMapping[str]]) -> None:
d = cls()
try:
@@ -405,15 +518,16 @@ class BaseMultiDictTest:
except Exception as e:
repr(d)
- assert sys.exc_info()[1] == e
+ assert sys.exc_info()[1] == e # noqa: PT017
@pytest.mark.parametrize(
- "op", [operator.or_, operator.and_, operator.sub, operator.xor]
+ "op",
+ (operator.or_, operator.and_, operator.sub, operator.xor),
)
- @pytest.mark.parametrize("other", [{"other"}])
- def test_op_issue_410(
+ @pytest.mark.parametrize("other", ({"other"},))
+ def test_op_issue_aiohttp_issue_410(
self,
- cls: _MultiDictClasses,
+ cls: Type[MutableMultiMapping[str]],
op: Callable[[object, object], object],
other: Set[str],
) -> None:
@@ -425,9 +539,9 @@ class BaseMultiDictTest:
except Exception as e:
op(d.keys(), other)
- assert sys.exc_info()[1] == e
+ assert sys.exc_info()[1] == e # noqa: PT017
- def test_weakref(self, cls: _MultiDictClasses) -> None:
+ def test_weakref(self, cls: Type[MutableMultiMapping[str]]) -> None:
called = False
def cb(wr: object) -> None:
@@ -443,7 +557,7 @@ class BaseMultiDictTest:
def test_iter_length_hint_keys(
self,
- cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]]
+ cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]],
) -> None:
md = cls(a=1, b=2)
it = iter(md.keys())
@@ -451,7 +565,7 @@ class BaseMultiDictTest:
def test_iter_length_hint_items(
self,
- cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]]
+ cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]],
) -> None:
md = cls(a=1, b=2)
it = iter(md.items())
@@ -459,7 +573,7 @@ class BaseMultiDictTest:
def test_iter_length_hint_values(
self,
- cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]]
+ cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]],
) -> None:
md = cls(a=1, b=2)
it = iter(md.values())
@@ -467,7 +581,7 @@ class BaseMultiDictTest:
def test_ctor_list_arg_and_kwds(
self,
- cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]]
+ cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]],
) -> None:
arg = [("a", 1)]
obj = cls(arg, b=2)
@@ -476,7 +590,7 @@ class BaseMultiDictTest:
def test_ctor_tuple_arg_and_kwds(
self,
- cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]]
+ cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]],
) -> None:
arg = (("a", 1),)
obj = cls(arg, b=2)
@@ -485,7 +599,7 @@ class BaseMultiDictTest:
def test_ctor_deque_arg_and_kwds(
self,
- cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]]
+ cls: Union[Type[MultiDict[int]], Type[CIMultiDict[int]]],
) -> None:
arg = deque([("a", 1)])
obj = cls(arg, b=2)
@@ -494,9 +608,19 @@ class BaseMultiDictTest:
class TestMultiDict(BaseMultiDictTest):
- @pytest.fixture(params=["MultiDict", ("MultiDict", "MultiDictProxy")])
- def cls(self, request: Any, _multidict: Any) -> Any:
- return chained_callable(_multidict, request.param)
+ @pytest.fixture(
+ params=[
+ ("MultiDict",),
+ ("MultiDict", "MultiDictProxy"),
+ ],
+ )
+ def cls( # type: ignore[misc]
+ self,
+ request: pytest.FixtureRequest,
+ multidict_module: ModuleType,
+ ) -> Callable[..., MultiMapping[int | str] | MutableMultiMapping[int | str]]:
+ """Make a case-sensitive multidict class/proxy constructor."""
+ return chained_callable(multidict_module, request.param)
def test__repr__(self, cls: Type[MultiDict[str]]) -> None:
d = cls()
@@ -523,7 +647,8 @@ class TestMultiDict(BaseMultiDictTest):
assert d.getall("some_key", default) is default
def test_preserve_stable_ordering(
- self, cls: Type[MultiDict[Union[str, int]]]
+ self,
+ cls: Type[MultiDict[Union[str, int]]],
) -> None:
d = cls([("a", 1), ("b", "2"), ("a", 3)])
s = "&".join("{}={}".format(k, v) for k, v in d.items())
@@ -533,8 +658,6 @@ class TestMultiDict(BaseMultiDictTest):
def test_get(self, cls: Type[MultiDict[int]]) -> None:
d = cls([("a", 1), ("a", 2)])
assert d["a"] == 1
- assert d.get("a") == 1
- assert d.get("z", 3) == 3
def test_items__repr__(self, cls: Type[MultiDict[str]]) -> None:
d = cls([("key", "value1")], key="value2")
@@ -551,9 +674,19 @@ class TestMultiDict(BaseMultiDictTest):
class TestCIMultiDict(BaseMultiDictTest):
- @pytest.fixture(params=["CIMultiDict", ("CIMultiDict", "CIMultiDictProxy")])
- def cls(self, request: Any, _multidict: Any) -> Any:
- return chained_callable(_multidict, request.param)
+ @pytest.fixture(
+ params=[
+ ("CIMultiDict",),
+ ("CIMultiDict", "CIMultiDictProxy"),
+ ],
+ )
+ def cls( # type: ignore[misc]
+ self,
+ request: pytest.FixtureRequest,
+ multidict_module: ModuleType,
+ ) -> Callable[..., MultiMapping[int | str] | MutableMultiMapping[int | str]]:
+ """Make a case-insensitive multidict class/proxy constructor."""
+ return chained_callable(multidict_module, request.param)
def test_basics(self, cls: Type[CIMultiDict[str]]) -> None:
d = cls([("KEY", "value1")], KEY="value2")
diff --git a/contrib/python/multidict/tests/test_mutable_multidict.py b/contrib/python/multidict/tests/test_mutable_multidict.py
index 3f66e279ad..3cacec25af 100644
--- a/contrib/python/multidict/tests/test_mutable_multidict.py
+++ b/contrib/python/multidict/tests/test_mutable_multidict.py
@@ -1,40 +1,43 @@
import string
import sys
+from typing import Type
import pytest
+from multidict import MultiMapping, MutableMultiMapping
-class TestMutableMultiDict:
- @pytest.fixture
- def cls(self, _multidict):
- return _multidict.MultiDict
-
- @pytest.fixture
- def proxy_cls(self, _multidict):
- return _multidict.MultiDictProxy
-
- @pytest.fixture
- def istr(self, _multidict):
- return _multidict.istr
- def test_copy(self, cls):
- d1 = cls(key="value", a="b")
+class TestMutableMultiDict:
+ def test_copy(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d1 = case_sensitive_multidict_class(key="value", a="b")
d2 = d1.copy()
assert d1 == d2
assert d1 is not d2
- def test__repr__(self, cls):
- d = cls()
- assert str(d) == "<%s()>" % cls.__name__
+ def test__repr__(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
+ assert str(d) == "<%s()>" % case_sensitive_multidict_class.__name__
- d = cls([("key", "one"), ("key", "two")])
+ d = case_sensitive_multidict_class([("key", "one"), ("key", "two")])
- expected = "<%s('key': 'one', 'key': 'two')>" % cls.__name__
+ expected = (
+ f"<{case_sensitive_multidict_class.__name__}"
+ "('key': 'one', 'key': 'two')>"
+ )
assert str(d) == expected
- def test_getall(self, cls):
- d = cls([("key", "value1")], key="value2")
+ def test_getall(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class([("key", "value1")], key="value2")
assert len(d) == 2
assert d.getall("key") == ["value1", "value2"]
@@ -44,10 +47,12 @@ class TestMutableMultiDict:
default = object()
assert d.getall("some_key", default) is default
- assert d.getall(key="some_key", default=default) is default
- def test_add(self, cls):
- d = cls()
+ def test_add(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
assert d == {}
d["key"] = "one"
@@ -66,8 +71,11 @@ class TestMutableMultiDict:
assert 3 == len(d)
assert d.getall("foo") == ["bar"]
- def test_extend(self, cls):
- d = cls()
+ def test_extend(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
assert d == {}
d.extend([("key", "one"), ("key", "two")], key=3, foo="bar")
@@ -80,7 +88,7 @@ class TestMutableMultiDict:
assert ("key", 3) in itms
assert ("foo", "bar") in itms
- other = cls(bar="baz")
+ other = case_sensitive_multidict_class(bar="baz")
assert other == {"bar": "baz"}
d.extend(other)
@@ -95,24 +103,34 @@ class TestMutableMultiDict:
with pytest.raises(TypeError):
d.extend("foo", "bar")
- def test_extend_from_proxy(self, cls, proxy_cls):
- d = cls([("a", "a"), ("b", "b")])
- proxy = proxy_cls(d)
+ def test_extend_from_proxy(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ case_sensitive_multidict_proxy_class: Type[MultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class([("a", "a"), ("b", "b")])
+ proxy = case_sensitive_multidict_proxy_class(d)
- d2 = cls()
+ d2 = case_sensitive_multidict_class()
d2.extend(proxy)
assert [("a", "a"), ("b", "b")] == list(d2.items())
- def test_clear(self, cls):
- d = cls([("key", "one")], key="two", foo="bar")
+ def test_clear(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class([("key", "one")], key="two", foo="bar")
d.clear()
assert d == {}
assert list(d.items()) == []
- def test_del(self, cls):
- d = cls([("key", "one"), ("key", "two")], foo="bar")
+ def test_del(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class([("key", "one"), ("key", "two")], foo="bar")
assert list(d.keys()) == ["key", "key", "foo"]
del d["key"]
@@ -122,37 +140,52 @@ class TestMutableMultiDict:
with pytest.raises(KeyError, match="key"):
del d["key"]
- def test_set_default(self, cls):
- d = cls([("key", "one"), ("key", "two")], foo="bar")
+ def test_set_default(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class([("key", "one"), ("key", "two")], foo="bar")
assert "one" == d.setdefault("key", "three")
- assert "three" == d.setdefault(key="otherkey", default="three")
+ assert "three" == d.setdefault("otherkey", "three")
assert "otherkey" in d
assert "three" == d["otherkey"]
- def test_popitem(self, cls):
- d = cls()
+ def test_popitem(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
d.add("key", "val1")
d.add("key", "val2")
assert ("key", "val1") == d.popitem()
assert [("key", "val2")] == list(d.items())
- def test_popitem_empty_multidict(self, cls):
- d = cls()
+ def test_popitem_empty_multidict(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
with pytest.raises(KeyError):
d.popitem()
- def test_pop(self, cls):
- d = cls()
+ def test_pop(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
d.add("key", "val1")
d.add("key", "val2")
assert "val1" == d.pop("key")
assert {"key": "val2"} == d
- def test_pop2(self, cls):
- d = cls()
+ def test_pop2(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
d.add("key", "val1")
d.add("key2", "val2")
d.add("key", "val3")
@@ -160,23 +193,31 @@ class TestMutableMultiDict:
assert "val1" == d.pop("key")
assert [("key2", "val2"), ("key", "val3")] == list(d.items())
- def test_pop_default(self, cls):
- d = cls(other="val")
+ def test_pop_default(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class(other="val")
assert "default" == d.pop("key", "default")
- assert "default" == d.pop(key="key", default="default")
assert "other" in d
- def test_pop_raises(self, cls):
- d = cls(other="val")
+ def test_pop_raises(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class(other="val")
with pytest.raises(KeyError, match="key"):
d.pop("key")
assert "other" in d
- def test_replacement_order(self, cls):
- d = cls()
+ def test_replacement_order(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
d.add("key1", "val1")
d.add("key2", "val2")
d.add("key1", "val3")
@@ -188,39 +229,59 @@ class TestMutableMultiDict:
assert expected == list(d.items())
- def test_nonstr_key(self, cls):
- d = cls()
+ def test_nonstr_key(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
with pytest.raises(TypeError):
d[1] = "val"
- def test_istr_key(self, cls, istr):
- d = cls()
- d[istr("1")] = "val"
- assert type(list(d.keys())[0]) is istr
-
- def test_str_derived_key(self, cls):
+ def test_istr_key(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ case_insensitive_str_class: Type[str],
+ ) -> None:
+ d = case_sensitive_multidict_class()
+ d[case_insensitive_str_class("1")] = "val"
+ assert type(list(d.keys())[0]) is case_insensitive_str_class
+
+ def test_str_derived_key(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
class A(str):
pass
- d = cls()
+ d = case_sensitive_multidict_class()
d[A("1")] = "val"
assert type(list(d.keys())[0]) is A
- def test_istr_key_add(self, cls, istr):
- d = cls()
- d.add(istr("1"), "val")
- assert type(list(d.keys())[0]) is istr
-
- def test_str_derived_key_add(self, cls):
+ def test_istr_key_add(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ case_insensitive_str_class: Type[str],
+ ) -> None:
+ d = case_sensitive_multidict_class()
+ d.add(case_insensitive_str_class("1"), "val")
+ assert type(list(d.keys())[0]) is case_insensitive_str_class
+
+ def test_str_derived_key_add(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
class A(str):
pass
- d = cls()
+ d = case_sensitive_multidict_class()
d.add(A("1"), "val")
assert type(list(d.keys())[0]) is A
- def test_popall(self, cls):
- d = cls()
+ def test_popall(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
d.add("key1", "val1")
d.add("key2", "val2")
d.add("key1", "val3")
@@ -228,19 +289,27 @@ class TestMutableMultiDict:
assert ["val1", "val3"] == ret
assert {"key2": "val2"} == d
- def test_popall_default(self, cls):
- d = cls()
+ def test_popall_default(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
assert "val" == d.popall("key", "val")
- assert "val" == d.popall(key="key", default="val")
- def test_popall_key_error(self, cls):
- d = cls()
+ def test_popall_key_error(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_sensitive_multidict_class()
with pytest.raises(KeyError, match="key"):
d.popall("key")
- def test_large_multidict_resizing(self, cls):
+ def test_large_multidict_resizing(
+ self,
+ case_sensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
SIZE = 1024
- d = cls()
+ d = case_sensitive_multidict_class()
for i in range(SIZE):
d["key" + str(i)] = i
@@ -251,20 +320,11 @@ class TestMutableMultiDict:
class TestCIMutableMultiDict:
- @pytest.fixture
- def cls(self, _multidict):
- return _multidict.CIMultiDict
-
- @pytest.fixture
- def proxy_cls(self, _multidict):
- return _multidict.CIMultiDictProxy
-
- @pytest.fixture
- def istr(self, _multidict):
- return _multidict.istr
-
- def test_getall(self, cls):
- d = cls([("KEY", "value1")], KEY="value2")
+ def test_getall(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class([("KEY", "value1")], KEY="value2")
assert d != {"KEY": "value1"}
assert len(d) == 2
@@ -274,53 +334,74 @@ class TestCIMutableMultiDict:
with pytest.raises(KeyError, match="some_key"):
d.getall("some_key")
- def test_ctor(self, cls):
- d = cls(k1="v1")
+ def test_ctor(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class(k1="v1")
assert "v1" == d["K1"]
assert ("k1", "v1") in d.items()
- def test_setitem(self, cls):
- d = cls()
+ def test_setitem(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class()
d["k1"] = "v1"
assert "v1" == d["K1"]
assert ("k1", "v1") in d.items()
- def test_delitem(self, cls):
- d = cls()
+ def test_delitem(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class()
d["k1"] = "v1"
assert "K1" in d
del d["k1"]
assert "K1" not in d
- def test_copy(self, cls):
- d1 = cls(key="KEY", a="b")
+ def test_copy(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d1 = case_insensitive_multidict_class(key="KEY", a="b")
d2 = d1.copy()
assert d1 == d2
assert d1.items() == d2.items()
assert d1 is not d2
- def test__repr__(self, cls):
- d = cls()
- assert str(d) == "<%s()>" % cls.__name__
+ def test__repr__(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class()
+ assert str(d) == "<%s()>" % case_insensitive_multidict_class.__name__
- d = cls([("KEY", "one"), ("KEY", "two")])
+ d = case_insensitive_multidict_class([("KEY", "one"), ("KEY", "two")])
- expected = "<%s('KEY': 'one', 'KEY': 'two')>" % cls.__name__
+ expected = (
+ f"<{case_insensitive_multidict_class.__name__}"
+ "('KEY': 'one', 'KEY': 'two')>"
+ )
assert str(d) == expected
- def test_add(self, cls):
- d = cls()
+ def test_add(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class()
assert d == {}
d["KEY"] = "one"
assert ("KEY", "one") in d.items()
- assert d == cls({"Key": "one"})
+ assert d == case_insensitive_multidict_class({"Key": "one"})
assert d.getall("key") == ["one"]
d["KEY"] = "two"
assert ("KEY", "two") in d.items()
- assert d == cls({"Key": "two"})
+ assert d == case_insensitive_multidict_class({"Key": "two"})
assert d.getall("key") == ["two"]
d.add("KEY", "one")
@@ -338,8 +419,11 @@ class TestCIMutableMultiDict:
assert 4 == len(d)
assert d.getall("test") == ["test"]
- def test_extend(self, cls):
- d = cls()
+ def test_extend(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class()
assert d == {}
d.extend([("KEY", "one"), ("key", "two")], key=3, foo="bar")
@@ -351,7 +435,7 @@ class TestCIMutableMultiDict:
assert ("key", 3) in itms
assert ("foo", "bar") in itms
- other = cls(Bar="baz")
+ other = case_insensitive_multidict_class(Bar="baz")
assert other == {"Bar": "baz"}
d.extend(other)
@@ -368,24 +452,37 @@ class TestCIMutableMultiDict:
with pytest.raises(TypeError):
d.extend("foo", "bar")
- def test_extend_from_proxy(self, cls, proxy_cls):
- d = cls([("a", "a"), ("b", "b")])
- proxy = proxy_cls(d)
+ def test_extend_from_proxy(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ case_insensitive_multidict_proxy_class: Type[MultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class([("a", "a"), ("b", "b")])
+ proxy = case_insensitive_multidict_proxy_class(d)
- d2 = cls()
+ d2 = case_insensitive_multidict_class()
d2.extend(proxy)
assert [("a", "a"), ("b", "b")] == list(d2.items())
- def test_clear(self, cls):
- d = cls([("KEY", "one")], key="two", foo="bar")
+ def test_clear(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class([("KEY", "one")], key="two", foo="bar")
d.clear()
assert d == {}
assert list(d.items()) == []
- def test_del(self, cls):
- d = cls([("KEY", "one"), ("key", "two")], foo="bar")
+ def test_del(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class(
+ [("KEY", "one"), ("key", "two")],
+ foo="bar",
+ )
del d["key"]
assert d == {"foo": "bar"}
@@ -394,16 +491,25 @@ class TestCIMutableMultiDict:
with pytest.raises(KeyError, match="key"):
del d["key"]
- def test_set_default(self, cls):
- d = cls([("KEY", "one"), ("key", "two")], foo="bar")
+ def test_set_default(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class(
+ [("KEY", "one"), ("key", "two")],
+ foo="bar",
+ )
assert "one" == d.setdefault("key", "three")
assert "three" == d.setdefault("otherkey", "three")
assert "otherkey" in d
assert ("otherkey", "three") in d.items()
assert "three" == d["OTHERKEY"]
- def test_popitem(self, cls):
- d = cls()
+ def test_popitem(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class()
d.add("KEY", "val1")
d.add("key", "val2")
@@ -412,57 +518,83 @@ class TestCIMutableMultiDict:
assert isinstance(pair[0], str)
assert [("key", "val2")] == list(d.items())
- def test_popitem_empty_multidict(self, cls):
- d = cls()
+ def test_popitem_empty_multidict(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class()
with pytest.raises(KeyError):
d.popitem()
- def test_pop(self, cls):
- d = cls()
+ def test_pop(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class()
d.add("KEY", "val1")
d.add("key", "val2")
assert "val1" == d.pop("KEY")
assert {"key": "val2"} == d
- def test_pop_lowercase(self, cls):
- d = cls()
+ def test_pop_lowercase(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class()
d.add("KEY", "val1")
d.add("key", "val2")
assert "val1" == d.pop("key")
assert {"key": "val2"} == d
- def test_pop_default(self, cls):
- d = cls(OTHER="val")
+ def test_pop_default(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class(OTHER="val")
assert "default" == d.pop("key", "default")
assert "other" in d
- def test_pop_raises(self, cls):
- d = cls(OTHER="val")
+ def test_pop_raises(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d = case_insensitive_multidict_class(OTHER="val")
with pytest.raises(KeyError, match="KEY"):
d.pop("KEY")
assert "other" in d
- def test_extend_with_istr(self, cls, istr):
- us = istr("aBc")
- d = cls()
+ def test_extend_with_istr(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ case_insensitive_str_class: Type[str],
+ ) -> None:
+ us = case_insensitive_str_class("aBc")
+ d = case_insensitive_multidict_class()
d.extend([(us, "val")])
assert [("aBc", "val")] == list(d.items())
- def test_copy_istr(self, cls, istr):
- d = cls({istr("Foo"): "bar"})
+ def test_copy_istr(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ case_insensitive_str_class: Type[str],
+ ) -> None:
+ d = case_insensitive_multidict_class({case_insensitive_str_class("Foo"): "bar"})
d2 = d.copy()
assert d == d2
- def test_eq(self, cls):
- d1 = cls(Key="val")
- d2 = cls(KEY="val")
+ def test_eq(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ d1 = case_insensitive_multidict_class(Key="val")
+ d2 = case_insensitive_multidict_class(KEY="val")
assert d1 == d2
@@ -470,8 +602,11 @@ class TestCIMutableMultiDict:
sys.implementation.name == "pypy",
reason="getsizeof() is not implemented on PyPy",
)
- def test_sizeof(self, cls):
- md = cls()
+ def test_sizeof(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ md = case_insensitive_multidict_class()
s1 = sys.getsizeof(md)
for i in string.ascii_lowercase:
for j in string.ascii_uppercase:
@@ -484,29 +619,41 @@ class TestCIMutableMultiDict:
sys.implementation.name == "pypy",
reason="getsizeof() is not implemented on PyPy",
)
- def test_min_sizeof(self, cls):
- md = cls()
+ def test_min_sizeof(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
+ md = case_insensitive_multidict_class()
assert sys.getsizeof(md) < 1024
- def test_issue_620_items(self, cls):
+ def test_issue_620_items(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
# https://github.com/aio-libs/multidict/issues/620
- d = cls({"a": "123, 456", "b": "789"})
+ d = case_insensitive_multidict_class({"a": "123, 456", "b": "789"})
before_mutation_items = d.items()
d["c"] = "000"
# This causes an error on pypy.
list(before_mutation_items)
- def test_issue_620_keys(self, cls):
+ def test_issue_620_keys(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
# https://github.com/aio-libs/multidict/issues/620
- d = cls({"a": "123, 456", "b": "789"})
+ d = case_insensitive_multidict_class({"a": "123, 456", "b": "789"})
before_mutation_keys = d.keys()
d["c"] = "000"
# This causes an error on pypy.
list(before_mutation_keys)
- def test_issue_620_values(self, cls):
+ def test_issue_620_values(
+ self,
+ case_insensitive_multidict_class: Type[MutableMultiMapping[str]],
+ ) -> None:
# https://github.com/aio-libs/multidict/issues/620
- d = cls({"a": "123, 456", "b": "789"})
+ d = case_insensitive_multidict_class({"a": "123, 456", "b": "789"})
before_mutation_values = d.values()
d["c"] = "000"
# This causes an error on pypy.
diff --git a/contrib/python/multidict/tests/test_mypy.py b/contrib/python/multidict/tests/test_mypy.py
index 62bb62e52d..38751fdb9b 100644
--- a/contrib/python/multidict/tests/test_mypy.py
+++ b/contrib/python/multidict/tests/test_mypy.py
@@ -194,6 +194,7 @@ def test_setitem() -> None:
d1[key] = "b"
d2[key] = "b"
+
def test_delitem() -> None:
d1: multidict.MultiDict[str] = multidict.MultiDict({"a": "b"})
d2: multidict.CIMultiDict[str] = multidict.CIMultiDict({"a": "b"})
@@ -248,6 +249,7 @@ def test_update_mapping() -> None:
d1.update({key: "b"})
d2.update({key: "b"})
+
def test_popone() -> None:
d1: multidict.MultiDict[str] = multidict.MultiDict({"a": "b"})
d2: multidict.CIMultiDict[str] = multidict.CIMultiDict({"a": "b"})
diff --git a/contrib/python/multidict/tests/test_pickle.py b/contrib/python/multidict/tests/test_pickle.py
index ce7383684f..48adea13f0 100644
--- a/contrib/python/multidict/tests/test_pickle.py
+++ b/contrib/python/multidict/tests/test_pickle.py
@@ -3,80 +3,37 @@ from pathlib import Path
import pytest
-from multidict._compat import USE_EXTENSIONS
-from multidict._multidict_py import CIMultiDict as PyCIMultiDict
-from multidict._multidict_py import CIMultiDictProxy as PyCIMultiDictProxy
-from multidict._multidict_py import MultiDict as PyMultiDict # noqa: E402
-from multidict._multidict_py import MultiDictProxy as PyMultiDictProxy
+import yatest.common as yc
+here = Path(yc.source_path(__file__)).resolve().parent
-import yatest.common
-if USE_EXTENSIONS:
- from multidict._multidict import ( # type: ignore
- CIMultiDict,
- CIMultiDictProxy,
- MultiDict,
- MultiDictProxy,
- )
-
-
-here = Path(yatest.common.test_source_path()).resolve()
-
-
-@pytest.fixture(
- params=(["MultiDict", "CIMultiDict"] if USE_EXTENSIONS else [])
- + ["PyMultiDict", "PyCIMultiDict"]
-)
-def cls_name(request):
- return request.param
-
-
-@pytest.fixture(
- params=([MultiDict, CIMultiDict] if USE_EXTENSIONS else [])
- + [PyMultiDict, PyCIMultiDict],
- ids=(["MultiDict", "CIMultiDict"] if USE_EXTENSIONS else [])
- + ["PyMultiDict", "PyCIMultiDict"],
-)
-def cls(request):
- return request.param
-
-
-@pytest.fixture(
- params=(
- [(MultiDictProxy, MultiDict), (CIMultiDictProxy, CIMultiDict)]
- if USE_EXTENSIONS
- else []
- )
- + [(PyMultiDictProxy, PyMultiDict), (PyCIMultiDictProxy, PyCIMultiDict)],
- ids=(["MultiDictProxy", "CIMultiDictProxy"] if USE_EXTENSIONS else [])
- + ["PyMultiDictProxy", "PyCIMultiDictProxy"],
-)
-def proxy_classes(request):
- return request.param
-
-
-def test_pickle(cls, pickle_protocol):
- d = cls([("a", 1), ("a", 2)])
+def test_pickle(any_multidict_class, pickle_protocol):
+ d = any_multidict_class([("a", 1), ("a", 2)])
pbytes = pickle.dumps(d, pickle_protocol)
obj = pickle.loads(pbytes)
assert d == obj
- assert isinstance(obj, cls)
+ assert isinstance(obj, any_multidict_class)
-def test_pickle_proxy(proxy_classes):
- proxy_cls, dict_cls = proxy_classes
- d = dict_cls([("a", 1), ("a", 2)])
- proxy = proxy_cls(d)
+def test_pickle_proxy(any_multidict_class, any_multidict_proxy_class):
+ d = any_multidict_class([("a", 1), ("a", 2)])
+ proxy = any_multidict_proxy_class(d)
with pytest.raises(TypeError):
pickle.dumps(proxy)
-def test_load_from_file(pickle_protocol, cls_name):
- cls = globals()[cls_name]
- d = cls([("a", 1), ("a", 2)])
- fname = "{}.pickle.{}".format(cls_name.lower(), pickle_protocol)
+def test_load_from_file(any_multidict_class, multidict_implementation, pickle_protocol):
+ multidict_class_name = any_multidict_class.__name__
+ pickle_file_basename = "-".join(
+ (
+ multidict_class_name.lower(),
+ multidict_implementation.tag,
+ )
+ )
+ d = any_multidict_class([("a", 1), ("a", 2)])
+ fname = f"{pickle_file_basename}.pickle.{pickle_protocol}"
p = here / fname
with p.open("rb") as f:
obj = pickle.load(f)
assert d == obj
- assert isinstance(obj, cls)
+ assert isinstance(obj, any_multidict_class)
diff --git a/contrib/python/multidict/tests/test_types.py b/contrib/python/multidict/tests/test_types.py
index 3ae2cbb844..ceaa391e37 100644
--- a/contrib/python/multidict/tests/test_types.py
+++ b/contrib/python/multidict/tests/test_types.py
@@ -4,62 +4,65 @@ import types
import pytest
-def test_proxies(_multidict):
- assert issubclass(_multidict.CIMultiDictProxy, _multidict.MultiDictProxy)
+def test_proxies(multidict_module):
+ assert issubclass(
+ multidict_module.CIMultiDictProxy,
+ multidict_module.MultiDictProxy,
+ )
-def test_dicts(_multidict):
- assert issubclass(_multidict.CIMultiDict, _multidict.MultiDict)
+def test_dicts(multidict_module):
+ assert issubclass(multidict_module.CIMultiDict, multidict_module.MultiDict)
-def test_proxy_not_inherited_from_dict(_multidict):
- assert not issubclass(_multidict.MultiDictProxy, _multidict.MultiDict)
+def test_proxy_not_inherited_from_dict(multidict_module):
+ assert not issubclass(multidict_module.MultiDictProxy, multidict_module.MultiDict)
-def test_dict_not_inherited_from_proxy(_multidict):
- assert not issubclass(_multidict.MultiDict, _multidict.MultiDictProxy)
+def test_dict_not_inherited_from_proxy(multidict_module):
+ assert not issubclass(multidict_module.MultiDict, multidict_module.MultiDictProxy)
-def test_multidict_proxy_copy_type(_multidict):
- d = _multidict.MultiDict(key="val")
- p = _multidict.MultiDictProxy(d)
- assert isinstance(p.copy(), _multidict.MultiDict)
+def test_multidict_proxy_copy_type(multidict_module):
+ d = multidict_module.MultiDict(key="val")
+ p = multidict_module.MultiDictProxy(d)
+ assert isinstance(p.copy(), multidict_module.MultiDict)
-def test_cimultidict_proxy_copy_type(_multidict):
- d = _multidict.CIMultiDict(key="val")
- p = _multidict.CIMultiDictProxy(d)
- assert isinstance(p.copy(), _multidict.CIMultiDict)
+def test_cimultidict_proxy_copy_type(multidict_module):
+ d = multidict_module.CIMultiDict(key="val")
+ p = multidict_module.CIMultiDictProxy(d)
+ assert isinstance(p.copy(), multidict_module.CIMultiDict)
-def test_create_multidict_proxy_from_nonmultidict(_multidict):
+def test_create_multidict_proxy_from_nonmultidict(multidict_module):
with pytest.raises(TypeError):
- _multidict.MultiDictProxy({})
+ multidict_module.MultiDictProxy({})
-def test_create_multidict_proxy_from_cimultidict(_multidict):
- d = _multidict.CIMultiDict(key="val")
- p = _multidict.MultiDictProxy(d)
+def test_create_multidict_proxy_from_cimultidict(multidict_module):
+ d = multidict_module.CIMultiDict(key="val")
+ p = multidict_module.MultiDictProxy(d)
assert p == d
-def test_create_multidict_proxy_from_multidict_proxy_from_mdict(_multidict):
- d = _multidict.MultiDict(key="val")
- p = _multidict.MultiDictProxy(d)
+def test_create_multidict_proxy_from_multidict_proxy_from_mdict(multidict_module):
+ d = multidict_module.MultiDict(key="val")
+ p = multidict_module.MultiDictProxy(d)
assert p == d
- p2 = _multidict.MultiDictProxy(p)
+ p2 = multidict_module.MultiDictProxy(p)
assert p2 == p
-def test_create_cimultidict_proxy_from_cimultidict_proxy_from_ci(_multidict):
- d = _multidict.CIMultiDict(key="val")
- p = _multidict.CIMultiDictProxy(d)
+def test_create_cimultidict_proxy_from_cimultidict_proxy_from_ci(multidict_module):
+ d = multidict_module.CIMultiDict(key="val")
+ p = multidict_module.CIMultiDictProxy(d)
assert p == d
- p2 = _multidict.CIMultiDictProxy(p)
+ p2 = multidict_module.CIMultiDictProxy(p)
assert p2 == p
-def test_create_cimultidict_proxy_from_nonmultidict(_multidict):
+def test_create_cimultidict_proxy_from_nonmultidict(multidict_module):
with pytest.raises(
TypeError,
match=(
@@ -67,11 +70,11 @@ def test_create_cimultidict_proxy_from_nonmultidict(_multidict):
"not <class 'dict'>"
),
):
- _multidict.CIMultiDictProxy({})
+ multidict_module.CIMultiDictProxy({})
-def test_create_ci_multidict_proxy_from_multidict(_multidict):
- d = _multidict.MultiDict(key="val")
+def test_create_ci_multidict_proxy_from_multidict(multidict_module):
+ d = multidict_module.MultiDict(key="val")
with pytest.raises(
TypeError,
match=(
@@ -79,31 +82,32 @@ def test_create_ci_multidict_proxy_from_multidict(_multidict):
"not <class 'multidict._multidict.*.MultiDict'>"
),
):
- _multidict.CIMultiDictProxy(d)
+ multidict_module.CIMultiDictProxy(d)
@pytest.mark.skipif(
sys.version_info >= (3, 9), reason="Python 3.9 uses GenericAlias which is different"
)
-def test_generic_exists(_multidict) -> None:
- assert _multidict.MultiDict[int] is _multidict.MultiDict
- assert _multidict.MultiDictProxy[int] is _multidict.MultiDictProxy
- assert _multidict.CIMultiDict[int] is _multidict.CIMultiDict
- assert _multidict.CIMultiDictProxy[int] is _multidict.CIMultiDictProxy
+def test_generic_exists(multidict_module) -> None:
+ assert multidict_module.MultiDict[int] is multidict_module.MultiDict
+ assert multidict_module.MultiDictProxy[int] is multidict_module.MultiDictProxy
+ assert multidict_module.CIMultiDict[int] is multidict_module.CIMultiDict
+ assert multidict_module.CIMultiDictProxy[int] is multidict_module.CIMultiDictProxy
@pytest.mark.skipif(
sys.version_info < (3, 9), reason="Python 3.9 is required for GenericAlias"
)
-def test_generic_alias(_multidict) -> None:
-
- assert _multidict.MultiDict[int] == types.GenericAlias(_multidict.MultiDict, (int,))
- assert _multidict.MultiDictProxy[int] == types.GenericAlias(
- _multidict.MultiDictProxy, (int,)
+def test_generic_alias(multidict_module) -> None:
+ assert multidict_module.MultiDict[int] == types.GenericAlias(
+ multidict_module.MultiDict, (int,)
+ )
+ assert multidict_module.MultiDictProxy[int] == types.GenericAlias(
+ multidict_module.MultiDictProxy, (int,)
)
- assert _multidict.CIMultiDict[int] == types.GenericAlias(
- _multidict.CIMultiDict, (int,)
+ assert multidict_module.CIMultiDict[int] == types.GenericAlias(
+ multidict_module.CIMultiDict, (int,)
)
- assert _multidict.CIMultiDictProxy[int] == types.GenericAlias(
- _multidict.CIMultiDictProxy, (int,)
+ assert multidict_module.CIMultiDictProxy[int] == types.GenericAlias(
+ multidict_module.CIMultiDictProxy, (int,)
)
diff --git a/contrib/python/multidict/tests/test_update.py b/contrib/python/multidict/tests/test_update.py
index 4bacdbce77..f455327857 100644
--- a/contrib/python/multidict/tests/test_update.py
+++ b/contrib/python/multidict/tests/test_update.py
@@ -1,97 +1,68 @@
from collections import deque
+from typing import Type
-import pytest
+from multidict import MultiMapping
-from multidict._compat import USE_EXTENSIONS
-from multidict._multidict_py import CIMultiDict as PyCIMultiDict
-from multidict._multidict_py import MultiDict as PyMultiDict # noqa: E402
-if USE_EXTENSIONS:
- from multidict._multidict import CIMultiDict, MultiDict # type: ignore
-
-
-@pytest.fixture(
- params=([MultiDict, CIMultiDict] if USE_EXTENSIONS else [])
- + [PyMultiDict, PyCIMultiDict],
- ids=(["MultiDict", "CIMultiDict"] if USE_EXTENSIONS else [])
- + ["PyMultiDict", "PyCIMultiDict"],
-)
-def cls(request):
- return request.param
-
-
-@pytest.fixture
-def md_cls(_multidict):
- return _multidict.MultiDict
-
-
-@pytest.fixture
-def ci_md_cls(_multidict):
- return _multidict.CIMultiDict
-
-
-@pytest.fixture
-def istr(_multidict):
- return _multidict.istr
-
-
-def test_update_replace(cls):
- obj1 = cls([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
- obj2 = cls([("a", 4), ("b", 5), ("a", 6)])
+def test_update_replace(any_multidict_class: Type[MultiMapping[str]]) -> None:
+ obj1 = any_multidict_class([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
+ obj2 = any_multidict_class([("a", 4), ("b", 5), ("a", 6)])
obj1.update(obj2)
expected = [("a", 4), ("b", 5), ("a", 6), ("c", 10)]
assert list(obj1.items()) == expected
-def test_update_append(cls):
- obj1 = cls([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
- obj2 = cls([("a", 4), ("a", 5), ("a", 6)])
+def test_update_append(any_multidict_class: Type[MultiMapping[str]]) -> None:
+ obj1 = any_multidict_class([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
+ obj2 = any_multidict_class([("a", 4), ("a", 5), ("a", 6)])
obj1.update(obj2)
expected = [("a", 4), ("b", 2), ("a", 5), ("c", 10), ("a", 6)]
assert list(obj1.items()) == expected
-def test_update_remove(cls):
- obj1 = cls([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
- obj2 = cls([("a", 4)])
+def test_update_remove(any_multidict_class: Type[MultiMapping[str]]) -> None:
+ obj1 = any_multidict_class([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
+ obj2 = any_multidict_class([("a", 4)])
obj1.update(obj2)
expected = [("a", 4), ("b", 2), ("c", 10)]
assert list(obj1.items()) == expected
-def test_update_replace_seq(cls):
- obj1 = cls([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
+def test_update_replace_seq(any_multidict_class: Type[MultiMapping[str]]) -> None:
+ obj1 = any_multidict_class([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
obj2 = [("a", 4), ("b", 5), ("a", 6)]
obj1.update(obj2)
expected = [("a", 4), ("b", 5), ("a", 6), ("c", 10)]
assert list(obj1.items()) == expected
-def test_update_replace_seq2(cls):
- obj1 = cls([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
+def test_update_replace_seq2(any_multidict_class: Type[MultiMapping[str]]) -> None:
+ obj1 = any_multidict_class([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
obj1.update([("a", 4)], b=5, a=6)
expected = [("a", 4), ("b", 5), ("a", 6), ("c", 10)]
assert list(obj1.items()) == expected
-def test_update_append_seq(cls):
- obj1 = cls([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
+def test_update_append_seq(any_multidict_class: Type[MultiMapping[str]]) -> None:
+ obj1 = any_multidict_class([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
obj2 = [("a", 4), ("a", 5), ("a", 6)]
obj1.update(obj2)
expected = [("a", 4), ("b", 2), ("a", 5), ("c", 10), ("a", 6)]
assert list(obj1.items()) == expected
-def test_update_remove_seq(cls):
- obj1 = cls([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
+def test_update_remove_seq(any_multidict_class: Type[MultiMapping[str]]) -> None:
+ obj1 = any_multidict_class([("a", 1), ("b", 2), ("a", 3), ("c", 10)])
obj2 = [("a", 4)]
obj1.update(obj2)
expected = [("a", 4), ("b", 2), ("c", 10)]
assert list(obj1.items()) == expected
-def test_update_md(md_cls):
- d = md_cls()
+def test_update_md(
+ case_sensitive_multidict_class: Type[MultiMapping[str]],
+) -> None:
+ d = case_sensitive_multidict_class()
d.add("key", "val1")
d.add("key", "val2")
d.add("key2", "val3")
@@ -101,19 +72,24 @@ def test_update_md(md_cls):
assert [("key", "val"), ("key2", "val3")] == list(d.items())
-def test_update_istr_ci_md(ci_md_cls, istr):
- d = ci_md_cls()
- d.add(istr("KEY"), "val1")
+def test_update_istr_ci_md(
+ case_insensitive_multidict_class: Type[MultiMapping[str]],
+ case_insensitive_str_class: str,
+) -> None:
+ d = case_insensitive_multidict_class()
+ d.add(case_insensitive_str_class("KEY"), "val1")
d.add("key", "val2")
d.add("key2", "val3")
- d.update({istr("key"): "val"})
+ d.update({case_insensitive_str_class("key"): "val"})
assert [("key", "val"), ("key2", "val3")] == list(d.items())
-def test_update_ci_md(ci_md_cls):
- d = ci_md_cls()
+def test_update_ci_md(
+ case_insensitive_multidict_class: Type[MultiMapping[str]],
+) -> None:
+ d = case_insensitive_multidict_class()
d.add("KEY", "val1")
d.add("key", "val2")
d.add("key2", "val3")
@@ -123,24 +99,30 @@ def test_update_ci_md(ci_md_cls):
assert [("Key", "val"), ("key2", "val3")] == list(d.items())
-def test_update_list_arg_and_kwds(cls):
- obj = cls()
+def test_update_list_arg_and_kwds(
+ any_multidict_class: Type[MultiMapping[str]],
+) -> None:
+ obj = any_multidict_class()
arg = [("a", 1)]
obj.update(arg, b=2)
assert list(obj.items()) == [("a", 1), ("b", 2)]
assert arg == [("a", 1)]
-def test_update_tuple_arg_and_kwds(cls):
- obj = cls()
+def test_update_tuple_arg_and_kwds(
+ any_multidict_class: Type[MultiMapping[str]],
+) -> None:
+ obj = any_multidict_class()
arg = (("a", 1),)
obj.update(arg, b=2)
assert list(obj.items()) == [("a", 1), ("b", 2)]
assert arg == (("a", 1),)
-def test_update_deque_arg_and_kwds(cls):
- obj = cls()
+def test_update_deque_arg_and_kwds(
+ any_multidict_class: Type[MultiMapping[str]],
+) -> None:
+ obj = any_multidict_class()
arg = deque([("a", 1)])
obj.update(arg, b=2)
assert list(obj.items()) == [("a", 1), ("b", 2)]
diff --git a/contrib/python/multidict/tests/test_version.py b/contrib/python/multidict/tests/test_version.py
index 9b25c0e72d..e004afa112 100644
--- a/contrib/python/multidict/tests/test_version.py
+++ b/contrib/python/multidict/tests/test_version.py
@@ -1,201 +1,222 @@
-from typing import Type
+from typing import Callable, Type
import pytest
from multidict import MultiMapping
-from multidict._compat import USE_EXTENSIONS
-from multidict._multidict_py import CIMultiDict as _CIMultiDict
-from multidict._multidict_py import MultiDict as _MultiDict # noqa: E402
-from multidict._multidict_py import getversion as _getversion
-
-if USE_EXTENSIONS:
- from multidict._multidict import ( # type: ignore
- CIMultiDict,
- MultiDict,
- getversion,
- )
-
-
-class VersionMixin:
- cls: Type[MultiMapping[str]]
-
- def getver(self, md):
- raise NotImplementedError
-
- def test_getversion_bad_param(self):
- with pytest.raises(TypeError):
- self.getver(1)
-
- def test_ctor(self):
- m1 = self.cls()
- v1 = self.getver(m1)
- m2 = self.cls()
- v2 = self.getver(m2)
- assert v1 != v2
-
- def test_add(self):
- m = self.cls()
- v = self.getver(m)
- m.add("key", "val")
- assert self.getver(m) > v
-
- def test_delitem(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- del m["key"]
- assert self.getver(m) > v
-
- def test_delitem_not_found(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- with pytest.raises(KeyError):
- del m["notfound"]
- assert self.getver(m) == v
-
- def test_setitem(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- m["key"] = "val2"
- assert self.getver(m) > v
-
- def test_setitem_not_found(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- m["notfound"] = "val2"
- assert self.getver(m) > v
-
- def test_clear(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- m.clear()
- assert self.getver(m) > v
-
- def test_setdefault(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- m.setdefault("key2", "val2")
- assert self.getver(m) > v
-
- def test_popone(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- m.popone("key")
- assert self.getver(m) > v
-
- def test_popone_default(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- m.popone("key2", "default")
- assert self.getver(m) == v
- m.popone(key="key2", default="default")
- assert self.getver(m) == v
-
- def test_popone_key_error(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- with pytest.raises(KeyError):
- m.popone("key2")
- assert self.getver(m) == v
-
- def test_pop(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- m.pop("key")
- assert self.getver(m) > v
-
- def test_pop_default(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- m.pop("key2", "default")
- assert self.getver(m) == v
-
- def test_pop_key_error(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- with pytest.raises(KeyError):
- m.pop("key2")
- assert self.getver(m) == v
-
- def test_popall(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- m.popall("key")
- assert self.getver(m) > v
-
- def test_popall_default(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- m.popall("key2", "default")
- assert self.getver(m) == v
-
- def test_popall_key_error(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- with pytest.raises(KeyError):
- m.popall("key2")
- assert self.getver(m) == v
-
- def test_popitem(self):
- m = self.cls()
- m.add("key", "val")
- v = self.getver(m)
- m.popitem()
- assert self.getver(m) > v
-
- def test_popitem_key_error(self):
- m = self.cls()
- v = self.getver(m)
- with pytest.raises(KeyError):
- m.popitem()
- assert self.getver(m) == v
-
-
-if USE_EXTENSIONS:
-
- class TestMultiDict(VersionMixin):
-
- cls = MultiDict
-
- def getver(self, md):
- return getversion(md)
-
-
-if USE_EXTENSIONS:
-
- class TestCIMultiDict(VersionMixin):
- cls = CIMultiDict
- def getver(self, md):
- return getversion(md)
-
-
-class TestPyMultiDict(VersionMixin):
-
- cls = _MultiDict # type: ignore[assignment]
-
- def getver(self, md):
- return _getversion(md)
-
-
-class TestPyCIMultiDict(VersionMixin):
-
- cls = _CIMultiDict # type: ignore[assignment]
-
- def getver(self, md):
- return _getversion(md)
+def test_getversion_bad_param(multidict_getversion_callable):
+ with pytest.raises(TypeError):
+ multidict_getversion_callable(1)
+
+
+def test_ctor(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m1 = any_multidict_class()
+ v1 = multidict_getversion_callable(m1)
+ m2 = any_multidict_class()
+ v2 = multidict_getversion_callable(m2)
+ assert v1 != v2
+
+
+def test_add(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ v = multidict_getversion_callable(m)
+ m.add("key", "val")
+ assert multidict_getversion_callable(m) > v
+
+
+def test_delitem(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ del m["key"]
+ assert multidict_getversion_callable(m) > v
+
+
+def test_delitem_not_found(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ with pytest.raises(KeyError):
+ del m["notfound"]
+ assert multidict_getversion_callable(m) == v
+
+
+def test_setitem(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ m["key"] = "val2"
+ assert multidict_getversion_callable(m) > v
+
+
+def test_setitem_not_found(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ m["notfound"] = "val2"
+ assert multidict_getversion_callable(m) > v
+
+
+def test_clear(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ m.clear()
+ assert multidict_getversion_callable(m) > v
+
+
+def test_setdefault(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ m.setdefault("key2", "val2")
+ assert multidict_getversion_callable(m) > v
+
+
+def test_popone(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ m.popone("key")
+ assert multidict_getversion_callable(m) > v
+
+
+def test_popone_default(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ m.popone("key2", "default")
+ assert multidict_getversion_callable(m) == v
+
+
+def test_popone_key_error(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ with pytest.raises(KeyError):
+ m.popone("key2")
+ assert multidict_getversion_callable(m) == v
+
+
+def test_pop(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ m.pop("key")
+ assert multidict_getversion_callable(m) > v
+
+
+def test_pop_default(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ m.pop("key2", "default")
+ assert multidict_getversion_callable(m) == v
+
+
+def test_pop_key_error(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ with pytest.raises(KeyError):
+ m.pop("key2")
+ assert multidict_getversion_callable(m) == v
+
+
+def test_popall(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ m.popall("key")
+ assert multidict_getversion_callable(m) > v
+
+
+def test_popall_default(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ m.popall("key2", "default")
+ assert multidict_getversion_callable(m) == v
+
+
+def test_popall_key_error(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ with pytest.raises(KeyError):
+ m.popall("key2")
+ assert multidict_getversion_callable(m) == v
+
+
+def test_popitem(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ m.add("key", "val")
+ v = multidict_getversion_callable(m)
+ m.popitem()
+ assert multidict_getversion_callable(m) > v
+
+
+def test_popitem_key_error(
+ any_multidict_class: Type[MultiMapping[str]],
+ multidict_getversion_callable: Callable,
+) -> None:
+ m = any_multidict_class()
+ v = multidict_getversion_callable(m)
+ with pytest.raises(KeyError):
+ m.popitem()
+ assert multidict_getversion_callable(m) == v
diff --git a/contrib/python/multidict/ya.make b/contrib/python/multidict/ya.make
index bdba18c601..65195b87ce 100644
--- a/contrib/python/multidict/ya.make
+++ b/contrib/python/multidict/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(6.0.4)
+VERSION(6.0.5)
LICENSE(Apache-2.0)
diff --git a/yt/yt/core/rpc/config.cpp b/yt/yt/core/rpc/config.cpp
index ec29c3b88c..cd0d4a28a5 100644
--- a/yt/yt/core/rpc/config.cpp
+++ b/yt/yt/core/rpc/config.cpp
@@ -98,6 +98,9 @@ void TMethodConfig::Register(TRegistrar registrar)
registrar.Parameter("queue_size_limit", &TThis::QueueSizeLimit)
.Alias("max_queue_size")
.Optional();
+ registrar.Parameter("queue_bytes_size_limit", &TThis::QueueBytesSizeLimit)
+ .Alias("max_queue_bytes_size")
+ .Optional();
registrar.Parameter("concurrency_limit", &TThis::ConcurrencyLimit)
.Alias("max_concurrency")
.Optional();
diff --git a/yt/yt/core/rpc/config.h b/yt/yt/core/rpc/config.h
index 9cdf971d18..26214ea5fc 100644
--- a/yt/yt/core/rpc/config.h
+++ b/yt/yt/core/rpc/config.h
@@ -152,6 +152,7 @@ class TMethodConfig
public:
std::optional<bool> Heavy;
std::optional<int> QueueSizeLimit;
+ std::optional<i64> QueueBytesSizeLimit;
std::optional<int> ConcurrencyLimit;
std::optional<NLogging::ELogLevel> LogLevel;
std::optional<TDuration> LoggingSuppressionTimeout;
diff --git a/yt/yt/core/rpc/service_detail.cpp b/yt/yt/core/rpc/service_detail.cpp
index 92e81ea0ed..5c37360540 100644
--- a/yt/yt/core/rpc/service_detail.cpp
+++ b/yt/yt/core/rpc/service_detail.cpp
@@ -166,6 +166,13 @@ auto TServiceBase::TMethodDescriptor::SetQueueSizeLimit(int value) const -> TMet
return result;
}
+auto TServiceBase::TMethodDescriptor::SetQueueBytesSizeLimit(i64 value) const -> TMethodDescriptor
+{
+ auto result = *this;
+ result.QueueBytesSizeLimit = value;
+ return result;
+}
+
auto TServiceBase::TMethodDescriptor::SetConcurrencyLimit(int value) const -> TMethodDescriptor
{
auto result = *this;
@@ -271,6 +278,7 @@ TServiceBase::TRuntimeMethodInfo::TRuntimeMethodInfo(
, ResponseLoggingAnchor(NLogging::TLogManager::Get()->RegisterDynamicAnchor(
Format("%v.%v ->", ServiceId.ServiceName, Descriptor.Method)))
, RequestQueueSizeLimitErrorCounter(Profiler.Counter("/request_queue_size_errors"))
+ , RequestQueueBytesSizeLimitErrorCounter(Profiler.Counter("/request_queue_bytes_size_errors"))
, UnauthenticatedRequestsCounter(Profiler.Counter("/unauthenticated_requests"))
, LoggingSuppressionFailedRequestThrottler(
CreateReconfigurableThroughputThrottler(
@@ -1313,13 +1321,18 @@ void TRequestQueue::ConfigureWeightThrottler(const TThroughputThrottlerConfigPtr
WeightThrottler_.Reconfigure(config);
}
-bool TRequestQueue::IsQueueLimitSizeExceeded() const
+bool TRequestQueue::IsQueueSizeLimitExceeded() const
{
- return
- QueueSize_.load(std::memory_order::relaxed) >=
+ return QueueSize_.load(std::memory_order::relaxed) >=
RuntimeInfo_->QueueSizeLimit.load(std::memory_order::relaxed);
}
+bool TRequestQueue::IsQueueBytesSizeLimitExceeded() const
+{
+ return QueueBytesSize_.load(std::memory_order::relaxed) >=
+ RuntimeInfo_->QueueBytesSizeLimit.load(std::memory_order::relaxed);
+}
+
int TRequestQueue::GetQueueSize() const
{
return QueueSize_.load(std::memory_order::relaxed);
@@ -1343,7 +1356,7 @@ void TRequestQueue::OnRequestArrived(TServiceBase::TServiceContextPtr context)
// Slow path.
DecrementConcurrency();
- IncrementQueueSize();
+ IncrementQueueSize(context);
context->BeforeEnqueued();
YT_VERIFY(Queue_.enqueue(std::move(context)));
@@ -1401,7 +1414,7 @@ void TRequestQueue::ScheduleRequestsFromQueue()
return;
}
- DecrementQueueSize();
+ DecrementQueueSize(context);
context->AfterDequeued();
if (context->IsCanceled()) {
context.Reset();
@@ -1432,15 +1445,26 @@ void TRequestQueue::RunRequest(TServiceBase::TServiceContextPtr context)
}
}
-int TRequestQueue::IncrementQueueSize()
+void TRequestQueue::IncrementQueueSize(const TServiceBase::TServiceContextPtr& context)
{
- return ++QueueSize_;
+ ++QueueSize_;
+
+ auto requestSize =
+ GetMessageBodySize(context->GetRequestMessage()) +
+ GetTotalMessageAttachmentSize(context->GetRequestMessage());
+ QueueBytesSize_ += requestSize;
}
-void TRequestQueue::DecrementQueueSize()
+void TRequestQueue::DecrementQueueSize(const TServiceBase::TServiceContextPtr& context)
{
auto newQueueSize = --QueueSize_;
YT_ASSERT(newQueueSize >= 0);
+
+ auto requestSize =
+ GetMessageBodySize(context->GetRequestMessage()) +
+ GetTotalMessageAttachmentSize(context->GetRequestMessage());
+ auto oldQueueBytesSize = QueueBytesSize_.fetch_sub(requestSize);
+ YT_ASSERT(oldQueueBytesSize >= requestSize);
}
int TRequestQueue::IncrementConcurrency()
@@ -1610,7 +1634,7 @@ void TServiceBase::HandleRequest(
auto maybeThrottled = GetThrottledError(*header);
- if (requestQueue->IsQueueLimitSizeExceeded()) {
+ if (requestQueue->IsQueueSizeLimitExceeded()) {
runtimeInfo->RequestQueueSizeLimitErrorCounter.Increment();
replyError(TError(
NRpc::EErrorCode::RequestQueueSizeLimitExceeded,
@@ -1621,6 +1645,17 @@ void TServiceBase::HandleRequest(
return;
}
+ if (requestQueue->IsQueueBytesSizeLimitExceeded()) {
+ runtimeInfo->RequestQueueBytesSizeLimitErrorCounter.Increment();
+ replyError(TError(
+ NRpc::EErrorCode::RequestQueueSizeLimitExceeded,
+ "Request queue bytes size limit exceeded")
+ << TErrorAttribute("limit", runtimeInfo->QueueBytesSizeLimit.load())
+ << TErrorAttribute("queue", requestQueue->GetName())
+ << maybeThrottled);
+ return;
+ }
+
TCurrentTraceContextGuard traceContextGuard(traceContext);
// NOTE: Do not use replyError() after this line.
@@ -2387,6 +2422,7 @@ TServiceBase::TRuntimeMethodInfoPtr TServiceBase::RegisterMethod(const TMethodDe
runtimeInfo->Heavy.store(descriptor.Options.Heavy);
runtimeInfo->QueueSizeLimit.store(descriptor.QueueSizeLimit);
+ runtimeInfo->QueueBytesSizeLimit.store(descriptor.QueueBytesSizeLimit);
runtimeInfo->ConcurrencyLimit.Reconfigure(descriptor.ConcurrencyLimit);
runtimeInfo->LogLevel.store(descriptor.LogLevel);
runtimeInfo->LoggingSuppressionTimeout.store(descriptor.LoggingSuppressionTimeout);
@@ -2398,6 +2434,9 @@ TServiceBase::TRuntimeMethodInfoPtr TServiceBase::RegisterMethod(const TMethodDe
profiler.AddFuncGauge("/request_queue_size_limit", MakeStrong(this), [=] {
return runtimeInfo->QueueSizeLimit.load(std::memory_order::relaxed);
});
+ profiler.AddFuncGauge("/request_queue_bytes_size_limit", MakeStrong(this), [=] {
+ return runtimeInfo->QueueBytesSizeLimit.load(std::memory_order::relaxed);
+ });
profiler.AddFuncGauge("/concurrency_limit", MakeStrong(this), [=] {
return runtimeInfo->ConcurrencyLimit.GetDynamicLimit();
});
@@ -2461,6 +2500,7 @@ void TServiceBase::DoConfigure(
runtimeInfo->Heavy.store(methodConfig->Heavy.value_or(descriptor.Options.Heavy));
runtimeInfo->QueueSizeLimit.store(methodConfig->QueueSizeLimit.value_or(descriptor.QueueSizeLimit));
+ runtimeInfo->QueueBytesSizeLimit.store(methodConfig->QueueBytesSizeLimit.value_or(descriptor.QueueBytesSizeLimit));
runtimeInfo->ConcurrencyLimit.Reconfigure(methodConfig->ConcurrencyLimit.value_or(descriptor.ConcurrencyLimit));
runtimeInfo->LogLevel.store(methodConfig->LogLevel.value_or(descriptor.LogLevel));
runtimeInfo->LoggingSuppressionTimeout.store(methodConfig->LoggingSuppressionTimeout.value_or(descriptor.LoggingSuppressionTimeout));
diff --git a/yt/yt/core/rpc/service_detail.h b/yt/yt/core/rpc/service_detail.h
index ba52cf514b..87a9458431 100644
--- a/yt/yt/core/rpc/service_detail.h
+++ b/yt/yt/core/rpc/service_detail.h
@@ -560,6 +560,9 @@ protected:
//! Maximum number of requests in queue (both waiting and executing).
int QueueSizeLimit = 10'000;
+ //! Maximum total size of requests in queue (both waiting and executing).
+ i64 QueueBytesSizeLimit = 2_GB;
+
//! Maximum number of requests executing concurrently.
int ConcurrencyLimit = 10'000;
@@ -597,6 +600,7 @@ protected:
TMethodDescriptor SetHeavy(bool value) const;
TMethodDescriptor SetResponseCodec(NCompression::ECodec value) const;
TMethodDescriptor SetQueueSizeLimit(int value) const;
+ TMethodDescriptor SetQueueBytesSizeLimit(i64 value) const;
TMethodDescriptor SetConcurrencyLimit(int value) const;
TMethodDescriptor SetSystem(bool value) const;
TMethodDescriptor SetLogLevel(NLogging::ELogLevel value) const;
@@ -700,11 +704,13 @@ protected:
std::atomic<bool> Pooled = true;
std::atomic<int> QueueSizeLimit = 0;
+ std::atomic<i64> QueueBytesSizeLimit = 0;
TDynamicConcurrencyLimit ConcurrencyLimit;
std::atomic<double> WaitingTimeoutFraction = 0;
NProfiling::TCounter RequestQueueSizeLimitErrorCounter;
+ NProfiling::TCounter RequestQueueBytesSizeLimitErrorCounter;
NProfiling::TCounter UnauthenticatedRequestsCounter;
std::atomic<NLogging::ELogLevel> LogLevel = {};
@@ -1019,7 +1025,8 @@ public:
bool Register(TServiceBase* service, TServiceBase::TRuntimeMethodInfo* runtimeInfo);
void Configure(const TMethodConfigPtr& config);
- bool IsQueueLimitSizeExceeded() const;
+ bool IsQueueSizeLimitExceeded() const;
+ bool IsQueueBytesSizeLimitExceeded() const;
int GetQueueSize() const;
int GetConcurrency() const;
@@ -1054,14 +1061,15 @@ private:
std::atomic<bool> Throttled_ = false;
std::atomic<int> QueueSize_ = 0;
+ std::atomic<i64> QueueBytesSize_ = 0;
moodycamel::ConcurrentQueue<TServiceBase::TServiceContextPtr> Queue_;
void ScheduleRequestsFromQueue();
void RunRequest(TServiceBase::TServiceContextPtr context);
- int IncrementQueueSize();
- void DecrementQueueSize();
+ void IncrementQueueSize(const TServiceBase::TServiceContextPtr& context);
+ void DecrementQueueSize(const TServiceBase::TServiceContextPtr& context);
int IncrementConcurrency();
void DecrementConcurrency();