Implementation of dependency injection for Python 3
Overall
score
92%
Advanced service registration using factory functions for complex instantiation scenarios. Supports different factory signatures, service lifestyles, and provides flexibility for services that require custom initialization logic.
Registers a factory function that creates singleton services - the factory is called once and the result is cached.
def add_singleton_by_factory(self, factory: FactoryCallableType, return_type: Optional[Type] = None) -> Container:
"""
Register a singleton service created by a factory function.
Args:
factory: Factory function to create the service instance
return_type: Expected return type (inferred from factory if not provided)
Returns:
Container instance for method chaining
"""Registers a factory function that creates transient services - the factory is called every time the service is resolved.
def add_transient_by_factory(self, factory: FactoryCallableType, return_type: Optional[Type] = None) -> Container:
"""
Register a transient service created by a factory function.
Args:
factory: Factory function to create service instances
return_type: Expected return type (inferred from factory if not provided)
Returns:
Container instance for method chaining
"""Registers a factory function that creates scoped services - the factory is called once per scope and the result is cached within that scope.
def add_scoped_by_factory(self, factory: FactoryCallableType, return_type: Optional[Type] = None) -> Container:
"""
Register a scoped service created by a factory function.
Args:
factory: Factory function to create service instances
return_type: Expected return type (inferred from factory if not provided)
Returns:
Container instance for method chaining
"""Rodi supports three different factory function signatures for maximum flexibility:
Simple factory functions that take no arguments and create service instances.
FactoryCallableNoArguments = Callable[[], Any]Usage example:
def create_database_service():
connection_string = get_connection_string_from_config()
return DatabaseService(connection_string)
container.add_singleton_by_factory(create_database_service, DatabaseService)Factory functions that take an ActivationScope parameter for context-aware service creation.
FactoryCallableSingleArgument = Callable[[ActivationScope], Any]Usage example:
def create_request_logger(scope: ActivationScope):
request_context = scope.get(RequestContext)
return Logger(f"Request-{request_context.request_id}")
container.add_scoped_by_factory(create_request_logger, Logger)Factory functions that take both an ActivationScope and the requested Type for advanced factory scenarios.
FactoryCallableTwoArguments = Callable[[ActivationScope, Type], Any]Usage example:
def create_generic_repository(scope: ActivationScope, entity_type: Type):
db_context = scope.get(DatabaseContext)
return GenericRepository(db_context, entity_type)
container.add_scoped_by_factory(create_generic_repository)Combined type hint for all supported factory function signatures.
FactoryCallableType = Union[FactoryCallableNoArguments, FactoryCallableSingleArgument, FactoryCallableTwoArguments]Use factories to create services that depend on external configuration:
def create_email_service():
config = load_email_config()
if config.provider == "smtp":
return SmtpEmailService(config.smtp_settings)
elif config.provider == "sendgrid":
return SendGridEmailService(config.api_key)
else:
raise ValueError(f"Unknown email provider: {config.provider}")
container.add_singleton_by_factory(create_email_service, EmailService)Create different service implementations based on environment:
def create_storage_service():
if os.getenv("ENVIRONMENT") == "production":
return S3StorageService(
bucket=os.getenv("S3_BUCKET"),
access_key=os.getenv("AWS_ACCESS_KEY")
)
else:
return LocalFileStorageService(path="./storage")
container.add_singleton_by_factory(create_storage_service, StorageService)Use factories for services requiring complex initialization logic:
def create_cache_service(scope: ActivationScope):
config = scope.get(CacheConfiguration)
# Complex setup logic
cache = RedisCache(config.connection_string)
cache.set_serializer(JsonSerializer())
cache.configure_eviction_policy(config.eviction_policy)
# Setup cache warming
if config.warm_cache:
cache.warm_up(config.warm_up_keys)
return cache
container.add_singleton_by_factory(create_cache_service, CacheService)Create services conditionally based on runtime state:
def create_audit_service(scope: ActivationScope):
user = scope.get(CurrentUser)
if user.requires_audit_logging:
return DatabaseAuditService(scope.get(AuditDatabase))
else:
return NoOpAuditService()
container.add_scoped_by_factory(create_audit_service, AuditService)Install with Tessl CLI
npx tessl i tessl/pypi-rodidocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10