Add init implementation and tests

This commit is contained in:
Roman Mogylatov 2022-07-09 22:20:15 -04:00
parent 6164b4f45d
commit ea48fab8d3
11 changed files with 7972 additions and 7380 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -132,8 +132,9 @@ cdef class Configuration(Object):
cdef str __name cdef str __name
cdef bint __strict cdef bint __strict
cdef dict __children cdef dict __children
cdef list __yaml_files
cdef list __ini_files cdef list __ini_files
cdef list __yaml_files
cdef list __json_files
cdef list __pydantic_settings cdef list __pydantic_settings
cdef object __weakref__ cdef object __weakref__

View File

@ -238,8 +238,9 @@ class Configuration(Object[Any]):
default: Optional[Any] = None, default: Optional[Any] = None,
*, *,
strict: bool = False, strict: bool = False,
yaml_files: Optional[_Iterable[Union[Path, str]]] = None,
ini_files: Optional[_Iterable[Union[Path, str]]] = None, ini_files: Optional[_Iterable[Union[Path, str]]] = None,
yaml_files: Optional[_Iterable[Union[Path, str]]] = None,
json_files: Optional[_Iterable[Union[Path, str]]] = None,
pydantic_settings: Optional[_Iterable[PydanticSettings]] = None, pydantic_settings: Optional[_Iterable[PydanticSettings]] = None,
) -> None: ... ) -> None: ...
def __enter__(self) -> Configuration : ... def __enter__(self) -> Configuration : ...
@ -259,11 +260,14 @@ class Configuration(Object[Any]):
def get_children(self) -> _Dict[str, ConfigurationOption]: ... def get_children(self) -> _Dict[str, ConfigurationOption]: ...
def set_children(self, children: _Dict[str, ConfigurationOption]) -> Configuration: ... def set_children(self, children: _Dict[str, ConfigurationOption]) -> Configuration: ...
def get_ini_files(self) -> _List[Union[Path, str]]: ...
def set_ini_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ...
def get_yaml_files(self) -> _List[Union[Path, str]]: ... def get_yaml_files(self) -> _List[Union[Path, str]]: ...
def set_yaml_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ... def set_yaml_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ...
def get_ini_files(self) -> _List[Union[Path, str]]: ... def get_json_files(self) -> _List[Union[Path, str]]: ...
def set_ini_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ... def set_json_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ...
def get_pydantic_settings(self) -> _List[PydanticSettings]: ... def get_pydantic_settings(self) -> _List[PydanticSettings]: ...
def set_pydantic_settings(self, settings: _Iterable[PydanticSettings]) -> Configuration: ... def set_pydantic_settings(self, settings: _Iterable[PydanticSettings]) -> Configuration: ...

View File

