Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MicroReg

PyPI version Python License: MIT Checked with mypy

A lightweight, zero-dependency Python library for registering, discovering, and managing functions or classes with attached metadata.

MicroReg acts as a strict, flat-namespace catalog for software components — useful for plugin systems, sensor registries, tool catalogs, and anything that benefits from a central lookup table of callables.


Features

  • Zero dependencies — standard library only
  • Strict uniqueness — duplicate names raise an error immediately; no silent overwrites
  • Passive storage — metadata is stored as-is; no schema validation
  • Dynamic discovery — auto-import modules to trigger decorator-based registrations
  • Fully typed — passes mypy --strict

Installation

pip install micro-reg

Requires Python 3.10+.


Quickstart

from micro_reg import Registry

reg = Registry("hardware_tools")

@reg.register(name="read_voltage", type="sensor", unit="V")
def read_voltage() -> float:
    return 5.0

func, meta = reg.get("read_voltage")
print(func())   # 5.0
print(meta)     # {'type': 'sensor', 'unit': 'V'}

API Reference

Registry(name: str)

Creates a new registry with a given label. The label is for identification only and does not affect behaviour.

reg = Registry("my_tools")
print(reg.name)  # "my_tools"

@reg.register(name: str, **metadata)

Decorator that registers a callable under a unique name with optional metadata.

@reg.register(name="greet", language="en")
def greet() -> str:
    return "hello"
  • name must be unique within the registry.
  • Any additional keyword arguments are stored as metadata.
  • The original callable is returned unwrapped — its behaviour is unchanged.

Raises: DuplicateRegistrationError if name is already registered.


reg.get(name: str) -> tuple[Callable, dict]

Retrieves a registered callable and its metadata by name.

func, meta = reg.get("greet")
func()   # "hello"
meta     # {"language": "en"}

Raises: KeyError if name is not registered.


reg.discover(search_path: str) -> None

Dynamically imports all Python modules found under search_path. Any module that uses @reg.register(...) at the top level will trigger those registrations as a side effect of being imported.

reg.discover("/path/to/plugins")

Raises:

  • FileNotFoundError if the path does not exist.
  • NotADirectoryError if the path is not a directory.

See Advanced: Discovery for a full example.


DuplicateRegistrationError

Raised when attempting to register a name that already exists in the registry.

from micro_reg import DuplicateRegistrationError

try:
    @reg.register(name="read_voltage")
    def another_sensor() -> float:
        return 0.0
except DuplicateRegistrationError as e:
    print(e.name)   # "read_voltage"
    print(e)        # Name already registered: 'read_voltage'

Attributes:

  • name: str — the name that caused the conflict.

Advanced: Discovery

The discovery pattern is useful for plugin systems where callables live in separate modules and should be loaded automatically.

Directory layout:

my_project/
    plugins/
        __init__.py
        sensors.py
        actuators.py
    main.py

plugins/sensors.py:

from main import reg

@reg.register(name="temperature", unit="C")
def read_temperature() -> float:
    return 22.5

plugins/actuators.py:

from main import reg

@reg.register(name="motor", type="actuator")
def spin_motor() -> bool:
    return True

main.py:

from micro_reg import Registry

reg = Registry("hardware")
reg.discover("plugins")

func, meta = reg.get("temperature")
print(func())   # 22.5
print(meta)     # {"unit": "C"}

discover() walks the directory, imports each module, and the decorators run as side effects — populating the registry without any manual wiring.


Error Handling

from micro_reg import Registry, DuplicateRegistrationError

reg = Registry("tools")

@reg.register(name="ping")
def ping() -> str:
    return "pong"

# Duplicate name
try:
    @reg.register(name="ping")
    def ping2() -> str:
        return "pong2"
except DuplicateRegistrationError as e:
    print(f"Conflict: {e.name}")  # Conflict: ping

# Missing name
try:
    reg.get("nonexistent")
except KeyError:
    print("Not found")

Examples

See the examples/ directory for runnable scripts:


Contributing

git clone https://gitlab.com/your-username/micro-reg.git
cd micro-reg
pip install -e ".[dev]"

# Run tests
pytest

# Type checking
mypy micro_reg --strict

# Lint & format
ruff check .
ruff format .

All public classes, methods, and functions require docstrings. Code must pass mypy --strict and ruff check before submitting.


License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages