Skip to main content

A code generator for dependency injection (DI) in Python which is based on the mediator and factory patterns

Project description

Reactor DI for Python

CI Coverage Status PyPI version Python versions License: MIT

A code generator for dependency injection (DI) in Python which is based on the mediator and factory patterns.

Features

  • Two powerful decorators: @module and @law_of_demeter
  • Code generation approach: Generates DI code rather than runtime injection
  • Mediator pattern: Central coordination of dependencies
  • Factory pattern: Object creation abstraction
  • Type-safe: Full type hint support
  • Python 3.8+ support: Requires Python 3.8+ due to @cached_property usage

Installation

pip install reactor-di

Quick Start

from reactor_di import module, law_of_demeter, CachingStrategy

class DatabaseConfig:
    host = "localhost"
    port = 5432
    timeout = 30

@law_of_demeter("_config")
class DatabaseService:
    _config: DatabaseConfig
    _host: str      # Forwarded from config.host
    _port: int      # Forwarded from config.port
    _timeout: int   # Forwarded from config.timeout
    
    def connect(self) -> str:
        return f"Connected to {self._host}:{self._port} (timeout: {self._timeout}s)"

# Module: Automatic DI: Implements annotations as @cached_property functions
@module(CachingStrategy.NOT_THREAD_SAFE)
class AppModule:
    config: DatabaseConfig      # Directly instantiated
    database: DatabaseService   # Synthesized with dependencies

# Usage
app = AppModule()
db_service = app.database
print(db_service.connect())  # → "Connected to localhost:5432 (timeout: 30s)"

# Properties are cleanly forwarded
print(db_service._host)      # → "localhost" (from config.host)
print(db_service._timeout)   # → 30 (from config.timeout)

Examples

The examples/ directory contains testable examples that demonstrate all the features shown in this README:

  • quick_start.py - The complete Quick Start example above, converted to testable format
  • quick_start_advanced.py - Advanced quick start with inheritance patterns
  • caching_strategy.py - Demonstrates CachingStrategy.DISABLED vs CachingStrategy.NOT_THREAD_SAFE
  • stacked_decorators.py - Shows using multiple @law_of_demeter decorators on the same class
  • custom_prefix.py - Demonstrates custom prefix options (prefix='', prefix='cfg_', etc.)
  • side_effects.py - Tests side effect isolation during decoration

Running Examples

# Run all examples as tests
uv run pytest examples/

# Run a specific example
uv run pytest examples/quick_start.py

All examples are automatically tested as part of the CI pipeline to ensure they stay current with the codebase.

Architecture

Reactor DI uses a code generation approach with clean separation of concerns:

  • module.py - The @module decorator for dependency injection containers
  • law_of_demeter.py - The @law_of_demeter decorator for property forwarding
  • caching.py - Caching strategies (CachingStrategy.DISABLED, CachingStrategy.NOT_THREAD_SAFE)
  • type_utils.py - Simplified type checking utilities (Python 3.8+ stable APIs)

The decorators work together through simple hasattr checks - @law_of_demeter creates forwarding properties that @module recognizes as already implemented, enabling clean cooperation without complex validation logic.

Advanced Usage

Caching Strategies

from reactor_di import module, CachingStrategy

# No caching - components created fresh each time
@module(CachingStrategy.DISABLED)
class DevModule:
    service: MyService

# Cached components - same instance returned (not thread-safe)
@module(CachingStrategy.NOT_THREAD_SAFE)
class ProdModule:
    service: MyService

Multiple Decorator Integration

@law_of_demeter("_config")    # Creates forwarding properties
@law_of_demeter("_module")    # Auto-setup: self._config = self._module.config
class ResourceController:
    def __init__(self, module):
        self._module = module
        # Decorator automatically sets up: self._config = module.config
    
    # From _config
    _timeout: int
    _is_dry_run: bool
    
    # From _module  
    _api: object
    _namespace: str

Custom Prefixes

# No prefix - direct forwarding
@law_of_demeter('config', prefix='')
class DirectController:
    timeout: int        # → config.timeout
    is_dry_run: bool    # → config.is_dry_run

# Custom prefix
@law_of_demeter('config', prefix='cfg_')
class PrefixController:
    cfg_timeout: int        # → config.timeout
    cfg_is_dry_run: bool    # → config.is_dry_run

