Skip to content

Deprecate UNSPECIFIED for simple enums#221

Open
llucax wants to merge 9 commits into
frequenz-floss:v0.x.xfrom
llucax:no-unspecified-phase-b
Open

Deprecate UNSPECIFIED for simple enums#221
llucax wants to merge 9 commits into
frequenz-floss:v0.x.xfrom
llucax:no-unspecified-phase-b

Conversation

@llucax

@llucax llucax commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Deprecate EnergyMarketCodeType.UNSPECIFIED, Metric.UNSPECIFIED and MetricConnectionCategory.UNSPECIFIED and add new safe accessor methods to retrieve the valid enum values or raise an exception:

  • DeliveryArea.get_code_type()
  • MetricConnection.get_category()
  • MetricSample.get_metric()

The UNSPECIFIED value is now stored as a low-level 0 integer, so users can still access it directly if needed, but regular use will raise an exception if trying to use an unspecified or unrecognized value. This should lead to much simpler happy path, while still allowing for the possibility of handling unspecified values in a controlled manner and making rare and error conditions more explicit.

The ElectricalComponentCategory and XxxType enums are not affected by this change, as they do not have an UNSPECIFIED value, but will be completely removed in the future.

Part of #223.

@github-actions github-actions Bot added part:docs Affects the documentation part:tests Affects the unit, integration and performance (benchmarks) tests part:tooling Affects the development tooling (CI, deployment, dependency management, etc.) part:grid Affects the grid protobuf definitions part:metrics Affects the metrics protobuf definitions part:microgrid Affects the microgrid protobuf definitions labels Jun 23, 2026
@llucax

llucax commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

Blocked because it is based on #220.

@llucax llucax force-pushed the no-unspecified-phase-b branch from c249ece to 829c162 Compare June 25, 2026 14:24
@llucax llucax marked this pull request as ready for review June 25, 2026 14:24
@llucax llucax requested a review from a team as a code owner June 25, 2026 14:24
@llucax llucax requested review from daniel-zullo-frequenz and removed request for a team June 25, 2026 14:24
@llucax llucax self-assigned this Jun 25, 2026
@llucax llucax added this to the v0.4.1 milestone Jun 25, 2026
@llucax

llucax commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

