Implement from_*() methods and add tests

This commit is contained in:
Roman Mogylatov 2021-02-24 08:56:09 -05:00
parent 3c3c6def6d
commit 73d9c97c1b
5 changed files with 3212 additions and 2252 deletions

File diff suppressed because it is too large Load Diff

View File

@ -51,8 +51,8 @@ class Container:
def reset_singletons(self) -> SingletonResetContext[C_Base]: ... def reset_singletons(self) -> SingletonResetContext[C_Base]: ...
def check_dependencies(self) -> None: ... def check_dependencies(self) -> None: ...
def from_schema(self, schema: Dict[Any, Any]) -> None: ... def from_schema(self, schema: Dict[Any, Any]) -> None: ...
def from_yaml_schema(self, filepath: Union[Path, str]) -> None: def from_yaml_schema(self, filepath: Union[Path, str], loader: Optional[Any]=None) -> None: ...
def from_json_schema(self, filepath: Union[Path, str]) -> None: def from_json_schema(self, filepath: Union[Path, str]) -> None: ...
@overload @overload
def resolve_provider_name(self, provider: Provider) -> str: ... def resolve_provider_name(self, provider: Provider) -> str: ...
@classmethod @classmethod

View File

@ -1,5 +1,6 @@
"""Containers module.""" """Containers module."""
import json
import sys import sys
try: try:
@ -7,6 +8,11 @@ try:
except ImportError: except ImportError:
asyncio = None asyncio = None
try:
import yaml
except ImportError:
yaml = None
import six import six
from . import providers, errors from . import providers, errors
@ -336,15 +342,32 @@ class DynamicContainer(Container):
for name, provider in build_schema(schema).items(): for name, provider in build_schema(schema).items():
self.set_provider(name, provider) self.set_provider(name, provider)
def from_yaml_schema(self, filepath): def from_yaml_schema(self, filepath, loader=None):
"""Build container providers from YAML file schema.""" """Build container providers from YAML schema.
# TODO
... You can specify type of loader as a second argument. By default, method
uses ``SafeLoader``.
"""
if yaml is None:
raise errors.Error(
'Unable to load yaml schema - PyYAML is not installed. '
'Install PyYAML or install Dependency Injector with yaml extras: '
'"pip install dependency-injector[yaml]"'
)
if loader is None:
loader = yaml.SafeLoader
with open(filepath) as file:
schema = yaml.load(file, loader)
self.from_schema(schema)
def from_json_schema(self, filepath): def from_json_schema(self, filepath):
"""Build container providers from JSON file schema.""" """Build container providers from JSON schema."""
# TODO with open(filepath) as file:
... schema = json.load(file)
self.from_schema(schema)
def resolve_provider_name(self, provider): def resolve_provider_name(self, provider):
"""Try to resolve provider name.""" """Try to resolve provider name."""

View File

