mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-11-13 09:13:30 +01:00
fix(config): validate prediction providers before the prediction exists
The provider settings (weather, PV forecast, load, electricity price, feed-in tariff, electricity fee) validate their provider id against the providers of the prediction instance. While the configuration is created, that instance does not exist yet, and the validation falls back to fixed lists. These were incomplete: weather knew only 'WeatherImport', load lacked 'LoadAkkudoktorAdjusted'. A configuration file with e.g. weather provider 'OpenMeteo' then fails to load: Provider 'OpenMeteo' is not a valid weather provider: ['WeatherImport'] This is hidden today because ConfigEOS.documentation_mode() is always true (_force_documentation_mode is a pydantic private attribute, whose class attribute is a truthy descriptor), and get_prediction() then creates the prediction instance on access. Once documentation mode is enabled only explicitly, the configuration does not load. Derive the provider ids from the provider classes instead (prediction_provider_ids). They no longer depend on whether the prediction instance exists, so the validation is the same before and after initialization. Additional changes - Add the test fixture uncreated_config, which lets get_config(init=True) create a new configuration from the config file and restores the old one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
4475774c06
commit
a0e57a18b7
@@ -854,3 +854,34 @@ class TestDeviceSettings:
|
||||
def test_device_map_rejects_conflicting_identity(self):
|
||||
with pytest.raises(ValidationError, match="device_id"):
|
||||
DevicesCommonSettings.model_validate({"batteries": {"house": {"device_id": "other"}}})
|
||||
|
||||
|
||||
class TestConfigProviderValidation:
|
||||
"""Provider ids are validated while the configuration is created."""
|
||||
|
||||
def test_config_with_providers_is_created_before_the_prediction(
|
||||
self, uncreated_config, monkeypatch
|
||||
):
|
||||
"""No prediction instance exists yet while the configuration is created."""
|
||||
from akkudoktoreos.core import coreabc
|
||||
from akkudoktoreos.core.version import __version__
|
||||
|
||||
providers = {
|
||||
"weather": {"provider": "OpenMeteo"},
|
||||
"load": {"provider": "LoadAkkudoktorAdjusted"},
|
||||
"pvforecast": {"provider": "PVForecastPVLib"},
|
||||
"elecprice": {"provider": "ElecPriceEnergyCharts"},
|
||||
"feedintariff": {"provider": "FeedInTariffFixed"},
|
||||
"elecfee": {"provider": "ElecFeeFixed"},
|
||||
}
|
||||
# A current version: the file is validated as is, without migration.
|
||||
uncreated_config.write_text(json.dumps({"general": {"version": __version__}, **providers}))
|
||||
monkeypatch.setattr(coreabc, "_prediction_eos", None)
|
||||
# Outside of documentation mode get_prediction() does not create the
|
||||
# prediction instance on access.
|
||||
monkeypatch.setattr(ConfigEOS, "documentation_mode", classmethod(lambda cls: False))
|
||||
|
||||
config = coreabc.get_config(init=True)
|
||||
|
||||
for section, value in providers.items():
|
||||
assert getattr(config, section).provider == value["provider"]
|
||||
|
||||
Reference in New Issue
Block a user