flwr-nightly 1.19.0.dev20250512__py3-none-any.whl → 1.19.0.dev20250514__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. flwr/client/grpc_rere_client/grpc_adapter.py +18 -0
  2. flwr/common/heartbeat.py +63 -1
  3. flwr/common/inflatable.py +35 -3
  4. flwr/common/record/array.py +10 -1
  5. flwr/common/record/arrayrecord.py +65 -1
  6. flwr/common/record/configrecord.py +10 -1
  7. flwr/common/record/metricrecord.py +10 -1
  8. flwr/common/record/recorddict.py +69 -1
  9. flwr/proto/fleet_pb2.py +2 -2
  10. flwr/proto/fleet_pb2_grpc.py +69 -0
  11. flwr/proto/fleet_pb2_grpc.pyi +27 -0
  12. flwr/proto/heartbeat_pb2.py +5 -1
  13. flwr/proto/heartbeat_pb2.pyi +26 -0
  14. flwr/proto/message_pb2.py +9 -1
  15. flwr/proto/message_pb2.pyi +44 -0
  16. flwr/proto/serverappio_pb2.py +24 -23
  17. flwr/proto/serverappio_pb2_grpc.py +104 -0
  18. flwr/proto/serverappio_pb2_grpc.pyi +41 -0
  19. flwr/proto/simulationio_pb2.py +12 -11
  20. flwr/proto/simulationio_pb2_grpc.py +35 -0
  21. flwr/proto/simulationio_pb2_grpc.pyi +14 -0
  22. flwr/server/serverapp/app.py +18 -0
  23. flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +8 -0
  24. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +35 -0
  25. flwr/server/superlink/serverappio/serverappio_servicer.py +50 -0
  26. flwr/server/superlink/simulation/simulationio_servicer.py +23 -0
  27. flwr/simulation/app.py +17 -0
  28. {flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250514.dist-info}/METADATA +1 -1
  29. {flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250514.dist-info}/RECORD +31 -31
  30. {flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250514.dist-info}/WHEEL +0 -0
  31. {flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250514.dist-info}/entry_points.txt +0 -0
@@ -49,6 +49,12 @@ from flwr.proto.heartbeat_pb2 import ( # pylint: disable=E0611
49
49
  SendNodeHeartbeatRequest,
50
50
  SendNodeHeartbeatResponse,
51
51
  )
52
+ from flwr.proto.message_pb2 import ( # pylint: disable=E0611
53
+ PullObjectRequest,
54
+ PullObjectResponse,
55
+ PushObjectRequest,
56
+ PushObjectResponse,
57
+ )
52
58
  from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
53
59
 
54
60
  T = TypeVar("T", bound=GrpcMessage)
@@ -151,3 +157,15 @@ class GrpcAdapter:
151
157
  ) -> GetFabResponse:
152
158
  """."""
153
159
  return self._send_and_receive(request, GetFabResponse, **kwargs)
160
+
161
+ def PushObject( # pylint: disable=C0103
162
+ self, request: PushObjectRequest, **kwargs: Any
163
+ ) -> PushObjectResponse:
164
+ """."""
165
+ return self._send_and_receive(request, PushObjectResponse, **kwargs)
166
+
167
+ def PullObject( # pylint: disable=C0103
168
+ self, request: PullObjectRequest, **kwargs: Any
169
+ ) -> PullObjectResponse:
170
+ """."""
171
+ return self._send_and_receive(request, PullObjectResponse, **kwargs)
flwr/common/heartbeat.py CHANGED
@@ -17,8 +17,16 @@
17
17
 
18
18
  import random
19
19
  import threading
20
- from typing import Callable
20
+ from typing import Callable, Union
21
21
 
