Skip to content

Improve DeliveryArea validation and error handling#241

Open
llucax wants to merge 14 commits into
frequenz-floss:v0.x.xfrom
llucax:name-delivery-area
Open

Improve DeliveryArea validation and error handling#241
llucax wants to merge 14 commits into
frequenz-floss:v0.x.xfrom
llucax:name-delivery-area

Conversation

@llucax

@llucax llucax commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Adds a new delivery-area class hierarchy:

  • frequenz.client.common.grid.BaseDeliveryArea — abstract common supertype of the two concrete leaves; not directly instantiable.
  • frequenz.client.common.grid.DeliveryArea — well-formed delivery area (retroactively made a subclass of BaseDeliveryArea; its shared __str__ and get_code_type() are hoisted to the base).
  • frequenz.client.common.grid.InvalidDeliveryArea — malformed wire data; same fields as DeliveryArea with no invariants enforced, so callers can inspect whatever the server actually sent.

Also adds frequenz.client.common.grid.proto.v1alpha8.delivery_area_from_proto2 returning DeliveryArea | InvalidDeliveryArea. This is the replacement for delivery_area_from_proto (which is deprecated now) and is what microgrid_from_proto uses internally.

This deprecates construction of frequenz.client.common.grid.DeliveryArea with invalid data. A well-formed DeliveryArea has a non-empty code and a non-UNSPECIFIED code_type. Constructing one with invalid data currently emits a DeprecationWarning; a future release will replace the warning with a hard ValueError. Prefer delivery_area_from_proto2 to load delivery areas from the wire — malformed messages become InvalidDeliveryArea instances instead.

Part of #239.

@github-actions github-actions Bot added part:docs Affects the documentation part:tests Affects the unit, integration and performance (benchmarks) tests part:grid Affects the grid protobuf definitions part:microgrid Affects the microgrid protobuf definitions labels Jul 6, 2026
@llucax llucax mentioned this pull request Jul 6, 2026
5 tasks
@llucax llucax force-pushed the name-delivery-area branch 2 times, most recently from 9e9a1c6 to 8e6ce9e Compare July 7, 2026 12:36
@github-actions github-actions Bot added part:tooling Affects the development tooling (CI, deployment, dependency management, etc.) part:metrics Affects the metrics protobuf definitions labels Jul 7, 2026
llucax added 14 commits July 7, 2026 15:28
Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
`UnrecognizedEnumValueError` should only be raised from high-level
wrappers, not protobuf conversion functions. Replace it with a simple
`ValueError`, in this case someone just called the function with the
wrong arguments.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
This exception will be the base for any exception raised when an
attribute that holds invalid data is accessed through a semantic
accessor.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Add a new top-level exception `MissingFieldError`, sibling of
`UnspecifiedEnumValueError`, to signal that a semantic accessor was
called on a wrapper field that resolves to `None` because the underlying
field was not set on the wire.

The first user is the upcoming `Microgrid.get_delivery_area()` accessor
(delivery area may be `None`, `InvalidDeliveryArea`, or `DeliveryArea`),
but the pattern is expected to recur wherever an accessor unifies a
`T | ... | None` field into a plain `T` return.

Like `Unspecified/UnrecognizedEnumValueError`, it multi-inherits from
`ClientCommonError` and `ValueError` for convenience.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Make `UnrecognizedEnumValueError` and `UnspecifiedEnumValueError`
inherit from `InvalidAttributeError`.

Also split exception tests as the file grew too much when adding the new
tests.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
This class will be used as the base for both valid and invalid delivery
area classes.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
`DeliveryArea`, the existing type, is retroactively made a subclass of
`BaseDeliveryArea`. Field shape and construction API are unchanged
(`code: str | None`, `code_type: EnergyMarketCodeType | int`) for
backwards compatibility, but a `__post_init__` is added with invariant
checks: a well-formed delivery area must have a non-empty `code` and a
specified `code_type`.

Constructing one without that doesn't pass those invariants will now
emit a `DeprecationWarning` (and it will raise `ValueError` in v0.5.0).

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
A `__post_init__` is added with invariant checks: a well-formed delivery
area must have a non-empty `code` and a specified `code_type`.

