From ae6639bafafe6cf5dfe19eab349a5d0b93c81432 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 15 Sep 2026 09:46:47 +0000 Subject: [PATCH 1/4] Write the v0.4.1 release summary Replace the template placeholder with an overview of the release: the new Microgrid and Assets API wrappers, the move to validity-in-the-type conversion with deprecations scheduled for v0.5.0, and a pointer to the intentional hard breaks listed in the Upgrading section. Signed-off-by: Leandro Lucarella --- RELEASE_NOTES.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b022dc72..574576b4 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,7 +7,14 @@ ## Summary - +> [!NOTE] +> Despite the patch version number, this is a huge release: 58 pull requests and over 320 commits, adding about 6,000 lines to the library, 9,000 lines of tests and 1,800 lines of documentation. It realizes the new library design while keeping backwards compatibility with v0.4.0; the remaining (breaking) cleanup of everything deprecated here will follow in v0.5.0. + +The release brings the wrappers for the Microgrid and Assets APIs (`Microgrid`, `Location`, `Lifetime`, and the whole `ElectricalComponent` class hierarchy with its connections) and settles how invalid wire data is handled: conversion functions no longer raise or report issues through side channels, they return an `Invalid*` representation instead, and safe `get_*()` accessors raise clear exceptions. Every `UNSPECIFIED` enum member, the electrical component category and type enums, and the `*_with_issues()` and single-return converters they replace are deprecated and scheduled for removal in v0.5.0. + +It also introduces 3 new guides in the documentation: a User Guide for users of the wrapper types, a Client Developer Guide for `frequenz-client-*` library authors, and a Wrapping Guide for anyone designing a wrapper. + +There are a few intentional hard breaks too, all listed in the Upgrading section: `MetricSample.bounds` became `bounds_set`, `MetricSample.sample_time` became `sample_time2`, `MetricConnection.name` is no longer optional, and some constructors that silently accepted invalid values now raise. ## Upgrading From 8e49f581d3414da2ea96aea3209f03e9209e0640 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 15 Sep 2026 09:46:59 +0000 Subject: [PATCH 2/4] Document undocumented breaking changes Two changes to symbols released in v0.4.0 were missing from the Upgrading section: * `Bounds` now raises `ValueError` on a `NaN` endpoint (#254). * `MetricConnection.name` is a plain `str` defaulting to `""` instead of `str | None` defaulting to `None` (#257). Add a bullet for each, with the migration hints. Signed-off-by: Leandro Lucarella --- RELEASE_NOTES.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 574576b4..e4d80c86 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -76,6 +76,12 @@ There are a few intentional hard breaks too, all listed in the Upgrading section The new converters (see New Features) encode an unspecified or unrecognized `metric` / `category` as a raw `int` (`Metric | int` / `MetricConnectionCategory | int`) and malformed bounds as an `InvalidBoundsSet` in the returned object, so callers inspect validity on the returned type instead of collecting issue strings via a side channel. The old converters continue to work but emit a `DeprecationWarning`. +* `frequenz.client.common.metrics.Bounds` now raises `ValueError` when constructed with a `NaN` endpoint (`lower` or `upper`), as it did already when `lower > upper`. A `NaN` endpoint made every membership test meaningless, so this was never a usable value. Use `None` for an unbounded direction, and `bounds_from_proto2` to load bounds from the wire, which returns `InvalidBounds` instead of raising. + +* `frequenz.client.common.metrics.MetricConnection.name` is now a plain `str` defaulting to `""` instead of `str | None` defaulting to `None`, mirroring the protobuf field, which has no presence and reads as `""` when unset. + + This is an intentional hard break of the released dataclass API (following the project's [0.x compatibility guidance](https://github.com/frequenz-floss/docs/blob/v0.x.x/python/semver-0.x.x.md)): passing `name=None` is now a type error, `connection.name is None` checks never match anymore (use `not connection.name`), and instances built with the old default no longer compare equal to instances built with the new one. + * `frequenz.client.common.metrics.Bounds.__str__` now renders as `[lower,upper]` (no space after the comma) to match the compact format used by `Lifetime` and to compose cleanly with the `` marker on `InvalidBounds`. * Several `__str__` representations were standardized around the `` marker, so a `grep ' Date: Tue, 15 Sep 2026 09:46:59 +0000 Subject: [PATCH 3/4] Fill the gaps in the New Features section * Mention that `metric_config_bounds` keys also store the raw `0` for unspecified metrics (#224). * Merge the two `Microgrid` bullets, which described the same addition. * Describe the `ElectricalComponent` boolean accessors (#237), the `CategorySpecificInfo` field (#257, #273) and the aggregated `metric_config_bounds` (#268). * Add a compact list of the smaller supporting types from #248 and #249 (`Invalid{Latitude,Longitude,CountryCode}`, `InvalidLifetime` and their errors). Signed-off-by: Leandro Lucarella --- RELEASE_NOTES.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e4d80c86..44d7daef 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -50,7 +50,7 @@ There are a few intentional hard breaks too, all listed in the Upgrading section * `frequenz.client.common.microgrid.electrical_components.ElectricalComponentStateCode` * `frequenz.client.common.streaming.Event` - When loading these types from protobuf using dataclass-level converters (e.g., `delivery_area_from_proto`, `metric_sample_from_proto`), the low-level fields (`code_type`, `category`, `metric`) now store the raw integer `0` for unspecified values instead of the deprecated member. Unspecified values should be rare errors, so it is better to expose them only via the low-level interface. + When loading these types from protobuf using dataclass-level converters (e.g., `delivery_area_from_proto`, `metric_sample_from_proto`), the low-level fields (`code_type`, `category`, `metric`, and the keys of `ElectricalComponent.metric_config_bounds`) now store the raw integer `0` for unspecified values instead of the deprecated member. Unspecified values should be rare errors, so it is better to expose them only via the low-level interface. Lower-level enum-level converters still return the deprecated member. @@ -197,13 +197,19 @@ There are a few intentional hard breaks too, all listed in the Upgrading section * Added a new `frequenz.client.common.types.Location` type together with the `frequenz.client.common.types.proto.v1alpha8.location_from_proto` conversion function. -* Added a new `frequenz.client.common.microgrid.Microgrid` type, together with the `frequenz.client.common.microgrid.proto.v1alpha8.microgrid_from_proto` conversion function. +* Added a new `frequenz.client.common.microgrid.Microgrid` type with a raising `is_active()` method, together with the `frequenz.client.common.microgrid.proto.v1alpha8.microgrid_from_proto` conversion function. * Added a new `frequenz.client.common.microgrid.electrical_components` package, featuring a `ElectricalComponent` class hierarchy and its families (battery, inverter, EV charger, etc.), and `ElectricalComponentConnection` class hierarchy, including `v1alpha8` proto conversion functions. The class of a component is its identity; components don't carry category or type attributes. The only exceptions are the error-recovery classes `UnrecognizedElectricalComponent` and `MismatchedCategoryElectricalComponent` (with a raw protobuf `category` value) and `UnrecognizedBattery`, `UnrecognizedInverter` and `UnrecognizedEvCharger` (with a raw protobuf `type` value), which preserve the raw protobuf values received from the protocol version used to load them. -* Added a new `frequenz.client.common.microgrid.Microgrid` type with a raising `is_active()` method, together with the `frequenz.client.common.microgrid.proto.v1alpha8.microgrid_from_proto` conversion function. + Components also expose the raising boolean accessors `provides_telemetry()` and `accepts_control()`, the category-specific fields as a `CategorySpecificInfo` (with the protobuf field names as keys for the fields this library doesn't wrap yet), and the metric configuration bounds aggregated per metric into a `BoundsSet | InvalidBoundsSet`. + +* Added smaller supporting types, each following the same validity-in-the-type pattern as the ones above: + + * `frequenz.client.common.types.InvalidLatitude`, `InvalidLongitude` and `InvalidCountryCode`, held by `Location` when the wire value is out of range or malformed, with the matching `InvalidLatitudeError`, `InvalidLongitudeError` and `InvalidCountryCodeError` raised by `Location.get_latitude()`, `get_longitude()`, `get_country_code()` and `get_country_code_or_none()`. + * `frequenz.client.common.microgrid.InvalidLifetime`, returned by `lifetime_from_proto` for a malformed lifetime, and `InvalidLifetimeError`, raised by the accessors resolving one. + * `frequenz.client.common.microgrid.electrical_components.CategorySpecificInfo`, the container for the category-specific fields of an `ElectricalComponent`. * Added three authored documentation guides, one per audience: From a26cf839acd64112322885d394e6ec45029e72f0 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 15 Sep 2026 09:47:00 +0000 Subject: [PATCH 4/4] Add release note for the `str()` exception messages Exceptions reporting an invalid value now render it with `str()` instead of `repr()` (#258); this was missing from Bug Fixes. Signed-off-by: Leandro Lucarella --- RELEASE_NOTES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 44d7daef..bf3fa90a 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -221,3 +221,4 @@ There are a few intentional hard breaks too, all listed in the Upgrading section * Fixed `EnumParityTest` so protobuf values whose Python member name exists with a different number fail parity checks instead of being treated as unmirrored protobuf values. * Fixed potential unexpected exceptions due to type-checking accepting `int` for code annotated to only accept `float`. Fixes #250. +* Exception messages reporting an invalid value now use its `str()` instead of its `repr()`, so they show the compact `` rendering instead of a verbose dataclass dump.