Registry / http-networking / multidict

multidict

JSON →
library6.7.1pypypi✓ verified 52d ago

multidict is a mapping implementation that allows multiple values per key, mirroring the semantics of HTTP headers and query strings. It provides four concrete classes — MultiDict (mutable), MultiDictProxy (immutable view), CIMultiDict (case-insensitive mutable), and CIMultiDictProxy (case-insensitive immutable view) — plus the istr helper for pre-folded string keys. Current version is 6.7.1 (released January 2026). The library ships an optional C extension; release cadence is frequent patch releases with periodic minor releases adding features such as the new merge() method (6.6.0) and a hash-table backend replacing the previous O(N) array (6.5.0).

http-networkingserializationweb-framework
pip install multidict
Install & Compatibility
Where this runs
tested against v6.7.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.925 runs
installs and imports cleanly · install 0.0s · import 0.022s · 18.8MB
glibc
py 3.103.925 runs
installs and imports cleanly · install 1.9s · import 0.020s · 19MB
17MB installed
● package 17MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

MultiDict
from multidict import MultiDict
from multidict._multidict import MultiDict
Never import from the private _multidict (C) or _multidict_py (pure-Python) submodules directly; always import from the top-level multidict package.
CIMultiDict
from multidict import CIMultiDict
from multidict._multidict_py import CIMultiDict
Private submodule imports bypass the C/Python dispatch and are not part of the public API.
MultiDictProxy
from multidict import MultiDictProxy
MultiDictProxy raises TypeError if the argument is not a MultiDict instance — it cannot wrap a plain dict.
CIMultiDictProxy
from multidict import CIMultiDictProxy
CIMultiDictProxy raises TypeError if the argument is not a CIMultiDict instance.
istr
from multidict import istr
Use istr for pre-folded keys with CIMultiDict to avoid redundant lower() calls in hot paths.
getall
d.getall('key')
d['key']
d['key'] returns only the FIRST value for a key. Use getall() to retrieve all values for a duplicated key.

Demonstrates mutable MultiDict with duplicate keys, getall, add, and a case-insensitive CIMultiDict.

