def test_namedArguments(self): resolvedArguments = [ ResolvedArgument( 'myNumber', PrimitiveArgument(123, 'myNumber'), InspectedArgument('myNumber', DType('builtins', 'int')) ), ResolvedArgument( 'manuallyWiredService', ServiceArgument('my.module.ManuallyWiredClass', 'manuallyWiredService'), InspectedArgument('manuallyWiredService', DType('my.module.ManuallyWiredClass', 'ManuallyWiredClass')) ), ResolvedArgument( 'autowiredService', None, InspectedArgument('autowiredService', DType('my.module.OtherClass', 'OtherClass')), ) ] classes2Services = { 'my.module.OtherClass': {'OtherClass': ['my.module.OtherClass']} } newResolvedArguments = self.__argumentsAutowirer.autowire( 'my.module.MyClass', resolvedArguments, classes2Services, ) self.assertEqual(3, len(newResolvedArguments)) self.assertEqual(PrimitiveArgument(123, 'myNumber'), newResolvedArguments[0].argument) self.assertEqual(ServiceArgument('my.module.ManuallyWiredClass', 'manuallyWiredService'), newResolvedArguments[1].argument) self.assertEqual(ServiceArgument('my.module.OtherClass', 'autowiredService'), newResolvedArguments[2].argument)
def test_basic(self): serviceArgument = ServiceArgument('foo.Bar') inspectedArgument = InspectedArgument('bar', DType('foo.Bar', 'Bar')) services2Classes = {'foo.Bar': DType('foo.Bar', 'Bar')} aliases2Services = {} serviceArgument.checkTypeMatchesDefinition(inspectedArgument, services2Classes, aliases2Services)
def test_basic(self): service_argument = ServiceArgument("foo.Bar") inspected_argument = InspectedArgument("bar", DType("foo.Bar", "Bar")) services2_classes = {"foo.Bar": DType("foo.Bar", "Bar")} aliases2_services = {} service_argument.check_type_matches_definition(inspected_argument, services2_classes, aliases2_services)
def test_undefined_service(self): service_argument = ServiceArgument("foo.Bar") inspected_argument = InspectedArgument("bar", DType("foo.Bar", "Bar")) services2_classes = {} aliases2_services = {} with self.assertRaises(Exception) as error: service_argument.check_type_matches_definition( inspected_argument, services2_classes, aliases2_services) self.assertEqual("Undefined service foo.Bar", str(error.exception))
def test_interface(self): serviceArgument = ServiceArgument('injecta.mocks.Bar') inspectedArgument = InspectedArgument( 'bar', DType('injecta.mocks.BarInterface', 'BarInterface')) services2Classes = { 'injecta.mocks.Bar': DType('injecta.mocks.Bar', 'Bar') } aliases2Services = {} serviceArgument.checkTypeMatchesDefinition(inspectedArgument, services2Classes, aliases2Services)
def test_unknown_aliased_service(self): service_argument = ServiceArgument("foo.BarAlias") inspected_argument = InspectedArgument("bar", DType("foo.Bar", "Bar")) services2_classes = {} aliases2_services = {"foo.BarAlias": "foo.Bar"} with self.assertRaises(Exception) as error: service_argument.check_type_matches_definition( inspected_argument, services2_classes, aliases2_services) self.assertEqual('Aliased service "foo.Bar" does not exist', str(error.exception))
def test_interface(self): service_argument = ServiceArgument("injecta.mocks.Bar") inspected_argument = InspectedArgument( "bar", DType("injecta.mocks.BarInterface", "BarInterface")) services2_classes = { "injecta.mocks.Bar": DType("injecta.mocks.Bar", "Bar") } aliases2_services = {} service_argument.check_type_matches_definition(inspected_argument, services2_classes, aliases2_services)
def test_undefinedService(self): serviceArgument = ServiceArgument('foo.Bar') inspectedArgument = InspectedArgument('bar', DType('foo.Bar', 'Bar')) services2Classes = {} aliases2Services = {} with self.assertRaises(Exception) as error: serviceArgument.checkTypeMatchesDefinition(inspectedArgument, services2Classes, aliases2Services) self.assertEqual('Undefined service foo.Bar', str(error.exception))
def test_unknownAliasedService(self): serviceArgument = ServiceArgument('foo.BarAlias') inspectedArgument = InspectedArgument('bar', DType('foo.Bar', 'Bar')) services2Classes = {} aliases2Services = {'foo.BarAlias': 'foo.Bar'} with self.assertRaises(Exception) as error: serviceArgument.checkTypeMatchesDefinition(inspectedArgument, services2Classes, aliases2Services) self.assertEqual('Aliased service "foo.Bar" does not exist', str(error.exception))
def resolve(self, inspected_argument: InspectedArgument, service_name: str, classes2_services: dict): module_name = inspected_argument.dtype.module_name class_name = inspected_argument.dtype.class_name if class_name == "_empty": raise Exception("Cannot resolve argument {} for service {}".format( inspected_argument.name, service_name)) if module_name not in classes2_services: module_name_stripped = module_name[:module_name.rfind(".")] if module_name_stripped in classes2_services: raise Exception( "Consider changing service dtype from {} -> {} (invalid dtype)" .format(module_name_stripped + "." + class_name, module_name + "." + class_name)) raise Exception("Service not found for {} used in {}".format( module_name + "." + class_name, service_name)) if class_name not in classes2_services[module_name]: raise Exception("Service not found for {} used in {}".format( module_name + "." + class_name, service_name)) if len(classes2_services[module_name][class_name]) > 1: service_names = ", ".join( classes2_services[module_name][class_name]) raise Exception( "Multiple services of dtype {} in dtype {} defined ({}), dtype used in service {}" .format(class_name, module_name, service_names, service_name)) return ServiceArgument(classes2_services[module_name][class_name][0], inspected_argument.name)
def test_basic(self): raw_services = { "injecta.mocks.Bar.Bar": {"arguments": ["Jiri Koutny"]}, "injecta.mocks.Foo.Foo": {"arguments": ["@injecta.mocks.Bar.Bar"]}, "injecta.mocks.Bar.BarAlias": "@injecta.mocks.Bar.Bar", } expected_service1 = Service( "injecta.mocks.Bar.Bar", DType("injecta.mocks.Bar", "Bar"), [ PrimitiveArgument("Jiri Koutny"), ], ) expected_service2 = Service( "injecta.mocks.Foo.Foo", DType("injecta.mocks.Foo", "Foo"), [ ServiceArgument("injecta.mocks.Bar.Bar"), ], ) expected_alias1 = ServiceAlias("injecta.mocks.Bar.BarAlias", "injecta.mocks.Bar.Bar") services, aliases = self.__services_preparer.prepare(raw_services) self.assertEqual(expected_service1, services[0]) self.assertEqual(expected_service2, services[1]) self.assertEqual(expected_alias1, aliases[0])
def resolve(self, resolvedArgument: ResolvedArgument, containerBuild: ContainerBuild): argument = resolvedArgument.argument if not isinstance(argument, TaggedAliasedServiceArgument): return resolvedArgument servicesForTag = containerBuild.getServicesByTag(argument.tagName) if isinstance(argument.tagAlias, str): tagAlias = self.__resolveParameterValue(argument.tagAlias, containerBuild.parameters) else: tagAlias = argument.tagAlias for service in servicesForTag: tagAttributes = service.getTagAttributes(argument.tagName) if 'alias' not in tagAttributes: raise Exception( f'"alias" attribute is missing for tag {argument.tagName}') if tagAttributes['alias'] == tagAlias: resolvedArgument.modifyArgument( ServiceArgument(service.name, argument.name), 'tagged_aliased') return resolvedArgument raise Exception( f'No service tagged with {argument.tagName} found for alias: {tagAlias}' )
def parse(self, argument, name=None): if isinstance(argument, str): if argument[0:1] == '@': return ServiceArgument(argument[1:], name) return PrimitiveArgument(argument, name) if isinstance(argument, TaggedServices): return TaggedServicesArgument(argument.val, name) if isinstance(argument, TaggedAliasedService): return TaggedAliasedServiceArgument(argument.tagName, argument.tagAlias, name) if isinstance(argument, (int, bool)): return PrimitiveArgument(argument, name) if isinstance(argument, list): return ListArgument(list(map(self.parse, argument)), name) if isinstance(argument, dict): return DictArgument( {k: self.parse(v) for k, v in argument.items()}, name) raise Exception('Unexpected argument type: {}'.format(type(argument)))
def parse(self, service_name: str, raw_service: dict = None): if raw_service is None: return Service(service_name, self.__type_resolver.resolve(service_name)) arguments = self.__parse_arguments(raw_service) tags = raw_service["tags"] if "tags" in raw_service else [] class_ = self.__type_resolver.resolve( raw_service["class"] if "class" in raw_service else service_name) service = Service(service_name, class_, arguments, tags) if "autowire" in raw_service: service.set_autowire(raw_service["autowire"] is True) if "factory" in raw_service: if raw_service["factory"][0][0:1] != "@": raise Exception( "Factory service name must be prefixed with @ (service {})" .format(service_name)) service.set_factory(ServiceArgument(raw_service["factory"][0][1:]), raw_service["factory"][1]) return service
def parse(self, serviceName: str, rawService: dict = None): if rawService is None: return Service(serviceName, self.__typeResolver.resolve(serviceName)) arguments = self.__parseArguments(rawService) tags = rawService['tags'] if 'tags' in rawService else [] class_ = self.__typeResolver.resolve( rawService['class'] if 'class' in rawService else serviceName) # pylint: disable = invalid-name service = Service(serviceName, class_, arguments, tags) if 'autowire' in rawService: service.setAutowire(rawService['autowire'] is True) if 'factory' in rawService: if rawService['factory'][0][0:1] != '@': raise Exception( 'Factory service name must be prefixed with @ (service {})' .format(serviceName)) service.setFactory(ServiceArgument(rawService['factory'][0][1:]), rawService['factory'][1]) return service
def resolve(self, inspectedArgument: InspectedArgument, serviceName: str, classes2Services: dict): moduleName = inspectedArgument.dtype.moduleName className = inspectedArgument.dtype.className if className == '_empty': raise Exception('Cannot resolve argument {} for service {}'.format( inspectedArgument.name, serviceName)) if moduleName not in classes2Services: moduleNameStripped = moduleName[:moduleName.rfind('.')] if moduleNameStripped in classes2Services: raise Exception( 'Consider changing service dtype from {} -> {} (invalid dtype)' .format(moduleNameStripped + '.' + className, moduleName + '.' + className)) raise Exception('Service not found for {} used in {}'.format( moduleName + '.' + className, serviceName)) if className not in classes2Services[moduleName]: raise Exception('Service not found for {} used in {}'.format( moduleName + '.' + className, serviceName)) if len(classes2Services[moduleName][className]) > 1: serviceNames = ', '.join(classes2Services[moduleName][className]) raise Exception( 'Multiple services of dtype {} in dtype {} defined ({}), dtype used in service {}' .format(className, moduleName, serviceNames, serviceName)) return ServiceArgument(classes2Services[moduleName][className][0], inspectedArgument.name)
def test_named_arguments(self): resolved_arguments = [ ResolvedArgument( "my_number", PrimitiveArgument(123, "my_number"), InspectedArgument("my_number", DType("builtins", "int"))), ResolvedArgument( "manually_wired_service", ServiceArgument("my.module.ManuallyWiredClass", "manually_wired_service"), InspectedArgument( "manually_wired_service", DType("my.module.ManuallyWiredClass", "ManuallyWiredClass")), ), ResolvedArgument( "autowired_service", None, InspectedArgument("autowired_service", DType("my.module.OtherClass", "OtherClass")), ), ] classes2_services = { "my.module.OtherClass": { "OtherClass": ["my.module.OtherClass"] } } new_resolved_arguments = self.__arguments_autowirer.autowire( "my.module.MyClass", resolved_arguments, classes2_services, ) self.assertEqual(3, len(new_resolved_arguments)) self.assertEqual(PrimitiveArgument(123, "my_number"), new_resolved_arguments[0].argument) self.assertEqual( ServiceArgument("my.module.ManuallyWiredClass", "manually_wired_service"), new_resolved_arguments[1].argument) self.assertEqual( ServiceArgument("my.module.OtherClass", "autowired_service"), new_resolved_arguments[2].argument)
def resolve(self, resolvedArgument: ResolvedArgument, containerBuild: ContainerBuild): argument = resolvedArgument.argument if not isinstance(argument, TaggedServicesArgument): return resolvedArgument servicesForTag = containerBuild.getServicesByTag(argument.tagName) serviceArguments = list(map(lambda service: ServiceArgument(service.name), servicesForTag)) resolvedArgument.modifyArgument(ListArgument(serviceArguments, argument.name), 'tags') return resolvedArgument
def test_exception_object_for_string(self): with self.assertRaises(Exception) as error: self.__arguments_validator.validate( "injecta.mocks.Bar", [ResolvedArgument("name", ServiceArgument("injecta.mocks.Empty"), InspectedArgument("name", DType("builtins", "str")))], {"injecta.mocks.Empty": DType("injecta.mocks.Empty", "Empty")}, {}, ) self.assertEqual( 'Expected dtype "str", got "injecta.mocks.Empty.Empty" (argument "name", service "injecta.mocks.Bar")', str(error.exception) )
def modify_services(self, services: List[Service], aliases: List[ServiceAlias], parameters: Box): if is_running_in_console(): aliases.append( ServiceAlias("databricksbundle.logger", "consolebundle.logger")) else: service = Service("databricksbundle.logger", DType("logging", "Logger")) service.set_factory( ServiceArgument(NotebookLoggerFactory.__module__), "create") services.append(service) return services, aliases
def resolve(self, resolved_argument: ResolvedArgument, container_build: ContainerBuild): argument = resolved_argument.argument if not isinstance(argument, TaggedServicesArgument): return resolved_argument services_for_tag = container_build.get_services_by_tag( argument.tag_name) service_arguments = list( map(lambda service: ServiceArgument(service.name), services_for_tag)) resolved_argument.modify_argument( ListArgument(service_arguments, argument.name), "tags") return resolved_argument
def test_exceptionObjectForString(self): with self.assertRaises(Exception) as error: self.__argumentsValidator.validate( 'injecta.mocks.Bar', [ ResolvedArgument( 'name', ServiceArgument('injecta.mocks.Empty'), InspectedArgument('name', DType('builtins', 'str'))) ], {'injecta.mocks.Empty': DType('injecta.mocks.Empty', 'Empty')}, {}, ) self.assertEqual( 'Expected dtype "str", got "injecta.mocks.Empty.Empty" (argument "name", service "injecta.mocks.Bar")', str(error.exception))
def test_factory(self): result = self.__serviceParser.parse('injecta.api.ApiClient', { 'factory': ['@injecta.api.ApiClientFactory.ApiClientFactory', 'create'], 'arguments': [ 'Jirka', ] }) expected = Service( 'injecta.api.ApiClient', DType('injecta.api', 'ApiClient'), [ PrimitiveArgument('Jirka'), ] ) expected.setFactory(ServiceArgument('injecta.api.ApiClientFactory.ApiClientFactory'), 'create') self.assertEqual(expected, result)
def autowireArgument(resolvedArgument: ResolvedArgument): if resolvedArgument.argument or resolvedArgument.inspectedArgument.hasDefaultValue( ): return resolvedArgument if resolvedArgument.inspectedArgument.dtype.moduleName == ContainerInterface.__module__: serviceArgument = ServiceArgument('serviceContainer', resolvedArgument.name) resolvedArgument.modifyArgument(serviceArgument, 'container autowiring') return resolvedArgument serviceArgument = self.__argumentResolver.resolve( resolvedArgument.inspectedArgument, serviceName, classes2Services) resolvedArgument.modifyArgument(serviceArgument, 'autowiring') return resolvedArgument
def autowire_argument(resolved_argument: ResolvedArgument): if resolved_argument.argument or resolved_argument.inspected_argument.has_default_value( ): return resolved_argument if resolved_argument.inspected_argument.dtype.module_name == ContainerInterface.__module__: service_argument = ServiceArgument("service_container", resolved_argument.name) resolved_argument.modify_argument(service_argument, "container autowiring") return resolved_argument service_argument = self.__argument_resolver.resolve( resolved_argument.inspected_argument, service_name, classes2_services) resolved_argument.modify_argument(service_argument, "autowiring") return resolved_argument
def test_basic(self): result = self.__service_parser.parse( "injecta.api.ApiClient_test", { "class": "injecta.api.ApiClient.ApiClient", "autowire": True, "arguments": ["Jirka", 15, False, "@injecta.api.Connector"] }, ) expected = Service( "injecta.api.ApiClient_test", DType("injecta.api.ApiClient", "ApiClient"), [ PrimitiveArgument("Jirka"), PrimitiveArgument(15), PrimitiveArgument(False), ServiceArgument("injecta.api.Connector"), ], ) expected.set_autowire(True) self.assertEqual(expected, result)
def test_basic(self): rawServices = { 'injecta.mocks.Bar.Bar': { 'arguments': [ 'Jiri Koutny' ] }, 'injecta.mocks.Foo.Foo': { 'arguments': [ '@injecta.mocks.Bar.Bar' ] }, 'injecta.mocks.Bar.BarAlias': '@injecta.mocks.Bar.Bar', } expectedService1 = Service( 'injecta.mocks.Bar.Bar', DType('injecta.mocks.Bar', 'Bar'), [ PrimitiveArgument('Jiri Koutny'), ] ) expectedService2 = Service( 'injecta.mocks.Foo.Foo', DType('injecta.mocks.Foo', 'Foo'), [ ServiceArgument('injecta.mocks.Bar.Bar'), ] ) expectedAlias1 = ServiceAlias('injecta.mocks.Bar.BarAlias', 'injecta.mocks.Bar.Bar') services, aliases = self.__servicesPreparer.prepare(rawServices) self.assertEqual(expectedService1, services[0]) self.assertEqual(expectedService2, services[1]) self.assertEqual(expectedAlias1, aliases[0])
def test_factory(self): result = self.__service_parser.parse( "injecta.api.ApiClient", { "factory": ["@injecta.api.ApiClientFactory.ApiClientFactory", "create"], "arguments": [ "Jirka", ], }, ) expected = Service( "injecta.api.ApiClient", DType("injecta.api", "ApiClient"), [ PrimitiveArgument("Jirka"), ], ) expected.set_factory( ServiceArgument("injecta.api.ApiClientFactory.ApiClientFactory"), "create") self.assertEqual(expected, result)
def test_basic(self): result = self.__serviceParser.parse('injecta.api.ApiClient_test', { 'class': 'injecta.api.ApiClient.ApiClient', 'autowire': True, 'arguments': [ 'Jirka', 15, False, '@injecta.api.Connector' ] }) expected = Service( 'injecta.api.ApiClient_test', DType('injecta.api.ApiClient', 'ApiClient'), [ PrimitiveArgument('Jirka'), PrimitiveArgument(15), PrimitiveArgument(False), ServiceArgument('injecta.api.Connector'), ] ) expected.setAutowire(True) self.assertEqual(expected, result)
def resolve(self, resolved_argument: ResolvedArgument, container_build: ContainerBuild): argument = resolved_argument.argument if not isinstance(argument, TaggedAliasedServiceArgument): return resolved_argument services_for_tag = container_build.get_services_by_tag(argument.tag_name) if isinstance(argument.tag_alias, str): tag_alias = self.__resolve_parameter_value(argument.tag_alias, container_build.parameters) else: tag_alias = argument.tag_alias for service in services_for_tag: tag_attributes = service.get_tag_attributes(argument.tag_name) if "alias" not in tag_attributes: raise Exception(f'"alias" attribute is missing for tag {argument.tag_name}') if tag_attributes["alias"] == tag_alias: resolved_argument.modify_argument(ServiceArgument(service.name, argument.name), "tagged_aliased") return resolved_argument raise Exception(f"No service tagged with {argument.tag_name} found for alias: {tag_alias}")