Skip to content

Commit bcdb8c1

Browse files
committed
Rename GrpcStatusError to GrpcError
Also improve the docs for the class slightly to be more clear about which errors should be more protocol-independent and safer to catch. Signed-off-by: Leandro Lucarella <[email protected]>
1 parent afc135c commit bcdb8c1

File tree

4 files changed

+39
-38
lines changed

4 files changed

+39
-38
lines changed

src/frequenz/client/microgrid/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
DataLoss,
3333
EntityAlreadyExists,
3434
EntityNotFound,
35-
GrpcStatusError,
35+
GrpcError,
3636
InternalError,
3737
InvalidArgument,
3838
OperationAborted,
@@ -69,7 +69,7 @@
6969
"EntityNotFound",
7070
"Fuse",
7171
"GridMetadata",
72-
"GrpcStatusError",
72+
"GrpcError",
7373
"InternalError",
7474
"InvalidArgument",
7575
"InverterData",

src/frequenz/client/microgrid/_client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ async def components(self) -> Iterable[Component]:
9292
Raises:
9393
ClientError: If the are any errors communicating with the Microgrid API,
9494
most likely a subclass of
95-
[GrpcStatusError][frequenz.client.microgrid.GrpcStatusError].
95+
[GrpcError][frequenz.client.microgrid.GrpcError].
9696
"""
9797
try:
9898
component_list = await self.api.list_components(
@@ -172,7 +172,7 @@ async def connections(
172172
Raises:
173173
ClientError: If the are any errors communicating with the Microgrid API,
174174
most likely a subclass of
175-
[GrpcStatusError][frequenz.client.microgrid.GrpcStatusError].
175+
[GrpcError][frequenz.client.microgrid.GrpcError].
176176
"""
177177
connection_filter = pb_microgrid.ConnectionFilter(
178178
starts=list(starts), ends=list(ends)
@@ -391,7 +391,7 @@ async def set_power(self, component_id: int, power_w: float) -> None:
391391
Raises:
392392
ClientError: If the are any errors communicating with the Microgrid API,
393393
most likely a subclass of
394-
[GrpcStatusError][frequenz.client.microgrid.GrpcStatusError].
394+
[GrpcError][frequenz.client.microgrid.GrpcError].
395395
"""
396396
try:
397397
await self.api.set_power_active(
@@ -425,7 +425,7 @@ async def set_bounds(
425425
greater than 0.
426426
ClientError: If the are any errors communicating with the Microgrid API,
427427
most likely a subclass of
428-
[GrpcStatusError][frequenz.client.microgrid.GrpcStatusError].
428+
[GrpcError][frequenz.client.microgrid.GrpcError].
429429
"""
430430
if upper < 0:
431431
raise ValueError(f"Upper bound {upper} must be greater than or equal to 0.")

src/frequenz/client/microgrid/_exception.py

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def from_grpc_error(
5858
server_url: str,
5959
operation: str,
6060
grpc_error: grpclib.GRPCError,
61-
) -> GrpcStatusError:
61+
) -> GrpcError:
6262
"""Create an instance of the appropriate subclass from a gRPC error.
6363
6464
Args:
@@ -68,16 +68,16 @@ def from_grpc_error(
6868
6969
Returns:
7070
An instance of
71-
[GrpcStatusError][frequenz.client.microgrid.GrpcStatusError] if
71+
[GrpcError][frequenz.client.microgrid.GrpcError] if
7272
the gRPC status is not recognized, or an appropriate subclass if it is.
7373
"""
7474

7575
class Ctor(Protocol):
76-
"""A protocol for the constructor of a subclass of `GrpcStatusError`."""
76+
"""A protocol for the constructor of a subclass of `GrpcError`."""
7777

7878
def __call__(
7979
self, *, server_url: str, operation: str, grpc_error: grpclib.GRPCError
80-
) -> GrpcStatusError: ...
80+
) -> GrpcError: ...
8181

