A pythonic dependency injection library that assembles objects into graphs in an easy, maintainable way
—
Comprehensive error system providing clear, actionable feedback for dependency injection issues, from binding conflicts to circular dependencies. All errors inherit from the base Error class.
Base exception class for all Pinject-related errors.
class Error(Exception):
"""Base exception class for all Pinject errors."""Errors related to resolving dependencies and finding appropriate bindings.
class AmbiguousArgNameError(Error):
"""Multiple bindings match the same argument name, creating ambiguity."""
class MissingRequiredBindingError(Error):
"""Required binding not found during dependency resolution."""
class NothingInjectableForArgError(Error):
"""No injectable found for a required argument."""
class OnlyInstantiableViaProviderFunctionError(Error):
"""Class can only be instantiated through a provider function."""
class NonExplicitlyBoundClassError(Error):
"""Class not explicitly bound when only_use_explicit_bindings=True."""Errors that occur during binding specification and configuration.
class ConflictingExplicitBindingsError(Error):
"""Multiple explicit bindings defined for the same key."""
class ConflictingRequiredBindingError(Error):
"""Conflicting implicit bindings for the same requirement."""
class InvalidBindingTargetError(Error):
"""Binding target has wrong type for the binding."""
class MultipleBindingTargetArgsError(Error):
"""Multiple binding targets specified for the same key."""
class NoBindingTargetArgsError(Error):
"""No binding target specified when required."""
class EmptyBindingSpecError(Error):
"""BindingSpec has neither configure() method nor provider methods."""Errors related to incorrect usage of Pinject decorators.
class DecoratorAppliedToNonInitError(Error):
"""Decorator applied to non-__init__ method."""
class DuplicateDecoratorError(Error):
"""Same decorator applied twice to the same method."""
class EmptyProvidesDecoratorError(Error):
"""@provides() decorator used without arguments."""
class TooManyArgsToInjectDecoratorError(Error):
"""Both arg_names and all_except specified in @inject decorator."""
class NoRemainingArgsToInjectError(Error):
"""All arguments marked as directly passed, leaving none to inject."""
class PargsDisallowedWhenCopyingArgsError(Error):
"""*args not allowed with copy_args decorators."""Errors related to argument specification and annotation handling.
class NoSuchArgError(Error):
"""Reference to non-existent argument."""
class NoSuchArgToInjectError(Error):
"""Cannot inject into non-existent argument."""
class MultipleAnnotationsForSameArgError(Error):
"""Same argument annotated multiple times."""
class DirectlyPassingInjectedArgsError(Error):
"""Injected arguments passed directly to provider function."""
class WrongArgTypeError(Error):
"""Argument has wrong type."""
class WrongArgElementTypeError(Error):
"""Array/sequence element has wrong type."""
class EmptySequenceArgError(Error):
"""Empty sequence provided where non-empty sequence expected."""Errors related to object scope configuration and usage.
class BadDependencyScopeError(Error):
"""Invalid dependency relationship between scopes."""
class UnknownScopeError(Error):
"""Reference to unknown scope identifier."""
class OverridingDefaultScopeError(Error):
"""Attempt to override built-in scope (SINGLETON, PROTOTYPE)."""Errors related to circular dependency detection.
class CyclicInjectionError(Error):
"""Circular dependency detected in object graph."""Errors related to BindingSpec method configuration.
class ConfigureMethodMissingArgsError(Error):
"""BindingSpec configure method missing required arguments."""Errors related to injection policies and restrictions.
class InjectingNoneDisallowedError(Error):
"""None injection attempted when allow_injecting_none=False."""import pinject
class DatabaseService(object):
def __init__(self):
pass
class MockDatabaseService(object):
def __init__(self):
pass
# This will cause AmbiguousArgNameError
class UserService(object):
def __init__(self, database_service): # Ambiguous: which DatabaseService?
self.db = database_service
try:
obj_graph = pinject.new_object_graph(classes=[DatabaseService, MockDatabaseService])
user_service = obj_graph.provide(UserService)
except pinject.AmbiguousArgNameError as e:
print(f"Ambiguous binding: {e}")
# Solution: Use explicit bindings or annotations
class MyBindingSpec(pinject.BindingSpec):
def configure(self, bind):
bind('database_service').to_class(DatabaseService)
obj_graph = pinject.new_object_graph(
classes=[DatabaseService, MockDatabaseService],
binding_specs=[MyBindingSpec()]
)
user_service = obj_graph.provide(UserService) # Successimport pinject
class UserService(object):
def __init__(self, database_service): # database_service not available
self.db = database_service
try:
obj_graph = pinject.new_object_graph()
user_service = obj_graph.provide(UserService)
except pinject.MissingRequiredBindingError as e:
print(f"Missing binding: {e}")
print("Solution: Provide the required class or binding")
# Solution: Add the missing class
class DatabaseService(object):
def __init__(self):
pass
obj_graph = pinject.new_object_graph(classes=[DatabaseService])
user_service = obj_graph.provide(UserService) # Successimport pinject
class ServiceA(object):
def __init__(self, service_b):
self.service_b = service_b
class ServiceB(object):
def __init__(self, service_a):
self.service_a = service_a
try:
obj_graph = pinject.new_object_graph()
service_a = obj_graph.provide(ServiceA)
except pinject.CyclicInjectionError as e:
print(f"Circular dependency: {e}")
# Solution: Break the cycle with lazy injection or redesign
class ServiceA(object):
def __init__(self, service_b):
self.service_b = service_b
class ServiceB(object):
def __init__(self):
self.service_a = None # Set later to break cycle
def set_service_a(self, service_a):
self.service_a = service_a
obj_graph = pinject.new_object_graph()
service_a = obj_graph.provide(ServiceA)
service_b = obj_graph.provide(ServiceB)
service_b.set_service_a(service_a) # Manual resolutionimport pinject
class InvalidService(object):
@pinject.inject(['nonexistent_arg'])
def __init__(self, real_arg):
self.arg = real_arg
try:
obj_graph = pinject.new_object_graph()
service = obj_graph.provide(InvalidService)
except pinject.NoSuchArgToInjectError as e:
print(f"Invalid injection specification: {e}")
# Solution: Fix the decorator
class ValidService(object):
@pinject.inject(['real_arg'])
def __init__(self, real_arg):
self.arg = real_argimport pinject
class MyBindingSpec(pinject.BindingSpec):
def configure(self, bind):
# This will cause UnknownScopeError
bind('service').to_class(object, in_scope='unknown_scope')
try:
obj_graph = pinject.new_object_graph(binding_specs=[MyBindingSpec()])
except pinject.UnknownScopeError as e:
print(f"Unknown scope: {e}")
# Solution: Use valid scope or define custom scope
class ValidBindingSpec(pinject.BindingSpec):
def configure(self, bind):
bind('service').to_class(object, in_scope=pinject.SINGLETON)import pinject
# Enable detailed error reporting
obj_graph = pinject.new_object_graph(use_short_stack_traces=False)
class ComplexService(object):
def __init__(self, dep1, dep2, dep3):
pass
try:
service = obj_graph.provide(ComplexService)
except pinject.Error as e:
# All Pinject errors provide detailed context
print(f"Error type: {type(e).__name__}")
print(f"Error message: {e}")
print(f"Error occurred during: ComplexService instantiation")
# Errors include location information and context
# to help identify the exact source of the problemInstall with Tessl CLI
npx tessl i tessl/pypi-pinject