def _assert_providers_compatible_and_extract_template_func( providers, port_name): assert providers, 'why are you calling me if there are no providers for {}?'.format( port_name) func_map = {} spec_map = {} for provider in providers: func_map[provider] = func = get_template_funcs(provider)[port_name] spec_map[provider] = inspect.getargspec(func) non_generic_specs = { provider: spec for provider, spec in spec_map.iteritems() if spec != GENERIC_ARGSPEC } if not non_generic_specs: # all needs of this port did not specific an interface return func_map.itervalues().next() # just return the first one specs = non_generic_specs.values() if not all(spec == specs[0] for spec in specs): # we have a mixture of specs msg = 'The following components all need "{}" but expect different interfaces - {}'.format( port_name, ', '.join( sorted(p.__name__ for p in non_generic_specs.iterkeys()))) raise InconsistentInterface(msg) else: chosen_one = non_generic_specs.iterkeys().next() return func_map[chosen_one]
def attach_mock_provider(consumer, ports): assert isinstance(consumer, INeed) assert isinstance(ports, (list, dict)) invalid_ports = set(ports).difference(consumer.get_needs()) if invalid_ports: raise UnknownPort('Invalid ports for {} - {}'.format( consumer, ', '.join(invalid_ports))) # create the underlying object that will hold all the mock functions for the specified ports template_funcs = get_template_funcs(service=consumer) template_func_subset = {port: template_funcs[port] for port in ports} template_class = type('Mock' + consumer.__class__.__name__, (), template_func_subset) provider_impl = mock.create_autospec(spec=template_class, spec_set=True, instance=True) # supply return_value if provider if isinstance(ports, dict): for port, value in ports.iteritems(): getattr(provider_impl, port).return_value = value provider = object_as_provider(provider=provider_impl, ports=ports) auto_wire(components=[consumer, provider]) return provider_impl
def test_domain_inherits_needs_template_functions_from_the_services_they_encapsulate(self): D = self._get_domain_class() domain = D() template_funcs = get_template_funcs(service=domain) self.assertItemsEqual(['a', 'b'], template_funcs.keys()) self.assert_has_same_argspec(lambda self, x, y=123: None, template_funcs['a']) self.assert_has_same_argspec(lambda self, *args, **kwargs: None, template_funcs['b'])
def test_template_function_propagation_works_for_nested_domains(self): D = self._get_domain_class() class SuperDomain(Domain): __services__ = [D] __provides__ = AutoProvide() domain = SuperDomain() template_funcs = get_template_funcs(service=domain) self.assertItemsEqual(['a', 'b'], template_funcs.keys()) self.assert_has_same_argspec(lambda self, x, y=123: None, template_funcs['a']) self.assert_has_same_argspec(lambda self, *args, **kwargs: None, template_funcs['b'])
def test_default_template_func_is_consistent_and_has_wildcard_specs_but_not_callable(self): class MyService(Service): deps = Needs(ports=['a', 'b']) @provides def x(self): return self.deps.a() + self.deps.b() service = MyService() template_funcs = get_template_funcs(service=service) func = template_funcs['a'] self.assertIs(func, template_funcs['b']) self.assert_has_same_argspec(lambda self, *args, **kwargs: None, func) self.assertRaises(NotImplementedError, func, None) # template func meant as unbound methods so expects a 'self'
def test_needs_defined_using_Needs_class_has_template_funcs_with_correct_argspec(self): class MyService(Service): deps = Needs(ports=['a', 'b']) @provides def x(self): return self.deps.a() + self.deps.b() service = MyService() template_funcs = get_template_funcs(service=service) self.assertItemsEqual(['a', 'b'], template_funcs.keys()) def expected_template(self, *args, **kwargs): pass self.assert_has_same_argspec(expected_template, template_funcs['a']) self.assert_has_same_argspec(expected_template, template_funcs['b'])
def tests_template_function_propagation_for_services_with_same_needs_and_same_interface(self): class NeedsA(NeedsInterface): def a(self, x, y=123): pass class A(Service): deps = NeedsA() @provides def aaa(self): return self.deps.a() class NeedsAB(NeedsInterface): def a(self, x, y=123): # matching argspec pass def b(self, z): pass class AB(Service): deps = NeedsAB() @provides def abb(self): return self.deps.a() + self.deps.b() class B(Service): deps = Needs(['b']) # no interface, should still match @provides def bbb(self): return self.deps.b() class D(Domain): __services__ = [A, B, AB] __provides__ = AutoProvide() domain = D() template_funcs = get_template_funcs(service=domain) self.assertItemsEqual(['a', 'b'], template_funcs.keys()) self.assert_has_same_argspec(lambda self, x, y=123: None, template_funcs['a']) self.assert_has_same_argspec(lambda self, z: None, template_funcs['b'])
def test_needs_defined_using_NeedsInterface_class_has_templte_funcs_with_correct_argspec(self): class MyDeps(NeedsInterface): def a(self, x, y=123): pass def b(self, x, **kwargs): pass def c(self, *args, **kwargs): pass class MyService(Service): deps = MyDeps() @provides def x(self): return self.deps.a() + self.deps.b() + self.deps.c() service = MyService() template_funcs = get_template_funcs(service=service) self.assertItemsEqual(['a', 'b', 'c'], template_funcs.keys()) self.assert_has_same_argspec(lambda self, x, y=123: None, template_funcs['a']) self.assert_has_same_argspec(lambda self, x, **kwargs: None, template_funcs['b']) self.assert_has_same_argspec(lambda self, *args, **kwargs: None, template_funcs['c'])