8282
status_map: dict[grpclib.Status, Ctor] = {
8383
grpclib.Status.CANCELLED: OperationCancelled,
@@ -109,11 +109,12 @@ def __call__(
109109
)
110110

111111

112-
class GrpcStatusError(ClientError):
113-
"""The gRPC server returned an error status code.
112+
class GrpcError(ClientError):
113+
"""The gRPC server returned an error with a status code.
114114
115115
These errors are specific to gRPC. If you want to use the client in
116-
a protocol-independent way, you should avoid catching this exception.
116+
a protocol-independent way, you should avoid catching this exception. Catching
117+
subclasses that don't have *grpc* in their name should be protocol-independent.
117118
118119
References:
119120
* [gRPC status
@@ -152,7 +153,7 @@ def __init__( # pylint: disable=too-many-arguments
152153
"""The original gRPC error."""
153154

154155

155-
class UnrecognizedGrpcStatus(GrpcStatusError):
156+
class UnrecognizedGrpcStatus(GrpcError):
156157
"""The gRPC server returned an unrecognized status code."""
157158

158159
def __init__(
@@ -174,7 +175,7 @@ def __init__(
174175
)
175176

176177

177-
class OperationCancelled(GrpcStatusError):
178+
class OperationCancelled(GrpcError):
178179
"""The operation was cancelled."""
179180

180181
def __init__(
@@ -196,7 +197,7 @@ def __init__(
196197
)
197198

198199

199-
class UnknownError(GrpcStatusError):
200+
class UnknownError(GrpcError):
200201
"""There was an error that can't be described using other statuses."""
201202

202203
def __init__(
@@ -218,7 +219,7 @@ def __init__(
218219
)
219220

220221

221-
class InvalidArgument(GrpcStatusError, ValueError):
222+
class InvalidArgument(GrpcError, ValueError):
222223
"""The client specified an invalid argument.
223224
224225
Note that this error differs from
@@ -246,7 +247,7 @@ def __init__(
246247
)
247248

248249

249-
class OperationTimedOut(GrpcStatusError):
250+
class OperationTimedOut(GrpcError):
250251
"""The time limit was exceeded while waiting for the operationt o complete.
251252
252253
For operations that change the state of the system, this error may be returned even
@@ -274,7 +275,7 @@ def __init__(
274275
)
275276

276277

277-
class EntityNotFound(GrpcStatusError):
278+
class EntityNotFound(GrpcError):
278279
"""The requested entity was not found.
279280
280281
Note that this error differs from
@@ -301,7 +302,7 @@ def __init__(
301302
)
302303

303304

304-
class EntityAlreadyExists(GrpcStatusError):
305+
class EntityAlreadyExists(GrpcError):
305306
"""The entity that we attempted to create already exists."""
306307

307308
def __init__(
@@ -323,7 +324,7 @@ def __init__(
323324
)
324325

325326

326-
class PermissionDenied(GrpcStatusError):
327+
class PermissionDenied(GrpcError):
327328
"""The caller does not have permission to execute the specified operation.
328329
329330
Note that when the operation is rejected due to other reasons, such as the resources
@@ -354,7 +355,7 @@ def __init__(
354355
)
355356

356357

357-
class ResourceExhausted(GrpcStatusError):
358+
class ResourceExhausted(GrpcError):
358359
"""Some resource has been exhausted (for example per-user quota, disk space, etc.)."""
359360

360361
def __init__(
@@ -377,7 +378,7 @@ def __init__(
377378
)
378379

379380

380-
class OperationPreconditionFailed(GrpcStatusError):
381+
class OperationPreconditionFailed(GrpcError):
381382
"""The operation was rejected because the system is not in a required state.
382383
383384
For example, the directory to be deleted is non-empty, an rmdir operation is applied
@@ -405,7 +406,7 @@ def __init__(
405406
)
406407

407408

408-
class OperationAborted(GrpcStatusError):
409+
class OperationAborted(GrpcError):
409410
"""The operation was aborted.
410411
411412
Typically due to a concurrency issue or transaction abort.
@@ -430,7 +431,7 @@ def __init__(
430431
)
431432

432433

433-
class OperationOutOfRange(GrpcStatusError):
434+
class OperationOutOfRange(GrpcError):
434435
"""The operation was attempted past the valid range.
435436
436437
Unlike [InvalidArgument][frequenz.client.microgrid.InvalidArgument], this
@@ -461,7 +462,7 @@ def __init__(
461462
)
462463

463464

464-
class OperationNotImplemented(GrpcStatusError):
465+
class OperationNotImplemented(GrpcError):
465466
"""The operation is not implemented or not supported/enabled in this service."""
466467

467468
def __init__(
@@ -484,7 +485,7 @@ def __init__(
484485
)
485486

486487

487-
class InternalError(GrpcStatusError):
488+
class InternalError(GrpcError):
488489
"""Some invariants expected by the underlying system have been broken.
489490
490491
This error code is reserved for serious errors.
@@ -510,7 +511,7 @@ def __init__(
510511
)
511512

512513

513-
class ServiceUnavailable(GrpcStatusError):
514+
class ServiceUnavailable(GrpcError):
514515
"""The service is currently unavailable.
515516
516517
This is most likely a transient condition, which can be corrected by retrying with
@@ -536,7 +537,7 @@ def __init__(
536537
)
537538

538539

539-
class DataLoss(GrpcStatusError):
540+
class DataLoss(GrpcError):
540541
"""Unrecoverable data loss or corruption."""
541542

542543
def __init__(
@@ -558,7 +559,7 @@ def __init__(
558559
)
559560

560561

561-
class OperationUnauthenticated(GrpcStatusError):
562+
class OperationUnauthenticated(GrpcError):
562563
"""The request does not have valid authentication credentials for the operation."""
563564

564565
def __init__(

tests/test_exception.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
DataLoss,
1616
EntityAlreadyExists,
1717
EntityNotFound,
18-
GrpcStatusError,
18+
GrpcError,
1919
InternalError,
2020
InvalidArgument,
2121
OperationAborted,
@@ -33,15 +33,15 @@
3333
)
3434

3535

36-
class _GrpcStatusErrorCtor(Protocol):
37-
"""A protocol for the constructor of a subclass of `GrpcStatusError`."""
36+
class _GrpcErrorCtor(Protocol):
37+
"""A protocol for the constructor of a subclass of `GrpcErrorCtor`."""
3838

3939
def __call__(
4040
self, *, server_url: str, operation: str, grpc_error: grpclib.GRPCError
41-
) -> GrpcStatusError: ...
41+
) -> GrpcError: ...
4242

4343

44-
ERROR_TUPLES: list[tuple[type[GrpcStatusError], grpclib.Status, str, bool]] = [
44+
ERROR_TUPLES: list[tuple[type[GrpcError], grpclib.Status, str, bool]] = [
4545
(
4646
UnrecognizedGrpcStatus,
4747
mock.MagicMock(name="unknown_status"),
@@ -146,7 +146,7 @@ def __call__(
146146
"exception_class, grpc_status, expected_description, retryable", ERROR_TUPLES
147147
)
148148
def test_grpc_status_error(
149-
exception_class: _GrpcStatusErrorCtor,
149+
exception_class: _GrpcErrorCtor,
150150
grpc_status: grpclib.Status,
151151
expected_description: str,
152152
retryable: bool,
@@ -176,7 +176,7 @@ def test_grpc_unknown_status_error() -> None:
176176
"grpc error message",
177177
"grpc error details",
178178
)
179-
exception = GrpcStatusError(
179+
exception = GrpcError(
180180
server_url="http://testserver",
181181
operation="test_operation",
182182
description=expected_description,
@@ -210,7 +210,7 @@ def test_client_error() -> None:
210210
"exception_class, grpc_status, expected_description, retryable", ERROR_TUPLES
211211
)
212212
def test_from_grpc_error(
213-
exception_class: type[GrpcStatusError],
213+
exception_class: type[GrpcError],
214214
grpc_status: grpclib.Status,
215215
expected_description: str,
216216
retryable: bool,

0 commit comments

Comments
 (0)