mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-22 09:36:48 +03:00
Merge branch 'release/3.18.0' into master
This commit is contained in:
commit
5718140a82
4
Makefile
4
Makefile
|
@ -61,8 +61,8 @@ test-py3: build
|
|||
|
||||
check:
|
||||
# Static analysis
|
||||
flake8 --max-complexity=10 src/dependency_injector/
|
||||
flake8 --max-complexity=10 examples/
|
||||
flake8 src/dependency_injector/
|
||||
flake8 examples/
|
||||
# Code style analysis
|
||||
pydocstyle src/dependency_injector/
|
||||
pydocstyle examples/
|
||||
|
|
|
@ -7,6 +7,16 @@ that were made in every particular version.
|
|||
From version 0.7.6 *Dependency Injector* framework strictly
|
||||
follows `Semantic versioning`_
|
||||
|
||||
3.18.0
|
||||
------
|
||||
- Add ``Configuration.from_yaml()`` method to load configuration from the yaml file.
|
||||
- Add ``Configuration.from_ini()`` method to load configuration from the ini file.
|
||||
- Add ``Configuration.from_dict()`` method to load configuration from the dictionary.
|
||||
- Add ``Configuration.from_env()`` method to load configuration from the environment variable.
|
||||
- Add default value for ``name`` argument of ``Configuration`` provider.
|
||||
- Add documentation for ``Configuration`` provider.
|
||||
- Remove undocumented positional parameter of ``DependenciesContainer`` provider.
|
||||
|
||||
3.17.1
|
||||
------
|
||||
- Fix ``DynamicContainer`` deep-copying bug.
|
||||
|
|
88
docs/providers/configuration.rst
Normal file
88
docs/providers/configuration.rst
Normal file
|
@ -0,0 +1,88 @@
|
|||
Configuration providers
|
||||
-----------------------
|
||||
|
||||
.. currentmodule:: dependency_injector.providers
|
||||
|
||||
:py:class:`Configuration` provider provides configuration options to the other providers.
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration.py
|
||||
:language: python
|
||||
:emphasize-lines: 7,12-13,18-25
|
||||
:linenos:
|
||||
|
||||
It implements "use first, define later" principle.
|
||||
|
||||
Loading from ``ini`` file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:py:class:`Configuration` provider can load configuration from ``ini`` file using
|
||||
:py:meth:`Configuration.from_ini`:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_ini.py
|
||||
:language: python
|
||||
:lines: 6-
|
||||
:emphasize-lines: 3
|
||||
:linenos:
|
||||
|
||||
where ``examples/providers/configuration/config.ini`` is:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/config.ini
|
||||
:language: ini
|
||||
:linenos:
|
||||
|
||||
Loading from ``yaml`` file
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:py:class:`Configuration` provider can load configuration from ``yaml`` file using
|
||||
:py:meth:`Configuration.from_yaml`:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_yaml.py
|
||||
:language: python
|
||||
:lines: 6-
|
||||
:emphasize-lines: 3
|
||||
:linenos:
|
||||
|
||||
where ``examples/providers/configuration/config.yml`` is:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/config.yml
|
||||
:language: ini
|
||||
:linenos:
|
||||
|
||||
.. note::
|
||||
|
||||
Loading configuration from yaml requires ``PyYAML`` package. You can install
|
||||
`Dependency Injector` with extras ``pip install dependency-injector[yaml]`` or install
|
||||
``PyYAML`` separately ``pip install pyyaml``.
|
||||
|
||||
Loading from environment variable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:py:class:`Configuration` provider can load configuration from environment variable using
|
||||
:py:meth:`Configuration.from_env`:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_env.py
|
||||
:language: python
|
||||
:lines: 13-21
|
||||
:emphasize-lines: 3-5
|
||||
:linenos:
|
||||
|
||||
|
||||
Loading from multiple sources
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:py:class:`Configuration` provider can load configuration from multiple sources. Loaded
|
||||
configuration is merged recursively over existing configuration.
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_multiple.py
|
||||
:language: python
|
||||
:lines: 6-14
|
||||
:emphasize-lines: 3-4
|
||||
:linenos:
|
||||
|
||||
where ``examples/providers/configuration/config.local.yml`` is:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/config.local.yml
|
||||
:language: ini
|
||||
:linenos:
|
||||
|
||||
.. disqus::
|
|
@ -23,6 +23,7 @@ Providers package API docs - :py:mod:`dependency_injector.providers`
|
|||
coroutine
|
||||
object
|
||||
list
|
||||
configuration
|
||||
dependency
|
||||
overriding
|
||||
custom
|
||||
|
|
3
examples/providers/configuration/config.ini
Normal file
3
examples/providers/configuration/config.ini
Normal file
|
@ -0,0 +1,3 @@
|
|||
[aws]
|
||||
access_key_id = KEY
|
||||
secret_access_key = SECRET
|
3
examples/providers/configuration/config.local.yml
Normal file
3
examples/providers/configuration/config.local.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
aws:
|
||||
access_key_id: "LOCAL-KEY"
|
||||
secret_access_key: "LOCAL-SECRET"
|
3
examples/providers/configuration/config.yml
Normal file
3
examples/providers/configuration/config.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
aws:
|
||||
access_key_id: "KEY"
|
||||
secret_access_key: "SECRET"
|
26
examples/providers/configuration/configuration.py
Normal file
26
examples/providers/configuration/configuration.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
"""`Configuration` provider example."""
|
||||
|
||||
import boto3
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
|
||||
s3_client_factory = providers.Factory(
|
||||
boto3.client,
|
||||
's3',
|
||||
aws_access_key_id=config.aws.access_key_id,
|
||||
aws_secret_access_key=config.aws.secret_access_key,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
config.from_dict(
|
||||
{
|
||||
'aws': {
|
||||
'access_key_id': 'KEY',
|
||||
'secret_access_key': 'SECRET',
|
||||
},
|
||||
},
|
||||
)
|
||||
s3_client = s3_client_factory()
|
21
examples/providers/configuration/configuration_env.py
Normal file
21
examples/providers/configuration/configuration_env.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
"""`Configuration` provider values loading example."""
|
||||
|
||||
import os
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Emulate environment variables
|
||||
os.environ['AWS_ACCESS_KEY_ID'] = 'KEY'
|
||||
os.environ['AWS_SECRET_ACCESS_KEY'] = 'SECRET'
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
|
||||
config.aws.access_key_id.from_env('AWS_ACCESS_KEY_ID')
|
||||
config.aws.secret_access_key.from_env('AWS_SECRET_ACCESS_KEY')
|
||||
config.optional.from_env('UNDEFINED', 'default_value')
|
||||
|
||||
assert config.aws.access_key_id() == 'KEY'
|
||||
assert config.aws.secret_access_key() == 'SECRET'
|
||||
assert config.optional() == 'default_value'
|
13
examples/providers/configuration/configuration_ini.py
Normal file
13
examples/providers/configuration/configuration_ini.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
"""`Configuration` provider values loading example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
|
||||
config.from_ini('examples/providers/configuration/config.ini')
|
||||
|
||||
assert config() == {'aws': {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}}
|
||||
assert config.aws() == {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}
|
||||
assert config.aws.access_key_id() == 'KEY'
|
||||
assert config.aws.secret_access_key() == 'SECRET'
|
14
examples/providers/configuration/configuration_multiple.py
Normal file
14
examples/providers/configuration/configuration_multiple.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
"""`Configuration` provider values loading example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
|
||||
config.from_yaml('examples/providers/configuration/config.yml')
|
||||
config.from_yaml('examples/providers/configuration/config.local.yml')
|
||||
|
||||
assert config() == {'aws': {'access_key_id': 'LOCAL-KEY', 'secret_access_key': 'LOCAL-SECRET'}}
|
||||
assert config.aws() == {'access_key_id': 'LOCAL-KEY', 'secret_access_key': 'LOCAL-SECRET'}
|
||||
assert config.aws.access_key_id() == 'LOCAL-KEY'
|
||||
assert config.aws.secret_access_key() == 'LOCAL-SECRET'
|
13
examples/providers/configuration/configuration_yaml.py
Normal file
13
examples/providers/configuration/configuration_yaml.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
"""`Configuration` provider values loading example."""
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
config = providers.Configuration()
|
||||
|
||||
config.from_yaml('examples/providers/configuration/config.yml')
|
||||
|
||||
assert config() == {'aws': {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}}
|
||||
assert config.aws() == {'access_key_id': 'KEY', 'secret_access_key': 'SECRET'}
|
||||
assert config.aws.access_key_id() == 'KEY'
|
||||
assert config.aws.secret_access_key() == 'SECRET'
|
11
setup.py
11
setup.py
|
@ -39,13 +39,15 @@ setup(name='dependency-injector',
|
|||
maintainer_email='rmogilatov@gmail.com',
|
||||
url='https://github.com/ets-labs/python-dependency-injector',
|
||||
download_url='https://pypi.python.org/pypi/dependency_injector',
|
||||
install_requires=requirements,
|
||||
packages=[
|
||||
'dependency_injector',
|
||||
],
|
||||
package_dir={
|
||||
'': 'src',
|
||||
},
|
||||
package_data={
|
||||
'dependency_injector': ['*.pxd'],
|
||||
},
|
||||
ext_modules=[
|
||||
Extension('dependency_injector.containers',
|
||||
['src/dependency_injector/containers.c'],
|
||||
|
@ -56,8 +58,11 @@ setup(name='dependency-injector',
|
|||
define_macros=list(defined_macros.items()),
|
||||
extra_compile_args=['-O2']),
|
||||
],
|
||||
package_data={
|
||||
'dependency_injector': ['*.pxd'],
|
||||
install_requires=requirements,
|
||||
extras_require={
|
||||
'yaml': [
|
||||
'pyyaml',
|
||||
],
|
||||
},
|
||||
zip_safe=True,
|
||||
license='BSD New',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Dependency injector top-level package."""
|
||||
|
||||
__version__ = '3.17.1'
|
||||
__version__ = '3.18.0'
|
||||
"""Version number that follows semantic versioning.
|
||||
|
||||
:type: str
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,8 +3,8 @@
|
|||
Powered by Cython.
|
||||
"""
|
||||
|
||||
|
||||
import copy
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
import threading
|
||||
|
@ -21,6 +21,15 @@ else:
|
|||
else:
|
||||
_is_coroutine_marker = True
|
||||
|
||||
try:
|
||||
import ConfigParser as iniconfigparser
|
||||
except ImportError:
|
||||
import configparser as iniconfigparser
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
yaml = None
|
||||
|
||||
from .errors import (
|
||||
Error,
|
||||
|
@ -503,14 +512,10 @@ cdef class DependenciesContainer(Object):
|
|||
use_case.execute()
|
||||
"""
|
||||
|
||||
def __init__(self, provides=None, **dependencies):
|
||||
def __init__(self, **dependencies):
|
||||
"""Initializer."""
|
||||
self.__providers = dependencies
|
||||
|
||||
if provides:
|
||||
self._override_providers(container=provides)
|
||||
|
||||
super(DependenciesContainer, self).__init__(provides)
|
||||
super(DependenciesContainer, self).__init__(None)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
"""Create and return full copy of provider."""
|
||||
|
@ -997,10 +1002,7 @@ cdef class CoroutineDelegate(Delegate):
|
|||
|
||||
|
||||
cdef class Configuration(Object):
|
||||
"""Configuration provider.
|
||||
|
||||
Configuration provider helps with implementing late static binding of
|
||||
configuration options - use first, define later.
|
||||
"""Configuration provider provides configuration options to the other providers.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -1009,14 +1011,22 @@ cdef class Configuration(Object):
|
|||
print(config.section1.option1()) # None
|
||||
print(config.section1.option2()) # None
|
||||
|
||||
config.override({'section1': {'option1': 1,
|
||||
'option2': 2}})
|
||||
config.from_dict(
|
||||
{
|
||||
'section1': {
|
||||
'option1': 1,
|
||||
'option2': 2,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
print(config.section1.option1()) # 1
|
||||
print(config.section1.option2()) # 2
|
||||
"""
|
||||
|
||||
def __init__(self, name, default=None):
|
||||
DEFAULT_NAME = 'config'
|
||||
|
||||
def __init__(self, name=None, default=None):
|
||||
"""Initializer.
|
||||
|
||||
:param name: Name of configuration unit.
|
||||
|
@ -1027,6 +1037,9 @@ cdef class Configuration(Object):
|
|||
"""
|
||||
super(Configuration, self).__init__(default)
|
||||
|
||||
if name is None:
|
||||
name = self.DEFAULT_NAME
|
||||
|
||||
self.__name = name
|
||||
self.__children = self._create_children(default)
|
||||
self.__linked = list()
|
||||
|
@ -1155,6 +1168,82 @@ cdef class Configuration(Object):
|
|||
"""
|
||||
self.override(value)
|
||||
|
||||
def from_ini(self, filepath):
|
||||
"""Load configuration from the ini file.
|
||||
|
||||
Loaded configuration is merged recursively over existing configuration.
|
||||
|
||||
:param filepath: Path to the configuration file.
|
||||
:type filepath: str
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
parser = iniconfigparser.ConfigParser()
|
||||
parser.read([filepath])
|
||||
|
||||
config = {}
|
||||
for section in parser.sections():
|
||||
config[section] = dict(parser.items(section))
|
||||
|
||||
current_config = self.__call__()
|
||||
if not current_config:
|
||||
current_config = {}
|
||||
self.override(merge_dicts(current_config, config))
|
||||
|
||||
def from_yaml(self, filepath):
|
||||
"""Load configuration from the yaml file.
|
||||
|
||||
Loaded configuration is merged recursively over existing configuration.
|
||||
|
||||
:param filepath: Path to the configuration file.
|
||||
:type filepath: str
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if yaml is None:
|
||||
raise Error(
|
||||
'Unable to load yaml configuration - PyYAML is not installed. '
|
||||
'Install PyYAML or install Dependency Injector with yaml extras: '
|
||||
'"pip install dependency-injector[yaml]"'
|
||||
)
|
||||
|
||||
with open(filepath) as opened_file:
|
||||
config = yaml.load(opened_file, yaml.Loader)
|
||||
|
||||
current_config = self.__call__()
|
||||
if not current_config:
|
||||
current_config = {}
|
||||
self.override(merge_dicts(current_config, config))
|
||||
|
||||
def from_dict(self, options):
|
||||
"""Load configuration from the dictionary.
|
||||
|
||||
Loaded configuration is merged recursively over existing configuration.
|
||||
|
||||
:param options: Configuration options.
|
||||
:type options: dict
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
current_config = self.__call__()
|
||||
if not current_config:
|
||||
current_config = {}
|
||||
self.override(merge_dicts(current_config, options))
|
||||
|
||||
def from_env(self, name, default=None):
|
||||
"""Load configuration value from the environment variable.
|
||||
|
||||
:param name: Name of the environment variable.
|
||||
:type name: str
|
||||
|
||||
:param default: Default value that is used if environment variable does not exist.
|
||||
:type default: str
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
value = os.getenv(name, default)
|
||||
self.override(value)
|
||||
|
||||
def _create_children(self, value):
|
||||
children = dict()
|
||||
|
||||
|
@ -2119,7 +2208,6 @@ cdef class Container(Provider):
|
|||
deepcopy(self.container, memo),
|
||||
**deepcopy(self.overriding_providers, memo),
|
||||
)
|
||||
# self._copy_overridings(copied, memo)
|
||||
|
||||
return copied
|
||||
|
||||
|
@ -2321,3 +2409,24 @@ def __add_sys_streams(memo):
|
|||
memo[id(sys.stdin)] = sys.stdin
|
||||
memo[id(sys.stdout)] = sys.stdout
|
||||
memo[id(sys.stderr)] = sys.stderr
|
||||
|
||||
|
||||
def merge_dicts(dict1, dict2):
|
||||
"""Merge dictionaries recursively.
|
||||
|
||||
:param dict1: Dictionary 1
|
||||
:type dict1: dict
|
||||
|
||||
:param dict2: Dictionary 2
|
||||
:type dict2: dict
|
||||
|
||||
:return: New resulting dictionary
|
||||
:rtype: dict
|
||||
"""
|
||||
for key, value in dict1.items():
|
||||
if key in dict2:
|
||||
if isinstance(value, dict) and isinstance(dict2[key], dict):
|
||||
dict2[key] = merge_dicts(value, dict2[key])
|
||||
result = dict1.copy()
|
||||
result.update(dict2)
|
||||
return result
|
||||
|
|
|
@ -367,11 +367,3 @@ class DependenciesContainerTests(unittest.TestCase):
|
|||
|
||||
self.assertFalse(dependency.overridden)
|
||||
self.assertFalse(dependency.overridden)
|
||||
|
||||
def test_init_with_container_and_providers(self):
|
||||
provider = providers.DependenciesContainer(
|
||||
self.container, dependency=providers.Dependency())
|
||||
dependency = provider.dependency
|
||||
|
||||
self.assertTrue(dependency.overridden)
|
||||
self.assertIs(dependency.last_overriding, self.container.dependency)
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
"""Dependency injector config providers unit tests."""
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import unittest2 as unittest
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector import containers, providers, errors
|
||||
|
||||
|
||||
class ConfigTests(unittest.TestCase):
|
||||
|
@ -13,6 +18,10 @@ class ConfigTests(unittest.TestCase):
|
|||
def tearDown(self):
|
||||
del self.config
|
||||
|
||||
def test_default_name(self):
|
||||
config = providers.Configuration()
|
||||
self.assertEqual(config.get_name(), 'config')
|
||||
|
||||
def test_providers_are_providers(self):
|
||||
self.assertTrue(providers.is_provider(self.config.a))
|
||||
self.assertTrue(providers.is_provider(self.config.a.b))
|
||||
|
@ -246,3 +255,246 @@ class ConfigLinkingTests(unittest.TestCase):
|
|||
self.assertEqual(services.config(), {'value': 'services2'})
|
||||
self.assertEqual(services.config.value(), 'services2')
|
||||
self.assertEqual(services.value_getter(), 'services2')
|
||||
|
||||
|
||||
class ConfigFromIniTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.config = providers.Configuration(name='config')
|
||||
|
||||
_, self.config_file_1 = tempfile.mkstemp()
|
||||
with open(self.config_file_1, 'w') as config_file:
|
||||
config_file.write(
|
||||
'[section1]\n'
|
||||
'value1=1\n'
|
||||
'\n'
|
||||
'[section2]\n'
|
||||
'value2=2\n'
|
||||
)
|
||||
|
||||
_, self.config_file_2 = tempfile.mkstemp()
|
||||
with open(self.config_file_2, 'w') as config_file:
|
||||
config_file.write(
|
||||
'[section1]\n'
|
||||
'value1=11\n'
|
||||
'value11=11\n'
|
||||
'[section3]\n'
|
||||
'value3=3\n'
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
del self.config
|
||||
os.unlink(self.config_file_1)
|
||||
os.unlink(self.config_file_2)
|
||||
|
||||
def test(self):
|
||||
self.config.from_ini(self.config_file_1)
|
||||
|
||||
self.assertEqual(self.config(), {'section1': {'value1': '1'}, 'section2': {'value2': '2'}})
|
||||
self.assertEqual(self.config.section1(), {'value1': '1'})
|
||||
self.assertEqual(self.config.section1.value1(), '1')
|
||||
self.assertEqual(self.config.section2(), {'value2': '2'})
|
||||
self.assertEqual(self.config.section2.value2(), '2')
|
||||
|
||||
def test_merge(self):
|
||||
self.config.from_ini(self.config_file_1)
|
||||
self.config.from_ini(self.config_file_2)
|
||||
|
||||
self.assertEqual(
|
||||
self.config(),
|
||||
{
|
||||
'section1': {
|
||||
'value1': '11',
|
||||
'value11': '11',
|
||||
},
|
||||
'section2': {
|
||||
'value2': '2',
|
||||
},
|
||||
'section3': {
|
||||
'value3': '3',
|
||||
},
|
||||
},
|
||||
)
|
||||
self.assertEqual(self.config.section1(), {'value1': '11', 'value11': '11'})
|
||||
self.assertEqual(self.config.section1.value1(), '11')
|
||||
self.assertEqual(self.config.section1.value11(), '11')
|
||||
self.assertEqual(self.config.section2(), {'value2': '2'})
|
||||
self.assertEqual(self.config.section2.value2(), '2')
|
||||
self.assertEqual(self.config.section3(), {'value3': '3'})
|
||||
self.assertEqual(self.config.section3.value3(), '3')
|
||||
|
||||
|
||||
class ConfigFromYamlTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.config = providers.Configuration(name='config')
|
||||
|
||||
_, self.config_file_1 = tempfile.mkstemp()
|
||||
with open(self.config_file_1, 'w') as config_file:
|
||||
config_file.write(
|
||||
'section1:\n'
|
||||
' value1: 1\n'
|
||||
'\n'
|
||||
'section2:\n'
|
||||
' value2: 2\n'
|
||||
)
|
||||
|
||||
_, self.config_file_2 = tempfile.mkstemp()
|
||||
with open(self.config_file_2, 'w') as config_file:
|
||||
config_file.write(
|
||||
'section1:\n'
|
||||
' value1: 11\n'
|
||||
' value11: 11\n'
|
||||
'section3:\n'
|
||||
' value3: 3\n'
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
del self.config
|
||||
os.unlink(self.config_file_1)
|
||||
os.unlink(self.config_file_2)
|
||||
|
||||
@unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
|
||||
def test(self):
|
||||
self.config.from_yaml(self.config_file_1)
|
||||
|
||||
self.assertEqual(self.config(), {'section1': {'value1': 1}, 'section2': {'value2': 2}})
|
||||
self.assertEqual(self.config.section1(), {'value1': 1})
|
||||
self.assertEqual(self.config.section1.value1(), 1)
|
||||
self.assertEqual(self.config.section2(), {'value2': 2})
|
||||
self.assertEqual(self.config.section2.value2(), 2)
|
||||
|
||||
@unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
|
||||
def test_merge(self):
|
||||
self.config.from_yaml(self.config_file_1)
|
||||
self.config.from_yaml(self.config_file_2)
|
||||
|
||||
self.assertEqual(
|
||||
self.config(),
|
||||
{
|
||||
'section1': {
|
||||
'value1': 11,
|
||||
'value11': 11,
|
||||
},
|
||||
'section2': {
|
||||
'value2': 2,
|
||||
},
|
||||
'section3': {
|
||||
'value3': 3,
|
||||
},
|
||||
},
|
||||
)
|
||||
self.assertEqual(self.config.section1(), {'value1': 11, 'value11': 11})
|
||||
self.assertEqual(self.config.section1.value1(), 11)
|
||||
self.assertEqual(self.config.section1.value11(), 11)
|
||||
self.assertEqual(self.config.section2(), {'value2': 2})
|
||||
self.assertEqual(self.config.section2.value2(), 2)
|
||||
self.assertEqual(self.config.section3(), {'value3': 3})
|
||||
self.assertEqual(self.config.section3.value3(), 3)
|
||||
|
||||
def test_no_yaml_installed(self):
|
||||
@contextlib.contextmanager
|
||||
def no_yaml_module():
|
||||
yaml = providers.yaml
|
||||
providers.yaml = None
|
||||
|
||||
yield
|
||||
|
||||
providers.yaml = yaml
|
||||
|
||||
with no_yaml_module():
|
||||
with self.assertRaises(errors.Error) as error:
|
||||
self.config.from_yaml(self.config_file_1)
|
||||
|
||||
self.assertEqual(
|
||||
error.exception.args[0],
|
||||
'Unable to load yaml configuration - PyYAML is not installed. '
|
||||
'Install PyYAML or install Dependency Injector with yaml extras: '
|
||||
'"pip install dependency-injector[yaml]"',
|
||||
)
|
||||
|
||||
|
||||
class ConfigFromDict(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.config = providers.Configuration(name='config')
|
||||
|
||||
self.config_options_1 = {
|
||||
'section1': {
|
||||
'value1': '1',
|
||||
},
|
||||
'section2': {
|
||||
'value2': '2',
|
||||
},
|
||||
}
|
||||
self.config_options_2 = {
|
||||
'section1': {
|
||||
'value1': '11',
|
||||
'value11': '11',
|
||||
},
|
||||
'section3': {
|
||||
'value3': '3',
|
||||
},
|
||||
}
|
||||
|
||||
def test(self):
|
||||
self.config.from_dict(self.config_options_1)
|
||||
|
||||
self.assertEqual(self.config(), {'section1': {'value1': '1'}, 'section2': {'value2': '2'}})
|
||||
self.assertEqual(self.config.section1(), {'value1': '1'})
|
||||
self.assertEqual(self.config.section1.value1(), '1')
|
||||
self.assertEqual(self.config.section2(), {'value2': '2'})
|
||||
self.assertEqual(self.config.section2.value2(), '2')
|
||||
|
||||
def test_merge(self):
|
||||
self.config.from_dict(self.config_options_1)
|
||||
self.config.from_dict(self.config_options_2)
|
||||
|
||||
self.assertEqual(
|
||||
self.config(),
|
||||
{
|
||||
'section1': {
|
||||
'value1': '11',
|
||||
'value11': '11',
|
||||
},
|
||||
'section2': {
|
||||
'value2': '2',
|
||||
},
|
||||
'section3': {
|
||||
'value3': '3',
|
||||
},
|
||||
},
|
||||
)
|
||||
self.assertEqual(self.config.section1(), {'value1': '11', 'value11': '11'})
|
||||
self.assertEqual(self.config.section1.value1(), '11')
|
||||
self.assertEqual(self.config.section1.value11(), '11')
|
||||
self.assertEqual(self.config.section2(), {'value2': '2'})
|
||||
self.assertEqual(self.config.section2.value2(), '2')
|
||||
self.assertEqual(self.config.section3(), {'value3': '3'})
|
||||
self.assertEqual(self.config.section3.value3(), '3')
|
||||
|
||||
|
||||
class ConfigFromEnvTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.config = providers.Configuration(name='config')
|
||||
os.environ['CONFIG_TEST_ENV'] = 'test-value'
|
||||
|
||||
def tearDown(self):
|
||||
del self.config
|
||||
del os.environ['CONFIG_TEST_ENV']
|
||||
|
||||
def test(self):
|
||||
self.config.from_env('CONFIG_TEST_ENV')
|
||||
self.assertEqual(self.config(), 'test-value')
|
||||
|
||||
def test_default(self):
|
||||
self.config.from_env('UNDEFINED_ENV', 'default-value')
|
||||
self.assertEqual(self.config(), 'default-value')
|
||||
|
||||
def test_with_children(self):
|
||||
self.config.section1.value1.from_env('CONFIG_TEST_ENV')
|
||||
|
||||
self.assertIsNone(self.config())
|
||||
self.assertIsNone(self.config.section1())
|
||||
self.assertEqual(self.config.section1.value1(), 'test-value')
|
||||
|
|
5
tox.ini
5
tox.ini
|
@ -5,6 +5,8 @@ envlist=
|
|||
[testenv]
|
||||
deps=
|
||||
unittest2
|
||||
extras=
|
||||
yaml
|
||||
commands=
|
||||
unit2 discover -s tests/unit -p test_*_py3.py
|
||||
|
||||
|
@ -27,6 +29,9 @@ commands=
|
|||
commands=
|
||||
unit2 discover -s tests/unit -p test_*_py2_py3.py
|
||||
|
||||
[testenv:py34]
|
||||
extras=
|
||||
|
||||
[testenv:pypy]
|
||||
commands=
|
||||
unit2 discover -s tests/unit -p test_*_py2_py3.py
|
||||
|
|
Loading…
Reference in New Issue
Block a user