22
+ import grpc
23
+
24
+ # pylint: disable=E0611
25
+ from flwr.proto.heartbeat_pb2 import SendAppHeartbeatRequest
26
+ from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
27
+ from flwr.proto.simulationio_pb2_grpc import SimulationIoStub
28
+
29
+ # pylint: enable=E0611
22
30
  from .constant import (
23
31
  HEARTBEAT_BASE_MULTIPLIER,
24
32
  HEARTBEAT_CALL_TIMEOUT,
@@ -77,6 +85,11 @@ class HeartbeatSender:
77
85
  self._stop_event.set()
78
86
  self._thread.join()
79
87
 
88
+ @property
89
+ def is_running(self) -> bool:
90
+ """Return True if the heartbeat sender is running, False otherwise."""
91
+ return self._thread.is_alive() and not self._stop_event.is_set()
92
+
80
93
  def _run(self) -> None:
81
94
  """Periodically send heartbeats until stopped."""
82
95
  while not self._stop_event.is_set():
@@ -101,3 +114,52 @@ class HeartbeatSender:
101
114
  if not self._stop_event.is_set():
102
115
  if not self.heartbeat_fn():
103
116
  raise HeartbeatFailure
117
+
118
+
119
+ def get_grpc_app_heartbeat_fn(
120
+ stub: Union[ServerAppIoStub, SimulationIoStub],
121
+ run_id: int,
122
+ *,
123
+ failure_message: str,
124
+ ) -> Callable[[], bool]:
125
+ """Get the function to send a heartbeat to gRPC endpoint.
126
+
127
+ This function is for app heartbeats only. It is not used for node heartbeats.
128
+
129
+ Parameters
130
+ ----------
131
+ stub : Union[ServerAppIoStub, SimulationIoStub]
132
+ gRPC stub to send the heartbeat.
133
+ run_id : int
134
+ The run ID to use in the heartbeat request.
135
+ failure_message : str
136
+ Error message to raise if the heartbeat fails.
137
+
138
+ Returns
139
+ -------
140
+ Callable[[], bool]
141
+ Function that sends a heartbeat to the gRPC endpoint.
142
+ """
143
+ # Construct the heartbeat request
144
+ req = SendAppHeartbeatRequest(
145
+ run_id=run_id, heartbeat_interval=HEARTBEAT_DEFAULT_INTERVAL
146
+ )
147
+
148
+ def fn() -> bool:
149
+ # Call ServerAppIo API
150
+ try:
151
+ res = stub.SendAppHeartbeat(req)
152
+ except grpc.RpcError as e:
153
+ status_code = e.code()
154
+ if status_code == grpc.StatusCode.UNAVAILABLE:
155
+ return False
156
+ if status_code == grpc.StatusCode.DEADLINE_EXCEEDED:
157
+ return False
158
+ raise
159
+
160
+ # Check if not successful
161
+ if not res.success:
162
+ raise RuntimeError(failure_message)
163
+ return True
164
+
165
+ return fn
flwr/common/inflatable.py CHANGED
@@ -15,6 +15,8 @@
15
15
  """InflatableObject base class."""
16
16
 
17
17
 
18
+ from __future__ import annotations
19
+
18
20
  import hashlib
19
21
  from typing import TypeVar
20
22
 
@@ -31,7 +33,9 @@ class InflatableObject:
31
33
  raise NotImplementedError()
32
34
 
33
35
  @classmethod
34
- def inflate(cls, object_content: bytes) -> "InflatableObject":
36
+ def inflate(
37
+ cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
38
+ ) -> InflatableObject:
35
39
  """Inflate the object from bytes.
36
40
 
37
41
  Parameters
@@ -39,6 +43,10 @@ class InflatableObject:
39
43
  object_content : bytes
40
44
  The deflated object content.
41
45
 
46
+ children : Optional[dict[str, InflatableObject]] (default: None)
47
+ Dictionary of children InflatableObjects mapped to their object IDs. These
48
+ childrens enable the full inflation of the parent InflatableObject.
49
+
42
50
  Returns
43
51
  -------
44
52
  InflatableObject
@@ -51,6 +59,11 @@ class InflatableObject:
51
59
  """Get object_id."""
52
60
  return get_object_id(self.deflate())
53
61
 
62
+ @property
63
+ def children(self) -> dict[str, InflatableObject] | None:
64
+ """Get all child objects as a dictionary or None if there are no children."""
65
+ return None
66
+
54
67
 
55
68
  def get_object_id(object_content: bytes) -> str:
56
69
  """Return a SHA-256 hash of the (deflated) object content."""
@@ -92,5 +105,24 @@ def _get_object_body(object_content: bytes) -> bytes:
92
105
 
93
106
  def get_object_type_from_object_content(object_content: bytes) -> str:
94
107
  """Return object type from bytes."""
95
- obj_head: str = _get_object_head(object_content).decode(encoding="utf-8")
96
- return obj_head.split(TYPE_BODY_LEN_DIVIDER, 1)[0]
108
+ return get_object_head_values_from_object_content(object_content)[0]
109
+
110
+
111
+ def get_object_body_len_from_object_content(object_content: bytes) -> int:
112
+ """Return length of the object body."""
113
+ return get_object_head_values_from_object_content(object_content)[1]
114
+
115
+
116
+ def check_body_len_consistency(object_content: bytes) -> bool:
117
+ """Check that the object body is of length as specified in the head."""
118
+ body_len = get_object_body_len_from_object_content(object_content)
119
+ return body_len == len(_get_object_body(object_content))
120
+
121
+
122
+ def get_object_head_values_from_object_content(
123
+ object_content: bytes,
124
+ ) -> tuple[str, int]:
125
+ """Return object type and body length from object content."""
126
+ head = _get_object_head(object_content).decode(encoding="utf-8")
127
+ obj_type, body_len = head.split(TYPE_BODY_LEN_DIVIDER, 1)
128
+ return obj_type, int(body_len)
@@ -265,7 +265,9 @@ class Array(InflatableObject):
265
265
  return add_header_to_object_body(object_body=obj_body, cls=self)
266
266
 
267
267
  @classmethod
268
- def inflate(cls, object_content: bytes) -> Array:
268
+ def inflate(
269
+ cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
270
+ ) -> Array:
269
271
  """Inflate an Array from bytes.
270
272
 
271
273
  Parameters
@@ -273,11 +275,18 @@ class Array(InflatableObject):
273
275
  object_content : bytes
274
276
  The deflated object content of the Array.
275
277
 
278
+ children : Optional[dict[str, InflatableObject]] (default: None)
279
+ Must be ``None``. ``Array`` does not support child objects.
280
+ Providing any children will raise a ``ValueError``.
281
+
276
282
  Returns
277
283
  -------
278
284
  Array
279
285
  The inflated Array.
280
286
  """
287
+ if children is not None:
288
+ raise ValueError("`Array` objects do not have children.")
289
+
281
290
  obj_body = get_object_body(object_content, cls)
282
291
  proto_array = ArrayProto.FromString(obj_body)
283
292
  return cls(
@@ -18,6 +18,7 @@
18
18
  from __future__ import annotations
19
19
 
20
20
  import gc
21
+ import json
21
22
  import sys
22
23
  from collections import OrderedDict
23
24
  from logging import WARN
@@ -26,6 +27,7 @@ from typing import TYPE_CHECKING, Any, cast, overload
26
27
  import numpy as np
27
28
 
28
29
  from ..constant import GC_THRESHOLD
30
+ from ..inflatable import InflatableObject, add_header_to_object_body, get_object_body
29
31
  from ..logger import log
30
32
  from ..typing import NDArray
31
33
  from .array import Array
@@ -56,7 +58,7 @@ def _check_value(value: Array) -> None:
56
58
  )
57
59
 
58
60
 
59
- class ArrayRecord(TypedDict[str, Array]):
61
+ class ArrayRecord(TypedDict[str, Array], InflatableObject):
60
62
  """Array record.
61
63
 
62
64
  A typed dictionary (``str`` to :class:`Array`) that can store named arrays,
@@ -365,6 +367,68 @@ class ArrayRecord(TypedDict[str, Array]):
365
367
 
366
368
  return num_bytes
367
369
 
370
+ @property
371
+ def children(self) -> dict[str, InflatableObject]:
372
+ """Return a dictionary of Arrays with their Object IDs as keys."""
373
+ return {arr.object_id: arr for arr in self.values()}
374
+
375
+ def deflate(self) -> bytes:
376
+ """Deflate the ArrayRecord."""
377
+ # array_name: array_object_id mapping
378
+ array_refs: dict[str, str] = {}
379
+
380
+ for array_name, array in self.items():
381
+ array_refs[array_name] = array.object_id
382
+
383
+ # Serialize references dict
384
+ object_body = json.dumps(array_refs).encode("utf-8")
385
+ return add_header_to_object_body(object_body=object_body, cls=self)
386
+
387
+ @classmethod
388
+ def inflate(
389
+ cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
390
+ ) -> ArrayRecord:
391
+ """Inflate an ArrayRecord from bytes.
392
+
393
+ Parameters
394
+ ----------
395
+ object_content : bytes
396
+ The deflated object content of the ArrayRecord.
397
+ children : Optional[dict[str, InflatableObject]] (default: None)
398
+ Dictionary of children InflatableObjects mapped to their Object IDs.
399
+ These children enable the full inflation of the ArrayRecord.
400
+
401
+ Returns
402
+ -------
403
+ ArrayRecord
404
+ The inflated ArrayRecord.
405
+ """
406
+ if children is None:
407
+ children = {}
408
+
409
+ # Inflate mapping of array_names (keys in the ArrayRecord) to Arrays' object IDs
410
+ obj_body = get_object_body(object_content, cls)
411
+ array_refs: dict[str, str] = json.loads(obj_body.decode(encoding="utf-8"))
412
+
413
+ unique_arrays = set(array_refs.values())
414
+ children_obj_ids = set(children.keys())
415
+ if unique_arrays != children_obj_ids:
416
+ raise ValueError(
417
+ "Unexpected set of `children`. "
418
+ f"Expected {unique_arrays} but got {children_obj_ids}."
419
+ )
420
+
421
+ # Ensure children are of type Array
422
+ if not all(isinstance(arr, Array) for arr in children.values()):
423
+ raise ValueError("`Children` are expected to be of type `Array`.")
424
+
425
+ # Instantiate new ArrayRecord
426
+ return ArrayRecord(
427
+ OrderedDict(
428
+ {name: children[object_id] for name, object_id in array_refs.items()}
429
+ )
430
+ )
431
+
368
432
 
369
433
  class ParametersRecord(ArrayRecord):
370
434
  """Deprecated class ``ParametersRecord``, use ``ArrayRecord`` instead.
@@ -185,7 +185,9 @@ class ConfigRecord(TypedDict[str, ConfigRecordValues], InflatableObject):
185
185
  return add_header_to_object_body(object_body=obj_body, cls=self)
186
186
 
187
187
  @classmethod
188
- def inflate(cls, object_content: bytes) -> ConfigRecord:
188
+ def inflate(
189
+ cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
190
+ ) -> ConfigRecord:
189
191
  """Inflate a ConfigRecord from bytes.
190
192
 
191
193
  Parameters
@@ -193,11 +195,18 @@ class ConfigRecord(TypedDict[str, ConfigRecordValues], InflatableObject):
193
195
  object_content : bytes
194
196
  The deflated object content of the ConfigRecord.
195
197
 
198
+ children : Optional[dict[str, InflatableObject]] (default: None)
199
+ Must be ``None``. ``ConfigRecord`` does not support child objects.
200
+ Providing any children will raise a ``ValueError``.
201
+
196
202
  Returns
197
203
  -------
198
204
  ConfigRecord
199
205
  The inflated ConfigRecord.
200
206
  """
207
+ if children is not None:
208
+ raise ValueError("`ConfigRecord` objects do not have children.")
209
+
201
210
  obj_body = get_object_body(object_content, cls)
202
211
  config_record_proto = ProtoConfigRecord.FromString(obj_body)
203
212
 
@@ -160,7 +160,9 @@ class MetricRecord(TypedDict[str, MetricRecordValues], InflatableObject):
160
160
  return add_header_to_object_body(object_body=obj_body, cls=self)
161
161
 
162
162
  @classmethod
163
- def inflate(cls, object_content: bytes) -> MetricRecord:
163
+ def inflate(
164
+ cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
165
+ ) -> MetricRecord:
164
166
  """Inflate a MetricRecord from bytes.
165
167
 
166
168
  Parameters
@@ -168,11 +170,18 @@ class MetricRecord(TypedDict[str, MetricRecordValues], InflatableObject):
168
170
  object_content : bytes
169
171
  The deflated object content of the MetricRecord.
170
172
 
173
+ children : Optional[dict[str, InflatableObject]] (default: None)
174
+ Must be ``None``. ``MetricRecord`` does not support child objects.
175
+ Providing any children will raise a ``ValueError``.
176
+
171
177
  Returns
172
178
  -------
173
179
  MetricRecord
174
180
  The inflated MetricRecord.
175
181
  """
182
+ if children is not None:
183
+ raise ValueError("`MetricRecord` objects do not have children.")
184
+
176
185
  obj_body = get_object_body(object_content, cls)
177
186
  metric_record_proto = ProtoMetricRecord.FromString(obj_body)
178
187
 
@@ -17,10 +17,12 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
+ import json
20
21
  from logging import WARN
21
22
  from textwrap import indent
22
23
  from typing import TypeVar, Union, cast
23
24
 
25
+ from ..inflatable import InflatableObject, add_header_to_object_body, get_object_body
24
26
  from ..logger import log
25
27
  from .arrayrecord import ArrayRecord
26
28
  from .configrecord import ConfigRecord
@@ -97,7 +99,7 @@ class _SyncedDict(TypedDict[str, T]):
97
99
  )
98
100
 
99
101
 
100
- class RecordDict(TypedDict[str, RecordType]):
102
+ class RecordDict(TypedDict[str, RecordType], InflatableObject):
101
103
  """RecordDict stores groups of arrays, metrics and configs.
102
104
 
103
105
  A :class:`RecordDict` is the unified mechanism by which arrays,
@@ -286,6 +288,72 @@ class RecordDict(TypedDict[str, RecordType]):
286
288
  )
