Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
02664ff
Stop logging issues in `microgrid_from_proto()`
llucax Jul 13, 2026
2806358
Add `BaseBounds` abstract base class
llucax Jul 16, 2026
59a1e0f
Make `Bounds` inherit from `BaseBounds`
llucax Jul 16, 2026
2fe2afd
Use `[lower,upper]` format in `Bounds.__str__`
llucax Jul 16, 2026
e514905
Add `InvalidBounds`
llucax Jul 16, 2026
8ef2355
Add `MissingBounds`
llucax Jul 16, 2026
f8e093e
Add `InvalidBoundsError`
llucax Jul 16, 2026
bb21019
Add `bounds_from_proto2` conversion function
llucax Jul 16, 2026
9743350
Deprecate `bounds_from_proto`
llucax Jul 16, 2026
0353d63
Deprecate `bounds_from_proto_with_issues`
llucax Jul 16, 2026
712285b
Update `metric_config_bounds` to preserve invalid bounds
llucax Jul 16, 2026
628ad81
Add safe accessors for metric config bounds
llucax Jul 16, 2026
2855917
Split `Bounds` tests into per-type files
llucax Jul 16, 2026
a8913a5
Remove `MissingBounds`
llucax Jul 17, 2026
1bc248f
Make `get_metric_config_bounds()` mimic `dict.get()`
llucax Jul 17, 2026
c217991
Update release notes
llucax Jul 16, 2026
3c71a2d
Add `__contains__` to `Bounds`
llucax Jul 19, 2026
26a871e
Add `__bool__` and `is_bounded()` to `Bounds`
llucax Jul 19, 2026
6257a90
Add `BoundsSet`
llucax Jul 19, 2026
529a234
Add `InvalidBoundsSet`
llucax Jul 19, 2026
38ba219
Migrate `MetricSample.bounds` to `bounds_set`
llucax Jul 19, 2026
8d4b8f2
Add `InvalidBoundsSetError`
llucax Jul 19, 2026
8b09979
Add safe accessor `MetricSample.get_bounds_set()`
llucax Jul 19, 2026
af6a08a
Reject `NaN` in bounds membership tests
llucax Jul 19, 2026
1c13dbb
Normalize the deprecated `MetricSample.bounds` property
llucax Jul 19, 2026
9f45805
Update release notes
llucax Jul 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,24 @@

A well-formed `DeliveryArea` has a non-empty `code` and a specified (non-`UNSPECIFIED`) `code_type`. Constructing one with invalid data currently emits a `DeprecationWarning`; a future release will replace the warning with a hard `ValueError`. To opt into the upcoming behavior right now, pass `_raise_on_invalid=True` to the constructor. Prefer `delivery_area_from_proto2` to load delivery areas from the wire — malformed messages become `InvalidDeliveryArea` instances instead.

* `frequenz.client.common.metrics.proto.v1alpha8.bounds_from_proto` is now deprecated; use `bounds_from_proto2` instead.

The new converter returns `Bounds | InvalidBounds` and surfaces malformed wire data at the type level rather than raising a `ValueError` when `lower > upper`. The old converter continues to work but emits a `DeprecationWarning`.

* `frequenz.client.common.metrics.proto.v1alpha8.bounds_from_proto_with_issues` is now deprecated with no direct replacement.

Validity is now encoded in the return type of `bounds_from_proto2` (`Bounds | InvalidBounds`), so callers should inspect the returned type instead of collecting issue strings via a side channel. The old converter continues to work but emits a `DeprecationWarning`.