@ -1925,24 +1925,29 @@ cdef class Configuration(Object):
DEFAULT_NAME = "config" DEFAULT_NAME = "config"
def __init__(self, name=DEFAULT_NAME, default=None, strict=False, yaml_files=None, ini_files=None, pydantic_settings=None): def __init__(self, name=DEFAULT_NAME, default=None, strict=False, ini_files=None, yaml_files=None, json_files=None, pydantic_settings=None):
self.__name = name self.__name = name
self.__strict = strict self.__strict = strict
self.__children = {} self.__children = {}
self.__yaml_files = []
self.__ini_files = [] self.__ini_files = []
self.__yaml_files = []
self.__json_files = []
self.__pydantic_settings = [] self.__pydantic_settings = []
super().__init__(provides={}) super().__init__(provides={})
self.set_default(default) self.set_default(default)
if ini_files is None:
ini_files = []
self.set_ini_files(ini_files)
if yaml_files is None: if yaml_files is None:
yaml_files = [] yaml_files = []
self.set_yaml_files(yaml_files) self.set_yaml_files(yaml_files)
if ini_files is None: if json_files is None:
ini_files = [] json_files = []
self.set_ini_files(ini_files) self.set_json_files(json_files)
if pydantic_settings is None: if pydantic_settings is None:
pydantic_settings = [] pydantic_settings = []
@ -1958,8 +1963,9 @@ cdef class Configuration(Object):
copied.set_default(self.get_default()) copied.set_default(self.get_default())
copied.set_strict(self.get_strict()) copied.set_strict(self.get_strict())
copied.set_children(deepcopy(self.get_children(), memo)) copied.set_children(deepcopy(self.get_children(), memo))
copied.set_yaml_files(self.get_yaml_files())
copied.set_ini_files(self.get_ini_files()) copied.set_ini_files(self.get_ini_files())
copied.set_yaml_files(self.get_yaml_files())
copied.set_json_files(self.get_json_files())
copied.set_pydantic_settings(self.get_pydantic_settings()) copied.set_pydantic_settings(self.get_pydantic_settings())
self._copy_overridings(copied, memo) self._copy_overridings(copied, memo)
@ -2052,6 +2058,15 @@ cdef class Configuration(Object):
self.__yaml_files = list(files) self.__yaml_files = list(files)
return self return self
def get_json_files(self):
"""Return list of JSON files."""
return list(self.__json_files)
def set_json_files(self, files):
"""Set list of JSON files."""
self.__json_files = list(files)
return self
def get_pydantic_settings(self): def get_pydantic_settings(self):
"""Return list of Pydantic settings.""" """Return list of Pydantic settings."""
return list(self.__pydantic_settings) return list(self.__pydantic_settings)
@ -2078,11 +2093,14 @@ cdef class Configuration(Object):
:param envs_required: When True, raises an error on undefined environment variable. :param envs_required: When True, raises an error on undefined environment variable.
:type envs_required: bool :type envs_required: bool
""" """
for file in self.get_ini_files():
self.from_ini(file, required=required, envs_required=envs_required)
for file in self.get_yaml_files(): for file in self.get_yaml_files():
self.from_yaml(file, required=required, envs_required=envs_required) self.from_yaml(file, required=required, envs_required=envs_required)
for file in self.get_ini_files(): for file in self.get_json_files():
self.from_ini(file, required=required, envs_required=envs_required) self.from_json(file, required=required, envs_required=envs_required)
for settings in self.get_pydantic_settings(): for settings in self.get_pydantic_settings():
self.from_pydantic(settings, required=required) self.from_pydantic(settings, required=required)

View File

@ -1,5 +1,7 @@
from pathlib import Path from pathlib import Path
from dependency_injector import providers from dependency_injector import providers
from pydantic import BaseSettings as PydanticSettings
# Test 1: to check the getattr # Test 1: to check the getattr
@ -8,7 +10,19 @@ provider1 = providers.Factory(dict, a=config1.a)
# Test 2: to check the from_*() method # Test 2: to check the from_*() method
config2 = providers.Configuration() config2 = providers.Configuration()
config2_init_args = providers.Configuration(
name="config",
strict=True,
default={},
ini_files=["config.ini", Path("config.ini")],
yaml_files=["config.yml", Path("config.yml")],
json_files=["config.json", Path("config.json")],
pydantic_settings=[PydanticSettings()],
)
config2.from_dict({}) config2.from_dict({})
config2.from_value({})
config2.from_ini("config.ini") config2.from_ini("config.ini")
config2.from_ini(Path("config.ini")) config2.from_ini(Path("config.ini"))
@ -23,6 +37,8 @@ config2.from_env("ENV", as_=int, default=123)
config2.from_env("ENV", as_=float, required=True) config2.from_env("ENV", as_=float, required=True)
config2.from_env("ENV", as_=lambda env: str(env)) config2.from_env("ENV", as_=lambda env: str(env))
config2.from_pydantic(PydanticSettings())
# Test 3: to check as_*() methods # Test 3: to check as_*() methods
config3 = providers.Configuration() config3 = providers.Configuration()
int3: providers.Callable[int] = config3.option.as_int() int3: providers.Callable[int] = config3.option.as_int()

View File

@ -47,6 +47,11 @@ def test_set_files(config):
assert config.get_ini_files() == ["file1.ini", "file2.ini"] assert config.get_ini_files() == ["file1.ini", "file2.ini"]
def test_copy(config, ini_config_file_1, ini_config_file_2):
config_copy = providers.deepcopy(config)
assert config_copy.get_ini_files() == [ini_config_file_1, ini_config_file_2]
def test_file_does_not_exist(config): def test_file_does_not_exist(config):
config.set_ini_files(["./does_not_exist.ini"]) config.set_ini_files(["./does_not_exist.ini"])
config.load() config.load()

