|
|
- from __future__ import absolute_import
-
- import sys
- from collections import abc
- from collections.abc import Iterable, Set
-
- from cpython.object cimport PyObject_Str, Py_NE, PyObject_RichCompare
-
- from ._abc import MultiMapping, MutableMultiMapping
- from ._istr import istr
-
- from ._multidict_iter cimport *
- from ._multidict_views cimport *
- from ._pair_list cimport *
-
- cdef object _marker = object()
-
- upstr = istr # for relaxing backward compatibility problems
- cdef object _istr = istr
-
- pair_list_init(istr)
- # multidict_iter_init()
- multidict_views_init()
-
- def getversion(_Base md):
- return pair_list_version(md._impl)
-
-
- cdef class _Base:
-
- cdef object _impl
-
- def impl(self):
- return self._impl
-
- def getall(self, key, default=_marker):
- """Return a list of all values matching the key."""
- try:
- return pair_list_get_all(self._impl, key)
- except KeyError:
- if default is not _marker:
- return default
- else:
- raise
-
- def getone(self, key, default=_marker):
- """Get first value matching the key."""
- return self._getone(key, default)
-
- cdef _getone(self, key, default):
- try:
- return pair_list_get_one(self._impl, key)
- except KeyError:
- if default is not _marker:
- return default
- else:
- raise
-
- # Mapping interface #
-
- def __getitem__(self, key):
- return self._getone(key, _marker)
-
- def get(self, key, default=None):
- """Get first value matching the key.
-
- The method is alias for .getone().
- """
- return self._getone(key, default)
-
- def __contains__(self, key):
- return self._contains(key)
-
- cdef _contains(self, key):
- return pair_list_contains(self._impl, key)
-
- def __iter__(self):
- return iter(self.keys())
-
- def __len__(self):
- return pair_list_len(self._impl)
-
- cpdef keys(self):
- """Return a new view of the dictionary's keys."""
- return multidict_keysview_new(self)
-
- def items(self):
- """Return a new view of the dictionary's items *(key, value) pairs)."""
- return multidict_itemsview_new(self)
-
- def values(self):
- """Return a new view of the dictionary's values."""
- return multidict_valuesview_new(self)
-
- def __repr__(self):
- lst = []
- for k, v in self.items():
- lst.append("'{}': {!r}".format(k, v))
- body = ', '.join(lst)
- return '<{}({})>'.format(self.__class__.__name__, body)
-
- def __eq__(self, arg):
- cdef Py_ssize_t pos1
- cdef PyObject *identity1
- cdef PyObject *value1
- cdef Py_hash_t h1
-
- cdef Py_ssize_t pos2
- cdef PyObject *identity2
- cdef PyObject *value2
- cdef Py_hash_t h2
-
- cdef _Base other
-
- if isinstance(arg, _Base):
- other = <_Base>arg
- if pair_list_len(self._impl) != pair_list_len(other._impl):
- return False
- pos1 = pos2 = 0
- while (_pair_list_next(self._impl, &pos1, &identity1,
- NULL, &value1, &h1) and
- _pair_list_next(other._impl, &pos2, &identity2,
- NULL, &value2, &h2)):
- if h1 != h2:
- return False
- if PyObject_RichCompare(<object>identity1, <object>identity2, Py_NE):
- return False
- if PyObject_RichCompare(<object>value1, <object>value2, Py_NE):
- return False
- return True
- elif isinstance(arg, abc.Mapping):
- return bool(pair_list_eq_to_mapping(self._impl, arg))
- else:
- return NotImplemented
-
-
- cdef class MultiDictProxy(_Base):
- _proxy_classes = (MultiDict, MultiDictProxy)
- _base_class = MultiDict
-
- def __init__(self, arg):
- cdef _Base base
- if not isinstance(arg, self._proxy_classes):
- raise TypeError(
- 'ctor requires {} instance'
- ', not {}'.format(
- ' or '.join(self._proxy_classes),
- type(arg)))
-
- base = arg
- self._impl = base._impl
-
- def __reduce__(self):
- raise TypeError("can't pickle {} objects"
- .format(self.__class__.__name__))
-
- def copy(self):
- """Return a copy of itself."""
- return self._base_class(self)
-
- MultiMapping.register(MultiDictProxy)
-
-
- cdef class CIMultiDictProxy(MultiDictProxy):
- _proxy_classes = (CIMultiDict, CIMultiDictProxy)
- _base_class = CIMultiDict
-
-
- MultiMapping.register(CIMultiDictProxy)
-
-
- cdef str _str(key):
- typ = type(key)
- if typ is str:
- return <str>key
- if typ is _istr:
- return PyObject_Str(key)
- elif issubclass(typ, str):
- return str(key)
- else:
- raise TypeError("MultiDict keys should be either str "
- "or subclasses of str")
-
-
- cdef class MultiDict(_Base):
- """An ordered dictionary that can have multiple values for each key."""
-
- def __init__(self, *args, **kwargs):
- self._impl = pair_list_new()
- self._extend(args, kwargs, 'MultiDict', True)
-
- def __reduce__(self):
- return (
- self.__class__,
- (list(self.items()),)
- )
-
- cdef _extend(self, tuple args, dict kwargs, name, bint do_add):
- cdef object key
- cdef object value
- cdef object arg
- cdef object i
-
- if len(args) > 1:
- raise TypeError("{} takes at most 1 positional argument"
- " ({} given)".format(name, len(args)))
-
- if args:
- arg = args[0]
- if isinstance(arg, _Base) and not kwargs:
- if do_add:
- self._append_items((<_Base>arg)._impl)
- else:
- self._update_items((<_Base>arg)._impl)
- else:
- if hasattr(arg, 'items'):
- arg = arg.items()
- if kwargs:
- arg = list(arg)
- arg.extend(list(kwargs.items()))
- if do_add:
- self._append_items_seq(arg, name)
- else:
- pair_list_update_from_seq(self._impl, arg)
- else:
- arg = list(kwargs.items())
- if do_add:
- self._append_items_seq(arg, name)
- else:
- pair_list_update_from_seq(self._impl, arg)
-
- cdef object _update_items(self, object impl):
- pair_list_update(self._impl, impl)
-
- cdef object _append_items(self, object impl):
- cdef PyObject *key
- cdef PyObject *val
- cdef Py_ssize_t pos
- pos = 0
- while _pair_list_next(impl, &pos, NULL, &key, &val, NULL):
- self._add(<object>key, <object>val)
-
- cdef object _append_items_seq(self, object arg, object name):
- cdef object i
- cdef object key
- cdef object value
- for i in arg:
- if not len(i) == 2:
- raise TypeError(
- "{} takes either dict or list of (key, value) "
- "tuples".format(name))
- key = i[0]
- value = i[1]
- self._add(key, value)
-
- cdef _add(self, key, value):
- pair_list_add(self._impl, key, value);
-
- cdef _replace(self, key, value):
- pair_list_replace(self._impl, key, value)
-
- def add(self, key, value):
- """Add the key and value, not overwriting any previous value."""
- self._add(key, value)
-
- def copy(self):
- """Return a copy of itself."""
- ret = MultiDict()
- ret._extend((list(self.items()),), {}, 'copy', True)
- return ret
-
- def extend(self, *args, **kwargs):
- """Extend current MultiDict with more values.
-
- This method must be used instead of update.
- """
- self._extend(args, kwargs, "extend", True)
-
- def clear(self):
- """Remove all items from MultiDict"""
- pair_list_clear(self._impl)
-
- # MutableMapping interface #
-
- def __setitem__(self, key, value):
- self._replace(key, value)
-
- def __delitem__(self, key):
- pair_list_del(self._impl, key)
-
- def setdefault(self, key, default=None):
- """Return value for key, set value to default if key is not present."""
- return pair_list_set_default(self._impl, key, default)
-
- def popone(self, key, default=_marker):
- """Remove the last occurrence of key and return the corresponding
- value.
-
- If key is not found, default is returned if given, otherwise
- KeyError is raised.
-
- """
- try:
- return pair_list_pop_one(self._impl, key)
- except KeyError:
- if default is _marker:
- raise
- else:
- return default
-
- pop = popone
-
- 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.
-
- """
- try:
- return pair_list_pop_all(self._impl, key)
- except KeyError:
- if default is _marker:
- raise
- else:
- return default
-
- def popitem(self):
- """Remove and return an arbitrary (key, value) pair."""
- return pair_list_pop_item(self._impl)
-
- def update(self, *args, **kwargs):
- """Update the dictionary from *other*, overwriting existing keys."""
- self._extend(args, kwargs, "update", False)
-
-
- MutableMultiMapping.register(MultiDict)
-
-
- cdef class CIMultiDict(MultiDict):
- """An ordered dictionary that can have multiple values for each key."""
-
- def __init__(self, *args, **kwargs):
- self._impl = ci_pair_list_new()
- self._extend(args, kwargs, 'CIMultiDict', True)
-
- def __reduce__(self):
- return (
- self.__class__,
- (list(self.items()),),
- )
-
- def copy(self):
- """Return a copy of itself."""
- ret = CIMultiDict()
- ret._extend((list(self.items()),), {}, 'copy', True)
- return ret
-
-
- MutableMultiMapping.register(CIMultiDict)
-
|