from multidict import MultiDict, MultiDictProxy, CIMultiDict, istr # --- Mutable multi-valued dict --- d = MultiDict([('a', 1), ('b', 2), ('a', 3)]) assert d['a'] == 1 # returns FIRST value only assert d.getall('a') == [1, 3] # all values for key d.add('b', 99) # append without replacing assert len(d) == 4 # --- set() replaces ALL entries for that key --- d['a'] = 99 assert d.getall('a') == [99] # --- Read-only proxy (dynamic view) --- proxy = MultiDictProxy(d) assert proxy['b'] == 2 d.add('b', 42) assert proxy.getall('b') == [2, 99, 42] # proxy reflects changes # --- Case-insensitive dict --- ci = CIMultiDict(Content_Type='application/json') assert 'content-type' in ci assert ci['CONTENT-TYPE'] == 'application/json' # --- istr for pre-folded keys (performance) --- HDR = istr('Content-Type') assert ci[HDR] == 'application/json' # --- merge (6.6+): copies key only if not already present --- base = MultiDict(a=1) base.merge(MultiDict(a=99, b=2)) assert base['a'] == 1 # not overwritten assert base['b'] == 2
Debug
Known issues
gotchad['key'] returns only the FIRST value for a duplicated key. Iterating .keys() yields ALL keys including duplicates. Use getall('key') to fetch every value.
fix
Replace d['key'] with d.getall('key') when multiple values per key are expected.
affects: all
gotchad['key'] = value replaces ALL existing entries for that key with a single entry, not just the first. Use d.add('key', value) to append without clobbering existing values.
fix
Use d.add(key, value) to append a value while preserving existing entries for the same key.
affects: all
breaking6.5.0 switched the internal storage from a linear array (O(N) lookups) to a hash table (O(1) lookups). MultiDict.add() and extend() are now 25-50% slower; single lookups are 25-50% faster and bulk operations are 2-3x faster. Code relying on iteration order of keys() after deletions may observe subtly different compaction behaviour.
fix
Upgrade to >=6.5.1 which fixes a resize-with-deleted-slots bug introduced in 6.5.0. Treat key iteration order as insertion-order stable but do not assume slot density.
affects: >=6.5.0
breakingMultiDictProxy and CIMultiDictProxy raise TypeError if passed a plain dict or any non-MultiDict mapping. They only accept the matching MultiDict subclass.
fix
Wrap the source mapping in MultiDict() first: MultiDictProxy(MultiDict(plain_dict)).
affects: all
gotchaSetting MULTIDICT_NO_EXTENSIONS=1 at runtime forces the pure-Python implementation even when the C extension wheel is installed. The pure-Python path is roughly 20-50x slower. This env var also suppresses C extension compilation at build time if set during pip install.
fix
Do not set MULTIDICT_NO_EXTENSIONS in production. For Alpine Linux / source builds without a C compiler, the pure-Python wheel is automatically used as a fallback starting with 6.x.
affects: all
deprecatedDirectly importing from private submodules multidict._multidict (C extension) or multidict._multidict_py (pure Python) is not part of the public API and can break across patch releases. The internal _Impl class was removed from the pure-Python implementation in 6.4.x.
fix
Always import from the top-level package: from multidict import MultiDict, CIMultiDict, ...
affects: all
gotchaCIMultiDict stores and returns keys as istr (a str subclass with preserved original case), not plain str. Identity or strict type checks against str will pass since istr derives from str, but isinstance checks for exactly str may differ from expectations when iterating keys.
fix
Use str(key) if you need a plain str, or compare with == rather than 'is'. istr is a subclass of str so equality checks work normally.
affects: >=6.3.0
gotcha`MultiDict` performs case-sensitive key lookups, while `CIMultiDict` performs case-insensitive lookups. If you are expecting case-insensitive behavior (e.g., when working with HTTP headers), ensure you are using `CIMultiDict`.
fix
For case-insensitive key access, use `CIMultiDict` instead of `MultiDict`. Ensure the object `ci` is an instance of `CIMultiDict` if you expect `assert 'content-type' in ci` to pass when only 'Content-Type' is present.
affects: all
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'multidict'
The `multidict` package is not installed in the Python environment being used, or there's a mismatch in virtual environments.
fix
Install the package using pip: `pip install multidict` or `python -m pip install multidict`.
ERROR: Could not build wheels for multidict, which is required to install pyproject.toml-based projects
This error occurs when `pip` cannot compile the optional C extension for `multidict` during installation. This often happens on systems without a C compiler, required Python development headers, or with newer Python versions (e.g., Python 3.12) for which pre-built wheels might not yet be available.
fix
Ensure you have a C compiler (e.g., Build Tools for Visual Studio on Windows, or `build-essential` on Debian/Ubuntu) and Python development headers installed. Alternatively, you can force the installation of the pure-Python version (which will be slower) using the environment variable: `MULTIDICT_NO_EXTENSIONS=1 pip install multidict`.
KeyError: 'some_key'
Attempting to access a key in a `MultiDict` (or its variants) using bracket notation `d['key']` when that key does not exist in the dictionary.
fix
Use the `.get()` method, which returns `None` or a specified default value if the key is not found, or check for key existence with `if 'key' in d:` before accessing. To get all values for a key, use `.getall('key')`.
AttributeError: 'MultiDict' object has no attribute 'iteritems'
This error typically occurs when migrating Python 2 code to Python 3. The `iteritems()`, `iterkeys()`, and `itervalues()` methods were removed in Python 3; `MultiDict` (like standard Python dictionaries) provides `items()`, `keys()`, and `values()` which return view objects.
fix
Replace `d.iteritems()` with `d.items()`, `d.iterkeys()` with `d.keys()`, and `d.itervalues()` with `d.values()`. These methods return view objects in Python 3, which behave similarly to iterators for looping.
TypeError: can't pickle multidict._multidict.CIMultiDictProxy objects
`CIMultiDictProxy` (and `MultiDictProxy`) are designed as immutable views (proxies) of underlying mutable multidicts and are explicitly not pickleable by design, mirroring Python's `types.MappingProxyType` behavior.
fix
If you need to serialize the data, convert the proxy object to a mutable `CIMultiDict` or a standard dictionary first. For example, `import pickle; dct = multidict.CIMultiDict(original_proxy); pickled_dct = pickle.dumps(dct)` or `pickled_dict = pickle.dumps(dict(original_proxy))`.
Upgrade
Version history
6.7.1latest on PyPI
Audit
Dependencies

No dependency data recorded yet.

Agent activity
12 hits · last 30 days
node
4
seranking-bot
4
ahrefsbot
2
Amazon
1
Resources