Skip to content

Commit

Permalink
Added a proper validation function to check price_level_schedule and …
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
SebaLukas authored Nov 6, 2024
1 parent 8587152 commit 434f5f2
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 11 deletions.
21 changes: 10 additions & 11 deletions iso15118/shared/messages/iso15118_20/common_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@
V2GRequest,
V2GResponse,
)
from iso15118.shared.validators import one_field_must_be_set
from iso15118.shared.validators import (
one_field_must_be_set,
one_field_must_be_set_or_none,
)


class ECDHCurve(str, Enum):
Expand Down Expand Up @@ -713,24 +716,22 @@ class ChargingSchedule(BaseModel):
@root_validator(pre=True)
def either_price_levels_or_absolute_prices(cls, values):
"""
Either price_level_schedule or absolute_price_schedule must be set,
Either price_level_schedule, absolute_price_schedule or none must be set,
depending on whether abstract price levels or absolute prices are used
to indicate costs for the charging session.
Pydantic validators are "class methods",
see https://pydantic-docs.helpmanual.io/usage/validators/
"""
# pylint: disable=no-self-argument
# pylint: disable=no-self-use
if one_field_must_be_set(
if one_field_must_be_set_or_none(
[
"price_level_schedule",
"PriceLevelSchedule",
"absolute_price_schedule",
"AbsolutePriceSchedule",
],
values,
True,
):
return values

Expand All @@ -750,24 +751,22 @@ class DischargingSchedule(BaseModel):
@root_validator(pre=True)
def either_price_levels_or_absolute_prices(cls, values):
"""
Either price_level_schedule or absolute_price_schedule must be set,
depending on abstract price levels or absolute prices are used to
indicate costs for the charging session.
Either price_level_schedule, absolute_price_schedule or none must be set,
depending on whether abstract price levels or absolute prices are used
to indicate costs for the charging session.
Pydantic validators are "class methods",
see https://pydantic-docs.helpmanual.io/usage/validators/
"""
# pylint: disable=no-self-argument
# pylint: disable=no-self-use
if one_field_must_be_set(
if one_field_must_be_set_or_none(
[
"price_level_schedule",
"PriceLevelSchedule",
"absolute_price_schedule",
"AbsolutePriceSchedule",
],
values,
True,
):
return values

Expand Down
28 changes: 28 additions & 0 deletions iso15118/shared/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,31 @@ def one_field_must_be_set(
)

return True


def one_field_must_be_set_or_none(field_options: List[str], values: dict) -> bool:
"""
In several messages, there is the option to choose one of two or more
possible fields, where all fields are defined as optional in the
corresponding model but exactly one or none of them needs to be set.
Args:
field_options: List of optional field names and aliases of a model.
For each field, we need both the field name and the alias
because when instantiating a pydantic model, we use the
pythonic field names, but when de-serialising the model
through JSON via the EXI codec, we use the aliases.
values: The dict with the model's fields
"""
field_values = [values.get(f"{field_name}") for field_name in field_options]
set_fields = [x for x in field_values if x is not None]

if len(set_fields) > 1:
raise ValueError(
f"Exactly one field must be set but {len(set_fields)} "
"are set instead. "
f"\nSet fields: {set_fields}"
f"\nField options: {field_options}"
)

return True

0 comments on commit 434f5f2

Please sign in to comment.