async def test_config_subclass_abc(mocker): import abc import attr from buvar import config, di mocker.patch.dict(config.Config.__buvar_config_sections__, clear=True) class GeneralConfig(config.Config, section=None): ... class FooBase(metaclass=abc.ABCMeta): @abc.abstractmethod def foo(self): ... @attr.s(auto_attribs=True) class FooConfig(config.Config, FooBase, section="foo"): bar: str def foo(self): ... assert config.skip_section not in config.Config.__buvar_config_sections__ assert FooBase not in config.Config.__buvar_config_sections__.values() assert config.Config.__buvar_config_sections__["foo"] is FooConfig cfg = config.ConfigSource({"foo": {"bar": "abc"}}, env_prefix="PREFIX") foo_config = await di.nject(FooConfig, source=cfg) assert foo_config == FooConfig(bar="abc")
def test_nested_attrs_typing(): import typing import attr from buvar import config @attr.s(auto_attribs=True) class Baz: baz: str = "foobar" @attr.s(auto_attribs=True) class Bar: baz: Baz @attr.s(auto_attribs=True) class Foo: bars: typing.List[Bar] = [] source = config.ConfigSource( {"foo": { "bars": [{ "baz": { "baz": "something else" } }] }}, env_prefix="TEST") foo = source.load(Foo, "foo") assert foo == Foo(bars=[Bar(baz=Baz(baz="something else"))])
def test_config_missing(): import attr from buvar import config source: dict = {"foo": {}} @attr.s(auto_attribs=True) class FooConfig: bar: str = config.var() cfg = config.ConfigSource(source) with pytest.raises(ValueError): cfg.load(FooConfig, "foo")
def test_load_general_config(): import attr import typing from buvar import config sources = [{"foo": "bar", "group": {"some": "value"}}] cfg = config.ConfigSource(*sources, env_prefix="PREFIX") @attr.s(auto_attribs=True) class GeneralVars: foo: str baz: typing.Optional[float] = None general = cfg.load(GeneralVars) assert general == GeneralVars("bar", None)
def buvar_config_source(): from buvar import config config_source = config.ConfigSource() return config_source
@attr.s(auto_attribs=True) class GeneralConfig: """Simple config.""" log_level: str = "INFO" plugins: typing.Set[str] = set() # get config from file user_config = toml.load( os.environ.get("USER_CONFIG", os.path.dirname(__file__) + "/user_config.toml")) # your components registry cmps = components.Components() # make config values overwritable by environment vars source = cmps.add(config.ConfigSource(user_config, env_prefix="APP")) general_config = cmps.add(source.load(GeneralConfig)) # setup structlog log.setup_logging(tty=sys.stdout.isatty(), level=general_config.log_level) sl = structlog.get_logger() sl.info("Starting process", pid=os.getpid()) sl.debug("Config used", **source) plugin.stage(config, *general_config.plugins, components=cmps)
async def test_config_generic_adapter(mocker): import attr import typing from buvar import config, di mocker.patch.dict(config.Config.__buvar_config_sections__, clear=True) @attr.s(auto_attribs=True) class FooConfig(config.Config, section="foo"): bar: str = "default" foobar: float = 9.87 baz: bool = config.bool_var(default=False) @attr.s(auto_attribs=True) class BarConfig(config.Config, section="bar"): bim: float foo: FooConfig = FooConfig() @attr.s(auto_attribs=True, kw_only=True) class BimConfig(config.Config, section="bim"): bar: BarConfig bam: bool = config.bool_var() bum: int = config.var(123) lst: typing.List = config.var(list) sources = [ { "bar": { "bim": "123.4", "foo": { "bar": "1.23", "baz": "true" } } }, { "foo": { "bar": "value", "foobar": 123.5, "baz": True } }, { "bar": { "bim": "123.4" }, "bim": { "bar": { "bim": 1.23 }, "bam": "on", "lst": [1, 2, 3] }, }, ] mocker.patch( "os.environ", { "PREFIX_BAR_BIM": "0", "PREFIX_BAR_FOO_FOOBAR": "7.77", "PREFIX_BAR_FOO_BAZ": "false", }, ) cfg = config.ConfigSource(*sources, env_prefix="PREFIX") foo_config = await di.nject(FooConfig, source=cfg) assert foo_config == FooConfig(bar="value", foobar=123.5, baz=True)
async def test_config_source_schematize(mocker): from buvar import config import typing import attr @attr.s(auto_attribs=True) class FooConfig: bar: str = "default" foobar: float = 9.87 baz: bool = config.bool_var(default=False) @attr.s(auto_attribs=True) class BarConfig: bim: float foo: FooConfig = FooConfig() @attr.s(auto_attribs=True, kw_only=True) class BimConfig: bar: BarConfig bam: bool = config.bool_var() bum: int = config.var(123) lst: typing.List = config.var(list) sources = [ { "bar": { "bim": "123.4", "foo": { "bar": "1.23", "baz": "true" } } }, { "foo": { "bar": "value", "foobar": 123.5, "baz": True } }, { "bar": { "bim": "123.4" }, "bim": { "bar": { "bim": 1.23 }, "bam": "on", "lst": [1, 2, 3] }, }, ] mocker.patch( "os.environ", { "PREFIX_BAR_BIM": "0", "PREFIX_BAR_FOO_FOOBAR": "7.77", "PREFIX_BAR_FOO_BAZ": "false", }, ) cfg = config.ConfigSource(*sources, env_prefix="PREFIX") # foo_config = await adapters.nject(FooConfig, source=cfg) bim = cfg.load(BimConfig, "bim") bar = cfg.load(BarConfig, "bar") foo = cfg.load(FooConfig, "foo") assert (bar, foo, bim) == ( BarConfig(bim=0.0, foo=FooConfig(bar="1.23", foobar=7.77, baz=False)), FooConfig(bar="value", foobar=123.5, baz=True), BimConfig(bar=BarConfig(bim=1.23), bam=True, lst=[1, 2, 3]), )