* `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 `<invalid:...>` marker on `InvalidBounds`.

* `frequenz.client.common.metrics.MetricSample.bounds` is now deprecated; use `bounds_set` instead.

The field type changed from `list[Bounds]` to `BoundsSet | InvalidBoundsSet` (see New Features). Reads and construction remain backward compatible: passing the `bounds=` keyword argument still works (it builds a `BoundsSet` and emits a `DeprecationWarning`), and reading `MetricSample.bounds` still returns the valid `Bounds` as a `list` (also emitting a `DeprecationWarning`). The compatibility property returns only the valid, normalized bounds, so it may differ from the raw wire list when bounds overlapped or touched.

* `frequenz.client.common.metrics.proto.v1alpha8.metric_sample_from_proto_with_issues` no longer drops invalid bounds or reports them as a major issue.

Malformed bounds are now preserved in the returned `MetricSample.bounds_set` as an `InvalidBoundsSet` (validity is encoded in the type), so the previous "bounds for ... is invalid, ignoring these bounds" major issue is no longer produced.

## New Features

* Added 4 new electrical component classes for categories that previously collapsed into `UnrecognizedElectricalComponent`:
Expand Down Expand Up @@ -81,6 +99,8 @@
* `frequenz.client.common.grid.DeliveryArea.get_code_type()`
* `frequenz.client.common.metrics.MetricConnection.get_category()`
* `frequenz.client.common.metrics.MetricSample.get_metric()`
* `frequenz.client.common.metrics.MetricSample.get_bounds_set()`
* `frequenz.client.common.microgrid.electrical_components.ElectricalComponent.get_metric_config_bounds()`

* Added new delivery-area class hierarchy:

Expand All @@ -92,6 +112,20 @@

* Added a new `frequenz.client.common.microgrid.Lifetime` type together with the `frequenz.client.common.microgrid.proto.v1alpha8.lifetime_from_proto` conversion function.

* Added `frequenz.client.common.metrics.proto.v1alpha8.bounds_from_proto2` returning `Bounds | InvalidBounds`. This is the replacement for the now-deprecated `bounds_from_proto`.

* `frequenz.client.common.metrics.Bounds` gained containment check capabilities:

* `value in bounds` (`__contains__`) tests membership, inclusive on both ends, with a `None` bound meaning unbounded in that direction.
* `bool(bounds)` and `bounds.is_bounded()` report whether the bounds restrict anything; a fully unbounded `Bounds()` is falsy.

* Added a new bounds-set class hierarchy:

* `frequenz.client.common.metrics.BoundsSet` — a normalized union of `Bounds` with an efficient `value in bounds_set` membership test. Overlapping and touching bounds are merged on construction, and the empty set is the unbounded set (it contains every value and is falsy).
* `frequenz.client.common.metrics.InvalidBoundsSet` — a set built from bounds that included at least one `InvalidBounds`; it preserves all the raw bounds unmerged and provides no membership test.

* Added a new `frequenz.client.common.metrics.MetricSample.bounds_set` field, typed `BoundsSet | InvalidBoundsSet`, replacing the deprecated `bounds` list (see Upgrading). Malformed wire bounds are preserved as an `InvalidBoundsSet` instead of being dropped. Use `get_bounds_set()` to resolve it to a valid `BoundsSet` or a clear `InvalidBoundsSetError`.

* 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.
Expand All @@ -100,6 +134,8 @@

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.

`ElectricalComponent.metric_config_bounds` is typed `Mapping[Metric | int, Bounds | InvalidBounds]`: malformed wire entries are preserved as `InvalidBounds` instead of being silently dropped, and entries that named a metric but carried no (or an empty) `config_bounds` submessage load as an unbounded `Bounds()` (a `Bounds` with neither bound set imposes no limit in either direction). Use `get_metric_config_bounds()` to resolve an entry to a valid `Bounds` or a clear `InvalidBoundsError`; it mimics `dict.get()`, returning an unbounded `Bounds()` (or a caller-supplied `default`) for absent metrics.

* 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.

## Bug Fixes
Expand Down
16 changes: 15 additions & 1 deletion src/frequenz/client/common/metrics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@

"""Metrics definitions."""

from ._bounds import Bounds
from ._bounds import (
BaseBounds,
Bounds,
BoundsSet,
InvalidBounds,
InvalidBoundsError,
InvalidBoundsSet,
InvalidBoundsSetError,
)
from ._metric import Metric
from ._sample import (
AggregatedMetricValue,
Expand All @@ -16,7 +24,13 @@
__all__ = [
"AggregatedMetricValue",
"AggregationMethod",
"BaseBounds",
"Bounds",
"BoundsSet",
"InvalidBounds",
"InvalidBoundsError",
"InvalidBoundsSet",
"InvalidBoundsSetError",
"Metric",
"MetricConnection",
"MetricConnectionCategory",
Expand Down
Loading
Loading