From 26180675bd3e0b24403ffd760f13f4a103bb4555 Mon Sep 17 00:00:00 2001 From: Laurent LAPORTE Date: Mon, 5 Feb 2024 18:03:42 +0100 Subject: [PATCH] fix(model): allow models to have `None` values --- .../study/business/areas/renewable_management.py | 4 ++-- .../study/business/areas/st_storage_management.py | 2 +- .../study/business/areas/thermal_management.py | 4 ++-- .../study/business/thematic_trimming_management.py | 2 +- antarest/study/business/xpansion_management.py | 2 +- .../rawstudy/model/filesystem/config/cluster.py | 7 ++++++- antarest/study/web/study_data_blueprint.py | 14 ++++++++++++-- .../study_data_blueprint/test_renewable.py | 2 +- .../study_data_blueprint/test_st_storage.py | 2 +- .../study_data_blueprint/test_thermal.py | 2 +- 10 files changed, 28 insertions(+), 13 deletions(-) diff --git a/antarest/study/business/areas/renewable_management.py b/antarest/study/business/areas/renewable_management.py index 56a4b44a8d..abb0d17503 100644 --- a/antarest/study/business/areas/renewable_management.py +++ b/antarest/study/business/areas/renewable_management.py @@ -37,7 +37,7 @@ class TimeSeriesInterpretation(EnumIgnoreCase): @camel_case_model -class RenewableClusterInput(RenewableProperties, metaclass=AllOptionalMetaclass): +class RenewableClusterInput(RenewableProperties, metaclass=AllOptionalMetaclass, use_none=True): """ Model representing the data structure required to edit an existing renewable cluster. """ @@ -76,7 +76,7 @@ def to_config(self, study_version: t.Union[str, int]) -> RenewableConfigType: @camel_case_model -class RenewableClusterOutput(RenewableConfig, metaclass=AllOptionalMetaclass): +class RenewableClusterOutput(RenewableConfig, metaclass=AllOptionalMetaclass, use_none=True): """ Model representing the output data structure to display the details of a renewable cluster. """ diff --git a/antarest/study/business/areas/st_storage_management.py b/antarest/study/business/areas/st_storage_management.py index 8d1edd59b1..e607edca58 100644 --- a/antarest/study/business/areas/st_storage_management.py +++ b/antarest/study/business/areas/st_storage_management.py @@ -37,7 +37,7 @@ @camel_case_model -class STStorageInput(STStorageProperties, metaclass=AllOptionalMetaclass): +class STStorageInput(STStorageProperties, metaclass=AllOptionalMetaclass, use_none=True): """ Model representing the form used to EDIT an existing short-term storage. """ diff --git a/antarest/study/business/areas/thermal_management.py b/antarest/study/business/areas/thermal_management.py index b421775557..6f24c41ee7 100644 --- a/antarest/study/business/areas/thermal_management.py +++ b/antarest/study/business/areas/thermal_management.py @@ -30,7 +30,7 @@ @camel_case_model -class ThermalClusterInput(Thermal860Properties, metaclass=AllOptionalMetaclass): +class ThermalClusterInput(Thermal860Properties, metaclass=AllOptionalMetaclass, use_none=True): """ Model representing the data structure required to edit an existing thermal cluster within a study. """ @@ -70,7 +70,7 @@ def to_config(self, study_version: t.Union[str, int]) -> ThermalConfigType: @camel_case_model -class ThermalClusterOutput(Thermal860Config, metaclass=AllOptionalMetaclass): +class ThermalClusterOutput(Thermal860Config, metaclass=AllOptionalMetaclass, use_none=True): """ Model representing the output data structure to display the details of a thermal cluster within a study. """ diff --git a/antarest/study/business/thematic_trimming_management.py b/antarest/study/business/thematic_trimming_management.py index 4259046701..1ebfeebe04 100644 --- a/antarest/study/business/thematic_trimming_management.py +++ b/antarest/study/business/thematic_trimming_management.py @@ -12,7 +12,7 @@ from antarest.study.storage.variantstudy.model.command.update_config import UpdateConfig -class ThematicTrimmingFormFields(FormFieldsBaseModel, metaclass=AllOptionalMetaclass): +class ThematicTrimmingFormFields(FormFieldsBaseModel, metaclass=AllOptionalMetaclass, use_none=True): """ This class manages the configuration of result filtering in a simulation. diff --git a/antarest/study/business/xpansion_management.py b/antarest/study/business/xpansion_management.py index dc595d5428..f3adadad32 100644 --- a/antarest/study/business/xpansion_management.py +++ b/antarest/study/business/xpansion_management.py @@ -196,7 +196,7 @@ def from_config(cls, config_obj: JSON) -> "GetXpansionSettings": return cls.construct(**config_obj) -class UpdateXpansionSettings(XpansionSettings, metaclass=AllOptionalMetaclass): +class UpdateXpansionSettings(XpansionSettings, metaclass=AllOptionalMetaclass, use_none=True): """ DTO object used to update the Xpansion settings. diff --git a/antarest/study/storage/rawstudy/model/filesystem/config/cluster.py b/antarest/study/storage/rawstudy/model/filesystem/config/cluster.py index 2c7053e3ce..4563a0d217 100644 --- a/antarest/study/storage/rawstudy/model/filesystem/config/cluster.py +++ b/antarest/study/storage/rawstudy/model/filesystem/config/cluster.py @@ -84,9 +84,14 @@ class ClusterProperties(ItemProperties): @property def installed_capacity(self) -> float: - """""" + # fields may contain `None` values if they are turned into `Optional` fields + if self.unit_count is None or self.nominal_capacity is None: + return 0.0 return self.unit_count * self.nominal_capacity @property def enabled_capacity(self) -> float: + # fields may contain `None` values if they are turned into `Optional` fields + if self.enabled is None or self.installed_capacity is None: + return 0.0 return self.enabled * self.installed_capacity diff --git a/antarest/study/web/study_data_blueprint.py b/antarest/study/web/study_data_blueprint.py index 3bd394f0e6..c7e6ac17fd 100644 --- a/antarest/study/web/study_data_blueprint.py +++ b/antarest/study/web/study_data_blueprint.py @@ -25,8 +25,18 @@ RenewableClusterInput, RenewableClusterOutput, ) -from antarest.study.business.areas.st_storage_management import * # noqa -from antarest.study.business.areas.thermal_management import * # noqa +from antarest.study.business.areas.st_storage_management import ( + STStorageCreation, + STStorageInput, + STStorageMatrix, + STStorageOutput, + STStorageTimeSeries, +) +from antarest.study.business.areas.thermal_management import ( + ThermalClusterCreation, + ThermalClusterInput, + ThermalClusterOutput, +) from antarest.study.business.binding_constraint_management import ( BindingConstraintPropertiesWithName, ConstraintTermDTO, diff --git a/tests/integration/study_data_blueprint/test_renewable.py b/tests/integration/study_data_blueprint/test_renewable.py index c3bb7eaa79..14f1f4388a 100644 --- a/tests/integration/study_data_blueprint/test_renewable.py +++ b/tests/integration/study_data_blueprint/test_renewable.py @@ -201,7 +201,7 @@ def test_lifecycle( json=bad_properties, ) assert res.status_code == 422, res.json() - assert res.json()["exception"] == "ValidationError", res.json() + assert res.json()["exception"] == "RequestValidationError", res.json() # The renewable cluster properties should not have been updated. res = client.get( diff --git a/tests/integration/study_data_blueprint/test_st_storage.py b/tests/integration/study_data_blueprint/test_st_storage.py index ed3a45a360..1065a68e8b 100644 --- a/tests/integration/study_data_blueprint/test_st_storage.py +++ b/tests/integration/study_data_blueprint/test_st_storage.py @@ -223,7 +223,7 @@ def test_lifecycle__nominal( json=bad_properties, ) assert res.status_code == 422, res.json() - assert res.json()["exception"] == "ValidationError", res.json() + assert res.json()["exception"] == "RequestValidationError", res.json() # The short-term storage properties should not have been updated. res = client.get( diff --git a/tests/integration/study_data_blueprint/test_thermal.py b/tests/integration/study_data_blueprint/test_thermal.py index 587a5abcf5..1890d44acf 100644 --- a/tests/integration/study_data_blueprint/test_thermal.py +++ b/tests/integration/study_data_blueprint/test_thermal.py @@ -526,7 +526,7 @@ def test_lifecycle( json=bad_properties, ) assert res.status_code == 422, res.json() - assert res.json()["exception"] == "ValidationError", res.json() + assert res.json()["exception"] == "RequestValidationError", res.json() # The thermal cluster properties should not have been updated. res = client.get(