Unblocked, ready for review.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates frequenz-client-common’s high-level enum handling to discourage using UNSPECIFIED enum members directly while preserving forward compatibility with raw protobuf integer values. It introduces “safe” accessors that return only recognized enum members and otherwise raise explicit exceptions, keeping the public API Pythonic and making rare/erroneous cases more explicit (per #223).

Changes:

  • Deprecate UNSPECIFIED members for selected “simple” enums and store the unspecified protobuf value as raw int(0) in dataclass-level conversions.
  • Add semantic accessor methods (get_*) that either return a known enum member or raise UnspecifiedValueError / the new UnrecognizedValueError.
  • Enhance enum parity tests to support deprecated/absent members and expand unit/proto conversion test coverage for the new behavior.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/test_exception.py Adds tests for new UnrecognizedValueError and verifies __all__ export ordering.
tests/metrics/test_sample_metric_sample.py Adds unit tests for MetricSample.get_metric() behavior across known/unspecified/unrecognized values.
tests/metrics/test_sample_metric_connection.py Adds unit tests for MetricConnection.get_category() behavior across known/unspecified/unrecognized values.
tests/metrics/proto/v1alpha8/test_sample_metric_sample.py Verifies proto→dataclass conversion stores unspecified metric as raw 0 without deprecation warnings.
tests/metrics/proto/v1alpha8/test_sample_metric_connection.py Verifies proto→dataclass conversion stores unspecified category as raw 0 and remains warning-clean.
tests/metrics/proto/v1alpha8/test_metric.py Marks UNSPECIFIED as a deprecated member for parity testing.
tests/metrics/proto/v1alpha8/test_metric_connection_category.py Marks UNSPECIFIED as a deprecated member for parity testing.
tests/grid/test_delivery_area.py Adds unit tests for DeliveryArea.get_code_type() and deprecation behavior of UNSPECIFIED.
tests/grid/proto/v1alpha8/test_delivery_area.py Updates expectations for unspecified code type stored as raw 0 and adds accessor error test.
src/frequenz/client/common/test/enum_parity.py Extends parity scaffold with deprecation-aware and “absent member” modes.
src/frequenz/client/common/microgrid/electrical_components/proto/v1alpha8/_electrical_component.py Avoids resolving deprecated Metric.UNSPECIFIED by handling raw 0 directly when parsing config bounds.
src/frequenz/client/common/microgrid/electrical_components/_electrical_component.py Updates docstring to describe unspecified metric as proto value 0 rather than enum member.
src/frequenz/client/common/metrics/proto/v1alpha8/_sample.py Stores unspecified metric/category as raw 0 before invoking enum converters (prevents deprecation warnings).
src/frequenz/client/common/metrics/_sample.py Deprecates MetricConnectionCategory.UNSPECIFIED and adds get_category() / get_metric() safe accessors.
src/frequenz/client/common/metrics/_metric.py Deprecates Metric.UNSPECIFIED using frequenz.core.enum.deprecated_member.
src/frequenz/client/common/grid/proto/v1alpha8/_delivery_area.py Stores unspecified code type as raw 0 and reports issues without resolving deprecated enum member.
src/frequenz/client/common/grid/_delivery_area.py Deprecates EnergyMarketCodeType.UNSPECIFIED and adds DeliveryArea.get_code_type() safe accessor.
src/frequenz/client/common/_exception.py Introduces UnrecognizedValueError and clarifies UnspecifiedValueError semantics.
src/frequenz/client/common/init.py Exports UnrecognizedValueError at the package root via __all__.
RELEASE_NOTES.md Documents enum deprecations, new safe getters, and exception behavior (needs edits per review comments).
pyproject.toml Bumps frequenz-core minimum version to support deprecated enum members.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread RELEASE_NOTES.md Outdated
Comment thread RELEASE_NOTES.md
Comment thread RELEASE_NOTES.md Outdated
@Marenz

Marenz commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

needs rebase

llucax added 2 commits June 29, 2026 17:16
Semantic accessors need to tell apart two distinct situations: a value
the server left unspecified, and a value the server set but this client
version does not recognize yet. The latter must carry the raw integer so
resilient callers can forward it.

Add `UnrecognizedValueError(ClientCommonError, ValueError)` storing the
raw value on `.value`, and narrow `UnspecifiedValueError`'s docstring to
the unspecified-only case, cross-referencing the new error.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Give the shared enum-parity scaffold two opt-in class variables,
`deprecated_members` and `absent_members`, both defaulting to an empty
`frozenset` so every existing subclass keeps its current behaviour.

When a member name is listed in `deprecated_members`, the parity checks
that merely resolve it suppress the `DeprecationWarning` (via a small
`_maybe_ignore_deprecation` context manager), `test_from_proto` asserts
the enum-level converter returns the still-present member and warns, and
a new `test_deprecated_members_warn` asserts the warning directly.

A new `test_absent_members` covers the future case where a member is
removed from the Python enum while the protobuf enum still defines its
value.

This unblocks deprecating the three `UNSPECIFIED` members in later
commit without touching their parity subclasses yet.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
llucax added 7 commits June 29, 2026 17:25
Mark `EnergyMarketCodeType.UNSPECIFIED` as a deprecated member.

The dataclass-level `delivery_area_from_proto` now stores the raw int
`0` for an unspecified value instead of materializing the deprecated
member. The enum-level `energy_market_code_type_from_proto`/`_to_proto`
converters are left untouched and still return the member for known
values. These will automatically stop handling `UNSPECIFIED` once it's
completely removed.

`DeliveryArea.get_code_type()` will be introduced in a follow-up commit.

Bump the `frequenz-core` dependency to be able to use the
`deprecated_member()` helper.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
The dataclass-level converters now store the raw int `0` for an
unspecified value instead of materializing the deprecated member:
`metric_sample_from_proto_with_issues` reads the raw proto value and keep
`0` as a plain `int`, and the enum-level converters are left untouched.

`MetricSample.get_metric()` will be introduced in a follow-up commit.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
The dataclass-level converters now store the raw int `0` for an
unspecified value instead of materializing the deprecated member:
`metric_connection_from_proto_with_issues` reads the raw proto value and keep
`0` as a plain `int`.

`MetricConnection.get_category()` will be added in a follow-up commit.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
This is the higher-level accessor for the `code_type` attribute: it
resolves the value to a known `EnergyMarketCodeType` member or raises a
clear, catchable error.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Reading the low-level `category` fields can yield the raw int `0` for
an unspecified value or an unknown `int` for a value this client
does not recognize. These convenience methods resolve the field to a
known enum member or raise a clear, catchable error.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Reading the low-level `metric` fields can yield the raw int `0` for an
unspecified value or an unknown `int` for a value this client does not
recognize. These convenience methods resolve the field to a known enum
member or raise a clear, catchable error.

Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
Signed-off-by: Leandro Lucarella <luca-frequenz@llucax.com>
@llucax llucax force-pushed the no-unspecified-phase-b branch from dbca974 to 3cdc627 Compare June 29, 2026 15:26
@llucax

llucax commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

Done.

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.

3 participants