Skip to main content

mnemoreg

A tiny, dependency-free, thread-safe registry mapping useful for registering callables and values by string keys. Designed to be embedded in other projects or used as a small standalone utility.

Key points

  • Small, stdlib-only implementation.
  • Thread-safe (uses RLock for mutations).
  • Simple decorator-based registration for callables.
  • Optional descriptions for stored values: each stored entry can carry an optional human-readable description (string) that is accessible via Registry.snapshot().

Quick facts

  • Package exports: Registry, AlreadyRegisteredError, NotRegisteredError, StorageProtocol, and __version__.
  • Main implementation: mnemoreg/core.py.
  • Storage helpers live in mnemoreg/_storage (default in-memory backend is exported as MemoryStorage — note: the name contains a historical typo).

Install

From PyPI:

pip install mnemoreg

From source (editable/development):

git clone https://github.com/i3iorn/mnemoreg.git
cd mnemoreg
python -m venv .venv
# Windows cmd.exe:
.venv\Scripts\activate
# PowerShell:
.venv\Scripts\Activate.ps1
# Unix/macOS:
source .venv/bin/activate

pip install -e .
# dev extras:
pip install -e .[dev]

Usage (quick)

The Registry behaves like a mapping from string keys to values. Examples:

from mnemoreg import Registry, OverwritePolicy

r = Registry[str, int]()
r['one'] = 1
assert r['one'] == 1

# decorator registration (explicit key) with optional description
@r.register('plus', description='adds one')
def plus(x: int) -> int:
    return x + 1

assert r['plus'](4) == 5

# decorator registration (uses function.__name__ when key omitted)
@r.register()
def multiply(x: int, y: int) -> int:
    return x * y

assert r['multiply'](3, 4) == 12

# bulk operations (acquires the same lock for the block)
with r.bulk():
    r['a'] = 1
    r['b'] = 2

# removal
del r['a']

# snapshot returns a mapping of StoredItem objects that wrap the value and expose an optional description
snap = r.snapshot()      # shallow dict copy; values are StoredItem objects
item = snap['plus']
assert item.value(2) == 3
assert item.description == 'adds one'

# to_dict / to_json produce a shallow mapping of *values* (descriptions are not included by default)
# if you need to persist descriptions you can use from_dict/update with the Stored tuple form described below.
s = r.to_json()          # JSON string of values only
new_r = Registry.from_json(s)

Storing descriptions and the Stored tuple

Internally, the storage backend stores entries as a 2-tuple (value, description). This is exposed via a convenient type alias in the library (see mnemoreg._types.Stored). The tuple form is:

(value_or_None, Optional[str])

Examples:

  • Register via decorator with description:

    @r.register('f', description='does something') def f(x): ...

  • Update or create entries using the Stored form (keeps description):

    Stored tuple (value, description)

    r.update({'a': (1, 'one')})

  • Create a Registry from a dict that already contains descriptions:

    new = Registry.from_dict({'k': (42, 'answer')})

Notes about serialization and round-tripping

  • Registry.to_dict() and Registry.to_json() produce mappings of values only (they call snapshot() and extract .value). Descriptions are intentionally omitted from that shallow JSON representation to keep to_json() focused on JSON-serializable payloads.

  • If you want to persist descriptions you must use the Stored tuple form when calling Registry.from_dict() or Registry.update() so the description is kept in the backend. Example:

    saved = registry._store.to_dict() # low-level store representation: {k: (value, description)} Registry.from_dict(saved)