@ -59,9 +59,14 @@ def _setup_injections(
arg_injections = data.get('args') arg_injections = data.get('args')
if arg_injections: if arg_injections:
for arg in arg_injections: for arg in arg_injections:
injection = None
if isinstance(arg, str):
injection = _resolve_provider(container, arg) injection = _resolve_provider(container, arg)
if not injection: if not injection:
injection = arg injection = arg
args.append(injection) args.append(injection)
if args: if args:
provider.add_args(*args) provider.add_args(*args)
@ -69,9 +74,14 @@ def _setup_injections(
kwarg_injections = data.get('kwargs') kwarg_injections = data.get('kwargs')
if kwarg_injections: if kwarg_injections:
for name, arg in kwarg_injections.items(): for name, arg in kwarg_injections.items():
injection = None
if isinstance(arg, str):
injection = _resolve_provider(container, arg) injection = _resolve_provider(container, arg)
if not injection: if not injection:
injection = arg injection = arg
kwargs[name] = injection kwargs[name] = injection
if kwargs: if kwargs:
provider.add_kwargs(**kwargs) provider.add_kwargs(**kwargs)
@ -112,7 +122,7 @@ def _get_provider_cls(provider_cls_name: str) -> Type[providers.Provider]:
if custom_provider_type: if custom_provider_type:
return custom_provider_type return custom_provider_type
raise SchemaError(f'Undefined provider class: "{provider_cls_name}"') raise SchemaError(f'Undefined provider class "{provider_cls_name}"')
def _fetch_provider_cls_from_std(provider_cls_name: str) -> Optional[Type[providers.Provider]]: def _fetch_provider_cls_from_std(provider_cls_name: str) -> Optional[Type[providers.Provider]]:
@ -134,7 +144,16 @@ def _import_provider_cls(provider_cls_name: str) -> Optional[Type[providers.Prov
def _import_string(string_name: str) -> Optional[object]: def _import_string(string_name: str) -> Optional[object]:
segments = string_name.split('.') segments = string_name.split('.')
if len(segments) == 1:
member = __builtins__.get(segments[0])
if member:
return member
module_name = '.'.join(segments[:-1]) module_name = '.'.join(segments[:-1])
if not module_name:
return None
member = segments[-1] member = segments[-1]
module = importlib.import_module(module_name) module = importlib.import_module(module_name)
return getattr(module, member, None) return getattr(module, member, None)

View File

@ -0,0 +1,162 @@
import contextlib
import json
import os.path
import tempfile
import unittest
import yaml
from dependency_injector import containers, providers, errors
class FromSchemaTests(unittest.TestCase):
def test(self):
container = containers.DynamicContainer()
container.from_schema(
{
'version': '1',
'providers': {
'provider1': {
'provider': 'Factory',
'provides': 'list',
'args': [1, 2, 3],
},
'provider2': {
'provider': 'Factory',
'provides': 'dict',
'kwargs': {
'one': 'provider1',
'two': 2,
},
},
},
},
)
self.assertIsInstance(container.provider1, providers.Factory)
self.assertIs(container.provider1.provides, list)
self.assertEqual(container.provider1.args, (1, 2, 3))
self.assertIsInstance(container.provider2, providers.Factory)
self.assertIs(container.provider2.provides, dict)
self.assertEqual(container.provider2.kwargs, {'one': container.provider1, 'two': 2})
class FromYamlSchemaTests(unittest.TestCase):
def test(self):
container = containers.DynamicContainer()
with tempfile.TemporaryDirectory() as tmp_dir:
schema_path = os.path.join(tmp_dir, 'schema.yml')
with open(schema_path, 'w') as file:
file.write("""
version: "1"
providers:
provider1:
provider: Factory
provides: list
args:
- 1
- 2
- 3
provider2:
provider: Factory
provides: dict
kwargs:
one: provider1
two: 2
""")
container.from_yaml_schema(schema_path)
self.assertIsInstance(container.provider1, providers.Factory)
self.assertIs(container.provider1.provides, list)
self.assertEqual(container.provider1.args, (1, 2, 3))
self.assertIsInstance(container.provider2, providers.Factory)
self.assertIs(container.provider2.provides, dict)
self.assertEqual(container.provider2.kwargs, {'one': container.provider1, 'two': 2})
def test_with_loader(self):
container = containers.DynamicContainer()
with tempfile.TemporaryDirectory() as tmp_dir:
schema_path = os.path.join(tmp_dir, 'schema.yml')
with open(schema_path, 'w') as file:
file.write("""
version: "1"
providers:
provider:
provider: Factory
provides: list
args: [1, 2, 3]
""")
container.from_yaml_schema(schema_path, loader=yaml.Loader)
self.assertIsInstance(container.provider, providers.Factory)
self.assertIs(container.provider.provides, list)
self.assertEqual(container.provider.args, (1, 2, 3))
def test_no_yaml_installed(self):
@contextlib.contextmanager
def no_yaml_module():
containers.yaml = None
yield
containers.yaml = yaml
container = containers.DynamicContainer()
with no_yaml_module():
with self.assertRaises(errors.Error) as error:
container.from_yaml_schema('./no-yaml-installed.yml')
self.assertEqual(
error.exception.args[0],
'Unable to load yaml schema - PyYAML is not installed. '
'Install PyYAML or install Dependency Injector with yaml extras: '
'"pip install dependency-injector[yaml]"',
)
class FromJsonSchemaTests(unittest.TestCase):
def test(self):
container = containers.DynamicContainer()
with tempfile.TemporaryDirectory() as tmp_dir:
schema_path = os.path.join(tmp_dir, 'schema.json')
with open(schema_path, 'w') as file:
file.write(
json.dumps(
{
'version': '1',
'providers': {
'provider1': {
'provider': 'Factory',
'provides': 'list',
'args': [1, 2, 3],
},
'provider2': {
'provider': 'Factory',
'provides': 'dict',
'kwargs': {
'one': 'provider1',
'two': 2,
},
},
},
},
indent=4,
),
)
container.from_json_schema(schema_path)
self.assertIsInstance(container.provider1, providers.Factory)
self.assertIs(container.provider1.provides, list)
self.assertEqual(container.provider1.args, (1, 2, 3))
self.assertIsInstance(container.provider2, providers.Factory)
self.assertIs(container.provider2.provides, dict)
self.assertEqual(container.provider2.kwargs, {'one': container.provider1, 'two': 2})