287
289
  return self.config_records
288
290
 
291
+ @property
292
+ def children(self) -> dict[str, InflatableObject]:
293
+ """Return a dictionary of records with their Object IDs as keys."""
294
+ return {record.object_id: record for record in self.values()}
295
+
296
+ def deflate(self) -> bytes:
297
+ """Deflate the RecordDict."""
298
+ # record_name: record_object_id mapping
299
+ record_refs: dict[str, str] = {}
300
+
301
+ for record_name, record in self.items():
302
+ record_refs[record_name] = record.object_id
303
+
304
+ # Serialize references dict
305
+ object_body = json.dumps(record_refs).encode("utf-8")
306
+ return add_header_to_object_body(object_body=object_body, cls=self)
307
+
308
+ @classmethod
309
+ def inflate(
310
+ cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
311
+ ) -> RecordDict:
312
+ """Inflate an RecordDict from bytes.
313
+
314
+ Parameters
315
+ ----------
316
+ object_content : bytes
317
+ The deflated object content of the RecordDict.
318
+ children : Optional[dict[str, InflatableObject]] (default: None)
319
+ Dictionary of children InflatableObjects mapped to their Object IDs.
320
+ These children enable the full inflation of the RecordDict. Default is None.
321
+
322
+ Returns
323
+ -------
324
+ RecordDict
325
+ The inflated RecordDict.
326
+ """
327
+ if children is None:
328
+ children = {}
329
+
330
+ # Inflate mapping of record_names (keys in the RecordDict) to Record' object IDs
331
+ obj_body = get_object_body(object_content, cls)
332
+ record_refs: dict[str, str] = json.loads(obj_body.decode(encoding="utf-8"))
333
+
334
+ unique_records = set(record_refs.values())
335
+ children_obj_ids = set(children.keys())
336
+ if unique_records != children_obj_ids:
337
+ raise ValueError(
338
+ "Unexpected set of `children`. "
339
+ f"Expected {unique_records} but got {children_obj_ids}."
340
+ )
341
+
342
+ # Ensure children are one of the *Record objects exepecte in a RecordDict
343
+ if not all(
344
+ isinstance(ch, (ArrayRecord, ConfigRecord, MetricRecord))
345
+ for ch in children.values()
346
+ ):
347
+ raise ValueError(
348
+ "`Children` are expected to be of type `ArrayRecord`, "
349
+ "`ConfigRecord` or `MetricRecord`."
350
+ )
351
+
352
+ # Instantiate new RecordDict
353
+ return RecordDict(
354
+ {name: children[object_id] for name, object_id in record_refs.items()} # type: ignore
355
+ )
356
+
289
357
 
