ProvenPin Install

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

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.