diff --git a/src/dependency_injector/schema.py b/src/dependency_injector/schema.py index 996fab22..023e397f 100644 --- a/src/dependency_injector/schema.py +++ b/src/dependency_injector/schema.py @@ -6,52 +6,64 @@ from typing import Dict, Any, Type, Optional from . import containers, providers -Schema = Dict[Any, Any] +ContainerSchema = Dict[Any, Any] +ProviderSchema = Dict[Any, Any] class SchemaProcessorV1: - def __init__(self, schema: Schema) -> None: + def __init__(self, schema: ContainerSchema) -> None: self._schema = schema self._container = containers.DynamicContainer() def process(self): """Process schema.""" - self._create_providers(self._schema) - self._setup_injections(self._schema) + self._create_providers(self._schema['container']) + self._setup_injections(self._schema['container']) def get_providers(self): """Return providers.""" return self._container.providers - def _create_providers(self, schema: Schema, container: Optional[containers.Container] = None) -> None: + def _create_providers( + self, + provider_schema: ProviderSchema, + container: Optional[containers.Container] = None, + ) -> None: if container is None: container = self._container - for provider_name, data in schema['providers'].items(): - provider_type = _get_provider_cls(data['provider']) - args = [] + for provider_name, data in provider_schema.items(): + provider = None - provides = data.get('provides') - if provides: - provides = _import_string(provides) + if 'provider' in data: + provider_type = _get_provider_cls(data['provider']) + args = [] + + provides = data.get('provides') if provides: - args.append(provides) + provides = _import_string(provides) + if provides: + args.append(provides) - if provider_type is providers.Container: - provides = containers.DynamicContainer - args.append(provides) + provider = provider_type(*args) + + if provider is None: + provider = providers.Container(containers.DynamicContainer) - provider = provider_type(*args) container.set_provider(provider_name, provider) if isinstance(provider, providers.Container): - self._create_providers(schema=data, container=provider) + self._create_providers(provider_schema=data, container=provider) - def _setup_injections(self, schema: Schema, container: Optional[containers.Container] = None) -> None: + def _setup_injections( + self, + provider_schema: ProviderSchema, + container: Optional[containers.Container] = None, + ) -> None: if container is None: container = self._container - for provider_name, data in schema['providers'].items(): + for provider_name, data in provider_schema.items(): provider = getattr(container, provider_name) args = [] kwargs = {} @@ -61,10 +73,22 @@ class SchemaProcessorV1: for arg in arg_injections: injection = None - if isinstance(arg, str): - injection = self._resolve_provider(arg) + if isinstance(arg, str) and arg.startswith('container.'): + injection = self._resolve_provider(arg[len('container.'):]) - # TODO: add inline injections + # TODO: refactoring + if isinstance(arg, dict): + provider_args = [] + provider_type = _get_provider_cls(arg.get('provider')) + provides = arg.get('provides') + if provides: + provides = _import_string(provides) + if provides: + provider_args.append(provides) + for provider_arg in arg.get('args', []): + if isinstance(provider_arg, str) and provider_arg.startswith('container.'): + provider_args.append(self._resolve_provider(provider_arg[len('container.'):])) + injection = provider_type(*provider_args) if not injection: injection = arg @@ -78,8 +102,8 @@ class SchemaProcessorV1: for name, arg in kwarg_injections.items(): injection = None - if isinstance(arg, str): - injection = self._resolve_provider(arg) + if isinstance(arg, str) and arg.startswith('container.'): + injection = self._resolve_provider(arg[len('container.'):]) # TODO: refactoring if isinstance(arg, dict): @@ -91,7 +115,8 @@ class SchemaProcessorV1: if provides: provider_args.append(provides) for provider_arg in arg.get('args', []): - provider_args.append(self._resolve_provider(provider_arg)) + if isinstance(provider_arg, str) and provider_arg.startswith('container.'): + provider_args.append(self._resolve_provider(provider_arg[len('container.'):])) injection = provider_type(*provider_args) if not injection: @@ -102,7 +127,7 @@ class SchemaProcessorV1: provider.add_kwargs(**kwargs) if isinstance(provider, providers.Container): - self._setup_injections(schema=data, container=provider) + self._setup_injections(provider_schema=data, container=provider) def _resolve_provider(self, name: str) -> Optional[providers.Provider]: segments = name.split('.') @@ -127,7 +152,7 @@ class SchemaProcessorV1: return provider -def build_schema(schema: Schema) -> Dict[str, providers.Provider]: +def build_schema(schema: ContainerSchema) -> Dict[str, providers.Provider]: """Build provider schema.""" schema_processor = SchemaProcessorV1(schema) schema_processor.process() diff --git a/tests/unit/samples/schemasample/container-multiple-inline.yml b/tests/unit/samples/schemasample/container-multiple-inline.yml index 58a3f08e..a089508f 100644 --- a/tests/unit/samples/schemasample/container-multiple-inline.yml +++ b/tests/unit/samples/schemasample/container-multiple-inline.yml @@ -1,61 +1,58 @@ version: "1" -providers: +container: core: - provider: Container - providers: - config: - provider: Configuration + config: + provider: Configuration gateways: - provider: Container - providers: - database_client: - provider: Singleton - provides: sqlite3.connect - args: - - core.config.database.dsn + database_client: + provider: Singleton + provides: sqlite3.connect + args: + - provider: Callable + provides: schemasample.utils.return_ + args: + - container.core.config.database.dsn - s3_client: - provider: Singleton - provides: boto3.client - kwargs: - service_name: s3 - aws_access_key_id: core.config.aws.access_key_id - aws_secret_access_key: core.config.aws.secret_access_key + s3_client: + provider: Singleton + provides: boto3.client + kwargs: + service_name: s3 + aws_access_key_id: container.core.config.aws.access_key_id + aws_secret_access_key: container.core.config.aws.secret_access_key services: - provider: Container - providers: - user: - provider: Factory - provides: schemasample.services.UserService - kwargs: - db: - provider: Callable - provides: schemasample.utils.return_ - args: - - gateways.database_client + user: + provider: Factory + provides: schemasample.services.UserService + kwargs: + db: + provider: Callable + provides: schemasample.utils.return_ + args: + - container.gateways.database_client - auth: - provider: Factory - provides: schemasample.services.AuthService - kwargs: - db: - provider: Callable - provides: schemasample.utils.return_ - args: - - gateways.database_client - token_ttl: core.config.auth.token_ttl.as_int() + auth: + provider: Factory + provides: schemasample.services.AuthService + kwargs: + db: + provider: Callable + provides: schemasample.utils.return_ + args: + - container.gateways.database_client + token_ttl: container.core.config.auth.token_ttl.as_int() - photo: - provider: Factory - provides: schemasample.services.PhotoService - kwargs: - db: - provider: Callable - provides: schemasample.utils.return_ - args: - - gateways.database_client - s3: gateways.s3_client + photo: + provider: Factory + provides: schemasample.services.PhotoService + kwargs: + db: + provider: Callable + provides: schemasample.utils.return_ + args: + - container.gateways.database_client + s3: container.gateways.s3_client diff --git a/tests/unit/samples/schemasample/container-multiple-reordered.yml b/tests/unit/samples/schemasample/container-multiple-reordered.yml index e899daa5..245c4f37 100644 --- a/tests/unit/samples/schemasample/container-multiple-reordered.yml +++ b/tests/unit/samples/schemasample/container-multiple-reordered.yml @@ -1,49 +1,43 @@ version: "1" -providers: +container: services: - provider: Container - providers: - user: - provider: Factory - provides: schemasample.services.UserService - kwargs: - db: gateways.database_client + user: + provider: Factory + provides: schemasample.services.UserService + kwargs: + db: container.gateways.database_client - auth: - provider: Factory - provides: schemasample.services.AuthService - kwargs: - db: gateways.database_client - token_ttl: core.config.auth.token_ttl.as_int() + auth: + provider: Factory + provides: schemasample.services.AuthService + kwargs: + db: container.gateways.database_client + token_ttl: container.core.config.auth.token_ttl.as_int() - photo: - provider: Factory - provides: schemasample.services.PhotoService - kwargs: - db: gateways.database_client - s3: gateways.s3_client + photo: + provider: Factory + provides: schemasample.services.PhotoService + kwargs: + db: container.gateways.database_client + s3: container.gateways.s3_client gateways: - provider: Container - providers: - database_client: - provider: Singleton - provides: sqlite3.connect - args: - - core.config.database.dsn + database_client: + provider: Singleton + provides: sqlite3.connect + args: + - container.core.config.database.dsn - s3_client: - provider: Singleton - provides: boto3.client - kwargs: - service_name: s3 - aws_access_key_id: core.config.aws.access_key_id - aws_secret_access_key: core.config.aws.secret_access_key + s3_client: + provider: Singleton + provides: boto3.client + kwargs: + service_name: s3 + aws_access_key_id: core.config.aws.access_key_id + aws_secret_access_key: core.config.aws.secret_access_key core: - provider: Container - providers: - config: - provider: Configuration + config: + provider: Configuration diff --git a/tests/unit/samples/schemasample/container-multiple.yml b/tests/unit/samples/schemasample/container-multiple.yml index b0616c72..03a5221a 100644 --- a/tests/unit/samples/schemasample/container-multiple.yml +++ b/tests/unit/samples/schemasample/container-multiple.yml @@ -1,49 +1,43 @@ version: "1" -providers: +container: core: - provider: Container - providers: - config: - provider: Configuration + config: + provider: Configuration gateways: - provider: Container - providers: - database_client: - provider: Singleton - provides: sqlite3.connect - args: - - core.config.database.dsn + database_client: + provider: Singleton + provides: sqlite3.connect + args: + - container.core.config.database.dsn - s3_client: - provider: Singleton - provides: boto3.client - kwargs: - service_name: s3 - aws_access_key_id: core.config.aws.access_key_id - aws_secret_access_key: core.config.aws.secret_access_key + s3_client: + provider: Singleton + provides: boto3.client + kwargs: + service_name: s3 + aws_access_key_id: container.core.config.aws.access_key_id + aws_secret_access_key: container.core.config.aws.secret_access_key services: - provider: Container - providers: - user: - provider: Factory - provides: schemasample.services.UserService - kwargs: - db: gateways.database_client + user: + provider: Factory + provides: schemasample.services.UserService + kwargs: + db: container.gateways.database_client - auth: - provider: Factory - provides: schemasample.services.AuthService - kwargs: - db: gateways.database_client - token_ttl: core.config.auth.token_ttl.as_int() + auth: + provider: Factory + provides: schemasample.services.AuthService + kwargs: + db: container.gateways.database_client + token_ttl: container.core.config.auth.token_ttl.as_int() - photo: - provider: Factory - provides: schemasample.services.PhotoService - kwargs: - db: gateways.database_client - s3: gateways.s3_client + photo: + provider: Factory + provides: schemasample.services.PhotoService + kwargs: + db: container.gateways.database_client + s3: container.gateways.s3_client diff --git a/tests/unit/samples/schemasample/container-single.yml b/tests/unit/samples/schemasample/container-single.yml index e90a0429..ad732992 100644 --- a/tests/unit/samples/schemasample/container-single.yml +++ b/tests/unit/samples/schemasample/container-single.yml @@ -1,6 +1,6 @@ version: "1" -providers: +container: config: provider: Configuration @@ -8,32 +8,32 @@ providers: provider: Singleton provides: sqlite3.connect args: - - config.database.dsn + - container.config.database.dsn s3_client: provider: Singleton provides: boto3.client kwargs: service_name: s3 - aws_access_key_id: config.aws.access_key_id - aws_secret_access_key: config.aws.secret_access_key + aws_access_key_id: container.config.aws.access_key_id + aws_secret_access_key: container.config.aws.secret_access_key user_service: provider: Factory provides: schemasample.services.UserService kwargs: - db: database_client + db: container.database_client auth_service: provider: Factory provides: schemasample.services.AuthService kwargs: - db: database_client - token_ttl: config.auth.token_ttl.as_int() + db: container.database_client + token_ttl: container.config.auth.token_ttl.as_int() photo_service: provider: Factory provides: schemasample.services.PhotoService kwargs: - db: database_client - s3: s3_client + db: container.database_client + s3: container.s3_client diff --git a/tests/unit/schema/test_containers_api_py36.py b/tests/unit/schema/test_containers_api_py36.py index 6dd136f8..eb44bd4d 100644 --- a/tests/unit/schema/test_containers_api_py36.py +++ b/tests/unit/schema/test_containers_api_py36.py @@ -15,7 +15,7 @@ class FromSchemaTests(unittest.TestCase): container.from_schema( { 'version': '1', - 'providers': { + 'container': { 'provider1': { 'provider': 'Factory', 'provides': 'list', @@ -25,7 +25,7 @@ class FromSchemaTests(unittest.TestCase): 'provider': 'Factory', 'provides': 'dict', 'kwargs': { - 'one': 'provider1', + 'one': 'container.provider1', 'two': 2, }, }, @@ -52,7 +52,7 @@ class FromYamlSchemaTests(unittest.TestCase): with open(schema_path, 'w') as file: file.write(""" version: "1" - providers: + container: provider1: provider: Factory provides: list @@ -64,7 +64,7 @@ class FromYamlSchemaTests(unittest.TestCase): provider: Factory provides: dict kwargs: - one: provider1 + one: container.provider1 two: 2 """) @@ -86,7 +86,7 @@ class FromYamlSchemaTests(unittest.TestCase): with open(schema_path, 'w') as file: file.write(""" version: "1" - providers: + container: provider: provider: Factory provides: list @@ -131,7 +131,7 @@ class FromJsonSchemaTests(unittest.TestCase): json.dumps( { 'version': '1', - 'providers': { + 'container': { 'provider1': { 'provider': 'Factory', 'provides': 'list', @@ -141,7 +141,7 @@ class FromJsonSchemaTests(unittest.TestCase): 'provider': 'Factory', 'provides': 'dict', 'kwargs': { - 'one': 'provider1', + 'one': 'container.provider1', 'two': 2, }, },