mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-07-05 12:53:30 +03:00
Add implementation and basic test
This commit is contained in:
parent
1fabbf314b
commit
1005c51bd0
File diff suppressed because it is too large
Load Diff
|
@ -35,6 +35,11 @@ try:
|
|||
except ImportError:
|
||||
yaml = None
|
||||
|
||||
try:
|
||||
import pydantic
|
||||
except ImportError:
|
||||
pydantic = None
|
||||
|
||||
from .errors import (
|
||||
Error,
|
||||
NoSuchProviderError,
|
||||
|
@ -1413,7 +1418,6 @@ cdef class ConfigurationOption(Provider):
|
|||
'"pip install dependency-injector[yaml]"'
|
||||
)
|
||||
|
||||
|
||||
if loader is None:
|
||||
loader = YamlLoader
|
||||
|
||||
|
@ -1433,6 +1437,37 @@ cdef class ConfigurationOption(Provider):
|
|||
current_config = {}
|
||||
self.override(merge_dicts(current_config, config))
|
||||
|
||||
def from_pydantic(self, settings, required=UNDEFINED, **kwargs):
|
||||
"""Load configuration from pydantic settings.
|
||||
|
||||
Loaded configuration is merged recursively over existing configuration.
|
||||
|
||||
:param settings: Pydantic settings instances.
|
||||
:type settings: :py:class:`pydantic.BaseSettings`
|
||||
|
||||
:param required: When required is True, raise an exception if settings dict is empty.
|
||||
:type required: bool
|
||||
|
||||
:param kwargs: Keyword arguments forwarded to ``pydantic.BaseSettings.dict()`` call.
|
||||
:type kwargs: Dict[Any, Any]
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if pydantic is None:
|
||||
raise Error(
|
||||
'Unable to load pydantic configuration - pydantic is not installed. '
|
||||
'Install pydantic or install Dependency Injector with pydantic extras: '
|
||||
'"pip install dependency-injector[pydantic]"'
|
||||
)
|
||||
|
||||
if not isinstance(settings, pydantic.BaseSettings):
|
||||
raise Error(
|
||||
'Unable to recognize settings instance, expect "pydantic.BaseSettings", '
|
||||
'got {0} instead'.format(settings)
|
||||
)
|
||||
|
||||
self.from_dict(settings.dict(**kwargs), required=required)
|
||||
|
||||
def from_dict(self, options, required=UNDEFINED):
|
||||
"""Load configuration from the dictionary.
|
||||
|
||||
|
@ -1766,6 +1801,37 @@ cdef class Configuration(Object):
|
|||
current_config = {}
|
||||
self.override(merge_dicts(current_config, config))
|
||||
|
||||
def from_pydantic(self, settings, required=UNDEFINED, **kwargs):
|
||||
"""Load configuration from pydantic settings.
|
||||
|
||||
Loaded configuration is merged recursively over existing configuration.
|
||||
|
||||
:param settings: Pydantic settings instances.
|
||||
:type settings: :py:class:`pydantic.BaseSettings`
|
||||
|
||||
:param required: When required is True, raise an exception if settings dict is empty.
|
||||
:type required: bool
|
||||
|
||||
:param kwargs: Keyword arguments forwarded to ``pydantic.BaseSettings.dict()`` call.
|
||||
:type kwargs: Dict[Any, Any]
|
||||
|
||||
:rtype: None
|
||||
"""
|
||||
if pydantic is None:
|
||||
raise Error(
|
||||
'Unable to load pydantic configuration - pydantic is not installed. '
|
||||
'Install pydantic or install Dependency Injector with pydantic extras: '
|
||||
'"pip install dependency-injector[pydantic]"'
|
||||
)
|
||||
|
||||
if not isinstance(settings, pydantic.BaseSettings):
|
||||
raise Error(
|
||||
'Unable to recognize settings instance, expect "pydantic.BaseSettings", '
|
||||
'got {0} instead'.format(settings)
|
||||
)
|
||||
|
||||
self.from_dict(settings.dict(**kwargs), required=required)
|
||||
|
||||
def from_dict(self, options, required=UNDEFINED):
|
||||
"""Load configuration from the dictionary.
|
||||
|
||||
|
|
|
@ -14,6 +14,11 @@ try:
|
|||
except ImportError:
|
||||
yaml = None
|
||||
|
||||
try:
|
||||
import pydantic
|
||||
except ImportError:
|
||||
pydantic = None
|
||||
|
||||
|
||||
class ConfigTests(unittest.TestCase):
|
||||
|
||||
|
@ -723,6 +728,140 @@ class ConfigFromYamlWithEnvInterpolationTests(unittest.TestCase):
|
|||
self.assertEqual(self.config.option.section1.value1(), 'test-value')
|
||||
|
||||
|
||||
class ConfigFromPydanticTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.config = providers.Configuration(name='config')
|
||||
|
||||
class Section11(pydantic.BaseModel):
|
||||
value1 = 1
|
||||
|
||||
class Section12(pydantic.BaseModel):
|
||||
value2 = 2
|
||||
|
||||
class Settings1(pydantic.BaseSettings):
|
||||
section1 = Section11()
|
||||
section2 = Section12()
|
||||
|
||||
self.Settings1 = Settings1
|
||||
|
||||
class Section21(pydantic.BaseModel):
|
||||
value1 = 11
|
||||
value11 = 11
|
||||
|
||||
class Section3(pydantic.BaseModel):
|
||||
value3 = 3
|
||||
|
||||
class Settings2(pydantic.BaseSettings):
|
||||
section1 = Section21()
|
||||
section2 = Section3()
|
||||
|
||||
self.Settings2 = Settings2
|
||||
|
||||
def test(self):
|
||||
self.config.from_pydantic(self.Settings1())
|
||||
|
||||
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)
|
||||
#
|
||||
# @unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
|
||||
# def test_file_does_not_exist(self):
|
||||
# self.config.from_yaml('./does_not_exist.yml')
|
||||
# self.assertEqual(self.config(), {})
|
||||
#
|
||||
# @unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
|
||||
# def test_file_does_not_exist_strict_mode(self):
|
||||
# self.config = providers.Configuration(strict=True)
|
||||
# with self.assertRaises(IOError):
|
||||
# self.config.from_yaml('./does_not_exist.yml')
|
||||
#
|
||||
# @unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
|
||||
# def test_option_file_does_not_exist(self):
|
||||
# self.config.option.from_yaml('./does_not_exist.yml')
|
||||
# self.assertIsNone(self.config.option())
|
||||
#
|
||||
# @unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
|
||||
# def test_option_file_does_not_exist_strict_mode(self):
|
||||
# self.config = providers.Configuration(strict=True)
|
||||
# with self.assertRaises(IOError):
|
||||
# self.config.option.from_yaml('./does_not_exist.yml')
|
||||
#
|
||||
# @unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
|
||||
# def test_required_file_does_not_exist(self):
|
||||
# with self.assertRaises(IOError):
|
||||
# self.config.from_yaml('./does_not_exist.yml', required=True)
|
||||
#
|
||||
# @unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
|
||||
# def test_required_option_file_does_not_exist(self):
|
||||
# with self.assertRaises(IOError):
|
||||
# self.config.option.from_yaml('./does_not_exist.yml', required=True)
|
||||
#
|
||||
# @unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
|
||||
# def test_not_required_file_does_not_exist_strict_mode(self):
|
||||
# self.config = providers.Configuration(strict=True)
|
||||
# self.config.from_yaml('./does_not_exist.yml', required=False)
|
||||
# self.assertEqual(self.config(), {})
|
||||
#
|
||||
# @unittest.skipIf(sys.version_info[:2] == (3, 4), 'PyYAML does not support Python 3.4')
|
||||
# def test_not_required_option_file_does_not_exist_strict_mode(self):
|
||||
# self.config = providers.Configuration(strict=True)
|
||||
# self.config.option.from_yaml('./does_not_exist.yml', required=False)
|
||||
# with self.assertRaises(errors.Error):
|
||||
# self.config.option()
|
||||
|
||||
def test_no_pydantic_installed(self):
|
||||
@contextlib.contextmanager
|
||||
def no_pydantic_module():
|
||||
pydantic = providers.pydantic
|
||||
providers.pydantic = None
|
||||
|
||||
yield
|
||||
|
||||
providers.pydantic = pydantic
|
||||
|
||||
with no_pydantic_module():
|
||||
with self.assertRaises(errors.Error) as error:
|
||||
self.config.from_pydantic(self.Settings1())
|
||||
|
||||
self.assertEqual(
|
||||
error.exception.args[0],
|
||||
'Unable to load pydantic configuration - pydantic is not installed. '
|
||||
'Install pydantic or install Dependency Injector with pydantic extras: '
|
||||
'"pip install dependency-injector[pydantic]"',
|
||||
)
|
||||
|
||||
|
||||
class ConfigFromDict(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
Loading…
Reference in New Issue
Block a user