def test_injector_failure(): # Dataclass wants a value, doesn't have a default, and it # isn't in props or injector @dataclass class AgeAthlete: age: int # Note that this field is required props = dict() injectables = dict() with pytest.raises(TypeError): inject(props, injectables, AgeAthlete)
def test_injector_injectedattr_missing_class(): """ Ask for a class not registered as injectable """ class Jersey: pass @dataclass class InjectedAthlete: shoe_size: int = injected(Jersey, attr='size') shoe = Shoe(size=88) props = dict() injectables = {Shoe.__name__: shoe} with pytest.raises(InvalidInjectable) as exc: inject(props, injectables, InjectedAthlete) expected = 'Invalid injected type Jersey requested from type' assert expected == str(exc.value)
def test_injector_injected(): """ Create instance from data based on injectables """ shoe = Shoe(size=66) props = dict() injectables = {Shoe.__name__: shoe} athlete = inject(props, injectables, Athlete) assert 66 == athlete.shoe.size
def test_injector_props(): """ Create instance based on data from passed-in props """ shoe = Shoe(size=55) props = dict(shoe=shoe) injectables = dict() athlete = inject(props, injectables, Athlete) assert 55 == athlete.shoe.size
def test_injector_precedence(): # When both props and injectable, choose props shoe = Shoe(size=55) props = dict(shoe=shoe) shoe = Shoe(size=66) injectables = {Shoe.__name__: shoe} athlete = inject(props, injectables, Athlete) assert 55 == athlete.shoe.size
def test_injector_injected_double(): """ Tell the injector to hand attribute of another injectable """ @dataclass class InjectedAthlete: shoe_size: int = injected(Shoe, attr='size') shoe = Shoe(size=88) props = dict() injectables = {Shoe.__name__: shoe} athlete = inject(props, injectables, InjectedAthlete) assert 88 == athlete.shoe_size
def initialize(self): """ Commit the actions and initialize the registry """ dectate.commit(self.registry) # Get the injectables injectables = self.injectables # Stash ServiceManager stuff in injectables self.add_injectable(self.config) self.add_injectable(self) # Make the Registry injectable using a well-known name injectables['Registry'] = self.registry # Make each service config available as injectable for serviceconfig in self.config.serviceconfigs.values(): self.add_injectable(serviceconfig) # Get a list of services q = dectate.Query('service') services = list(q(self.registry)) # Go through each service, initialize it, then # put an instance in the service manager for action, target in services: # Use injector to make our target class props = dict() service = inject(props, injectables, target) # Store this in our dict of services name = action.name self.services[name] = service # Add this service, and its config, as injectable self.add_injectable(service) # TODO Should move more of this to a setup() function in each # service, to let them provide injectables if 'resource' in self.services: resources = self.services['resource'].resources self.add_injectable(resources) # Now the adapters in services['adapter']. Each adapter # can be dependency-injected...albeit carefully. Add the # (unique) for_ targets as injectable adapters. try: for action in AdapterAction.sorted_actions(self.registry): f = action[0].predicates['for_'].value self.adapters[f.__name__] = f except dectate.error.QueryError: # Likely a unit test that doesn't include adapters in # the registry pass
def test_injector_defaultfactory(): # Field has a default value which should be used instead of # injection @dataclass class DefaultValueAthlete: shoe: Shoe = field(default_factory=Shoe) props = dict() injectables = dict() athlete = inject(props, injectables, DefaultValueAthlete) assert 77 == athlete.shoe.size
def test_injector_defaultvalue(): # Field has a default value which should be used instead of # injection default_shoesize = Shoe(size=34523) @dataclass class DefaultValueAthlete: shoe: Shoe = default_shoesize props = dict() injectables = dict() athlete = inject(props, injectables, DefaultValueAthlete) assert 34523 == athlete.shoe.size
def test_injector_injected_callable(): """ Tell the injector to hand call result of another injectable """ @dataclass class CallableShoe: size: int def __call__(self): return self.size + 5 @dataclass class InjectedAthlete: shoe_size: int = injected(CallableShoe) shoe = CallableShoe(size=70) props = dict() injectables = {CallableShoe.__name__: shoe} athlete = inject(props, injectables, InjectedAthlete) assert 75 == athlete.shoe_size
def get_view(self, request) -> Optional[View]: """ Use the predicate registry to find the right view class """ # Grab ViewAction and use sorted_actions to find first match sorted_actions = ViewAction.sorted_actions(self.registry) # Find the first action which matches the args for action, view_class in sorted_actions: if action.all_predicates_match(request): # Use dependency injection to make an instance of # that view class view_instance = inject( dict(), # props self.get_injectables(request), view_class, request=request ) return view_instance # No matches, return None return None
def get_adapter(self, request, for_: Type[Any], **kwargs) -> Optional[Adapter]: """ Use the predicate registry to find the right adapter class """ # Grab AdapterAction and use sorted_actions to find first match sorted_actions = AdapterAction.sorted_actions(self.registry) # Find the first action which matches the args for action, adapter_class in sorted_actions: if action.all_predicates_match(request, for_=for_, **kwargs): # Use dependency injection to make an instance of # that adapter class adapter_instance = inject( kwargs, # props self.get_injectables(request), adapter_class, request=request) return adapter_instance # No matches, return None return None
def test_injector_fielddefault(): props = dict() injectables = dict() athlete = inject(props, injectables, Athlete) assert 77 == athlete.shoe.size