API / behavior summary

  • class Registry(Generic[K, V])

    • Mapping-like: __getitem__, __setitem__, __delitem__, __iter__, __len__, __contains__.
    • register(key: Optional[str] = None, description: Optional[str] = None) — decorator to register functions/values with optional description.
    • get(key, default=None), snapshot() — read helpers. snapshot() returns a dict of StoredItem objects which provide .value and .description.
    • from_dict(mapping), from_json(s) — classmethods to build a Registry from serialized data; from_dict accepts either a plain mapping of values or the internal Stored tuple mapping (value, description).
    • to_json(**kwargs) — serialize shallowly to JSON (values only).
    • bulk() — context manager that acquires the registry lock for batched operations.
    • update(mapping), clear().
  • Overwrite behavior: controlled by OverwritePolicy (FORBID = 0, ALLOW = 1, WARN = 2). The default is FORBID.

  • Exceptions: AlreadyRegisteredError, NotRegisteredError.

Notes and caveats (important)

  • Keys must be strings (type parameter K is bound to str). The registry will raise on invalid keys (empty string, contains whitespace, or wrong type).
  • to_dict() / to_json() intentionally drop descriptions. Use from_dict()/update() with Stored tuples if you need to preserve descriptions.
  • The Stored alias (Tuple[Optional[V], Optional[str]]) is available at mnemoreg._types for advanced uses.

Development

This project uses pytest, ruff, black, isort, mypy, and pre-commit hooks.

Typical local developer setup:

python -m venv .venv
# activate the venv
pip install -e .[dev]

Run tests:

python -m pytest -q

Format / lint / checks (examples):

ruff check --fix .
isort --profile black .
black .
pre-commit run --all-files
python -m mypy mnemoreg --ignore-missing-imports

CI & publishing

There are GitHub Actions workflows under .github/workflows/.

The publish.yml workflow (current behavior):

  • Triggers on: push to main or master, tag pushes matching v*.*.*, pull requests to main/master, and workflow_dispatch.
  • The workflow runs tests, then attempts to determine/create a semver tag and push it, builds distributions, and (optionally) uploads to PyPI if the MNEMOREG_PY_PI_TOKEN secret is configured.

If you don't want to trigger the publish flow or accidental publishes:

  • Work from a fork and open PRs from the fork — forks cannot push tags to the upstream repo and won't have the PyPI secret.
  • Work on non-main branches; pushes to non-main branches do not trigger the push trigger (but PRs to master do trigger pull_request).
  • Repository maintainers can tighten the workflow triggers (recommended): e.g. remove pull_request trigger, only run publish on explicit tag push or manual workflow_dispatch.
  • Ensure MNEMOREG_PY_PI_TOKEN is never added unless you intend to publish.

Contributing

Please follow the project's code style (black/ruff/isort) and add tests for new behavior. Suggested flow for external contributors:

  • Fork the repo.
  • Create a feature branch in your fork and open a PR to master.
  • Add tests and run the test suite locally.

License

MIT — see the LICENSE file.

Maintainers

i3iorn

Metadata

Release files for mnemoreg 0.3.11

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mnemoreg 0.3.11
File Size Uploaded
mnemoreg-0.3.11.tar.gz 28.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mnemoreg 0.3.11
File Interpreter ABI Platform
mnemoreg-0.3.11-py3-none-any.whl Python 3 none any Details

Total release size: 40.8 kB

Release files / mnemoreg-0.3.11.tar.gz

Download URL mnemoreg-0.3.11.tar.gz
Size 28.5 kB
Tags Source
SHA-256 checksum
How to use checksums
f7fc792023268c6ccab86182ba1a423f8d81375ba352ca52daacfb6cb16d9991
BLAKE2b-256 checksum
How to use checksums
c5e964325660adebade62dea58645f113363856cfab874f6096554301ade582a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.14

Release files / mnemoreg-0.3.11-py3-none-any.whl

Download URL mnemoreg-0.3.11-py3-none-any.whl
Size 12.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d89c6f2ada8e89c989a26cf7ad75bde3d1d1b7d958c3e3e8eeeacd3a8500a0ad
BLAKE2b-256 checksum
How to use checksums
bd360f82bb35553c648c0753a3168d2aed99a2d06ee208b37386587d80b98c23
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.14

Release history Release notifications | RSS feed

This release

0.3.11 This release

2 release files

0.3.9

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page