Skip to content

Commit 434f5f2

Browse files
authored
Added a proper validation function to check price_level_schedule and absolute_price_schedule (#31)
According the iso15118-20 schema file the charger can either send no price information, absolute or price_level. Signed-off-by: Sebastian Lukas <sebastian.lukas@pionix.de>
1 parent 8587152 commit 434f5f2

File tree

2 files changed

+38
-11
lines changed

2 files changed

+38
-11
lines changed

iso15118/shared/messages/iso15118_20/common_messages.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@
4444
V2GRequest,
4545
V2GResponse,
4646
)
47-
from iso15118.shared.validators import one_field_must_be_set
47+
from iso15118.shared.validators import (
48+
one_field_must_be_set,
49+
one_field_must_be_set_or_none,
50+
)
4851

4952

5053
class ECDHCurve(str, Enum):
@@ -713,24 +716,22 @@ class ChargingSchedule(BaseModel):
713716
@root_validator(pre=True)
714717
def either_price_levels_or_absolute_prices(cls, values):
715718
"""
716-
Either price_level_schedule or absolute_price_schedule must be set,
719+
Either price_level_schedule, absolute_price_schedule or none must be set,
717720
depending on whether abstract price levels or absolute prices are used
718721
to indicate costs for the charging session.
719-
720722
Pydantic validators are "class methods",
721723
see https://pydantic-docs.helpmanual.io/usage/validators/
722724
"""
723725
# pylint: disable=no-self-argument
724726
# pylint: disable=no-self-use
725-
if one_field_must_be_set(
727+
if one_field_must_be_set_or_none(
726728
[
727729
"price_level_schedule",
728730
"PriceLevelSchedule",
729731
"absolute_price_schedule",
730732
"AbsolutePriceSchedule",
731733
],
732734
values,
733-
True,
734735
):
735736
return values
736737

@@ -750,24 +751,22 @@ class DischargingSchedule(BaseModel):
750751
@root_validator(pre=True)
751752
def either_price_levels_or_absolute_prices(cls, values):
752753
"""
753-
Either price_level_schedule or absolute_price_schedule must be set,
754-
depending on abstract price levels or absolute prices are used to
755-
indicate costs for the charging session.
756-
754+
Either price_level_schedule, absolute_price_schedule or none must be set,
755+
depending on whether abstract price levels or absolute prices are used
756+
to indicate costs for the charging session.
757757
Pydantic validators are "class methods",
758758
see https://pydantic-docs.helpmanual.io/usage/validators/
759759
"""
760760
# pylint: disable=no-self-argument
761761
# pylint: disable=no-self-use
762-
if one_field_must_be_set(
762+
if one_field_must_be_set_or_none(
763763
[
764764
"price_level_schedule",
765765
"PriceLevelSchedule",
766766
"absolute_price_schedule",
767767
"AbsolutePriceSchedule",
768768
],
769769
values,
770-
True,
771770
):
772771
return values
773772

iso15118/shared/validators.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,31 @@ def one_field_must_be_set(
7878
)
7979

8080
return True
81+
82+
83+
def one_field_must_be_set_or_none(field_options: List[str], values: dict) -> bool:
84+
"""
85+
In several messages, there is the option to choose one of two or more
86+
possible fields, where all fields are defined as optional in the
87+
corresponding model but exactly one or none of them needs to be set.
88+
89+
Args:
90+
field_options: List of optional field names and aliases of a model.
91+
For each field, we need both the field name and the alias
92+
because when instantiating a pydantic model, we use the
93+
pythonic field names, but when de-serialising the model
94+
through JSON via the EXI codec, we use the aliases.
95+
values: The dict with the model's fields
96+
"""
97+
field_values = [values.get(f"{field_name}") for field_name in field_options]
98+
set_fields = [x for x in field_values if x is not None]
99+
100+
if len(set_fields) > 1:
101+
raise ValueError(
102+
f"Exactly one field must be set but {len(set_fields)} "
103+
"are set instead. "
104+
f"\nSet fields: {set_fields}"
105+
f"\nField options: {field_options}"
106+
)
107+
108+
return True

0 commit comments

Comments
 (0)