def resolve(self, obj, *resolving_arguments): """Takes an object such as a function or class method and resolves it's parameters from objects in the container. Arguments: obj {object} -- The object you want to resolve objects from via this container. Returns: object -- The object you tried resolving but with the correct dependencies injected. """ provider_list = [] passing_arguments = list(resolving_arguments) for _, value in self.get_parameters(obj): if ':' in str(value): provider_list.append(self._find_annotated_parameter(value)) elif self.resolve_parameters: provider_list.append(self._find_parameter(value)) elif resolving_arguments: try: provider_list.append(passing_arguments.pop(0)) except IndexError: raise ContainerError( 'Not enough dependencies passed. Resolving object needs {} dependencies.' .format(len(inspect.signature(obj).parameters))) else: raise ContainerError( "This container is not set to resolve parameters. You can set this in the container" " constructor using the 'resolve_parameters=True' keyword argument." ) try: return obj(*provider_list) except TypeError as e: raise ContainerError(str(e))
def load(self, directories, instantiate=False): """Load all classes found in a list of directories into the container. Arguments: directories {list} -- List of directories to search. Keyword Arguments: instantiate {bool} -- Whether or not to instantiate the class (default: {False}) Raises: ContainerError -- Thrown when the container is not loaded into the class. AutoloadContainerOverwrite -- Thrown when the container already has the key binding. """ self.instantiate = instantiate if not self.app: raise ContainerError( 'Container not specified. Pass the container into the constructor') for (module_loader, name, ispkg) in pkgutil.iter_modules(directories): search_path = module_loader.path for obj in inspect.getmembers(self._get_module_members(module_loader, name)): # If the object is a class and the objects module starts with the search path if inspect.isclass(obj[1]) and obj[1].__module__.split('.')[:-1] == search_path.split('/'): if self.app.has(obj[1].__name__) and not self.app.make(obj[1].__name__).__module__.startswith(search_path): raise AutoloadContainerOverwrite( 'Container already has the key: {}. Cannot overwrite a container key that exists outside of your application.'.format(obj[1].__name__)) self.app.bind(obj[1].__name__, self._can_instantiate(obj))
def _find_annotated_parameter(self, parameter): """Find a given annotation in the container. Arguments: parameter {object} -- The object to find in the container. Raises: ContainerError -- Thrown when the dependency is not found in the container. Returns: object -- Returns the object found in the container. """ for dummy, provider_class in self.providers.items(): if parameter.annotation == provider_class or parameter.annotation == provider_class.__class__: obj = provider_class self.fire_hook('resolve', parameter, obj) return obj elif inspect.isclass(provider_class) and issubclass(provider_class, parameter.annotation) or issubclass(provider_class.__class__, parameter.annotation): obj = provider_class self.fire_hook('resolve', parameter, obj) return obj raise ContainerError( 'The dependency with the {0} annotation could not be resolved by the container'.format(parameter))
def _find_parameter(self, keyword): """Find a parameter in the container. Arguments: parameter {inspect.Paramater} -- Parameter to search for. Raises: ContainerError -- Thrown when the dependency is not found in the container. Returns: object -- Returns the object found in the container """ parameter = str(keyword) if parameter != 'self' and parameter in self.providers: obj = self.providers[parameter] self.fire_hook('resolve', parameter, obj) return obj elif '=' in parameter: return keyword.default raise ContainerError( 'The parameter dependency with the key of {0} could not be found in the container'.format( parameter) )
def _find_parameter(self, parameter): """ Find a parameter in the container """ parameter = str(parameter) if parameter is not 'self' and parameter in self.providers: return self.providers[parameter] raise ContainerError( 'The dependency with the key of {0} could not be found in the container'.format(parameter) )
def _find_annotated_parameter(self, parameter): """ Find a given annotation in the container """ for provider, provider_class in self.providers.items(): if parameter.annotation == provider_class or parameter.annotation == provider_class.__class__: return provider_class elif inspect.isclass(provider_class) and issubclass(provider_class, parameter.annotation): return provider_class raise ContainerError('The dependency with the {0} annotation could not be resolved by the container'.format(parameter))
def _find_parameter(self, parameter): """Find a parameter in the container. Arguments: parameter {string} -- Parameter to search for. Raises: ContainerError -- Thrown when the dependency is not found in the container. Returns: object -- Returns the object found in the container """ parameter = str(parameter) if parameter is not 'self' and parameter in self.providers: obj = self.providers[parameter] self.fire_hook('resolve', parameter, obj) return obj raise ContainerError( 'The dependency with the key of {0} could not be found in the container' .format(parameter))
def load(self, directories, instantiate=False): self.instantiate = instantiate if not self.app: raise ContainerError( 'Container not specified. Pass the container into the constructor' ) for (module_loader, name, ispkg) in pkgutil.iter_modules(directories): search_path = module_loader.path for obj in inspect.getmembers( self._get_module_members(module_loader, name)): # If the object is a class and the objects module starts with the search path if inspect.isclass(obj[1]) and obj[1].__module__.startswith( search_path.replace('/', '.')): if self.app.has(obj[1].__name__) and not self.app.make( obj[1].__name__).__module__.startswith( search_path): raise AutoloadContainerOverwrite( 'Container already has the key: {}. Cannot overwrite a container key that exists outside of your application.' .format(obj[1].__name__)) self.app.bind(obj[1].__name__, self._can_instantiate(obj))
def resolve(self, obj, *resolving_arguments): """Takes an object such as a function or class method and resolves it's parameters from objects in the container. Arguments: obj {object} -- The object you want to resolve objects from via this container. Returns: object -- The object you tried resolving but with the correct dependencies injected. """ objects = [] passing_arguments = list(resolving_arguments) if self.remember and obj in self._remembered: objects = self._remembered[obj] try: return obj(*objects) except TypeError as e: raise ContainerError(str(e)) elif self.remember and not passing_arguments and inspect.ismethod(obj) and "{}.{}.{}".format(obj.__module__, obj.__self__.__class__.__name__, obj.__name__) in self._remembered: location = "{}.{}.{}".format(obj.__module__, obj.__self__.__class__.__name__, obj.__name__) objects = self._remembered[location] try: return obj(*objects) except TypeError as e: raise ContainerError(str(e)) else: for _, value in self.get_parameters(obj): if ':' in str(value): param = self._find_annotated_parameter(value) if inspect.isclass(param): param = self.resolve(param) objects.append(param) elif '=' in str(value): objects.append(value.default) elif '*' in str(value): continue elif self.resolve_parameters: objects.append(self._find_parameter(value)) elif resolving_arguments: try: objects.append(passing_arguments.pop(0)) except IndexError: raise ContainerError('Not enough dependencies passed. Resolving object needs {} dependencies.'.format(len(inspect.signature(obj).parameters))) else: raise ContainerError( "This container is not set to resolve parameters. You can set this in the container" " constructor using the 'resolve_parameters=True' keyword argument.") try: if self.remember: if not inspect.ismethod(obj): self._remembered[obj] = objects else: signature = "{}.{}.{}".format(obj.__module__, obj.__self__.__class__.__name__, obj.__name__) self._remembered[signature] = objects return obj(*objects) except (TypeError,) as e: import sys import traceback exception = ContainerError(str(e)) exc_type, exc_obj, exc_tb = sys.exc_info() exception.__class__.extras = [exc_type, exc_obj, exc_tb] exception.__class__.tb = traceback.extract_tb(exc_tb) exception.__class__.file = obj.__code__.co_filename raise exception from e
def __init__(self, z): y = x self.z = z raise ContainerError('Something Broke!')