Skip to main content

A flexible registry system for Python applications with auto-loading capabilities

Project description

Any Registries

PyPI version Python versions

A flexible and powerful registry system for Python applications with auto-loading capabilities. This package provides a generic registry pattern that can be used to register and retrieve any type of object (functions, classes, constants, etc.) with support for automatic module discovery and loading.

Features

  • Generic Type Support: Register any type of object (functions, classes, constants)
  • Auto-loading: Automatically discover and load modules based on glob patterns
  • Multiple Registration Keys: Register objects with multiple keys simultaneously
  • Key Functions: Use custom functions to generate registration keys
  • Environment Integration: Respects PROJECT_ROOT and BASE_DIR environment variables
  • Lazy Loading: Optional lazy loading for better performance
  • Type Hints: Full typing support for better IDE experience

Installation

pip install any-registries

Quick Start

Basic Usage

from any_registries import Registry

# Create a registry
my_registry = Registry()

# Register a function
@my_registry.register("my_function")
def my_function():
    return "Hello, World!"

# Register a class
@my_registry.register("my_class")
class MyClass:
    def __init__(self, name):
        self.name = name

# Retrieve and use registered items
func = my_registry.get("my_function")
print(func())  # Output: Hello, World!

cls = my_registry.get("my_class")
instance = cls("test")
print(instance.name)  # Output: test

Auto-loading Modules

The registry can automatically discover and load modules based on file patterns:

from any_registries import Registry

# Create registry with auto-loading
registry = Registry()
registry.auto_load("**/handlers/*.py", "**/processors/*.py")

# Or chain the calls
registry = Registry().auto_load("**/handlers/*.py").auto_load("**/processors/*.py")

# Force loading (if lazy loading is disabled)
registry.force_load()

Custom Key Functions

Use a custom function to generate registration keys:

def name_key(obj):
    return obj.__name__

registry = Registry(key=name_key)

@registry.register()  # No key needed, will use function name
def my_named_function():
    return "Named function"

# Retrieve using the function name
func = registry.get("my_named_function")

Environment Variables

The registry respects environment variables for base path discovery:

import os

# Set environment variable
os.environ["PROJECT_ROOT"] = "/my/project/root"

# Registry will use PROJECT_ROOT as base_path
registry = Registry()

# Or use BASE_DIR if PROJECT_ROOT is not set
os.environ["BASE_DIR"] = "/my/base/dir"
registry = Registry()

Advanced Usage

Plugin System Example

Create a simple plugin system:

from any_registries import Registry

# Create a plugin registry
plugins = Registry()

@plugins.register("database")
class DatabasePlugin:
    def connect(self):
        return "Connected to database"

@plugins.register("cache")
class CachePlugin:
    def get(self, key):
        return f"Cache value for {key}"

# Use plugins
db = plugins.get("database")()
print(db.connect())  # Output: Connected to database

cache = plugins.get("cache")()
print(cache.get("user:123"))  # Output: Cache value for user:123

Handler Registry Example

Register and use different handlers:

from any_registries import Registry

# Create handler registry
handlers = Registry()

@handlers.register("json")
def handle_json(data):
    import json
    return json.loads(data)

@handlers.register("csv")
def handle_csv(data):
    import csv
    import io
    return list(csv.reader(io.StringIO(data)))

# Use handlers
json_handler = handlers.get("json")
result = json_handler('{"name": "test"}')
print(result)  # Output: {'name': 'test'}

Factory Pattern Example

Use registry as a factory:

from any_registries import Registry

# Vehicle factory
vehicles = Registry()

@vehicles.register("car")
class Car:
    def __init__(self, model):
        self.model = model

    def start(self):
        return f"{self.model} car started"

@vehicles.register("bike")
class Bike:
    def __init__(self, model):
        self.model = model

    def start(self):
        return f"{self.model} bike started"

# Factory function
def create_vehicle(vehicle_type, model):
    vehicle_class = vehicles.get(vehicle_type)
    return vehicle_class(model)