API Reference

Core Decorators

@module(strategy: CachingStrategy = CachingStrategy.DISABLED)

Creates a dependency injection module that automatically instantiates and provides dependencies.

Parameters:

  • strategy: Caching strategy for component instances
    • CachingStrategy.DISABLED: Create new instances each time (default)
    • CachingStrategy.NOT_THREAD_SAFE: Cache instances (not thread-safe)

Usage:

@module(CachingStrategy.NOT_THREAD_SAFE)
class AppModule:
    config: Config
    service: Service  # Automatically injected with dependencies

@law_of_demeter(base_ref: str, prefix: str = "_")

Creates property forwarding from a base reference to avoid Law of Demeter violations.

Parameters:

  • base_ref: Name of the base object attribute to forward from
  • prefix: Prefix for forwarded property names (default: "_")

Usage:

@law_of_demeter("_config")
class Service:
    _timeout: int     # Forwards to _config.timeout
    _host: str        # Forwards to _config.host

Type Utilities

The simplified type utilities leverage Python 3.8+ stable type hint APIs:

get_alternative_names(name: str, prefix: str = "_") -> List[str]

Generates alternative names for dependency mapping (e.g., _configconfig).

has_constructor_assignment(class_type: Type[Any], attr_name: str) -> bool

Detects if a constructor assigns to an attribute using regex source analysis.

is_primitive_type(attr_type: Type[Any]) -> bool

Identifies primitive types (int, str, bool, etc.) that shouldn't be auto-instantiated.

Enums

CachingStrategy

Component caching strategies for the @module decorator.

  • DISABLED = "disabled": No caching, create new instances each time
  • NOT_THREAD_SAFE = "not_thread_safe": Cache instances (not thread-safe)

Development

This project uses modern Python tooling and best practices:

Setup

  1. Clone the repository
  2. Install dependencies:
    uv sync
    

Running Tests

# Run tests without coverage (default, fast for development)
uv run pytest

# Run tests with coverage and HTML/terminal reports
uv run pytest --cov

# Run example tests
uv run pytest examples/                     # Run all examples as tests (20 tests)
uv run pytest examples/caching_strategy.py  # Caching strategy examples (3 tests)
uv run pytest examples/custom_prefix.py     # Custom prefix examples (6 tests)
uv run pytest examples/quick_start.py       # Quick start examples (4 tests)

Debugging in PyCharm

The project is optimized for fast development and debugging:

  1. Default: Tests run without coverage for fast feedback and debugging
  2. Coverage analysis: Use --cov flag when you need coverage reports
  3. Coverage threshold: Set to 90% to maintain high code quality (when coverage is enabled)

This configuration ensures breakpoints work reliably and tests run quickly during development.

Code Quality

# Run linting
uv run ruff check src tests examples
uv run black --check src tests examples

# Run type checking
uv run mypy src

# Fix formatting
uv run black src tests examples

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests for new functionality with meaningful assertions
  5. Ensure all tests pass and 90% coverage is maintained
  6. Verify realistic code scenarios rather than mocking impossible edge cases
  7. Submit a pull request

License

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

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

reactor_di-0.1.3.tar.gz (61.8 kB view details)

Uploaded Source

Built Distribution

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

reactor_di-0.1.3-py3-none-any.whl (12.6 kB view details)

Uploaded Python 3

File details

Details for the file reactor_di-0.1.3.tar.gz.

File metadata

  • Download URL: reactor_di-0.1.3.tar.gz
  • Upload date:
  • Size: 61.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for reactor_di-0.1.3.tar.gz
Algorithm Hash digest
SHA256 93d4396e61048d11318bb6ee9d016f25431d1305b9a5f3cd44657b7ef7328ebc
MD5 e06268cf341291c6634196f89931b273
BLAKE2b-256 80f97cc1faf67c215659a29b3650aec6ac86712a3348f0d9d840b1c46f6f3f6a

See more details on using hashes here.

File details

Details for the file reactor_di-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: reactor_di-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 12.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for reactor_di-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 acfabb0bdab99489b0ab957be906e568b8290d9eea7a22e2bc02c5d4a5763b3c
MD5 804107b3d0b8c6fc6c3dd4aa9cf997ff
BLAKE2b-256 52ce462036d2c652950f5ed691f3847fb1348af8e63b365bb7359c591598490f

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