1818from frequenz .client .common .microgrid .electrical_components import ElectricalComponentId
1919
2020from ._microgrid import Microgrid
21- from ._microgrid_proto import microgrid_from_proto
21+ from ._microgrid_proto import microgrid_from_proto , microgrid_from_proto_with_issues
2222from .electrical_component ._connection import ComponentConnection
23- from .electrical_component ._connection_proto import component_connection_from_proto
23+ from .electrical_component ._connection_proto import (
24+ component_connection_from_proto ,
25+ component_connection_from_proto_with_issues ,
26+ )
2427from .electrical_component ._electrical_component import ElectricalComponent
25- from .electrical_component ._electrical_component_proto import electrical_component_proto
26- from .exceptions import ClientNotConnected
28+ from .electrical_component ._electrical_component_proto import (
29+ electrical_component_from_proto_with_issues ,
30+ electrical_component_proto ,
31+ )
32+ from .exceptions import (
33+ ClientNotConnected ,
34+ InvalidConnectionError ,
35+ InvalidElectricalComponentError ,
36+ InvalidMicrogridError ,
37+ )
2738
2839DEFAULT_GRPC_CALL_TIMEOUT = 60.0
2940"""The default timeout for gRPC calls made by this client (in seconds)."""
@@ -88,21 +99,30 @@ def stub(self) -> assets_pb2_grpc.PlatformAssetsAsyncStub:
8899 # use the async stub, so we cast the sync stub to the async stub.
89100 return self ._stub # type: ignore
90101
91- async def get_microgrid ( # noqa: DOC502 (raises ApiClientError indirectly)
92- self , microgrid_id : MicrogridId
102+ async def get_microgrid ( # noqa: DOC502,DOC503 (raises indirectly)
103+ self ,
104+ microgrid_id : MicrogridId ,
105+ * ,
106+ raise_on_errors : bool = False ,
93107 ) -> Microgrid :
94108 """
95109 Get the details of a microgrid.
96110
97111 Args:
98112 microgrid_id: The ID of the microgrid to get the details of.
113+ raise_on_errors: If True, raise an
114+ [InvalidMicrogridError][frequenz.client.assets.exceptions.InvalidMicrogridError]
115+ when major validation issues are found instead of just
116+ logging them.
99117
100118 Returns:
101119 The details of the microgrid.
102120
103121 Raises:
104122 ApiClientError: If there are any errors communicating with the Assets API,
105123 most likely a subclass of [GrpcError][frequenz.client.base.exception.GrpcError].
124+ InvalidMicrogridError: If `raise_on_errors` is True and major
125+ validation issues are found.
106126 """
107127 response = await call_stub_method (
108128 self ,
@@ -113,19 +133,48 @@ async def get_microgrid( # noqa: DOC502 (raises ApiClientError indirectly)
113133 method_name = "GetMicrogrid" ,
114134 )
115135
136+ if raise_on_errors :
137+ major_issues : list [str ] = []
138+ minor_issues : list [str ] = []
139+ microgrid = microgrid_from_proto_with_issues (
140+ response .microgrid ,
141+ major_issues = major_issues ,
142+ minor_issues = minor_issues ,
143+ )
144+ if major_issues :
145+ raise InvalidMicrogridError (
146+ microgrid = microgrid ,
147+ major_issues = major_issues ,
148+ minor_issues = minor_issues ,
149+ raw_message = response .microgrid ,
150+ )
151+ return microgrid
152+
116153 return microgrid_from_proto (response .microgrid )
117154
118155 async def list_microgrid_electrical_components (
119- self , microgrid_id : MicrogridId
156+ self ,
157+ microgrid_id : MicrogridId ,
158+ * ,
159+ raise_on_errors : bool = False ,
120160 ) -> list [ElectricalComponent ]:
121161 """
122162 Get the electrical components of a microgrid.
123163
124164 Args:
125165 microgrid_id: The ID of the microgrid to get the electrical components of.
166+ raise_on_errors: If True, raise an
167+ `ExceptionGroup[InvalidElectricalComponentError]`
168+ when major validation issues are found in any component instead
169+ of just logging them.
126170
127171 Returns:
128172 The electrical components of the microgrid.
173+
174+ Raises:
175+ ExceptionGroup: If `raise_on_errors` is True and major validation
176+ issues are found. All exceptions in the group are
177+ [InvalidElectricalComponentError][frequenz.client.assets.exceptions.InvalidElectricalComponentError].
129178 """
130179 response = await call_stub_method (
131180 self ,
@@ -138,6 +187,35 @@ async def list_microgrid_electrical_components(
138187 method_name = "ListMicrogridElectricalComponents" ,
139188 )
140189
190+ if raise_on_errors :
191+ components : list [ElectricalComponent ] = []
192+ exceptions : list [InvalidElectricalComponentError ] = []
193+ for component_pb in response .components :
194+ major_issues : list [str ] = []
195+ minor_issues : list [str ] = []
196+ component = electrical_component_from_proto_with_issues (
197+ component_pb ,
198+ major_issues = major_issues ,
199+ minor_issues = minor_issues ,
200+ )
201+ if major_issues :
202+ exceptions .append (
203+ InvalidElectricalComponentError (
204+ component = component ,
205+ major_issues = major_issues ,
206+ minor_issues = minor_issues ,
207+ raw_message = component_pb ,
208+ )
209+ )
210+ else :
211+ components .append (component )
212+ if exceptions :
213+ raise ExceptionGroup (
214+ f"{ len (exceptions )} electrical component(s) failed validation" ,
215+ exceptions ,
216+ )
217+ return components
218+
141219 return [
142220 electrical_component_proto (component ) for component in response .components
143221 ]
@@ -147,7 +225,9 @@ async def list_microgrid_electrical_component_connections(
147225 microgrid_id : MicrogridId ,
148226 source_component_ids : Iterable [ElectricalComponentId ] = (),
149227 destination_component_ids : Iterable [ElectricalComponentId ] = (),
150- ) -> list [ComponentConnection | None ]:
228+ * ,
229+ raise_on_errors : bool = False ,
230+ ) -> list [ComponentConnection ]:
151231 """
152232 Get the electrical component connections of a microgrid.
153233
@@ -158,9 +238,18 @@ async def list_microgrid_electrical_component_connections(
158238 these component IDs. If None or empty, no filtering is applied.
159239 destination_component_ids: Only return connections that terminate at
160240 these component IDs. If None or empty, no filtering is applied.
241+ raise_on_errors: If True, raise an
242+ `ExceptionGroup[InvalidConnectionError]`
243+ when major validation issues are found in any connection instead
244+ of just logging them.
161245
162246 Returns:
163247 The electrical component connections of the microgrid.
248+
249+ Raises:
250+ ExceptionGroup: If `raise_on_errors` is True and major validation
251+ issues are found. All exceptions in the group are
252+ [InvalidConnectionError][frequenz.client.assets.exceptions.InvalidConnectionError].
164253 """
165254 request = assets_pb2 .ListMicrogridElectricalComponentConnectionsRequest (
166255 microgrid_id = int (microgrid_id ),
@@ -177,9 +266,34 @@ async def list_microgrid_electrical_component_connections(
177266 method_name = "ListMicrogridElectricalComponentConnections" ,
178267 )
179268
180- return list (
181- map (
182- component_connection_from_proto ,
183- filter (bool , response .connections ),
184- )
185- )
269+ if raise_on_errors :
270+ valid_connections : list [ComponentConnection ] = []
271+ exceptions : list [InvalidConnectionError ] = []
272+ for conn_pb in filter (bool , response .connections ):
273+ major_issues : list [str ] = []
274+ connection = component_connection_from_proto_with_issues (
275+ conn_pb , major_issues = major_issues
276+ )
277+ if major_issues :
278+ exceptions .append (
279+ InvalidConnectionError (
280+ connection = connection ,
281+ major_issues = major_issues ,
282+ minor_issues = [],
283+ raw_message = conn_pb ,
284+ )
285+ )
286+ elif connection is not None :
287+ valid_connections .append (connection )
288+ if exceptions :
289+ raise ExceptionGroup (
290+ f"{ len (exceptions )} connection(s) failed validation" ,
291+ exceptions ,
292+ )
293+ return valid_connections
294+
295+ return [
296+ c
297+ for c in map (component_connection_from_proto , response .connections )
298+ if c is not None
299+ ]
0 commit comments