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 asMemoryStorage— 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()andRegistry.to_json()produce mappings of values only (they callsnapshot()and extract.value). Descriptions are intentionally omitted from that shallow JSON representation to keepto_json()focused on JSON-serializable payloads. -
If you want to persist descriptions you must use the Stored tuple form when calling
Registry.from_dict()orRegistry.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 ofStoredItemobjects which provide.valueand.description.from_dict(mapping),from_json(s)— classmethods to build a Registry from serialized data;from_dictaccepts 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().
- Mapping-like:
-
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
Kis bound tostr). The registry will raise on invalid keys (empty string, contains whitespace, or wrong type). to_dict()/to_json()intentionally drop descriptions. Usefrom_dict()/update()with Stored tuples if you need to preserve descriptions.- The
Storedalias (Tuple[Optional[V], Optional[str]]) is available atmnemoreg._typesfor 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
mainormaster, tag pushes matchingv*.*.*, pull requests tomain/master, andworkflow_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_TOKENsecret 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
pushtrigger (but PRs tomasterdo triggerpull_request). - Repository maintainers can tighten the workflow triggers (recommended): e.g. remove
pull_requesttrigger, only run publish on explicit tag push or manualworkflow_dispatch. - Ensure
MNEMOREG_PY_PI_TOKENis 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)
| File | Size | Uploaded | |
|---|---|---|---|
| mnemoreg-0.3.11.tar.gz | 28.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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
|