290
358
  class RecordSet(RecordDict):
291
359
  """Deprecated class ``RecordSet``, use ``RecordDict`` instead.
flwr/proto/fleet_pb2.py CHANGED
@@ -19,7 +19,7 @@ from flwr.proto import fab_pb2 as flwr_dot_proto_dot_fab__pb2
19
19
  from flwr.proto import message_pb2 as flwr_dot_proto_dot_message__pb2
20
20
 
21
21
 
22
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x1a\x66lwr/proto/heartbeat.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x18\x66lwr/proto/message.proto\"/\n\x11\x43reateNodeRequest\x12\x1a\n\x12heartbeat_interval\x18\x01 \x01(\x01\"4\n\x12\x43reateNodeResponse\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"3\n\x11\x44\x65leteNodeRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"\x14\n\x12\x44\x65leteNodeResponse\"J\n\x13PullMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x13\n\x0bmessage_ids\x18\x02 \x03(\t\"l\n\x14PullMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\"a\n\x13PushMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\"\xb0\x01\n\x14PushMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12>\n\x07results\x18\x02 \x03(\x0b\x32-.flwr.proto.PushMessagesResponse.ResultsEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\"\x1e\n\tReconnect\x12\x11\n\treconnect\x18\x01 \x01(\x04\x32\xb9\x04\n\x05\x46leet\x12M\n\nCreateNode\x12\x1d.flwr.proto.CreateNodeRequest\x1a\x1e.flwr.proto.CreateNodeResponse\"\x00\x12M\n\nDeleteNode\x12\x1d.flwr.proto.DeleteNodeRequest\x1a\x1e.flwr.proto.DeleteNodeResponse\"\x00\x12\x62\n\x11SendNodeHeartbeat\x12$.flwr.proto.SendNodeHeartbeatRequest\x1a%.flwr.proto.SendNodeHeartbeatResponse\"\x00\x12S\n\x0cPullMessages\x12\x1f.flwr.proto.PullMessagesRequest\x1a .flwr.proto.PullMessagesResponse\"\x00\x12S\n\x0cPushMessages\x12\x1f.flwr.proto.PushMessagesRequest\x1a .flwr.proto.PushMessagesResponse\"\x00\x12\x41\n\x06GetRun\x12\x19.flwr.proto.GetRunRequest\x1a\x1a.flwr.proto.GetRunResponse\"\x00\x12\x41\n\x06GetFab\x12\x19.flwr.proto.GetFabRequest\x1a\x1a.flwr.proto.GetFabResponse\"\x00\x62\x06proto3')
22
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x1a\x66lwr/proto/heartbeat.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x18\x66lwr/proto/message.proto\"/\n\x11\x43reateNodeRequest\x12\x1a\n\x12heartbeat_interval\x18\x01 \x01(\x01\"4\n\x12\x43reateNodeResponse\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"3\n\x11\x44\x65leteNodeRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"\x14\n\x12\x44\x65leteNodeResponse\"J\n\x13PullMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x13\n\x0bmessage_ids\x18\x02 \x03(\t\"l\n\x14PullMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\"a\n\x13PushMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\"\xb0\x01\n\x14PushMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12>\n\x07results\x18\x02 \x03(\x0b\x32-.flwr.proto.PushMessagesResponse.ResultsEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\"\x1e\n\tReconnect\x12\x11\n\treconnect\x18\x01 \x01(\x04\x32\xd7\x05\n\x05\x46leet\x12M\n\nCreateNode\x12\x1d.flwr.proto.CreateNodeRequest\x1a\x1e.flwr.proto.CreateNodeResponse\"\x00\x12M\n\nDeleteNode\x12\x1d.flwr.proto.DeleteNodeRequest\x1a\x1e.flwr.proto.DeleteNodeResponse\"\x00\x12\x62\n\x11SendNodeHeartbeat\x12$.flwr.proto.SendNodeHeartbeatRequest\x1a%.flwr.proto.SendNodeHeartbeatResponse\"\x00\x12S\n\x0cPullMessages\x12\x1f.flwr.proto.PullMessagesRequest\x1a .flwr.proto.PullMessagesResponse\"\x00\x12S\n\x0cPushMessages\x12\x1f.flwr.proto.PushMessagesRequest\x1a .flwr.proto.PushMessagesResponse\"\x00\x12\x41\n\x06GetRun\x12\x19.flwr.proto.GetRunRequest\x1a\x1a.flwr.proto.GetRunResponse\"\x00\x12\x41\n\x06GetFab\x12\x19.flwr.proto.GetFabRequest\x1a\x1a.flwr.proto.GetFabResponse\"\x00\x12M\n\nPushObject\x12\x1d.flwr.proto.PushObjectRequest\x1a\x1e.flwr.proto.PushObjectResponse\"\x00\x12M\n\nPullObject\x12\x1d.flwr.proto.PullObjectRequest\x1a\x1e.flwr.proto.PullObjectResponse\"\x00\x62\x06proto3')
23
23
 
24
24
  _globals = globals()
25
25
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -49,5 +49,5 @@ if _descriptor._USE_C_DESCRIPTORS == False:
49
49
  _globals['_RECONNECT']._serialized_start=801
50
50
  _globals['_RECONNECT']._serialized_end=831
51
51
  _globals['_FLEET']._serialized_start=834
52
- _globals['_FLEET']._serialized_end=1403
52
+ _globals['_FLEET']._serialized_end=1561
53
53
  # @@protoc_insertion_point(module_scope)
@@ -5,6 +5,7 @@ import grpc
5
5
  from flwr.proto import fab_pb2 as flwr_dot_proto_dot_fab__pb2
6
6
  from flwr.proto import fleet_pb2 as flwr_dot_proto_dot_fleet__pb2
7
7
  from flwr.proto import heartbeat_pb2 as flwr_dot_proto_dot_heartbeat__pb2
8
+ from flwr.proto import message_pb2 as flwr_dot_proto_dot_message__pb2
8
9
  from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
9
10
 
10
11
 
@@ -52,6 +53,16 @@ class FleetStub(object):
52
53
  request_serializer=flwr_dot_proto_dot_fab__pb2.GetFabRequest.SerializeToString,
53
54
  response_deserializer=flwr_dot_proto_dot_fab__pb2.GetFabResponse.FromString,
54
55
  )
56
+ self.PushObject = channel.unary_unary(
57
+ '/flwr.proto.Fleet/PushObject',
58
+ request_serializer=flwr_dot_proto_dot_message__pb2.PushObjectRequest.SerializeToString,
59
+ response_deserializer=flwr_dot_proto_dot_message__pb2.PushObjectResponse.FromString,
60
+ )
61
+ self.PullObject = channel.unary_unary(
62
+ '/flwr.proto.Fleet/PullObject',
63
+ request_serializer=flwr_dot_proto_dot_message__pb2.PullObjectRequest.SerializeToString,
64
+ response_deserializer=flwr_dot_proto_dot_message__pb2.PullObjectResponse.FromString,
65
+ )
55
66
 
56
67
 
57
68
  class FleetServicer(object):
@@ -106,6 +117,20 @@ class FleetServicer(object):
106
117
  context.set_details('Method not implemented!')
107
118
  raise NotImplementedError('Method not implemented!')
108
119
 
120
+ def PushObject(self, request, context):
121
+ """Push Object
122
+ """
123
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
124
+ context.set_details('Method not implemented!')
125
+ raise NotImplementedError('Method not implemented!')
126
+
127
+ def PullObject(self, request, context):
128
+ """Pull Object
129
+ """
130
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
131
+ context.set_details('Method not implemented!')
132
+ raise NotImplementedError('Method not implemented!')
133
+
109
134
 
110
135
  def add_FleetServicer_to_server(servicer, server):
111
136
  rpc_method_handlers = {
@@ -144,6 +169,16 @@ def add_FleetServicer_to_server(servicer, server):
144
169
  request_deserializer=flwr_dot_proto_dot_fab__pb2.GetFabRequest.FromString,
145
170
  response_serializer=flwr_dot_proto_dot_fab__pb2.GetFabResponse.SerializeToString,
146
171
  ),
172
+ 'PushObject': grpc.unary_unary_rpc_method_handler(
173
+ servicer.PushObject,
174
+ request_deserializer=flwr_dot_proto_dot_message__pb2.PushObjectRequest.FromString,
175
+ response_serializer=flwr_dot_proto_dot_message__pb2.PushObjectResponse.SerializeToString,
176
+ ),
177
+ 'PullObject': grpc.unary_unary_rpc_method_handler(
178
+ servicer.PullObject,
179
+ request_deserializer=flwr_dot_proto_dot_message__pb2.PullObjectRequest.FromString,
180
+ response_serializer=flwr_dot_proto_dot_message__pb2.PullObjectResponse.SerializeToString,
181
+ ),
147
182
  }
148
183
  generic_handler = grpc.method_handlers_generic_handler(
149
184
  'flwr.proto.Fleet', rpc_method_handlers)
@@ -272,3 +307,37 @@ class Fleet(object):
272
307
  flwr_dot_proto_dot_fab__pb2.GetFabResponse.FromString,
273
308
  options, channel_credentials,
274
309
  insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
310
+
311
+ @staticmethod
312
+ def PushObject(request,
313
+ target,
314
+ options=(),
315
+ channel_credentials=None,
316
+ call_credentials=None,
317
+ insecure=False,
318
+ compression=None,
319
+ wait_for_ready=None,
320
+ timeout=None,
321
+ metadata=None):
322
+ return grpc.experimental.unary_unary(request, target, '/flwr.proto.Fleet/PushObject',
323
+ flwr_dot_proto_dot_message__pb2.PushObjectRequest.SerializeToString,
324
+ flwr_dot_proto_dot_message__pb2.PushObjectResponse.FromString,
325
+ options, channel_credentials,
326
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
327
+
328
+ @staticmethod
329
+ def PullObject(request,
330
+ target,
331
+ options=(),
332
+ channel_credentials=None,
333
+ call_credentials=None,
334
+ insecure=False,
335
+ compression=None,
336
+ wait_for_ready=None,
337
+ timeout=None,
338
+ metadata=None):
339
+ return grpc.experimental.unary_unary(request, target, '/flwr.proto.Fleet/PullObject',
340
+ flwr_dot_proto_dot_message__pb2.PullObjectRequest.SerializeToString,
341
+ flwr_dot_proto_dot_message__pb2.PullObjectResponse.FromString,
342
+ options, channel_credentials,
343
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@@ -6,6 +6,7 @@ import abc
6
6
  import flwr.proto.fab_pb2
7
7
  import flwr.proto.fleet_pb2
8
8
  import flwr.proto.heartbeat_pb2
9
+ import flwr.proto.message_pb2
9
10
  import flwr.proto.run_pb2
10
11
  import grpc
11
12
 
@@ -48,6 +49,16 @@ class FleetStub:
48
49
  flwr.proto.fab_pb2.GetFabResponse]
49
50
  """Get FAB"""
50
51
 
52
+ PushObject: grpc.UnaryUnaryMultiCallable[
53
+ flwr.proto.message_pb2.PushObjectRequest,
54
+ flwr.proto.message_pb2.PushObjectResponse]
55
+ """Push Object"""
56
+
57
+ PullObject: grpc.UnaryUnaryMultiCallable[
58
+ flwr.proto.message_pb2.PullObjectRequest,
59
+ flwr.proto.message_pb2.PullObjectResponse]
60
+ """Pull Object"""
61
+
51
62
 
52
63
  class FleetServicer(metaclass=abc.ABCMeta):
53
64
  @abc.abstractmethod
@@ -104,5 +115,21 @@ class FleetServicer(metaclass=abc.ABCMeta):
104
115
  """Get FAB"""
105
116
  pass
106
117
 
118
+ @abc.abstractmethod
119
+ def PushObject(self,
120
+ request: flwr.proto.message_pb2.PushObjectRequest,
121
+ context: grpc.ServicerContext,
122
+ ) -> flwr.proto.message_pb2.PushObjectResponse:
123
+ """Push Object"""
124
+ pass
125
+
126
+ @abc.abstractmethod
127
+ def PullObject(self,
128
+ request: flwr.proto.message_pb2.PullObjectRequest,
129
+ context: grpc.ServicerContext,
130
+ ) -> flwr.proto.message_pb2.PullObjectResponse:
131
+ """Pull Object"""
132
+ pass
133
+
107
134
 
108
135
  def add_FleetServicer_to_server(servicer: FleetServicer, server: grpc.Server) -> None: ...
@@ -15,7 +15,7 @@ _sym_db = _symbol_database.Default()
15
15
  from flwr.proto import node_pb2 as flwr_dot_proto_dot_node__pb2
16
16
 
17
17
 
18
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1a\x66lwr/proto/heartbeat.proto\x12\nflwr.proto\x1a\x15\x66lwr/proto/node.proto\"V\n\x18SendNodeHeartbeatRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x1a\n\x12heartbeat_interval\x18\x02 \x01(\x01\",\n\x19SendNodeHeartbeatResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x62\x06proto3')
18
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1a\x66lwr/proto/heartbeat.proto\x12\nflwr.proto\x1a\x15\x66lwr/proto/node.proto\"V\n\x18SendNodeHeartbeatRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x1a\n\x12heartbeat_interval\x18\x02 \x01(\x01\",\n\x19SendNodeHeartbeatResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"E\n\x17SendAppHeartbeatRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x1a\n\x12heartbeat_interval\x18\x02 \x01(\x01\"+\n\x18SendAppHeartbeatResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x62\x06proto3')
19
19
 
20
20
  _globals = globals()
21
21
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -26,4 +26,8 @@ if _descriptor._USE_C_DESCRIPTORS == False:
26
26
  _globals['_SENDNODEHEARTBEATREQUEST']._serialized_end=151
27
27
  _globals['_SENDNODEHEARTBEATRESPONSE']._serialized_start=153
28
28
  _globals['_SENDNODEHEARTBEATRESPONSE']._serialized_end=197
29
+ _globals['_SENDAPPHEARTBEATREQUEST']._serialized_start=199
30
+ _globals['_SENDAPPHEARTBEATREQUEST']._serialized_end=268
31
+ _globals['_SENDAPPHEARTBEATRESPONSE']._serialized_start=270
32
+ _globals['_SENDAPPHEARTBEATRESPONSE']._serialized_end=313
29
33
  # @@protoc_insertion_point(module_scope)
@@ -38,3 +38,29 @@ class SendNodeHeartbeatResponse(google.protobuf.message.Message):
38
38
  ) -> None: ...
39
39
  def ClearField(self, field_name: typing_extensions.Literal["success",b"success"]) -> None: ...
40
40
  global___SendNodeHeartbeatResponse = SendNodeHeartbeatResponse
41
+
42
+ class SendAppHeartbeatRequest(google.protobuf.message.Message):
43
+ """App Heartbeat messages"""
44
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
45
+ RUN_ID_FIELD_NUMBER: builtins.int
46
+ HEARTBEAT_INTERVAL_FIELD_NUMBER: builtins.int
47
+ run_id: builtins.int
48
+ heartbeat_interval: builtins.float
49
+ def __init__(self,
50
+ *,
51
+ run_id: builtins.int = ...,
52
+ heartbeat_interval: builtins.float = ...,
53
+ ) -> None: ...
54
+ def ClearField(self, field_name: typing_extensions.Literal["heartbeat_interval",b"heartbeat_interval","run_id",b"run_id"]) -> None: ...
55
+ global___SendAppHeartbeatRequest = SendAppHeartbeatRequest
56
+
57
+ class SendAppHeartbeatResponse(google.protobuf.message.Message):
58
+ DESCRIPTOR: google.protobuf.descriptor.Descriptor
59
+ SUCCESS_FIELD_NUMBER: builtins.int
60
+ success: builtins.bool
61
+ def __init__(self,
62
+ *,
63
+ success: builtins.bool = ...,
64
+ ) -> None: ...
65
+ def ClearField(self, field_name: typing_extensions.Literal["success",b"success"]) -> None: ...
66
+ global___SendAppHeartbeatResponse = SendAppHeartbeatResponse