def _init(self): '''Initialize the injector, create and bind ApplicationScope, and load the default configuration. ''' self._scopes = {} self._scopes_stack = [] self._app_scope = ApplicationScope() self.bind_scope(ApplicationScope, self._app_scope) self._default_config()
class Injector(object): '''C{Injector} provides injection points with bindings, delegates storing bindings to specific scopes which coordinate objects life-cycle. @warning: Not thread-safe. ''' logger = logging.getLogger('inject.Injector') injector = None @classmethod def create(cls, autobind=True, echo=False): '''Create and register a new injector, and return it. @raise InjectorAlreadyRegistered: if another injector is already registered. ''' injector = cls(autobind=autobind, echo=echo) injector.register() return injector @classmethod def cls_get_injector(cls): '''Return a registered injector or raise an exception. @raise NoInjectorRegistered: if no injector is registered. ''' injector = cls.injector if injector is None: raise NoInjectorRegistered() return injector @classmethod def cls_register(cls, injector): '''Register an injector. @raise InjectorAlreadyRegistered: if another injector is already registered. ''' another = cls.injector if another is not None: raise InjectorAlreadyRegistered(another) cls.injector = injector cls.logger.info('Registered %r.', injector) @classmethod def cls_unregister(cls, injector=None): '''Unregister a given injector, or any injector.''' if injector and cls.injector is not injector: return latter = cls.injector cls.injector = None cls.logger.info('Unregistered %r.', latter) @classmethod def cls_is_registered(cls, injector=None): '''Return true if a given injector, or any injector is registered.''' if injector: return cls.injector is injector return cls.injector is not None def __init__(self, autobind=True, echo=False): '''Create a new injector instance. @ivar autobind: Whether to autobind not bound types, the default is true. @ivar echo: When set to true creates a default C{inject} logger, adds an stdout handler, and sets the logging level to DEBUG. It affects all injectors. ''' self.autobind = autobind if echo: configure_stdout_handler() self._init() def _init(self): '''Initialize the injector, create and bind ApplicationScope, and load the default configuration. ''' self._scopes = {} self._scopes_stack = [] self._app_scope = ApplicationScope() self.bind_scope(ApplicationScope, self._app_scope) self._default_config() def _default_config(self): '''Bind Injector to self, and create and bind ThreadScope and RequestScope. ''' self.bind(Injector, to=self) thread_scope = ThreadScope() self.bind_scope(ThreadScope, thread_scope) reqscope = RequestScope() self.bind_scope(RequestScope, reqscope) self.logger.info('Loaded the default configuration.') def clear(self): '''Remove all bindings and scopes and reinit the injector.''' self._app_scope = None self._scopes = None self._scopes_stack = None self.logger.info('Cleared all bindings.') self._init() def __contains__(self, type): '''Return true if type is bound, else return False.''' return self.is_bound(type) def bind(self, type, to=None): '''Set a binding for a type in the application scope.''' if self.is_bound(type): self.unbind(type) self._app_scope.bind(type, to) def unbind(self, type): '''Unbind the first occurrence of a type in any scope.''' for scope in self._scopes_stack: if scope.is_bound(type): scope.unbind(type) return def is_bound(self, type): '''Return true if a type is bound in any scope, else return False.''' for scope in self._scopes_stack: if scope.is_bound(type): return True return False def get(self, type, none=False): '''Return a binding for a type, or autobind it, or raise an error. @param none: If true, returns None when no binding is found, does not raise an error. @raise NotBoundError: if there is no binding for a type, and autobind is false or the type is not callable. ''' for scope in self._scopes_stack: if scope.is_bound(type) or scope.is_factory_bound(type): return scope.get(type) if self.autobind and callable(type): try: inst = type() except Exception, e: raise AutobindingFailed(type, e) self.bind(type, inst) return inst if none: return raise NotBoundError(type)
class Injector(object): '''C{Injector} provides injection points with bindings, delegates storing bindings to specific scopes which coordinate objects life-cycle. @warning: Not thread-safe. ''' logger = logging.getLogger('inject.Injector') def __init__(self, autobind=True, echo=False): '''Create a new injector instance. @ivar autobind: Whether to autobind not bound types, the default is true. @ivar echo: When set to true creates a default C{inject} logger, adds an stdout handler, and sets the logging level to DEBUG. It affects all injectors. ''' self.autobind = autobind if echo: configure_stdout_handler() self._init() def _init(self): '''Initialize the injector, create and bind ApplicationScope, and load the default configuration. ''' self._scopes = {} self._scopes_stack = [] self._app_scope = ApplicationScope() self.bind_scope(ApplicationScope, self._app_scope) self._default_config() def _default_config(self): '''Bind Injector to self, and create and bind ThreadScope and RequestScope. ''' self.bind(Injector, to=self) thread_scope = ThreadScope() self.bind_scope(ThreadScope, thread_scope) reqscope = RequestScope() self.bind_scope(RequestScope, reqscope) self.logger.info('Loaded the default configuration.') def clear(self): '''Remove all bindings and scopes and reinit the injector.''' self._app_scope = None self._scopes = None self._scopes_stack = None self.logger.info('Cleared all bindings.') self._init() def __contains__(self, type): '''Return true if type is bound, else return False.''' return self.is_bound(type) def bind(self, type, to=None): '''Set a binding for a type in the application scope.''' if self.is_bound(type): self.unbind(type) self._app_scope.bind(type, to) def unbind(self, type): '''Unbind the first occurrence of a type in any scope.''' for scope in self._scopes_stack: if scope.is_bound(type): scope.unbind(type) return def is_bound(self, type): '''Return true if a type is bound in any scope, else return False.''' for scope in self._scopes_stack: if scope.is_bound(type): return True return False def get(self, type, none=False): '''Return a binding for a type, or autobind it, or raise an error. @param none: If true, returns None when no binding is found, does not raise an error. @raise NotBoundError: if there is no binding for a type, and autobind is false or the type is not callable. ''' for scope in self._scopes_stack: if scope.is_bound(type) or scope.is_factory_bound(type): return scope.get(type) if self.autobind and isinstance(type, collections.Callable): try: inst = type() except Exception as e: raise AutobindingFailed(type, e) self.bind(type, inst) return inst if none: return raise NotBoundError(type) #========================================================================== # Factories #========================================================================== def bind_factory(self, type, factory): '''Bind a type factory in the application scope (at first, unbind an existing one if present). ''' if self.is_factory_bound(type): self.unbind_factory(type) self._app_scope.bind_factory(type, factory) def unbind_factory(self, type): '''Unbind the first occurrence of a type factory in any scope.''' for scope in self._scopes_stack: if scope.is_factory_bound(type): scope.unbind_factory(type) return def is_factory_bound(self, type): '''Return true if there is a bound type factory in any scope, else return false. ''' for scope in self._scopes_stack: if scope.is_factory_bound(type): return True return False #========================================================================== # Scopes #========================================================================== def bind_scope(self, scope_type, scope): '''Bind a new scope, unbind another one if present.''' self.unbind_scope(scope_type) self.bind(scope_type, scope) self._scopes[scope_type] = scope self._scopes_stack.append(scope) self.logger.info('Bound scope %r to %r.', scope_type, scope) def unbind_scope(self, scope_type): '''Unbind a scope.''' if scope_type not in self._scopes: return self.unbind(scope_type) scope = self._scopes[scope_type] del self._scopes[scope_type] self._scopes_stack.remove(scope) self.logger.info('Unbound scope %r.', scope) def is_scope_bound(self, scope_type): '''Return true if a scope is bound.''' return scope_type in self._scopes #========================================================================== # Registering/unregistering #========================================================================== def register(self): '''Register this injector, or raise an error. @raise InjectorAlreadyRegistered: if another injector is already registered. ''' global register register(self) def unregister(self): '''Unregister this injector.''' global unregister unregister(self) def is_registered(self): '''Return whether this injector is registered.''' global is_registered return is_registered(self)
def new_scope(self): return ApplicationScope()