View File

@ -0,0 +1,114 @@
"""Configuration(json_files=[...]) tests."""
import json
from dependency_injector import providers
from pytest import fixture, mark, raises
@fixture
def config(config_type, json_config_file_1, json_config_file_2):
if config_type == "strict":
return providers.Configuration(strict=True)
elif config_type == "default":
return providers.Configuration(json_files=[json_config_file_1, json_config_file_2])
else:
raise ValueError("Undefined config type \"{0}\"".format(config_type))
def test_load(config):
config.load()
assert config() == {
"section1": {
"value1": 11,
"value11": 11,
},
"section2": {
"value2": 2,
},
"section3": {
"value3": 3,
},
}
assert config.section1() == {"value1": 11, "value11": 11}
assert config.section1.value1() == 11
assert config.section1.value11() == 11
assert config.section2() == {"value2": 2}
assert config.section2.value2() == 2
assert config.section3() == {"value3": 3}
assert config.section3.value3() == 3
def test_get_files(config, json_config_file_1, json_config_file_2):
assert config.get_json_files() == [json_config_file_1, json_config_file_2]
def test_set_files(config):
config.set_json_files(["file1.json", "file2.json"])
assert config.get_json_files() == ["file1.json", "file2.json"]
def test_copy(config, json_config_file_1, json_config_file_2):
config_copy = providers.deepcopy(config)
assert config_copy.get_json_files() == [json_config_file_1, json_config_file_2]
def test_file_does_not_exist(config):
config.set_json_files(["./does_not_exist.json"])
config.load()
assert config() == {}
@mark.parametrize("config_type", ["strict"])
def test_file_does_not_exist_strict_mode(config):
config.set_json_files(["./does_not_exist.json"])
with raises(IOError):
config.load()
assert config() == {}
def test_required_file_does_not_exist(config):
config.set_json_files(["./does_not_exist.json"])
with raises(IOError):
config.load(required=True)
@mark.parametrize("config_type", ["strict"])
def test_not_required_file_does_not_exist_strict_mode(config):
config.set_json_files(["./does_not_exist.json"])
config.load(required=False)
assert config() == {}
def test_missing_envs_required(config, json_config_file_3):
with open(json_config_file_3, "w") as file:
file.write(
json.dumps(
{
"section": {
"undefined": "${UNDEFINED}",
},
},
),
)
config.set_json_files([json_config_file_3])
with raises(ValueError, match="Missing required environment variable \"UNDEFINED\""):
config.load(envs_required=True)
@mark.parametrize("config_type", ["strict"])
def test_missing_envs_not_required_in_strict_mode(config, json_config_file_3):
with open(json_config_file_3, "w") as file:
file.write(
json.dumps(
{
"section": {
"undefined": "${UNDEFINED}",
},
},
),
)
config.set_json_files([json_config_file_3])
config.load(envs_required=False)
assert config.section.undefined() == ""

View File

@ -80,6 +80,11 @@ def test_get_pydantic_settings(config, pydantic_settings_1, pydantic_settings_2)
assert config.get_pydantic_settings() == [pydantic_settings_1, pydantic_settings_2] assert config.get_pydantic_settings() == [pydantic_settings_1, pydantic_settings_2]
def test_copy(config, pydantic_settings_1, pydantic_settings_2):
config_copy = providers.deepcopy(config)
assert config_copy.get_pydantic_settings() == [pydantic_settings_1, pydantic_settings_2]
def test_set_pydantic_settings(config): def test_set_pydantic_settings(config):
class Settings3(pydantic.BaseSettings): class Settings3(pydantic.BaseSettings):
... ...

View File

@ -47,6 +47,11 @@ def test_set_files(config):
assert config.get_yaml_files() == ["file1.yml", "file2.yml"] assert config.get_yaml_files() == ["file1.yml", "file2.yml"]
def test_copy(config, yaml_config_file_1, yaml_config_file_2):
config_copy = providers.deepcopy(config)
assert config_copy.get_yaml_files() == [yaml_config_file_1, yaml_config_file_2]
def test_file_does_not_exist(config): def test_file_does_not_exist(config):
config.set_yaml_files(["./does_not_exist.yml"]) config.set_yaml_files(["./does_not_exist.yml"])
config.load() config.load()