diff --git a/src/akkudoktoreos/config/config.py b/src/akkudoktoreos/config/config.py index 932a2c2d..03096c6a 100644 --- a/src/akkudoktoreos/config/config.py +++ b/src/akkudoktoreos/config/config.py @@ -717,7 +717,9 @@ class ConfigEOS(SingletonMixin, SettingsEOSDefaults): logger.debug("Config init called again with parameters {} {}", args, kwargs) return logger.debug("Config init with parameters {} {}", args, kwargs) - self._setup(self, *args, **kwargs) + # Do not pass self - the first positional argument of pydantic_settings.BaseSettings + # is _case_sensitive, which would make environment variable lookup case sensitive. + self._setup(*args, **kwargs) def _setup(self, *args: Any, **kwargs: Any) -> None: """Re-initialize global settings.""" diff --git a/tests/conftest.py b/tests/conftest.py index a6a256a0..fc03a72e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -370,8 +370,8 @@ def config_eos_factory( assert not config_file_cwd.exists() config_eos = get_config(init=init) - # Ensure newly created configurations are respected - # Note: Workaround for pydantic_settings and pytest + # Ensure newly created configurations are respected and runtime settings of + # previous tests are dropped config_eos.reset_settings() # Check user data directory pathes (config_default_dirs[-1] == data_default_dir_user) diff --git a/tests/test_config.py b/tests/test_config.py index 31bbd86f..7acd1736 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -649,13 +649,32 @@ def test_reset_settings_drops_runtime_settings(config_eos_file): def test_set_nested_value_survives_merge(config_eos_file): """Granular updates are not lost by a later bulk update.""" - write_config_file(config_eos_file, {"optimization": {"genetic": {"individuals": 200}}}) + write_config_file( + config_eos_file, + { + "general": {"latitude": 48.0}, + "optimization": {"genetic": {"individuals": 200}}, + "pvforecast": { + "planes": [ + {"surface_tilt": 30.0, "surface_azimuth": azimuth, "peakpower": 5.0} + for azimuth in (0.0, 90.0) + ] + }, + }, + ) config_eos_file.set_nested_value("optimization/genetic/individuals", 400) - assert config_eos_file.optimization.genetic.individuals == 400 + # A list index can not be expressed by the settings dictionary + config_eos_file.set_nested_value("pvforecast/planes/1/peakpower", 9.9) + # Clearing a value must not be reverted by the config file either + config_eos_file.set_nested_value("general/latitude", None) - config_eos_file.merge_settings_from_dict({"general": {"latitude": 51.1657}}) + config_eos_file.merge_settings_from_dict({"server": {"port": 8600}}) + + assert config_eos_file.server.port == 8600 assert config_eos_file.optimization.genetic.individuals == 400 + assert config_eos_file.pvforecast.planes[1].peakpower == 9.9 + assert config_eos_file.general.latitude is None def test_revert_settings_restores_backup(config_eos_file): @@ -678,3 +697,13 @@ def test_revert_settings_restores_backup(config_eos_file): config_eos_file.revert_settings("backup") assert config_eos_file.optimization.genetic.individuals == 500 + + +def test_config_from_env_on_first_init(config_eos, config_default_dirs, monkeypatch): + """Environment variables are applied on the first configuration build.""" + config_eos.reset_instance() + + monkeypatch.setenv("EOS_CONFIG_DIR", str(config_default_dirs[0])) + monkeypatch.setenv("EOS_SERVER__PORT", "8553") + + assert ConfigEOS().server.port == 8553