Skip to content

Commit ad277d0

Browse files
authored
Rename *ValueError to *EnumValueError (#234)
Both custom exceptions raised by the semantic accessors are specifically about protobuf enum values: an UNSPECIFIED proto enum reaching a `get_*` accessor, or an integer the client does not recognize as a member of the wrapper enum. The current names suggest a generic value error and leave the enum-value origin implicit. Rename `UnspecifiedValueError` to `UnspecifiedEnumValueError` and `UnrecognizedValueError` to `UnrecognizedEnumValueError`, putting that origin in the type name. Part of #223.
2 parents 4d25245 + b857a39 commit ad277d0

17 files changed

Lines changed: 110 additions & 97 deletions

File tree

RELEASE_NOTES.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@
6363
* Added new exceptions:
6464
6565
* `frequenz.client.common.ClientCommonError` as a base exception for the package.
66-
* `frequenz.client.common.UnspecifiedValueError` for unspecified values (raw `0` or the deprecated member).
67-
* `frequenz.client.common.UnrecognizedValueError` for enum members not yet recognized by the library. Carries the raw integer value in its `value` attribute.
66+
* `frequenz.client.common.UnspecifiedEnumValueError` for unspecified enum values (raw `0` or the deprecated member).
67+
* `frequenz.client.common.UnrecognizedEnumValueError` for enum members not yet recognized by the library. Carries the raw integer value in its `value` attribute.
6868
6969
* Added safe convenience getters that raise the new exceptions for unspecified or unrecognized values:
7070

src/frequenz/client/common/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55

66
from ._exception import (
77
ClientCommonError,
8-
UnrecognizedValueError,
9-
UnspecifiedValueError,
8+
UnrecognizedEnumValueError,
9+
UnspecifiedEnumValueError,
1010
)
1111

1212
__all__ = [
1313
"ClientCommonError",
14-
"UnrecognizedValueError",
15-
"UnspecifiedValueError",
14+
"UnrecognizedEnumValueError",
15+
"UnspecifiedEnumValueError",
1616
]

src/frequenz/client/common/_exception.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ class ClientCommonError(Exception):
88
"""Base class for all errors raised by frequenz-client-common."""
99

1010

11-
class UnrecognizedValueError(ClientCommonError, ValueError):
12-
"""Raised when a semantic accessor sees an unrecognized protobuf value.
11+
class UnrecognizedEnumValueError(ClientCommonError, ValueError):
12+
"""Raised when a semantic accessor sees an unrecognized protobuf enum value.
1313
1414
This happens when the server sets an enum value that this version of the
1515
client does not recognize, as opposed to an unspecified value (see
16-
[`UnspecifiedValueError`][..UnspecifiedValueError]). The raw
16+
[`UnspecifiedEnumValueError`][..UnspecifiedEnumValueError]). The raw
1717
unrecognized value is available as `value`.
1818
1919
This is also a ``ValueError`` for convenience.
@@ -33,11 +33,11 @@ def __init__(self, value: int, message: str | None = None) -> None:
3333
)
3434

3535

36-
class UnspecifiedValueError(ClientCommonError, ValueError):
37-
"""Raised when a semantic accessor sees an unspecified protobuf value.
36+
class UnspecifiedEnumValueError(ClientCommonError, ValueError):
37+
"""Raised when a semantic accessor sees an unspecified protobuf enum value.
3838
3939
For a value that is set but not recognized by this client, see
40-
[`UnrecognizedValueError`][..UnrecognizedValueError].
40+
[`UnrecognizedEnumValueError`][..UnrecognizedEnumValueError].
4141
4242
This is also a [`ValueError`][] for convenience.
4343
"""

src/frequenz/client/common/grid/_delivery_area.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from frequenz.core.enum import Enum, deprecated_member, unique
1111

12-
from .._exception import UnrecognizedValueError, UnspecifiedValueError
12+
from .._exception import UnrecognizedEnumValueError, UnspecifiedEnumValueError
1313

1414

1515
@unique
@@ -109,21 +109,23 @@ def get_code_type(self) -> EnergyMarketCodeType:
109109
The code type, when it is a known `EnergyMarketCodeType` member.
110110
111111
Raises:
112-
UnspecifiedValueError: If the code type is unspecified.
113-
UnrecognizedValueError: If the code type is a value not recognized by
114-
this version of the client. The raw value is available on the
115-
exception's `value` attribute.
112+
UnspecifiedEnumValueError: If the code type is unspecified.
113+
UnrecognizedEnumValueError: If the code type is a value not
114+
recognized by this version of the client. The raw value is
115+
available on the exception's `value` attribute.
116116
"""
117117
# Suppressing the deprecation warning can be removed when UNSPECIFIED is removed
118118
with warnings.catch_warnings():
119119
warnings.filterwarnings("ignore", category=DeprecationWarning)
120120
match self.code_type:
121121
case 0 | EnergyMarketCodeType.UNSPECIFIED:
122-
raise UnspecifiedValueError(f"code type of {self} is unspecified")
122+
raise UnspecifiedEnumValueError(
123+
f"code type of {self} is unspecified"
124+
)
123125
case EnergyMarketCodeType() as code_type:
124126
return code_type
125127
case int() as code_type:
126-
raise UnrecognizedValueError(
128+
raise UnrecognizedEnumValueError(
127129
code_type,
128130
f"code type {code_type!r} of {self} is not a recognized "
129131
"EnergyMarketCodeType",

src/frequenz/client/common/metrics/_sample.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from frequenz.core.enum import Enum, deprecated_member, unique
1313

14-
from .._exception import UnrecognizedValueError, UnspecifiedValueError
14+
from .._exception import UnrecognizedEnumValueError, UnspecifiedEnumValueError
1515
from ._bounds import Bounds
1616
from ._metric import Metric
1717

@@ -147,21 +147,23 @@ def get_category(self) -> MetricConnectionCategory:
147147
The category when it is a known `MetricConnectionCategory` member.
148148
149149
Raises:
150-
UnspecifiedValueError: If the category is unspecified (the raw value
151-
`0` or a member whose value is `0`).
152-
UnrecognizedValueError: If the category is an `int` this client does
153-
not recognize. The raw value is available on the error's `value`
154-
attribute.
150+
UnspecifiedEnumValueError: If the category is unspecified (the raw
151+
value `0` or a member whose value is `0`).
152+
UnrecognizedEnumValueError: If the category is an `int` this
153+
client does not recognize. The raw value is available on the
154+
error's `value` attribute.
155155
"""
156156
with warnings.catch_warnings():
157157
warnings.filterwarnings("ignore", category=DeprecationWarning)
158158
match self.category:
159159
case 0 | MetricConnectionCategory.UNSPECIFIED:
160-
raise UnspecifiedValueError("connection category is unspecified")
160+
raise UnspecifiedEnumValueError(
161+
"connection category is unspecified"
162+
)
161163
case MetricConnectionCategory():
162164
return self.category
163165
case int():
164-
raise UnrecognizedValueError(
166+
raise UnrecognizedEnumValueError(
165167
self.category,
166168
f"connection category {self.category!r} is not a recognized "
167169
"MetricConnectionCategory",
@@ -293,21 +295,21 @@ def get_metric(self) -> Metric:
293295
The metric when it is a known `Metric` member.
294296
295297
Raises:
296-
UnspecifiedValueError: If the metric is unspecified (the raw value
297-
`0` or a member whose value is `0`).
298-
UnrecognizedValueError: If the metric is an `int` this client does
299-
not recognize. The raw value is available on the error's `value`
300-
attribute.
298+
UnspecifiedEnumValueError: If the metric is unspecified (the raw
299+
value `0` or a member whose value is `0`).
300+
UnrecognizedEnumValueError: If the metric is an `int` this client
301+
does not recognize. The raw value is available on the error's
302+
`value` attribute.
301303
"""
302304
with warnings.catch_warnings():
303305
warnings.filterwarnings("ignore", category=DeprecationWarning)
304306
match self.metric:
305307
case 0 | Metric.UNSPECIFIED:
306-
raise UnspecifiedValueError("sampled metric is unspecified")
308+
raise UnspecifiedEnumValueError("sampled metric is unspecified")
307309
case Metric():
308310
return self.metric
309311
case int():
310-
raise UnrecognizedValueError(
312+
raise UnrecognizedEnumValueError(
311313
self.metric,
312314
f"sampled metric {self.metric!r} is not a recognized Metric",
313315
)

src/frequenz/client/common/microgrid/_microgrid.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import datetime
77
from dataclasses import dataclass, field
88

9-
from .._exception import UnspecifiedValueError
9+
from .._exception import UnspecifiedEnumValueError
1010
from ..grid._delivery_area import DeliveryArea
1111
from ..types._location import Location
1212
from ._ids import EnterpriseId, MicrogridId
@@ -77,11 +77,11 @@ def is_active(self) -> bool:
7777
Whether the microgrid is active.
7878
7979
Raises:
80-
UnspecifiedValueError: If the status is unspecified, so whether the
81-
microgrid is active is unknown.
80+
UnspecifiedEnumValueError: If the status is unspecified, so whether
81+
the microgrid is active is unknown.
8282
"""
8383
if self._active is None:
84-
raise UnspecifiedValueError(
84+
raise UnspecifiedEnumValueError(
8585
f"status of microgrid {self} is unspecified; active state is unknown"
8686
)
8787
return self._active

src/frequenz/client/common/microgrid/electrical_components/_electrical_component.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from datetime import datetime, timezone
99
from typing import Any, Self
1010

11-
from ..._exception import UnspecifiedValueError
11+
from ..._exception import UnspecifiedEnumValueError
1212
from ...metrics import Bounds, Metric
1313
from ...types import Lifetime
1414
from .. import MicrogridId
@@ -109,11 +109,11 @@ def provides_telemetry(self) -> bool:
109109
Whether this electrical component provides telemetry data.
110110
111111
Raises:
112-
UnspecifiedValueError: If the operational mode is unspecified, so whether
113-
telemetry is provided is unknown.
112+
UnspecifiedEnumValueError: If the operational mode is unspecified,
113+
so whether telemetry is provided is unknown.
114114
"""
115115
if self._provides_telemetry is None:
116-
raise UnspecifiedValueError(
116+
raise UnspecifiedEnumValueError(
117117
f"operational mode of {self} is unspecified; "
118118
"telemetry availability is unknown"
119119
)
@@ -126,11 +126,11 @@ def accepts_control(self) -> bool:
126126
Whether this electrical component accepts control commands.
127127
128128
Raises:
129-
UnspecifiedValueError: If the operational mode is unspecified, so whether
130-
control commands are accepted is unknown.
129+
UnspecifiedEnumValueError: If the operational mode is unspecified,
130+
so whether control commands are accepted is unknown.
131131
"""
132132
if self._accepts_control is None:
133-
raise UnspecifiedValueError(
133+
raise UnspecifiedEnumValueError(
134134
f"operational mode of {self} is unspecified; "
135135
"control availability is unknown"
136136
)

src/frequenz/client/common/microgrid/electrical_components/proto/v1alpha8/_electrical_component.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
)
1414
from google.protobuf.json_format import MessageToDict
1515

16-
from ....._exception import UnrecognizedValueError
16+
from ....._exception import UnrecognizedEnumValueError
1717
from .....metrics import Bounds, Metric
1818
from .....metrics.proto.v1alpha8 import bounds_from_proto
1919
from .....proto import enum_from_proto
@@ -744,7 +744,7 @@ def electrical_component_class_from_proto(
744744
* `(<any other typeless category>, None)` → its concrete typeless class
745745
(`Breaker`, `Meter`, ... one per category).
746746
* `(<any known typeless category>, <non-None subtype>)` → raises
747-
`UnrecognizedValueError`.
747+
`UnrecognizedEnumValueError`.
748748
* `(<unknown category int>, <any subtype>)` → `UnrecognizedElectricalComponent`
749749
(subtype silently dropped).
750750
@@ -771,7 +771,7 @@ def electrical_component_class_from_proto(
771771
The corresponding electrical component class.
772772
773773
Raises:
774-
UnrecognizedValueError: If `subtype` is not `None` for a known
774+
UnrecognizedEnumValueError: If `subtype` is not `None` for a known
775775
typeless category — that combination has no representation in the
776776
protobuf wire format.
777777
"""
@@ -787,7 +787,7 @@ def electrical_component_class_from_proto(
787787
typeless_class = _TYPELESS_CLASS_BY_PROTO_CATEGORY.get(category)
788788
if typeless_class is not None:
789789
if subtype is not None:
790-
raise UnrecognizedValueError(int(subtype))
790+
raise UnrecognizedEnumValueError(int(subtype))
791791
return typeless_class
792792

793793
return UnrecognizedElectricalComponent

tests/grid/proto/v1alpha8/test_delivery_area.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import pytest
1010
from frequenz.api.common.v1alpha8.grid import delivery_area_pb2
1111

12-
from frequenz.client.common import UnspecifiedValueError
12+
from frequenz.client.common import UnspecifiedEnumValueError
1313
from frequenz.client.common.grid import EnergyMarketCodeType
1414
from frequenz.client.common.grid.proto.v1alpha8 import (
1515
delivery_area_from_proto,
@@ -122,7 +122,7 @@ def test_from_proto(
122122

123123

124124
def test_get_code_type_from_proto_unspecified_raises() -> None:
125-
"""A proto-loaded unspecified code type raises UnspecifiedValueError."""
125+
"""A proto-loaded unspecified code type raises UnspecifiedEnumValueError."""
126126
proto = delivery_area_pb2.DeliveryArea(
127127
code="TEST",
128128
code_type=(
@@ -133,5 +133,5 @@ def test_get_code_type_from_proto_unspecified_raises() -> None:
133133
warnings.simplefilter("error", DeprecationWarning)
134134
area = delivery_area_from_proto(proto)
135135
assert area.code_type == 0
136-
with pytest.raises(UnspecifiedValueError):
136+
with pytest.raises(UnspecifiedEnumValueError):
137137
area.get_code_type()

tests/grid/test_delivery_area.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88

99
import pytest
1010

11-
from frequenz.client.common import UnrecognizedValueError, UnspecifiedValueError
11+
from frequenz.client.common import (
12+
UnrecognizedEnumValueError,
13+
UnspecifiedEnumValueError,
14+
)
1215
from frequenz.client.common.grid import DeliveryArea, EnergyMarketCodeType
1316

1417

@@ -124,25 +127,25 @@ def test_get_code_type_returns_known_member(member: EnergyMarketCodeType) -> Non
124127

125128

126129
def test_get_code_type_raises_unspecified_for_int_zero() -> None:
127-
"""get_code_type() raises UnspecifiedValueError for a raw int 0 code type."""
130+
"""get_code_type() raises UnspecifiedEnumValueError for a raw int 0 code type."""
128131
area = DeliveryArea(code="TEST", code_type=0)
129-
with pytest.raises(UnspecifiedValueError):
132+
with pytest.raises(UnspecifiedEnumValueError):
130133
area.get_code_type()
131134

132135

133136
def test_get_code_type_raises_unspecified_for_value_zero_member() -> None:
134-
"""get_code_type() raises UnspecifiedValueError for the value-0 member."""
137+
"""get_code_type() raises UnspecifiedEnumValueError for the value-0 member."""
135138
with pytest.deprecated_call():
136139
area = DeliveryArea(code="TEST", code_type=EnergyMarketCodeType.UNSPECIFIED)
137140
with warnings.catch_warnings():
138141
warnings.simplefilter("error", DeprecationWarning)
139-
with pytest.raises(UnspecifiedValueError):
142+
with pytest.raises(UnspecifiedEnumValueError):
140143
area.get_code_type()
141144

142145

143146
def test_get_code_type_raises_unrecognized_for_unknown_int() -> None:
144-
"""get_code_type() raises UnrecognizedValueError carrying the raw value."""
147+
"""get_code_type() raises UnrecognizedEnumValueError carrying the raw value."""
145148
area = DeliveryArea(code="TEST", code_type=999)
146-
with pytest.raises(UnrecognizedValueError) as exc_info:
149+
with pytest.raises(UnrecognizedEnumValueError) as exc_info:
147150
area.get_code_type()
148151
assert exc_info.value.value == 999

0 commit comments

Comments
 (0)