Constructing one without that doesn't pass the invariant will now
emit a `DeprecationWarning` (and it will raise `ValueError` in v0.5.0).

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
`InvalidDeliveryArea` is added to represent malformed wire data. Same
fields as `BaseDeliveryArea`, no invariants enforced, so callers can
inspect whatever the server actually sent.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
The dedicated `InvalidDeliveryAreaError` (also a `ValueError` for
convenience) carries the offending `InvalidDeliveryArea` on
`.delivery_area` and will be raised by upcoming semantic accessors
(next commits) instead of forcing callers to distinguish the two.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Introduce `delivery_area_from_proto2`, sibling of the existing
`delivery_area_from_proto`, returning
`DeliveryArea | InvalidDeliveryArea` instead of a plain `DeliveryArea`.

The new converter enforces at the boundary the invariant that
`DeliveryArea.__post_init__` now warns about:

* `code` must be non-empty.
* `code_type` must not be raw `0` (i.e. unspecified).

A wire message that fails either check becomes an
`InvalidDeliveryArea` carrying the raw data verbatim, so callers can
inspect or report it via `InvalidDeliveryAreaError`. Unknown non-zero
`int` `code_type` values are still treated as valid to preserve forward
compatibility with new protobuf enum values.

Because the valid path constructs a `DeliveryArea` only when the
invariants already hold, `delivery_area_from_proto2` never triggers the
inner `DeprecationWarning` — and, unlike the old converter, it doesn't
log any "found issues" warning either: the return type itself now
signals whether the wire data was well-formed.

The existing `delivery_area_from_proto` remains unchanged and will be
marked `@deprecated` in a follow-up commit.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Loosen `Microgrid.delivery_area` from `DeliveryArea | None` to
`DeliveryArea | InvalidDeliveryArea | None` to reflect the three
possible wire states: absent, present-but-malformed, and well-formed.
`microgrid_from_proto` is switched to `delivery_area_from_proto2`, so
proto-loaded microgrids already carry the right variant on the union.

Add the semantic accessor `Microgrid.get_delivery_area() ->
DeliveryArea` so callers that need a valid delivery area don't have to
check for either failure mode by hand:

* `None` -> `MissingFieldError` (the field wasn't set on the wire).
* `InvalidDeliveryArea` -> `InvalidDeliveryAreaError`, with the
  offending instance available on `.delivery_area` for inspection.
* `DeliveryArea` -> returned unchanged.

Microgrid is unreleased so this widened field and the new accessor are
free additions — no backwards compatibility needed.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Mark `delivery_area_from_proto` as `@deprecated`, pointing callers at
`delivery_area_from_proto2`, which returns `DeliveryArea |
InvalidDeliveryArea` and surfaces malformed wire data at the type level
rather than as an ad-hoc log warning.

The internal `DeliveryArea(...)` construction inside
`delivery_area_from_proto` was already wrapped in
`warnings.catch_warnings()` when `DeliveryArea.__post_init__` gained
its soft invariant check, so the two suppressions compose correctly:
callers of the deprecated entry point see exactly one
`DeprecationWarning`, identifying `delivery_area_from_proto2` as the
replacement.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
@llucax llucax force-pushed the name-delivery-area branch from 8e6ce9e to 8a24201 Compare July 7, 2026 13:36
@llucax llucax self-assigned this Jul 7, 2026
@llucax llucax marked this pull request as ready for review July 7, 2026 13:39
@llucax llucax requested a review from a team as a code owner July 7, 2026 13:39
@llucax llucax requested review from eduardiazf and ela-kotulska-frequenz and removed request for a team July 7, 2026 13:39
@llucax llucax added this to the v0.4.1 milestone Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

part:docs Affects the documentation part:grid Affects the grid protobuf definitions part:metrics Affects the metrics protobuf definitions part:microgrid Affects the microgrid protobuf definitions part:tests Affects the unit, integration and performance (benchmarks) tests part:tooling Affects the development tooling (CI, deployment, dependency management, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant