Module - InjectQ Documentation
Author: InjectQ Contributors
Description: Modern Python dependency injection library

Skip to content

# Module API

::: injectq.modules.base

## Overview

Modules provide a way to organize and configure dependency injection bindings. They encapsulate related service registrations and can be composed to build complex applications.

## Basic Module Definition

    from injectq import Module

    class DatabaseModule(Module):
        def configure(self):
            # Database configuration
            self.bind(DatabaseConnection, DatabaseConnection).singleton()
            self.bind(UserRepository, UserRepository).scoped()
            self.bind(str, "postgresql://localhost:5432/app", name="connection_string")

## Module Installation

    # Install single module
    container.install(DatabaseModule())

    # Install multiple modules
    container.install([
        DatabaseModule(),
        ServiceModule(),
        ConfigurationModule()
    ])

## Advanced Module Features

### Conditional Bindings

    class ConditionalModule(Module):
        def configure(self):
            # Conditional binding based on environment
            if self.is_development():
                self.bind(Logger, ConsoleLogger).singleton()
            else:
                self.bind(Logger, FileLogger).singleton()

        def is_development(self) -> bool:
            return os.getenv("ENVIRONMENT") == "development"

### Module Composition

    class ApplicationModule(Module):
        def configure(self):
            # Install other modules
            self.install(DatabaseModule())
            self.install(SecurityModule())
            self.install(WebModule())

            # Additional bindings
            self.bind(ApplicationService, ApplicationService).singleton()

### Named Bindings

    class ConfigurationModule(Module):
        def configure(self):
            # Named string bindings
            self.bind(str, "localhost", name="database_host")
            self.bind(str, "5432", name="database_port")
            self.bind(str, "myapp", name="database_name")

            # Named service bindings
            self.bind(EmailService, SMTPEmailService, name="smtp_service").singleton()
            self.bind(EmailService, SendGridService, name="sendgrid_service").singleton()

## Module Lifecycle

### Initialization Hooks

    class ModuleWithHooks(Module):
        def configure(self):
            self.bind(MyService, MyService).singleton()

        def on_installed(self, container):
            """Called after module is installed."""
            print(f"Module installed in container: {container}")

        def on_container_built(self, container):
            """Called after container is fully built."""
            # Perform initialization
            service = container.get(MyService)
            service.initialize()

### Validation

    class ValidatedModule(Module):
        def configure(self):
            self.bind(RequiredService, RequiredService).singleton()

        def validate(self) -> List[str]:
            """Validate module configuration."""
            errors = []

            # Check required environment variables
            if not os.getenv("API_KEY"):
                errors.append("API_KEY environment variable is required")

            return errors

## Module Testing

### Test Modules

    from injectq.testing import TestModule

    class TestDatabaseModule(TestModule):
        def configure(self):
            # Override with test implementations
            self.bind(DatabaseConnection, MockDatabaseConnection).singleton()
            self.bind(UserRepository, InMemoryUserRepository).scoped()

### Module Mocking

    class MockServiceModule(Module):
        def __init__(self, mock_service):
            self.mock_service = mock_service

        def configure(self):
            self.bind(ExternalService, self.mock_service).singleton()

    # Usage in tests
    mock_service = Mock(spec=ExternalService)
    container.install(MockServiceModule(mock_service))

## Configuration Patterns

### Environment-Based Configuration

    class EnvironmentModule(Module):
        def __init__(self, environment: str):
            self.environment = environment

        def configure(self):
            if self.environment == "production":
                self.configure_production()
            elif self.environment == "development":
                self.configure_development()
            else:
                self.configure_test()

        def configure_production(self):
            self.bind(Logger, ProductionLogger).singleton()
            self.bind(Database, PostgreSQLDatabase).singleton()

        def configure_development(self):
            self.bind(Logger, ConsoleLogger).singleton()
            self.bind(Database, SQLiteDatabase).singleton()

        def configure_test(self):
            self.bind(Logger, NullLogger).singleton()
            self.bind(Database, InMemoryDatabase).singleton()

### Feature Flags

    class FeatureModule(Module):
        def __init__(self, features: Dict[str, bool]):
            self.features = features

        def configure(self):
            # Base services
            self.bind(UserService, UserService).singleton()

            # Feature-based services
            if self.features.get("analytics", False):
                self.bind(AnalyticsService, AnalyticsService).singleton()

            if self.features.get("caching", False):
                self.bind(CacheService, RedisCacheService).singleton()
            else:
                self.bind(CacheService, InMemoryCacheService).singleton()

## Module Documentation

### Self-Documenting Modules

    class DocumentedModule(Module):
        """
        Database module providing core data access services.

        Services provided:
        - DatabaseConnection: Main database connection
        - UserRepository: User data access
        - ProductRepository: Product data access

        Configuration:
        - Requires DATABASE_URL environment variable
        - Optional POOL_SIZE for connection pooling
        """

        def configure(self):
            # Implementation details documented inline

            # Core database connection (singleton for connection pooling)
            self.bind(DatabaseConnection, DatabaseConnection).singleton()

            # Repositories (scoped for unit-of-work pattern)
            self.bind(UserRepository, UserRepository).scoped()
            self.bind(ProductRepository, ProductRepository).scoped()

        def get_description(self) -> str:
            """Get module description."""
            return self.__doc__ or "No description available"

        def get_provided_services(self) -> List[type]:
            """Get list of services provided by this module."""
            return [DatabaseConnection, UserRepository, ProductRepository]

## Error Handling

    class RobustModule(Module):
        def configure(self):
            try:
                # Attempt to bind complex service
                self.bind(ComplexService, ComplexService).singleton()
            except ImportError:
                # Fallback to simple implementation
                self.bind(ComplexService, SimpleService).singleton()
            except Exception as e:
                # Log error and provide default
                print(f"Error configuring ComplexService: {e}")
                self.bind(ComplexService, DefaultService).singleton()