bidict two-way maps, inverse views and duplicate key errors: working versions (tested 2026-10-15)
Use bidict and OrderedBidict as bidirectional maps, resolve key and value collisions with forceput and OnDup, and handle the dedicated duplication errors.
passed6 passed · 0 failed2026-10-15 21:56 UTC- Status
- passed
- Last passed
- 2026-10-15 21:56 UTC
- Tests
- 6 / 6
- Language
- Python
- Runtime
- Python 3.13.16
pinned versions2
bidict@0.24.1pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt .venv/bin/python -m pytest -q
test environment
Python 3.13.16 linux 6.17.0-1022-azure x64 runner: github-actions 38813530570
The code
Exactly the files that passed. Your agent can pull them with get_recipe("bidict-two-way-map") (install), or see them on GitHub.
requirements.txt
bidict==0.24.1 pytest==9.1.1
two_way_map.py
from bidict import ON_DUP_DROP_OLD, OrderedBidict
class NameRegistry:
"""Ordered two-way directory mapping usernames to numeric ids."""
def __init__(self):
self._names = OrderedBidict()
def register(self, username, user_id):
# DROP_OLD evicts any existing item that collides on key or value.
self._names.put(username, user_id, on_dup=ON_DUP_DROP_OLD)
def rename(self, username, new_user_id):
# __setitem__ overwrites a duplicate key silently but still guards values.
self._names[username] = new_user_id
def id_of(self, username):
return self._names[username]
def name_of(self, user_id):
return self._names.inverse[user_id]
tests/test_two_way_map.py
import pytest
from bidict import (
KeyAndValueDuplicationError,
KeyDuplicationError,
ValueDuplicationError,
bidict,
frozenbidict,
)
from two_way_map import NameRegistry
def test_inverse_lookup_is_live():
reg = NameRegistry()
reg.register("alice", 1)
reg.register("bob", 2)
assert reg.id_of("alice") == 1
assert reg.name_of(2) == "bob"
assert reg._names.inverse == {1: "alice", 2: "bob"}
def test_register_evicts_both_sides():
reg = NameRegistry()
reg.register("alice", 1)
reg.register("alice", 2)
assert reg.id_of("alice") == 2
reg.register("carol", 2)
assert reg.name_of(2) == "carol"
assert "alice" not in reg._names
def test_duplicate_value_raises_dedicated_error():
b = bidict({"alice": 1})
# DuplicationError is not a ValueError subclass, so catch the specific type.
with pytest.raises(ValueDuplicationError):
b["bob"] = 1
assert dict(b) == {"alice": 1}
def test_put_is_stricter_than_setitem():
b = bidict({"alice": 1})
with pytest.raises(KeyDuplicationError):
b.put("alice", 2)
b["alice"] = 2
assert b.inverse[2] == "alice"
def test_key_and_value_collision_is_its_own_error():
b = bidict({"alice": 1, "bob": 2})
with pytest.raises(KeyAndValueDuplicationError):
b.put("alice", 2)
def test_frozenbidict_is_hashable_and_immutable():
f = frozenbidict({"alice": 1})
assert {f: "ok"}[f] == "ok"
with pytest.raises(TypeError):
f["bob"] = 2
pytest.ini
[pytest] pythonpath = .
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
~/.cursor/mcp.json
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }.vscode/mcp.json
{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }~/.codeium/windsurf/mcp_config.json
{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }MCP settings
{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.