SolarManager unter Versionsverwaltung
Erster Stand der Hintergrundprozesse, die auf der Synology unter /volume1/homes/wagner/SolarManager laufen: der Manager selbst, die Sammler je Geraet, die MQTT-Bruecke, der Wecker und - neu hinzugezogen - der AutoAction-Runner, der als Hintergrundprozess hierher gehoert und nicht ins Web-Verzeichnis. Zugangsdaten stehen nicht mehr im Quelltext, sondern in config.ini, die nicht mit eingecheckt wird. Vorlage ist config.ini.example, gelesen wird sie von konfig.py. Betroffen waren solarManager.py (Datenbank und Wattpilot), zeit.py, gatherWaterData.py, wecker.py und skoda_testdaten.py, das sich das Passwort bisher aus dem Quelltext eines anderen Moduls herausgesucht hat. Die Kia-Anbindung ist mit dem Fahrzeug entfallen: kiaTest.py, gatherCarData.py und hyundai_kia_connect_api sind nicht mehr dabei, ebenso gatherInverterData.py, auf das nur noch eine auskommentierte Zeile zeigte. Die mitgelieferten Bibliotheken bleiben im Repository - die NAS hat kein pip, sie muessen neben den Skripten liegen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
"""Multidict implementation.
|
||||
|
||||
HTTP Headers and URL query string require specific data structure:
|
||||
multidict. It behaves mostly like a dict but it can have
|
||||
several values for the same key.
|
||||
"""
|
||||
|
||||
from ._abc import MultiMapping, MutableMultiMapping
|
||||
from ._compat import USE_EXTENSIONS
|
||||
|
||||
__all__ = (
|
||||
"MultiMapping",
|
||||
"MutableMultiMapping",
|
||||
"MultiDictProxy",
|
||||
"CIMultiDictProxy",
|
||||
"MultiDict",
|
||||
"CIMultiDict",
|
||||
"upstr",
|
||||
"istr",
|
||||
"getversion",
|
||||
)
|
||||
|
||||
__version__ = "6.0.4"
|
||||
|
||||
|
||||
try:
|
||||
if not USE_EXTENSIONS:
|
||||
raise ImportError
|
||||
from ._multidict import (
|
||||
CIMultiDict,
|
||||
CIMultiDictProxy,
|
||||
MultiDict,
|
||||
MultiDictProxy,
|
||||
getversion,
|
||||
istr,
|
||||
)
|
||||
except ImportError: # pragma: no cover
|
||||
from ._multidict_py import (
|
||||
CIMultiDict,
|
||||
CIMultiDictProxy,
|
||||
MultiDict,
|
||||
MultiDictProxy,
|
||||
getversion,
|
||||
istr,
|
||||
)
|
||||
|
||||
|
||||
upstr = istr
|
||||
@@ -0,0 +1,150 @@
|
||||
import abc
|
||||
from typing import (
|
||||
Generic,
|
||||
Iterable,
|
||||
Iterator,
|
||||
Mapping,
|
||||
MutableMapping,
|
||||
TypeVar,
|
||||
overload,
|
||||
)
|
||||
|
||||
class istr(str): ...
|
||||
|
||||
upstr = istr
|
||||
|
||||
_S = str | istr
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
_T_co = TypeVar("_T_co", covariant=True)
|
||||
|
||||
_D = TypeVar("_D")
|
||||
|
||||
class MultiMapping(Mapping[_S, _T_co]):
|
||||
@overload
|
||||
@abc.abstractmethod
|
||||
def getall(self, key: _S) -> list[_T_co]: ...
|
||||
@overload
|
||||
@abc.abstractmethod
|
||||
def getall(self, key: _S, default: _D) -> list[_T_co] | _D: ...
|
||||
@overload
|
||||
@abc.abstractmethod
|
||||
def getone(self, key: _S) -> _T_co: ...
|
||||
@overload
|
||||
@abc.abstractmethod
|
||||
def getone(self, key: _S, default: _D) -> _T_co | _D: ...
|
||||
|
||||
_Arg = (Mapping[str, _T] | Mapping[istr, _T] | dict[str, _T]
|
||||
| dict[istr, _T] | MultiMapping[_T]
|
||||
| Iterable[tuple[str, _T]] | Iterable[tuple[istr, _T]])
|
||||
|
||||
class MutableMultiMapping(MultiMapping[_T], MutableMapping[_S, _T], Generic[_T]):
|
||||
@abc.abstractmethod
|
||||
def add(self, key: _S, value: _T) -> None: ...
|
||||
@abc.abstractmethod
|
||||
def extend(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...
|
||||
@overload
|
||||
@abc.abstractmethod
|
||||
def popone(self, key: _S) -> _T: ...
|
||||
@overload
|
||||
@abc.abstractmethod
|
||||
def popone(self, key: _S, default: _D) -> _T | _D: ...
|
||||
@overload
|
||||
@abc.abstractmethod
|
||||
def popall(self, key: _S) -> list[_T]: ...
|
||||
@overload
|
||||
@abc.abstractmethod
|
||||
def popall(self, key: _S, default: _D) -> list[_T] | _D: ...
|
||||
|
||||
class MultiDict(MutableMultiMapping[_T], Generic[_T]):
|
||||
def __init__(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...
|
||||
def copy(self) -> MultiDict[_T]: ...
|
||||
def __getitem__(self, k: _S) -> _T: ...
|
||||
def __setitem__(self, k: _S, v: _T) -> None: ...
|
||||
def __delitem__(self, v: _S) -> None: ...
|
||||
def __iter__(self) -> Iterator[_S]: ...
|
||||
def __len__(self) -> int: ...
|
||||
@overload
|
||||
def getall(self, key: _S) -> list[_T]: ...
|
||||
@overload
|
||||
def getall(self, key: _S, default: _D) -> list[_T] | _D: ...
|
||||
@overload
|
||||
def getone(self, key: _S) -> _T: ...
|
||||
@overload
|
||||
def getone(self, key: _S, default: _D) -> _T | _D: ...
|
||||
def add(self, key: _S, value: _T) -> None: ...
|
||||
def extend(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...
|
||||
@overload
|
||||
def popone(self, key: _S) -> _T: ...
|
||||
@overload
|
||||
def popone(self, key: _S, default: _D) -> _T | _D: ...
|
||||
@overload
|
||||
def popall(self, key: _S) -> list[_T]: ...
|
||||
@overload
|
||||
def popall(self, key: _S, default: _D) -> list[_T] | _D: ...
|
||||
|
||||
class CIMultiDict(MutableMultiMapping[_T], Generic[_T]):
|
||||
def __init__(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...
|
||||
def copy(self) -> CIMultiDict[_T]: ...
|
||||
def __getitem__(self, k: _S) -> _T: ...
|
||||
def __setitem__(self, k: _S, v: _T) -> None: ...
|
||||
def __delitem__(self, v: _S) -> None: ...
|
||||
def __iter__(self) -> Iterator[_S]: ...
|
||||
def __len__(self) -> int: ...
|
||||
@overload
|
||||
def getall(self, key: _S) -> list[_T]: ...
|
||||
@overload
|
||||
def getall(self, key: _S, default: _D) -> list[_T] | _D: ...
|
||||
@overload
|
||||
def getone(self, key: _S) -> _T: ...
|
||||
@overload
|
||||
def getone(self, key: _S, default: _D) -> _T | _D: ...
|
||||
def add(self, key: _S, value: _T) -> None: ...
|
||||
def extend(self, arg: _Arg[_T] = ..., **kwargs: _T) -> None: ...
|
||||
@overload
|
||||
def popone(self, key: _S) -> _T: ...
|
||||
@overload
|
||||
def popone(self, key: _S, default: _D) -> _T | _D: ...
|
||||
@overload
|
||||
def popall(self, key: _S) -> list[_T]: ...
|
||||
@overload
|
||||
def popall(self, key: _S, default: _D) -> list[_T] | _D: ...
|
||||
|
||||
class MultiDictProxy(MultiMapping[_T], Generic[_T]):
|
||||
def __init__(
|
||||
self, arg: MultiMapping[_T] | MutableMultiMapping[_T]
|
||||
) -> None: ...
|
||||
def copy(self) -> MultiDict[_T]: ...
|
||||
def __getitem__(self, k: _S) -> _T: ...
|
||||
def __iter__(self) -> Iterator[_S]: ...
|
||||
def __len__(self) -> int: ...
|
||||
@overload
|
||||
def getall(self, key: _S) -> list[_T]: ...
|
||||
@overload
|
||||
def getall(self, key: _S, default: _D) -> list[_T] | _D: ...
|
||||
@overload
|
||||
def getone(self, key: _S) -> _T: ...
|
||||
@overload
|
||||
def getone(self, key: _S, default: _D) -> _T | _D: ...
|
||||
|
||||
class CIMultiDictProxy(MultiMapping[_T], Generic[_T]):
|
||||
def __init__(
|
||||
self, arg: MultiMapping[_T] | MutableMultiMapping[_T]
|
||||
) -> None: ...
|
||||
def __getitem__(self, k: _S) -> _T: ...
|
||||
def __iter__(self) -> Iterator[_S]: ...
|
||||
def __len__(self) -> int: ...
|
||||
@overload
|
||||
def getall(self, key: _S) -> list[_T]: ...
|
||||
@overload
|
||||
def getall(self, key: _S, default: _D) -> list[_T] | _D: ...
|
||||
@overload
|
||||
def getone(self, key: _S) -> _T: ...
|
||||
@overload
|
||||
def getone(self, key: _S, default: _D) -> _T | _D: ...
|
||||
def copy(self) -> CIMultiDict[_T]: ...
|
||||
|
||||
def getversion(
|
||||
md: MultiDict[_T] | CIMultiDict[_T] | MultiDictProxy[_T] | CIMultiDictProxy[_T]
|
||||
) -> int: ...
|
||||
@@ -0,0 +1,48 @@
|
||||
import abc
|
||||
import sys
|
||||
import types
|
||||
from collections.abc import Mapping, MutableMapping
|
||||
|
||||
|
||||
class _TypingMeta(abc.ABCMeta):
|
||||
# A fake metaclass to satisfy typing deps in runtime
|
||||
# basically MultiMapping[str] and other generic-like type instantiations
|
||||
# are emulated.
|
||||
# Note: real type hints are provided by __init__.pyi stub file
|
||||
if sys.version_info >= (3, 9):
|
||||
|
||||
def __getitem__(self, key):
|
||||
return types.GenericAlias(self, key)
|
||||
|
||||
else:
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self
|
||||
|
||||
|
||||
class MultiMapping(Mapping, metaclass=_TypingMeta):
|
||||
@abc.abstractmethod
|
||||
def getall(self, key, default=None):
|
||||
raise KeyError
|
||||
|
||||
@abc.abstractmethod
|
||||
def getone(self, key, default=None):
|
||||
raise KeyError
|
||||
|
||||
|
||||
class MutableMultiMapping(MultiMapping, MutableMapping):
|
||||
@abc.abstractmethod
|
||||
def add(self, key, value):
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def extend(self, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def popone(self, key, default=None):
|
||||
raise KeyError
|
||||
|
||||
@abc.abstractmethod
|
||||
def popall(self, key, default=None):
|
||||
raise KeyError
|
||||
@@ -0,0 +1,14 @@
|
||||
import os
|
||||
import platform
|
||||
|
||||
NO_EXTENSIONS = bool(os.environ.get("MULTIDICT_NO_EXTENSIONS"))
|
||||
|
||||
PYPY = platform.python_implementation() == "PyPy"
|
||||
|
||||
USE_EXTENSIONS = not NO_EXTENSIONS and not PYPY
|
||||
|
||||
if USE_EXTENSIONS:
|
||||
try:
|
||||
from . import _multidict # noqa
|
||||
except ImportError:
|
||||
USE_EXTENSIONS = False
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,144 @@
|
||||
from collections.abc import ItemsView, Iterable, KeysView, Set, ValuesView
|
||||
|
||||
|
||||
def _abc_itemsview_register(view_cls):
|
||||
ItemsView.register(view_cls)
|
||||
|
||||
|
||||
def _abc_keysview_register(view_cls):
|
||||
KeysView.register(view_cls)
|
||||
|
||||
|
||||
def _abc_valuesview_register(view_cls):
|
||||
ValuesView.register(view_cls)
|
||||
|
||||
|
||||
def _viewbaseset_richcmp(view, other, op):
|
||||
if op == 0: # <
|
||||
if not isinstance(other, Set):
|
||||
return NotImplemented
|
||||
return len(view) < len(other) and view <= other
|
||||
elif op == 1: # <=
|
||||
if not isinstance(other, Set):
|
||||
return NotImplemented
|
||||
if len(view) > len(other):
|
||||
return False
|
||||
for elem in view:
|
||||
if elem not in other:
|
||||
return False
|
||||
return True
|
||||
elif op == 2: # ==
|
||||
if not isinstance(other, Set):
|
||||
return NotImplemented
|
||||
return len(view) == len(other) and view <= other
|
||||
elif op == 3: # !=
|
||||
return not view == other
|
||||
elif op == 4: # >
|
||||
if not isinstance(other, Set):
|
||||
return NotImplemented
|
||||
return len(view) > len(other) and view >= other
|
||||
elif op == 5: # >=
|
||||
if not isinstance(other, Set):
|
||||
return NotImplemented
|
||||
if len(view) < len(other):
|
||||
return False
|
||||
for elem in other:
|
||||
if elem not in view:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _viewbaseset_and(view, other):
|
||||
if not isinstance(other, Iterable):
|
||||
return NotImplemented
|
||||
if isinstance(view, Set):
|
||||
view = set(iter(view))
|
||||
if isinstance(other, Set):
|
||||
other = set(iter(other))
|
||||
if not isinstance(other, Set):
|
||||
other = set(iter(other))
|
||||
return view & other
|
||||
|
||||
|
||||
def _viewbaseset_or(view, other):
|
||||
if not isinstance(other, Iterable):
|
||||
return NotImplemented
|
||||
if isinstance(view, Set):
|
||||
view = set(iter(view))
|
||||
if isinstance(other, Set):
|
||||
other = set(iter(other))
|
||||
if not isinstance(other, Set):
|
||||
other = set(iter(other))
|
||||
return view | other
|
||||
|
||||
|
||||
def _viewbaseset_sub(view, other):
|
||||
if not isinstance(other, Iterable):
|
||||
return NotImplemented
|
||||
if isinstance(view, Set):
|
||||
view = set(iter(view))
|
||||
if isinstance(other, Set):
|
||||
other = set(iter(other))
|
||||
if not isinstance(other, Set):
|
||||
other = set(iter(other))
|
||||
return view - other
|
||||
|
||||
|
||||
def _viewbaseset_xor(view, other):
|
||||
if not isinstance(other, Iterable):
|
||||
return NotImplemented
|
||||
if isinstance(view, Set):
|
||||
view = set(iter(view))
|
||||
if isinstance(other, Set):
|
||||
other = set(iter(other))
|
||||
if not isinstance(other, Set):
|
||||
other = set(iter(other))
|
||||
return view ^ other
|
||||
|
||||
|
||||
def _itemsview_isdisjoint(view, other):
|
||||
"Return True if two sets have a null intersection."
|
||||
for v in other:
|
||||
if v in view:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _itemsview_repr(view):
|
||||
lst = []
|
||||
for k, v in view:
|
||||
lst.append("{!r}: {!r}".format(k, v))
|
||||
body = ", ".join(lst)
|
||||
return "{}({})".format(view.__class__.__name__, body)
|
||||
|
||||
|
||||
def _keysview_isdisjoint(view, other):
|
||||
"Return True if two sets have a null intersection."
|
||||
for k in other:
|
||||
if k in view:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _keysview_repr(view):
|
||||
lst = []
|
||||
for k in view:
|
||||
lst.append("{!r}".format(k))
|
||||
body = ", ".join(lst)
|
||||
return "{}({})".format(view.__class__.__name__, body)
|
||||
|
||||
|
||||
def _valuesview_repr(view):
|
||||
lst = []
|
||||
for v in view:
|
||||
lst.append("{!r}".format(v))
|
||||
body = ", ".join(lst)
|
||||
return "{}({})".format(view.__class__.__name__, body)
|
||||
|
||||
|
||||
def _mdrepr(md):
|
||||
lst = []
|
||||
for k, v in md.items():
|
||||
lst.append("'{}': {!r}".format(k, v))
|
||||
body = ", ".join(lst)
|
||||
return "<{}({})>".format(md.__class__.__name__, body)
|
||||
@@ -0,0 +1,526 @@
|
||||
import sys
|
||||
import types
|
||||
from array import array
|
||||
from collections import abc
|
||||
|
||||
from ._abc import MultiMapping, MutableMultiMapping
|
||||
|
||||
_marker = object()
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
GenericAlias = types.GenericAlias
|
||||
else:
|
||||
def GenericAlias(cls):
|
||||
return cls
|
||||
|
||||
|
||||
class istr(str):
|
||||
|
||||
"""Case insensitive str."""
|
||||
|
||||
__is_istr__ = True
|
||||
|
||||
|
||||
upstr = istr # for relaxing backward compatibility problems
|
||||
|
||||
|
||||
def getversion(md):
|
||||
if not isinstance(md, _Base):
|
||||
raise TypeError("Parameter should be multidict or proxy")
|
||||
return md._impl._version
|
||||
|
||||
|
||||
_version = array("Q", [0])
|
||||
|
||||
|
||||
class _Impl:
|
||||
__slots__ = ("_items", "_version")
|
||||
|
||||
def __init__(self):
|
||||
self._items = []
|
||||
self.incr_version()
|
||||
|
||||
def incr_version(self):
|
||||
global _version
|
||||
v = _version
|
||||
v[0] += 1
|
||||
self._version = v[0]
|
||||
|
||||
if sys.implementation.name != "pypy":
|
||||
|
||||
def __sizeof__(self):
|
||||
return object.__sizeof__(self) + sys.getsizeof(self._items)
|
||||
|
||||
|
||||
class _Base:
|
||||
def _title(self, key):
|
||||
return key
|
||||
|
||||
def getall(self, key, default=_marker):
|
||||
"""Return a list of all values matching the key."""
|
||||
identity = self._title(key)
|
||||
res = [v for i, k, v in self._impl._items if i == identity]
|
||||
if res:
|
||||
return res
|
||||
if not res and default is not _marker:
|
||||
return default
|
||||
raise KeyError("Key not found: %r" % key)
|
||||
|
||||
def getone(self, key, default=_marker):
|
||||
"""Get first value matching the key.
|
||||
|
||||
Raises KeyError if the key is not found and no default is provided.
|
||||
"""
|
||||
identity = self._title(key)
|
||||
for i, k, v in self._impl._items:
|
||||
if i == identity:
|
||||
return v
|
||||
if default is not _marker:
|
||||
return default
|
||||
raise KeyError("Key not found: %r" % key)
|
||||
|
||||
# Mapping interface #
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.getone(key)
|
||||
|
||||
def get(self, key, default=None):
|
||||
"""Get first value matching the key.
|
||||
|
||||
If the key is not found, returns the default (or None if no default is provided)
|
||||
"""
|
||||
return self.getone(key, default)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.keys())
|
||||
|
||||
def __len__(self):
|
||||
return len(self._impl._items)
|
||||
|
||||
def keys(self):
|
||||
"""Return a new view of the dictionary's keys."""
|
||||
return _KeysView(self._impl)
|
||||
|
||||
def items(self):
|
||||
"""Return a new view of the dictionary's items *(key, value) pairs)."""
|
||||
return _ItemsView(self._impl)
|
||||
|
||||
def values(self):
|
||||
"""Return a new view of the dictionary's values."""
|
||||
return _ValuesView(self._impl)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, abc.Mapping):
|
||||
return NotImplemented
|
||||
if isinstance(other, _Base):
|
||||
lft = self._impl._items
|
||||
rht = other._impl._items
|
||||
if len(lft) != len(rht):
|
||||
return False
|
||||
for (i1, k2, v1), (i2, k2, v2) in zip(lft, rht):
|
||||
if i1 != i2 or v1 != v2:
|
||||
return False
|
||||
return True
|
||||
if len(self._impl._items) != len(other):
|
||||
return False
|
||||
for k, v in self.items():
|
||||
nv = other.get(k, _marker)
|
||||
if v != nv:
|
||||
return False
|
||||
return True
|
||||
|
||||
def __contains__(self, key):
|
||||
identity = self._title(key)
|
||||
for i, k, v in self._impl._items:
|
||||
if i == identity:
|
||||
return True
|
||||
return False
|
||||
|
||||
def __repr__(self):
|
||||
body = ", ".join("'{}': {!r}".format(k, v) for k, v in self.items())
|
||||
return "<{}({})>".format(self.__class__.__name__, body)
|
||||
|
||||
__class_getitem__ = classmethod(GenericAlias)
|
||||
|
||||
|
||||
class MultiDictProxy(_Base, MultiMapping):
|
||||
"""Read-only proxy for MultiDict instance."""
|
||||
|
||||
def __init__(self, arg):
|
||||
if not isinstance(arg, (MultiDict, MultiDictProxy)):
|
||||
raise TypeError(
|
||||
"ctor requires MultiDict or MultiDictProxy instance"
|
||||
", not {}".format(type(arg))
|
||||
)
|
||||
|
||||
self._impl = arg._impl
|
||||
|
||||
def __reduce__(self):
|
||||
raise TypeError("can't pickle {} objects".format(self.__class__.__name__))
|
||||
|
||||
def copy(self):
|
||||
"""Return a copy of itself."""
|
||||
return MultiDict(self.items())
|
||||
|
||||
|
||||
class CIMultiDictProxy(MultiDictProxy):
|
||||
"""Read-only proxy for CIMultiDict instance."""
|
||||
|
||||
def __init__(self, arg):
|
||||
if not isinstance(arg, (CIMultiDict, CIMultiDictProxy)):
|
||||
raise TypeError(
|
||||
"ctor requires CIMultiDict or CIMultiDictProxy instance"
|
||||
", not {}".format(type(arg))
|
||||
)
|
||||
|
||||
self._impl = arg._impl
|
||||
|
||||
def _title(self, key):
|
||||
return key.title()
|
||||
|
||||
def copy(self):
|
||||
"""Return a copy of itself."""
|
||||
return CIMultiDict(self.items())
|
||||
|
||||
|
||||
class MultiDict(_Base, MutableMultiMapping):
|
||||
"""Dictionary with the support for duplicate keys."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._impl = _Impl()
|
||||
|
||||
self._extend(args, kwargs, self.__class__.__name__, self._extend_items)
|
||||
|
||||
if sys.implementation.name != "pypy":
|
||||
|
||||
def __sizeof__(self):
|
||||
return object.__sizeof__(self) + sys.getsizeof(self._impl)
|
||||
|
||||
def __reduce__(self):
|
||||
return (self.__class__, (list(self.items()),))
|
||||
|
||||
def _title(self, key):
|
||||
return key
|
||||
|
||||
def _key(self, key):
|
||||
if isinstance(key, str):
|
||||
return key
|
||||
else:
|
||||
raise TypeError(
|
||||
"MultiDict keys should be either str " "or subclasses of str"
|
||||
)
|
||||
|
||||
def add(self, key, value):
|
||||
identity = self._title(key)
|
||||
self._impl._items.append((identity, self._key(key), value))
|
||||
self._impl.incr_version()
|
||||
|
||||
def copy(self):
|
||||
"""Return a copy of itself."""
|
||||
cls = self.__class__
|
||||
return cls(self.items())
|
||||
|
||||
__copy__ = copy
|
||||
|
||||
def extend(self, *args, **kwargs):
|
||||
"""Extend current MultiDict with more values.
|
||||
|
||||
This method must be used instead of update.
|
||||
"""
|
||||
self._extend(args, kwargs, "extend", self._extend_items)
|
||||
|
||||
def _extend(self, args, kwargs, name, method):
|
||||
if len(args) > 1:
|
||||
raise TypeError(
|
||||
"{} takes at most 1 positional argument"
|
||||
" ({} given)".format(name, len(args))
|
||||
)
|
||||
if args:
|
||||
arg = args[0]
|
||||
if isinstance(args[0], (MultiDict, MultiDictProxy)) and not kwargs:
|
||||
items = arg._impl._items
|
||||
else:
|
||||
if hasattr(arg, "items"):
|
||||
arg = arg.items()
|
||||
if kwargs:
|
||||
arg = list(arg)
|
||||
arg.extend(list(kwargs.items()))
|
||||
items = []
|
||||
for item in arg:
|
||||
if not len(item) == 2:
|
||||
raise TypeError(
|
||||
"{} takes either dict or list of (key, value) "
|
||||
"tuples".format(name)
|
||||
)
|
||||
items.append((self._title(item[0]), self._key(item[0]), item[1]))
|
||||
|
||||
method(items)
|
||||
else:
|
||||
method(
|
||||
[
|
||||
(self._title(key), self._key(key), value)
|
||||
for key, value in kwargs.items()
|
||||
]
|
||||
)
|
||||
|
||||
def _extend_items(self, items):
|
||||
for identity, key, value in items:
|
||||
self.add(key, value)
|
||||
|
||||
def clear(self):
|
||||
"""Remove all items from MultiDict."""
|
||||
self._impl._items.clear()
|
||||
self._impl.incr_version()
|
||||
|
||||
# Mapping interface #
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._replace(key, value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
identity = self._title(key)
|
||||
items = self._impl._items
|
||||
found = False
|
||||
for i in range(len(items) - 1, -1, -1):
|
||||
if items[i][0] == identity:
|
||||
del items[i]
|
||||
found = True
|
||||
if not found:
|
||||
raise KeyError(key)
|
||||
else:
|
||||
self._impl.incr_version()
|
||||
|
||||
def setdefault(self, key, default=None):
|
||||
"""Return value for key, set value to default if key is not present."""
|
||||
identity = self._title(key)
|
||||
for i, k, v in self._impl._items:
|
||||
if i == identity:
|
||||
return v
|
||||
self.add(key, default)
|
||||
return default
|
||||
|
||||
def popone(self, key, default=_marker):
|
||||
"""Remove specified key and return the corresponding value.
|
||||
|
||||
If key is not found, d is returned if given, otherwise
|
||||
KeyError is raised.
|
||||
|
||||
"""
|
||||
identity = self._title(key)
|
||||
for i in range(len(self._impl._items)):
|
||||
if self._impl._items[i][0] == identity:
|
||||
value = self._impl._items[i][2]
|
||||
del self._impl._items[i]
|
||||
self._impl.incr_version()
|
||||
return value
|
||||
if default is _marker:
|
||||
raise KeyError(key)
|
||||
else:
|
||||
return default
|
||||
|
||||
pop = popone # type: ignore
|
||||
|
||||
def popall(self, key, default=_marker):
|
||||
"""Remove all occurrences of key and return the list of corresponding
|
||||
values.
|
||||
|
||||
If key is not found, default is returned if given, otherwise
|
||||
KeyError is raised.
|
||||
|
||||
"""
|
||||
found = False
|
||||
identity = self._title(key)
|
||||
ret = []
|
||||
for i in range(len(self._impl._items) - 1, -1, -1):
|
||||
item = self._impl._items[i]
|
||||
if item[0] == identity:
|
||||
ret.append(item[2])
|
||||
del self._impl._items[i]
|
||||
self._impl.incr_version()
|
||||
found = True
|
||||
if not found:
|
||||
if default is _marker:
|
||||
raise KeyError(key)
|
||||
else:
|
||||
return default
|
||||
else:
|
||||
ret.reverse()
|
||||
return ret
|
||||
|
||||
def popitem(self):
|
||||
"""Remove and return an arbitrary (key, value) pair."""
|
||||
if self._impl._items:
|
||||
i = self._impl._items.pop(0)
|
||||
self._impl.incr_version()
|
||||
return i[1], i[2]
|
||||
else:
|
||||
raise KeyError("empty multidict")
|
||||
|
||||
def update(self, *args, **kwargs):
|
||||
"""Update the dictionary from *other*, overwriting existing keys."""
|
||||
self._extend(args, kwargs, "update", self._update_items)
|
||||
|
||||
def _update_items(self, items):
|
||||
if not items:
|
||||
return
|
||||
used_keys = {}
|
||||
for identity, key, value in items:
|
||||
start = used_keys.get(identity, 0)
|
||||
for i in range(start, len(self._impl._items)):
|
||||
item = self._impl._items[i]
|
||||
if item[0] == identity:
|
||||
used_keys[identity] = i + 1
|
||||
self._impl._items[i] = (identity, key, value)
|
||||
break
|
||||
else:
|
||||
self._impl._items.append((identity, key, value))
|
||||
used_keys[identity] = len(self._impl._items)
|
||||
|
||||
# drop tails
|
||||
i = 0
|
||||
while i < len(self._impl._items):
|
||||
item = self._impl._items[i]
|
||||
identity = item[0]
|
||||
pos = used_keys.get(identity)
|
||||
if pos is None:
|
||||
i += 1
|
||||
continue
|
||||
if i >= pos:
|
||||
del self._impl._items[i]
|
||||
else:
|
||||
i += 1
|
||||
|
||||
self._impl.incr_version()
|
||||
|
||||
def _replace(self, key, value):
|
||||
key = self._key(key)
|
||||
identity = self._title(key)
|
||||
items = self._impl._items
|
||||
|
||||
for i in range(len(items)):
|
||||
item = items[i]
|
||||
if item[0] == identity:
|
||||
items[i] = (identity, key, value)
|
||||
# i points to last found item
|
||||
rgt = i
|
||||
self._impl.incr_version()
|
||||
break
|
||||
else:
|
||||
self._impl._items.append((identity, key, value))
|
||||
self._impl.incr_version()
|
||||
return
|
||||
|
||||
# remove all tail items
|
||||
i = rgt + 1
|
||||
while i < len(items):
|
||||
item = items[i]
|
||||
if item[0] == identity:
|
||||
del items[i]
|
||||
else:
|
||||
i += 1
|
||||
|
||||
|
||||
class CIMultiDict(MultiDict):
|
||||
"""Dictionary with the support for duplicate case-insensitive keys."""
|
||||
|
||||
def _title(self, key):
|
||||
return key.title()
|
||||
|
||||
|
||||
class _Iter:
|
||||
__slots__ = ("_size", "_iter")
|
||||
|
||||
def __init__(self, size, iterator):
|
||||
self._size = size
|
||||
self._iter = iterator
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
return next(self._iter)
|
||||
|
||||
def __length_hint__(self):
|
||||
return self._size
|
||||
|
||||
|
||||
class _ViewBase:
|
||||
def __init__(self, impl):
|
||||
self._impl = impl
|
||||
|
||||
def __len__(self):
|
||||
return len(self._impl._items)
|
||||
|
||||
|
||||
class _ItemsView(_ViewBase, abc.ItemsView):
|
||||
def __contains__(self, item):
|
||||
assert isinstance(item, tuple) or isinstance(item, list)
|
||||
assert len(item) == 2
|
||||
for i, k, v in self._impl._items:
|
||||
if item[0] == k and item[1] == v:
|
||||
return True
|
||||
return False
|
||||
|
||||
def __iter__(self):
|
||||
return _Iter(len(self), self._iter(self._impl._version))
|
||||
|
||||
def _iter(self, version):
|
||||
for i, k, v in self._impl._items:
|
||||
if version != self._impl._version:
|
||||
raise RuntimeError("Dictionary changed during iteration")
|
||||
yield k, v
|
||||
|
||||
def __repr__(self):
|
||||
lst = []
|
||||
for item in self._impl._items:
|
||||
lst.append("{!r}: {!r}".format(item[1], item[2]))
|
||||
body = ", ".join(lst)
|
||||
return "{}({})".format(self.__class__.__name__, body)
|
||||
|
||||
|
||||
class _ValuesView(_ViewBase, abc.ValuesView):
|
||||
def __contains__(self, value):
|
||||
for item in self._impl._items:
|
||||
if item[2] == value:
|
||||
return True
|
||||
return False
|
||||
|
||||
def __iter__(self):
|
||||
return _Iter(len(self), self._iter(self._impl._version))
|
||||
|
||||
def _iter(self, version):
|
||||
for item in self._impl._items:
|
||||
if version != self._impl._version:
|
||||
raise RuntimeError("Dictionary changed during iteration")
|
||||
yield item[2]
|
||||
|
||||
def __repr__(self):
|
||||
lst = []
|
||||
for item in self._impl._items:
|
||||
lst.append("{!r}".format(item[2]))
|
||||
body = ", ".join(lst)
|
||||
return "{}({})".format(self.__class__.__name__, body)
|
||||
|
||||
|
||||
class _KeysView(_ViewBase, abc.KeysView):
|
||||
def __contains__(self, key):
|
||||
for item in self._impl._items:
|
||||
if item[1] == key:
|
||||
return True
|
||||
return False
|
||||
|
||||
def __iter__(self):
|
||||
return _Iter(len(self), self._iter(self._impl._version))
|
||||
|
||||
def _iter(self, version):
|
||||
for item in self._impl._items:
|
||||
if version != self._impl._version:
|
||||
raise RuntimeError("Dictionary changed during iteration")
|
||||
yield item[1]
|
||||
|
||||
def __repr__(self):
|
||||
lst = []
|
||||
for item in self._impl._items:
|
||||
lst.append("{!r}".format(item[1]))
|
||||
body = ", ".join(lst)
|
||||
return "{}({})".format(self.__class__.__name__, body)
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef _MULTIDICT_DEFS_H
|
||||
#define _MULTIDICT_DEFS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
_Py_IDENTIFIER(lower);
|
||||
|
||||
/* We link this module statically for convenience. If compiled as a shared
|
||||
library instead, some compilers don't allow addresses of Python objects
|
||||
defined in other libraries to be used in static initializers here. The
|
||||
DEFERRED_ADDRESS macro is used to tag the slots where such addresses
|
||||
appear; the module init function must fill in the tagged slots at runtime.
|
||||
The argument is for documentation -- the macro ignores it.
|
||||
*/
|
||||
#define DEFERRED_ADDRESS(ADDR) 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef _MULTIDICT_C_H
|
||||
#define _MULTIDICT_C_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct { // 16 or 24 for GC prefix
|
||||
PyObject_HEAD // 16
|
||||
PyObject *weaklist;
|
||||
pair_list_t pairs;
|
||||
} MultiDictObject;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *weaklist;
|
||||
MultiDictObject *md;
|
||||
} MultiDictProxyObject;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
#ifndef _MULTIDICT_ISTR_H
|
||||
#define _MULTIDICT_ISTR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
PyUnicodeObject str;
|
||||
PyObject * canonical;
|
||||
} istrobject;
|
||||
|
||||
PyDoc_STRVAR(istr__doc__, "istr class implementation");
|
||||
|
||||
static PyTypeObject istr_type;
|
||||
|
||||
static inline void
|
||||
istr_dealloc(istrobject *self)
|
||||
{
|
||||
Py_XDECREF(self->canonical);
|
||||
PyUnicode_Type.tp_dealloc((PyObject*)self);
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
istr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *x = NULL;
|
||||
static char *kwlist[] = {"object", "encoding", "errors", 0};
|
||||
PyObject *encoding = NULL;
|
||||
PyObject *errors = NULL;
|
||||
PyObject *s = NULL;
|
||||
PyObject * ret = NULL;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO:str",
|
||||
kwlist, &x, &encoding, &errors)) {
|
||||
return NULL;
|
||||
}
|
||||
if (x != NULL && Py_TYPE(x) == &istr_type) {
|
||||
Py_INCREF(x);
|
||||
return x;
|
||||
}
|
||||
ret = PyUnicode_Type.tp_new(type, args, kwds);
|
||||
if (!ret) {
|
||||
goto fail;
|
||||
}
|
||||
s =_PyObject_CallMethodId(ret, &PyId_lower, NULL);
|
||||
if (!s) {
|
||||
goto fail;
|
||||
}
|
||||
((istrobject*)ret)->canonical = s;
|
||||
s = NULL; /* the reference is stollen by .canonical */
|
||||
return ret;
|
||||
fail:
|
||||
Py_XDECREF(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyTypeObject istr_type = {
|
||||
PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
|
||||
"multidict._multidict.istr",
|
||||
sizeof(istrobject),
|
||||
.tp_dealloc = (destructor)istr_dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT
|
||||
| Py_TPFLAGS_BASETYPE
|
||||
| Py_TPFLAGS_UNICODE_SUBCLASS,
|
||||
.tp_doc = istr__doc__,
|
||||
.tp_base = DEFERRED_ADDRESS(&PyUnicode_Type),
|
||||
.tp_new = (newfunc)istr_new,
|
||||
};
|
||||
|
||||
|
||||
static inline int
|
||||
istr_init(void)
|
||||
{
|
||||
istr_type.tp_base = &PyUnicode_Type;
|
||||
if (PyType_Ready(&istr_type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,238 @@
|
||||
#ifndef _MULTIDICT_ITER_H
|
||||
#define _MULTIDICT_ITER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static PyTypeObject multidict_items_iter_type;
|
||||
static PyTypeObject multidict_values_iter_type;
|
||||
static PyTypeObject multidict_keys_iter_type;
|
||||
|
||||
typedef struct multidict_iter {
|
||||
PyObject_HEAD
|
||||
MultiDictObject *md; // MultiDict or CIMultiDict
|
||||
Py_ssize_t current;
|
||||
uint64_t version;
|
||||
} MultidictIter;
|
||||
|
||||
static inline void
|
||||
_init_iter(MultidictIter *it, MultiDictObject *md)
|
||||
{
|
||||
Py_INCREF(md);
|
||||
|
||||
it->md = md;
|
||||
it->current = 0;
|
||||
it->version = pair_list_version(&md->pairs);
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_items_iter_new(MultiDictObject *md)
|
||||
{
|
||||
MultidictIter *it = PyObject_GC_New(
|
||||
MultidictIter, &multidict_items_iter_type);
|
||||
if (it == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_init_iter(it, md);
|
||||
|
||||
PyObject_GC_Track(it);
|
||||
return (PyObject *)it;
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_keys_iter_new(MultiDictObject *md)
|
||||
{
|
||||
MultidictIter *it = PyObject_GC_New(
|
||||
MultidictIter, &multidict_keys_iter_type);
|
||||
if (it == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_init_iter(it, md);
|
||||
|
||||
PyObject_GC_Track(it);
|
||||
return (PyObject *)it;
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_values_iter_new(MultiDictObject *md)
|
||||
{
|
||||
MultidictIter *it = PyObject_GC_New(
|
||||
MultidictIter, &multidict_values_iter_type);
|
||||
if (it == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_init_iter(it, md);
|
||||
|
||||
PyObject_GC_Track(it);
|
||||
return (PyObject *)it;
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_items_iter_iternext(MultidictIter *self)
|
||||
{
|
||||
PyObject *key = NULL;
|
||||
PyObject *value = NULL;
|
||||
PyObject *ret = NULL;
|
||||
|
||||
if (self->version != pair_list_version(&self->md->pairs)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_pair_list_next(&self->md->pairs, &self->current, NULL, &key, &value, NULL)) {
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = PyTuple_Pack(2, key, value);
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_values_iter_iternext(MultidictIter *self)
|
||||
{
|
||||
PyObject *value = NULL;
|
||||
|
||||
if (self->version != pair_list_version(&self->md->pairs)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!pair_list_next(&self->md->pairs, &self->current, NULL, NULL, &value)) {
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_keys_iter_iternext(MultidictIter *self)
|
||||
{
|
||||
PyObject *key = NULL;
|
||||
|
||||
if (self->version != pair_list_version(&self->md->pairs)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Dictionary changed during iteration");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!pair_list_next(&self->md->pairs, &self->current, NULL, &key, NULL)) {
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(key);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static inline void
|
||||
multidict_iter_dealloc(MultidictIter *self)
|
||||
{
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_XDECREF(self->md);
|
||||
PyObject_GC_Del(self);
|
||||
}
|
||||
|
||||
static inline int
|
||||
multidict_iter_traverse(MultidictIter *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->md);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
multidict_iter_clear(MultidictIter *self)
|
||||
{
|
||||
Py_CLEAR(self->md);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_iter_len(MultidictIter *self)
|
||||
{
|
||||
return PyLong_FromLong(pair_list_len(&self->md->pairs));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(length_hint_doc,
|
||||
"Private method returning an estimate of len(list(it)).");
|
||||
|
||||
static PyMethodDef multidict_iter_methods[] = {
|
||||
{
|
||||
"__length_hint__",
|
||||
(PyCFunction)(void(*)(void))multidict_iter_len,
|
||||
METH_NOARGS,
|
||||
length_hint_doc
|
||||
},
|
||||
{
|
||||
NULL,
|
||||
NULL
|
||||
} /* sentinel */
|
||||
};
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
static PyTypeObject multidict_items_iter_type = {
|
||||
PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
|
||||
"multidict._multidict._itemsiter", /* tp_name */
|
||||
sizeof(MultidictIter), /* tp_basicsize */
|
||||
.tp_dealloc = (destructor)multidict_iter_dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)multidict_iter_traverse,
|
||||
.tp_clear = (inquiry)multidict_iter_clear,
|
||||
.tp_iter = PyObject_SelfIter,
|
||||
.tp_iternext = (iternextfunc)multidict_items_iter_iternext,
|
||||
.tp_methods = multidict_iter_methods,
|
||||
};
|
||||
|
||||
static PyTypeObject multidict_values_iter_type = {
|
||||
PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
|
||||
"multidict._multidict._valuesiter", /* tp_name */
|
||||
sizeof(MultidictIter), /* tp_basicsize */
|
||||
.tp_dealloc = (destructor)multidict_iter_dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)multidict_iter_traverse,
|
||||
.tp_clear = (inquiry)multidict_iter_clear,
|
||||
.tp_iter = PyObject_SelfIter,
|
||||
.tp_iternext = (iternextfunc)multidict_values_iter_iternext,
|
||||
.tp_methods = multidict_iter_methods,
|
||||
};
|
||||
|
||||
static PyTypeObject multidict_keys_iter_type = {
|
||||
PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
|
||||
"multidict._multidict._keysiter", /* tp_name */
|
||||
sizeof(MultidictIter), /* tp_basicsize */
|
||||
.tp_dealloc = (destructor)multidict_iter_dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)multidict_iter_traverse,
|
||||
.tp_clear = (inquiry)multidict_iter_clear,
|
||||
.tp_iter = PyObject_SelfIter,
|
||||
.tp_iternext = (iternextfunc)multidict_keys_iter_iternext,
|
||||
.tp_methods = multidict_iter_methods,
|
||||
};
|
||||
|
||||
static inline int
|
||||
multidict_iter_init()
|
||||
{
|
||||
if (PyType_Ready(&multidict_items_iter_type) < 0 ||
|
||||
PyType_Ready(&multidict_values_iter_type) < 0 ||
|
||||
PyType_Ready(&multidict_keys_iter_type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,464 @@
|
||||
#ifndef _MULTIDICT_VIEWS_H
|
||||
#define _MULTIDICT_VIEWS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static PyTypeObject multidict_itemsview_type;
|
||||
static PyTypeObject multidict_valuesview_type;
|
||||
static PyTypeObject multidict_keysview_type;
|
||||
|
||||
static PyObject *viewbaseset_richcmp_func;
|
||||
static PyObject *viewbaseset_and_func;
|
||||
static PyObject *viewbaseset_or_func;
|
||||
static PyObject *viewbaseset_sub_func;
|
||||
static PyObject *viewbaseset_xor_func;
|
||||
|
||||
static PyObject *abc_itemsview_register_func;
|
||||
static PyObject *abc_keysview_register_func;
|
||||
static PyObject *abc_valuesview_register_func;
|
||||
|
||||
static PyObject *itemsview_isdisjoint_func;
|
||||
static PyObject *itemsview_repr_func;
|
||||
|
||||
static PyObject *keysview_repr_func;
|
||||
static PyObject *keysview_isdisjoint_func;
|
||||
|
||||
static PyObject *valuesview_repr_func;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *md;
|
||||
} _Multidict_ViewObject;
|
||||
|
||||
|
||||
/********** Base **********/
|
||||
|
||||
static inline void
|
||||
_init_view(_Multidict_ViewObject *self, PyObject *md)
|
||||
{
|
||||
Py_INCREF(md);
|
||||
self->md = md;
|
||||
}
|
||||
|
||||
static inline void
|
||||
multidict_view_dealloc(_Multidict_ViewObject *self)
|
||||
{
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_XDECREF(self->md);
|
||||
PyObject_GC_Del(self);
|
||||
}
|
||||
|
||||
static inline int
|
||||
multidict_view_traverse(_Multidict_ViewObject *self, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(self->md);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
multidict_view_clear(_Multidict_ViewObject *self)
|
||||
{
|
||||
Py_CLEAR(self->md);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline Py_ssize_t
|
||||
multidict_view_len(_Multidict_ViewObject *self)
|
||||
{
|
||||
return pair_list_len(&((MultiDictObject*)self->md)->pairs);
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_view_richcompare(PyObject *self, PyObject *other, int op)
|
||||
{
|
||||
PyObject *ret;
|
||||
PyObject *op_obj = PyLong_FromLong(op);
|
||||
if (op_obj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret = PyObject_CallFunctionObjArgs(
|
||||
viewbaseset_richcmp_func, self, other, op_obj, NULL);
|
||||
Py_DECREF(op_obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_view_and(PyObject *self, PyObject *other)
|
||||
{
|
||||
return PyObject_CallFunctionObjArgs(
|
||||
viewbaseset_and_func, self, other, NULL);
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_view_or(PyObject *self, PyObject *other)
|
||||
{
|
||||
return PyObject_CallFunctionObjArgs(
|
||||
viewbaseset_or_func, self, other, NULL);
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_view_sub(PyObject *self, PyObject *other)
|
||||
{
|
||||
return PyObject_CallFunctionObjArgs(
|
||||
viewbaseset_sub_func, self, other, NULL);
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_view_xor(PyObject *self, PyObject *other)
|
||||
{
|
||||
return PyObject_CallFunctionObjArgs(
|
||||
viewbaseset_xor_func, self, other, NULL);
|
||||
}
|
||||
|
||||
static PyNumberMethods multidict_view_as_number = {
|
||||
.nb_subtract = (binaryfunc)multidict_view_sub,
|
||||
.nb_and = (binaryfunc)multidict_view_and,
|
||||
.nb_xor = (binaryfunc)multidict_view_xor,
|
||||
.nb_or = (binaryfunc)multidict_view_or,
|
||||
};
|
||||
|
||||
/********** Items **********/
|
||||
|
||||
static inline PyObject *
|
||||
multidict_itemsview_new(PyObject *md)
|
||||
{
|
||||
_Multidict_ViewObject *mv = PyObject_GC_New(
|
||||
_Multidict_ViewObject, &multidict_itemsview_type);
|
||||
if (mv == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_init_view(mv, md);
|
||||
|
||||
PyObject_GC_Track(mv);
|
||||
return (PyObject *)mv;
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_itemsview_iter(_Multidict_ViewObject *self)
|
||||
{
|
||||
return multidict_items_iter_new((MultiDictObject*)self->md);
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_itemsview_repr(_Multidict_ViewObject *self)
|
||||
{
|
||||
return PyObject_CallFunctionObjArgs(
|
||||
itemsview_repr_func, self, NULL);
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_itemsview_isdisjoint(_Multidict_ViewObject *self, PyObject *other)
|
||||
{
|
||||
return PyObject_CallFunctionObjArgs(
|
||||
itemsview_isdisjoint_func, self, other, NULL);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(itemsview_isdisjoint_doc,
|
||||
"Return True if two sets have a null intersection.");
|
||||
|
||||
static PyMethodDef multidict_itemsview_methods[] = {
|
||||
{
|
||||
"isdisjoint",
|
||||
(PyCFunction)multidict_itemsview_isdisjoint,
|
||||
METH_O,
|
||||
itemsview_isdisjoint_doc
|
||||
},
|
||||
{
|
||||
NULL,
|
||||
NULL
|
||||
} /* sentinel */
|
||||
};
|
||||
|
||||
static inline int
|
||||
multidict_itemsview_contains(_Multidict_ViewObject *self, PyObject *obj)
|
||||
{
|
||||
PyObject *akey = NULL,
|
||||
*aval = NULL,
|
||||
*bkey = NULL,
|
||||
*bval = NULL,
|
||||
*iter = NULL,
|
||||
*item = NULL;
|
||||
int ret1, ret2;
|
||||
|
||||
if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bkey = PyTuple_GET_ITEM(obj, 0);
|
||||
bval = PyTuple_GET_ITEM(obj, 1);
|
||||
|
||||
iter = multidict_itemsview_iter(self);
|
||||
if (iter == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((item = PyIter_Next(iter)) != NULL) {
|
||||
akey = PyTuple_GET_ITEM(item, 0);
|
||||
aval = PyTuple_GET_ITEM(item, 1);
|
||||
|
||||
ret1 = PyObject_RichCompareBool(akey, bkey, Py_EQ);
|
||||
if (ret1 < 0) {
|
||||
Py_DECREF(iter);
|
||||
Py_DECREF(item);
|
||||
return -1;
|
||||
}
|
||||
ret2 = PyObject_RichCompareBool(aval, bval, Py_EQ);
|
||||
if (ret2 < 0) {
|
||||
Py_DECREF(iter);
|
||||
Py_DECREF(item);
|
||||
return -1;
|
||||
}
|
||||
if (ret1 > 0 && ret2 > 0)
|
||||
{
|
||||
Py_DECREF(iter);
|
||||
Py_DECREF(item);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Py_DECREF(item);
|
||||
}
|
||||
|
||||
Py_DECREF(iter);
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PySequenceMethods multidict_itemsview_as_sequence = {
|
||||
.sq_length = (lenfunc)multidict_view_len,
|
||||
.sq_contains = (objobjproc)multidict_itemsview_contains,
|
||||
};
|
||||
|
||||
static PyTypeObject multidict_itemsview_type = {
|
||||
PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
|
||||
"multidict._multidict._ItemsView", /* tp_name */
|
||||
sizeof(_Multidict_ViewObject), /* tp_basicsize */
|
||||
.tp_dealloc = (destructor)multidict_view_dealloc,
|
||||
.tp_repr = (reprfunc)multidict_itemsview_repr,
|
||||
.tp_as_number = &multidict_view_as_number,
|
||||
.tp_as_sequence = &multidict_itemsview_as_sequence,
|
||||
.tp_getattro = PyObject_GenericGetAttr,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)multidict_view_traverse,
|
||||
.tp_clear = (inquiry)multidict_view_clear,
|
||||
.tp_richcompare = multidict_view_richcompare,
|
||||
.tp_iter = (getiterfunc)multidict_itemsview_iter,
|
||||
.tp_methods = multidict_itemsview_methods,
|
||||
};
|
||||
|
||||
|
||||
/********** Keys **********/
|
||||
|
||||
static inline PyObject *
|
||||
multidict_keysview_new(PyObject *md)
|
||||
{
|
||||
_Multidict_ViewObject *mv = PyObject_GC_New(
|
||||
_Multidict_ViewObject, &multidict_keysview_type);
|
||||
if (mv == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_init_view(mv, md);
|
||||
|
||||
PyObject_GC_Track(mv);
|
||||
return (PyObject *)mv;
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_keysview_iter(_Multidict_ViewObject *self)
|
||||
{
|
||||
return multidict_keys_iter_new(((MultiDictObject*)self->md));
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_keysview_repr(_Multidict_ViewObject *self)
|
||||
{
|
||||
return PyObject_CallFunctionObjArgs(
|
||||
keysview_repr_func, self, NULL);
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_keysview_isdisjoint(_Multidict_ViewObject *self, PyObject *other)
|
||||
{
|
||||
return PyObject_CallFunctionObjArgs(
|
||||
keysview_isdisjoint_func, self, other, NULL);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(keysview_isdisjoint_doc,
|
||||
"Return True if two sets have a null intersection.");
|
||||
|
||||
static PyMethodDef multidict_keysview_methods[] = {
|
||||
{
|
||||
"isdisjoint",
|
||||
(PyCFunction)multidict_keysview_isdisjoint,
|
||||
METH_O,
|
||||
keysview_isdisjoint_doc
|
||||
},
|
||||
{
|
||||
NULL,
|
||||
NULL
|
||||
} /* sentinel */
|
||||
};
|
||||
|
||||
static inline int
|
||||
multidict_keysview_contains(_Multidict_ViewObject *self, PyObject *key)
|
||||
{
|
||||
return pair_list_contains(&((MultiDictObject*)self->md)->pairs, key);
|
||||
}
|
||||
|
||||
static PySequenceMethods multidict_keysview_as_sequence = {
|
||||
.sq_length = (lenfunc)multidict_view_len,
|
||||
.sq_contains = (objobjproc)multidict_keysview_contains,
|
||||
};
|
||||
|
||||
static PyTypeObject multidict_keysview_type = {
|
||||
PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
|
||||
"multidict._multidict._KeysView", /* tp_name */
|
||||
sizeof(_Multidict_ViewObject), /* tp_basicsize */
|
||||
.tp_dealloc = (destructor)multidict_view_dealloc,
|
||||
.tp_repr = (reprfunc)multidict_keysview_repr,
|
||||
.tp_as_number = &multidict_view_as_number,
|
||||
.tp_as_sequence = &multidict_keysview_as_sequence,
|
||||
.tp_getattro = PyObject_GenericGetAttr,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)multidict_view_traverse,
|
||||
.tp_clear = (inquiry)multidict_view_clear,
|
||||
.tp_richcompare = multidict_view_richcompare,
|
||||
.tp_iter = (getiterfunc)multidict_keysview_iter,
|
||||
.tp_methods = multidict_keysview_methods,
|
||||
};
|
||||
|
||||
|
||||
/********** Values **********/
|
||||
|
||||
static inline PyObject *
|
||||
multidict_valuesview_new(PyObject *md)
|
||||
{
|
||||
_Multidict_ViewObject *mv = PyObject_GC_New(
|
||||
_Multidict_ViewObject, &multidict_valuesview_type);
|
||||
if (mv == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_init_view(mv, md);
|
||||
|
||||
PyObject_GC_Track(mv);
|
||||
return (PyObject *)mv;
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_valuesview_iter(_Multidict_ViewObject *self)
|
||||
{
|
||||
return multidict_values_iter_new(((MultiDictObject*)self->md));
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
multidict_valuesview_repr(_Multidict_ViewObject *self)
|
||||
{
|
||||
return PyObject_CallFunctionObjArgs(
|
||||
valuesview_repr_func, self, NULL);
|
||||
}
|
||||
|
||||
static PySequenceMethods multidict_valuesview_as_sequence = {
|
||||
.sq_length = (lenfunc)multidict_view_len,
|
||||
};
|
||||
|
||||
static PyTypeObject multidict_valuesview_type = {
|
||||
PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
|
||||
"multidict._multidict._ValuesView", /* tp_name */
|
||||
sizeof(_Multidict_ViewObject), /* tp_basicsize */
|
||||
.tp_dealloc = (destructor)multidict_view_dealloc,
|
||||
.tp_repr = (reprfunc)multidict_valuesview_repr,
|
||||
.tp_as_sequence = &multidict_valuesview_as_sequence,
|
||||
.tp_getattro = PyObject_GenericGetAttr,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
.tp_traverse = (traverseproc)multidict_view_traverse,
|
||||
.tp_clear = (inquiry)multidict_view_clear,
|
||||
.tp_iter = (getiterfunc)multidict_valuesview_iter,
|
||||
};
|
||||
|
||||
|
||||
static inline int
|
||||
multidict_views_init()
|
||||
{
|
||||
PyObject *reg_func_call_result = NULL;
|
||||
PyObject *module = PyImport_ImportModule("multidict._multidict_base");
|
||||
if (module == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#define GET_MOD_ATTR(VAR, NAME) \
|
||||
VAR = PyObject_GetAttrString(module, NAME); \
|
||||
if (VAR == NULL) { \
|
||||
goto fail; \
|
||||
}
|
||||
|
||||
GET_MOD_ATTR(viewbaseset_richcmp_func, "_viewbaseset_richcmp");
|
||||
GET_MOD_ATTR(viewbaseset_and_func, "_viewbaseset_and");
|
||||
GET_MOD_ATTR(viewbaseset_or_func, "_viewbaseset_or");
|
||||
GET_MOD_ATTR(viewbaseset_sub_func, "_viewbaseset_sub");
|
||||
GET_MOD_ATTR(viewbaseset_xor_func, "_viewbaseset_xor");
|
||||
|
||||
GET_MOD_ATTR(abc_itemsview_register_func, "_abc_itemsview_register");
|
||||
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_repr_func, "_itemsview_repr");
|
||||
|
||||
GET_MOD_ATTR(keysview_repr_func, "_keysview_repr");
|
||||
GET_MOD_ATTR(keysview_isdisjoint_func, "_keysview_isdisjoint");
|
||||
|
||||
GET_MOD_ATTR(valuesview_repr_func, "_valuesview_repr");
|
||||
|
||||
if (PyType_Ready(&multidict_itemsview_type) < 0 ||
|
||||
PyType_Ready(&multidict_valuesview_type) < 0 ||
|
||||
PyType_Ready(&multidict_keysview_type) < 0)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// abc.ItemsView.register(_ItemsView)
|
||||
reg_func_call_result = PyObject_CallFunctionObjArgs(
|
||||
abc_itemsview_register_func, (PyObject*)&multidict_itemsview_type, NULL);
|
||||
if (reg_func_call_result == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
Py_DECREF(reg_func_call_result);
|
||||
|
||||
// abc.KeysView.register(_KeysView)
|
||||
reg_func_call_result = PyObject_CallFunctionObjArgs(
|
||||
abc_keysview_register_func, (PyObject*)&multidict_keysview_type, NULL);
|
||||
if (reg_func_call_result == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
Py_DECREF(reg_func_call_result);
|
||||
|
||||
// abc.ValuesView.register(_KeysView)
|
||||
reg_func_call_result = PyObject_CallFunctionObjArgs(
|
||||
abc_valuesview_register_func, (PyObject*)&multidict_valuesview_type, NULL);
|
||||
if (reg_func_call_result == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
Py_DECREF(reg_func_call_result);
|
||||
|
||||
Py_DECREF(module);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
Py_CLEAR(module);
|
||||
return -1;
|
||||
|
||||
#undef GET_MOD_ATTR
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
PEP-561 marker.
|
||||
Reference in New Issue
Block a user