# Use factory
my_car = create_vehicle("car", "Toyota")
print(my_car.start())  # Output: Toyota car started

API Reference

Registry Class

class Registry(Generic[TYPE_KEY, TYPE_TARGET]):
    def __init__(
        self,
        base_path: str | None = None,
        auto_loads: list | None = None,
        key: Callable | None = None,
        lazy_load: bool = True,
    ) -> None:
        """
        Initialize a new Registry.

        Args:
            base_path: Base path for module discovery (defaults to environment variables)
            auto_loads: List of glob patterns for auto-loading modules
            key: Function to generate keys from registered objects
            lazy_load: Whether to load modules lazily (default: True)
        """

Methods

  • get(key): Retrieve a registered object by key
  • auto_load(*patterns): Add patterns for auto-loading modules
  • force_load(): Force loading of all auto-load modules
  • registry: Property to access the internal registry dictionary

Exceptions

  • ItemNotRegistered: Raised when trying to retrieve a non-existent key

Configuration Options

Lazy Loading

By default, modules are loaded lazily when first accessed. Disable lazy loading:

registry = Registry(lazy_load=False)

Base Path Priority

The registry determines the base path in this order:

  1. Explicit base_path parameter
  2. PROJECT_ROOT environment variable
  3. BASE_DIR environment variable
  4. Current working directory (os.getcwd())

Testing

Run the test suite:

# Install development dependencies
pip install -e .[dev]

# Run core tests
pytest tests/test_registry.py

# Run tests with coverage
pytest --cov=any_registries

Development

Setting up Development Environment

# Clone the repository
git clone https://github.com/Starscribers/python-packages.git
cd python-packages/any-registries

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install in development mode
pip install -e .[dev]

# Install pre-commit hooks
pre-commit install

# Run tests
pytest

# Format code
ruff format src/ tests/
ruff check src/ tests/

# Type checking
mypy src/

Use Cases

  • Plugin Systems: Register and discover plugins dynamically
  • Handler Registries: Map keys to handler functions or classes
  • Factory Patterns: Register classes and create instances by key
  • Command Patterns: Register command handlers
  • Strategy Patterns: Register different algorithms or strategies
  • Configuration Management: Register configuration handlers
  • Data Processing: Register different data processors or transformers

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure tests pass (pytest)
  6. Format code (ruff format and ruff check)
  7. Commit your changes (git commit -m 'Add amazing feature')
  8. Push to the branch (git push origin feature/amazing-feature)
  9. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog

Version 0.2.0

  • Initial release
  • Basic registry functionality
  • Auto-loading support
  • Type hints and comprehensive tests
  • Python 3.8+ support

Support

If you encounter any issues or have questions:

  1. Check the Issues page
  2. Create a new issue with detailed information
  3. Include Python version and error traceback

Related Projects

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

any_registries-0.3.0.tar.gz (8.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

any_registries-0.3.0-py3-none-any.whl (6.9 kB view details)

Uploaded Python 3

File details

Details for the file any_registries-0.3.0.tar.gz.

File metadata

  • Download URL: any_registries-0.3.0.tar.gz
  • Upload date:
  • Size: 8.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.5

File hashes

Hashes for any_registries-0.3.0.tar.gz
Algorithm Hash digest
SHA256 065b5aa496a509ffa346a7ce21e8a3934cbe58a29a4cb32fd8232c020ded66f9
MD5 48061ce6bcf79afac5c11eb955cce187
BLAKE2b-256 af25554da4f2c47b59ce8ed4f5ee5aa8542f1cac6e65dfdff391e42c1bd96023

See more details on using hashes here.

File details

Details for the file any_registries-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for any_registries-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fc95c58ef597d0ac0886837a121018df35cc32ecc673b72482bc48048efb37bf
MD5 3458e870b3e1edbb04f0f0e7a46aadfc
BLAKE2b-256 8217ce5eb1dccf1b08d0ac6696cad6e45d3dff80bb8d606cde093c036cb206de

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page