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.
- flwr/client/grpc_rere_client/grpc_adapter.py +18 -0
- flwr/common/heartbeat.py +63 -1
- flwr/common/inflatable.py +35 -3
- flwr/common/record/array.py +10 -1
- flwr/common/record/arrayrecord.py +65 -1
- flwr/common/record/configrecord.py +10 -1
- flwr/common/record/metricrecord.py +10 -1
- flwr/common/record/recorddict.py +69 -1
- flwr/proto/fleet_pb2.py +2 -2
- flwr/proto/fleet_pb2_grpc.py +69 -0
- flwr/proto/fleet_pb2_grpc.pyi +27 -0
- flwr/proto/heartbeat_pb2.py +5 -1
- flwr/proto/heartbeat_pb2.pyi +26 -0
- flwr/proto/message_pb2.py +9 -1
- flwr/proto/message_pb2.pyi +44 -0
- flwr/proto/serverappio_pb2.py +24 -23
- flwr/proto/serverappio_pb2_grpc.py +104 -0
- flwr/proto/serverappio_pb2_grpc.pyi +41 -0
- flwr/proto/simulationio_pb2.py +12 -11
- flwr/proto/simulationio_pb2_grpc.py +35 -0
- flwr/proto/simulationio_pb2_grpc.pyi +14 -0
- flwr/server/serverapp/app.py +18 -0
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +8 -0
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +35 -0
- flwr/server/superlink/serverappio/serverappio_servicer.py +50 -0
- flwr/server/superlink/simulation/simulationio_servicer.py +23 -0
- flwr/simulation/app.py +17 -0
- {flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250514.dist-info}/METADATA +1 -1
- {flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250514.dist-info}/RECORD +31 -31
- {flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250514.dist-info}/WHEEL +0 -0
- {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(
|
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
|
-
|
96
|
-
|
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)
|
flwr/common/record/array.py
CHANGED
@@ -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(
|
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(
|
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(
|
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
|
|
flwr/common/record/recorddict.py
CHANGED
@@ -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\
|
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=
|
52
|
+
_globals['_FLEET']._serialized_end=1561
|
53
53
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/fleet_pb2_grpc.py
CHANGED
@@ -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)
|
flwr/proto/fleet_pb2_grpc.pyi
CHANGED
@@ -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: ...
|
flwr/proto/heartbeat_pb2.py
CHANGED
@@ -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)
|
flwr/proto/heartbeat_pb2.pyi
CHANGED
@@ -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
|