flwr-nightly 1.19.0.dev20250611__py3-none-any.whl → 1.19.0.dev20250613__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/cli/ls.py +12 -33
- flwr/cli/utils.py +18 -1
- flwr/client/grpc_rere_client/connection.py +47 -29
- flwr/client/grpc_rere_client/grpc_adapter.py +8 -0
- flwr/client/rest_client/connection.py +70 -51
- flwr/common/constant.py +4 -0
- flwr/common/inflatable.py +24 -0
- flwr/common/serde.py +2 -0
- flwr/common/typing.py +2 -0
- flwr/proto/fleet_pb2.py +12 -16
- flwr/proto/fleet_pb2.pyi +4 -19
- flwr/proto/fleet_pb2_grpc.py +34 -0
- flwr/proto/fleet_pb2_grpc.pyi +13 -0
- flwr/proto/message_pb2.py +15 -9
- flwr/proto/message_pb2.pyi +41 -0
- flwr/proto/run_pb2.py +24 -24
- flwr/proto/run_pb2.pyi +4 -1
- flwr/proto/serverappio_pb2.py +22 -26
- flwr/proto/serverappio_pb2.pyi +4 -19
- flwr/proto/serverappio_pb2_grpc.py +34 -0
- flwr/proto/serverappio_pb2_grpc.pyi +13 -0
- flwr/server/app.py +1 -0
- flwr/server/grid/grpc_grid.py +20 -9
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +25 -0
- flwr/server/superlink/fleet/message_handler/message_handler.py +33 -2
- flwr/server/superlink/fleet/rest_rere/rest_api.py +26 -2
- flwr/server/superlink/linkstate/in_memory_linkstate.py +20 -3
- flwr/server/superlink/linkstate/linkstate.py +6 -2
- flwr/server/superlink/linkstate/sqlite_linkstate.py +19 -7
- flwr/server/superlink/serverappio/serverappio_servicer.py +65 -29
- flwr/server/superlink/simulation/simulationio_servicer.py +2 -1
- flwr/server/superlink/utils.py +23 -10
- flwr/supercore/object_store/in_memory_object_store.py +160 -33
- flwr/supercore/object_store/object_store.py +54 -7
- flwr/superexec/deployment.py +6 -2
- flwr/superexec/exec_grpc.py +3 -0
- flwr/superexec/exec_servicer.py +125 -22
- flwr/superexec/executor.py +4 -0
- flwr/superexec/simulation.py +7 -1
- {flwr_nightly-1.19.0.dev20250611.dist-info → flwr_nightly-1.19.0.dev20250613.dist-info}/METADATA +1 -1
- {flwr_nightly-1.19.0.dev20250611.dist-info → flwr_nightly-1.19.0.dev20250613.dist-info}/RECORD +43 -43
- {flwr_nightly-1.19.0.dev20250611.dist-info → flwr_nightly-1.19.0.dev20250613.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.19.0.dev20250611.dist-info → flwr_nightly-1.19.0.dev20250613.dist-info}/entry_points.txt +0 -0
flwr/cli/ls.py
CHANGED
@@ -130,23 +130,16 @@ def ls( # pylint: disable=too-many-locals, too-many-branches, R0913, R0917
|
|
130
130
|
# Display information about a specific run ID
|
131
131
|
if run_id is not None:
|
132
132
|
typer.echo(f"🔍 Displaying information for run ID {run_id}...")
|
133
|
-
|
134
|
-
_display_one_run(stub, run_id, output_format)
|
133
|
+
formatted_runs = _display_one_run(stub, run_id)
|
135
134
|
# By default, list all runs
|
136
135
|
else:
|
137
136
|
typer.echo("📄 Listing all runs...")
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
typer.secho(
|
145
|
-
f"❌ {err}",
|
146
|
-
fg=typer.colors.RED,
|
147
|
-
bold=True,
|
148
|
-
)
|
149
|
-
raise typer.Exit(code=1) from err
|
137
|
+
formatted_runs = _list_runs(stub)
|
138
|
+
restore_output()
|
139
|
+
if output_format == CliOutputFormat.JSON:
|
140
|
+
Console().print_json(_to_json(formatted_runs))
|
141
|
+
else:
|
142
|
+
Console().print(_to_table(formatted_runs))
|
150
143
|
finally:
|
151
144
|
if channel:
|
152
145
|
channel.close()
|
@@ -300,37 +293,23 @@ def _to_json(run_list: list[_RunListType]) -> str:
|
|
300
293
|
return json.dumps({"success": True, "runs": runs_list})
|
301
294
|
|
302
295
|
|
303
|
-
def _list_runs(
|
304
|
-
stub: ExecStub,
|
305
|
-
output_format: str = CliOutputFormat.DEFAULT,
|
306
|
-
) -> None:
|
296
|
+
def _list_runs(stub: ExecStub) -> list[_RunListType]:
|
307
297
|
"""List all runs."""
|
308
298
|
with flwr_cli_grpc_exc_handler():
|
309
299
|
res: ListRunsResponse = stub.ListRuns(ListRunsRequest())
|
310
300
|
run_dict = {run_id: run_from_proto(proto) for run_id, proto in res.run_dict.items()}
|
311
301
|
|
312
|
-
|
313
|
-
if output_format == CliOutputFormat.JSON:
|
314
|
-
Console().print_json(_to_json(formatted_runs))
|
315
|
-
else:
|
316
|
-
Console().print(_to_table(formatted_runs))
|
302
|
+
return _format_runs(run_dict, res.now)
|
317
303
|
|
318
304
|
|
319
|
-
def _display_one_run(
|
320
|
-
stub: ExecStub,
|
321
|
-
run_id: int,
|
322
|
-
output_format: str = CliOutputFormat.DEFAULT,
|
323
|
-
) -> None:
|
305
|
+
def _display_one_run(stub: ExecStub, run_id: int) -> list[_RunListType]:
|
324
306
|
"""Display information about a specific run."""
|
325
307
|
with flwr_cli_grpc_exc_handler():
|
326
308
|
res: ListRunsResponse = stub.ListRuns(ListRunsRequest(run_id=run_id))
|
327
309
|
if not res.run_dict:
|
310
|
+
# This won't be reached as an gRPC error is raised if run_id is invalid
|
328
311
|
raise ValueError(f"Run ID {run_id} not found")
|
329
312
|
|
330
313
|
run_dict = {run_id: run_from_proto(proto) for run_id, proto in res.run_dict.items()}
|
331
314
|
|
332
|
-
|
333
|
-
if output_format == CliOutputFormat.JSON:
|
334
|
-
Console().print_json(_to_json(formatted_runs))
|
335
|
-
else:
|
336
|
-
Console().print(_to_table(formatted_runs))
|
315
|
+
return _format_runs(run_dict, res.now)
|
flwr/cli/utils.py
CHANGED
@@ -28,7 +28,12 @@ import typer
|
|
28
28
|
|
29
29
|
from flwr.cli.cli_user_auth_interceptor import CliUserAuthInterceptor
|
30
30
|
from flwr.common.auth_plugin import CliAuthPlugin
|
31
|
-
from flwr.common.constant import
|
31
|
+
from flwr.common.constant import (
|
32
|
+
AUTH_TYPE_JSON_KEY,
|
33
|
+
CREDENTIALS_DIR,
|
34
|
+
FLWR_DIR,
|
35
|
+
RUN_ID_NOT_FOUND_MESSAGE,
|
36
|
+
)
|
32
37
|
from flwr.common.grpc import (
|
33
38
|
GRPC_MAX_MESSAGE_LENGTH,
|
34
39
|
create_channel,
|
@@ -320,5 +325,17 @@ def flwr_cli_grpc_exc_handler() -> Iterator[None]:
|
|
320
325
|
fg=typer.colors.RED,
|
321
326
|
bold=True,
|
322
327
|
)
|
328
|
+
# pylint: disable=E1101
|
329
|
+
typer.secho(e.details(), fg=typer.colors.RED, bold=True)
|
330
|
+
raise typer.Exit(code=1) from None
|
331
|
+
if (
|
332
|
+
e.code() == grpc.StatusCode.NOT_FOUND
|
333
|
+
and e.details() == RUN_ID_NOT_FOUND_MESSAGE
|
334
|
+
):
|
335
|
+
typer.secho(
|
336
|
+
"❌ Run ID not found.",
|
337
|
+
fg=typer.colors.RED,
|
338
|
+
bold=True,
|
339
|
+
)
|
323
340
|
raise typer.Exit(code=1) from None
|
324
341
|
raise
|
@@ -31,7 +31,11 @@ from flwr.common import GRPC_MAX_MESSAGE_LENGTH
|
|
31
31
|
from flwr.common.constant import HEARTBEAT_CALL_TIMEOUT, HEARTBEAT_DEFAULT_INTERVAL
|
32
32
|
from flwr.common.grpc import create_channel, on_channel_state_change
|
33
33
|
from flwr.common.heartbeat import HeartbeatSender
|
34
|
-
from flwr.common.inflatable import
|
34
|
+
from flwr.common.inflatable import (
|
35
|
+
get_all_nested_objects,
|
36
|
+
get_object_tree,
|
37
|
+
no_object_id_recompute,
|
38
|
+
)
|
35
39
|
from flwr.common.inflatable_grpc_utils import (
|
36
40
|
make_pull_object_fn_grpc,
|
37
41
|
make_push_object_fn_grpc,
|
@@ -63,7 +67,9 @@ from flwr.proto.heartbeat_pb2 import ( # pylint: disable=E0611
|
|
63
67
|
SendNodeHeartbeatRequest,
|
64
68
|
SendNodeHeartbeatResponse,
|
65
69
|
)
|
66
|
-
from flwr.proto.message_pb2 import
|
70
|
+
from flwr.proto.message_pb2 import ( # pylint: disable=E0611
|
71
|
+
ConfirmMessageReceivedRequest,
|
72
|
+
)
|
67
73
|
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
68
74
|
from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
|
69
75
|
|
@@ -270,14 +276,23 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
270
276
|
|
271
277
|
if message_proto:
|
272
278
|
msg_id = message_proto.metadata.message_id
|
279
|
+
run_id = message_proto.metadata.run_id
|
273
280
|
all_object_contents = pull_objects(
|
274
281
|
list(response.objects_to_pull[msg_id].object_ids) + [msg_id],
|
275
282
|
pull_object_fn=make_pull_object_fn_grpc(
|
276
283
|
pull_object_grpc=stub.PullObject,
|
277
284
|
node=node,
|
278
|
-
run_id=
|
285
|
+
run_id=run_id,
|
279
286
|
),
|
280
287
|
)
|
288
|
+
|
289
|
+
# Confirm that the message has been received
|
290
|
+
stub.ConfirmMessageReceived(
|
291
|
+
ConfirmMessageReceivedRequest(
|
292
|
+
node=node, run_id=run_id, message_object_id=msg_id
|
293
|
+
)
|
294
|
+
)
|
295
|
+
|
281
296
|
in_message = cast(
|
282
297
|
Message, inflate_object_from_contents(msg_id, all_object_contents)
|
283
298
|
)
|
@@ -312,33 +327,36 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
312
327
|
log(ERROR, "Invalid out message")
|
313
328
|
return
|
314
329
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
response: PushMessagesResponse = stub.PushMessages(request=request)
|
329
|
-
|
330
|
-
if response.objects_to_push:
|
331
|
-
objs_to_push = set(response.objects_to_push[message.object_id].object_ids)
|
332
|
-
push_objects(
|
333
|
-
all_objects,
|
334
|
-
push_object_fn=make_push_object_fn_grpc(
|
335
|
-
push_object_grpc=stub.PushObject,
|
336
|
-
node=node,
|
337
|
-
run_id=message.metadata.run_id,
|
338
|
-
),
|
339
|
-
object_ids_to_push=objs_to_push,
|
330
|
+
with no_object_id_recompute():
|
331
|
+
# Get all nested objects
|
332
|
+
all_objects = get_all_nested_objects(message)
|
333
|
+
object_tree = get_object_tree(message)
|
334
|
+
|
335
|
+
# Serialize Message
|
336
|
+
message_proto = message_to_proto(
|
337
|
+
message=remove_content_from_message(message)
|
338
|
+
)
|
339
|
+
request = PushMessagesRequest(
|
340
|
+
node=node,
|
341
|
+
messages_list=[message_proto],
|
342
|
+
message_object_trees=[object_tree],
|
340
343
|
)
|
341
|
-
|
344
|
+
response: PushMessagesResponse = stub.PushMessages(request=request)
|
345
|
+
|
346
|
+
if response.objects_to_push:
|
347
|
+
objs_to_push = set(
|
348
|
+
response.objects_to_push[message.object_id].object_ids
|
349
|
+
)
|
350
|
+
push_objects(
|
351
|
+
all_objects,
|
352
|
+
push_object_fn=make_push_object_fn_grpc(
|
353
|
+
push_object_grpc=stub.PushObject,
|
354
|
+
node=node,
|
355
|
+
run_id=message.metadata.run_id,
|
356
|
+
),
|
357
|
+
object_ids_to_push=objs_to_push,
|
358
|
+
)
|
359
|
+
log(DEBUG, "Pushed %s objects to servicer.", len(objs_to_push))
|
342
360
|
|
343
361
|
# Cleanup
|
344
362
|
metadata = None
|
@@ -50,6 +50,8 @@ from flwr.proto.heartbeat_pb2 import ( # pylint: disable=E0611
|
|
50
50
|
SendNodeHeartbeatResponse,
|
51
51
|
)
|
52
52
|
from flwr.proto.message_pb2 import ( # pylint: disable=E0611
|
53
|
+
ConfirmMessageReceivedRequest,
|
54
|
+
ConfirmMessageReceivedResponse,
|
53
55
|
PullObjectRequest,
|
54
56
|
PullObjectResponse,
|
55
57
|
PushObjectRequest,
|
@@ -169,3 +171,9 @@ class GrpcAdapter:
|
|
169
171
|
) -> PullObjectResponse:
|
170
172
|
"""."""
|
171
173
|
return self._send_and_receive(request, PullObjectResponse, **kwargs)
|
174
|
+
|
175
|
+
def ConfirmMessageReceived( # pylint: disable=C0103
|
176
|
+
self, request: ConfirmMessageReceivedRequest, **kwargs: Any
|
177
|
+
) -> ConfirmMessageReceivedResponse:
|
178
|
+
"""."""
|
179
|
+
return self._send_and_receive(request, ConfirmMessageReceivedResponse, **kwargs)
|
@@ -30,7 +30,11 @@ from flwr.common import GRPC_MAX_MESSAGE_LENGTH
|
|
30
30
|
from flwr.common.constant import HEARTBEAT_DEFAULT_INTERVAL
|
31
31
|
from flwr.common.exit import ExitCode, flwr_exit
|
32
32
|
from flwr.common.heartbeat import HeartbeatSender
|
33
|
-
from flwr.common.inflatable import
|
33
|
+
from flwr.common.inflatable import (
|
34
|
+
get_all_nested_objects,
|
35
|
+
get_object_tree,
|
36
|
+
no_object_id_recompute,
|
37
|
+
)
|
34
38
|
from flwr.common.inflatable_rest_utils import (
|
35
39
|
make_pull_object_fn_rest,
|
36
40
|
make_push_object_fn_rest,
|
@@ -60,8 +64,9 @@ from flwr.proto.heartbeat_pb2 import ( # pylint: disable=E0611
|
|
60
64
|
SendNodeHeartbeatRequest,
|
61
65
|
SendNodeHeartbeatResponse,
|
62
66
|
)
|
63
|
-
from flwr.proto.message_pb2 import ObjectIDs # pylint: disable=E0611
|
64
67
|
from flwr.proto.message_pb2 import ( # pylint: disable=E0611
|
68
|
+
ConfirmMessageReceivedRequest,
|
69
|
+
ConfirmMessageReceivedResponse,
|
65
70
|
PullObjectRequest,
|
66
71
|
PullObjectResponse,
|
67
72
|
PushObjectRequest,
|
@@ -85,6 +90,7 @@ PATH_PUSH_OBJECT: str = "/api/v0/fleet/push-object"
|
|
85
90
|
PATH_SEND_NODE_HEARTBEAT: str = "api/v0/fleet/send-node-heartbeat"
|
86
91
|
PATH_GET_RUN: str = "/api/v0/fleet/get-run"
|
87
92
|
PATH_GET_FAB: str = "/api/v0/fleet/get-fab"
|
93
|
+
PATH_CONFIRM_MESSAGE_RECEIVED: str = "/api/v0/fleet/confirm-message-received"
|
88
94
|
|
89
95
|
T = TypeVar("T", bound=GrpcMessage)
|
90
96
|
|
@@ -320,6 +326,7 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
320
326
|
if message_proto:
|
321
327
|
log(INFO, "[Node] POST /%s: success", PATH_PULL_MESSAGES)
|
322
328
|
msg_id = message_proto.metadata.message_id
|
329
|
+
run_id = message_proto.metadata.run_id
|
323
330
|
|
324
331
|
def fn(request: PullObjectRequest) -> PullObjectResponse:
|
325
332
|
res = _request(
|
@@ -335,8 +342,17 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
335
342
|
pull_object_fn=make_pull_object_fn_rest(
|
336
343
|
pull_object_rest=fn,
|
337
344
|
node=node,
|
338
|
-
run_id=
|
345
|
+
run_id=run_id,
|
346
|
+
),
|
347
|
+
)
|
348
|
+
|
349
|
+
# Confirm that the message has been received
|
350
|
+
_request(
|
351
|
+
req=ConfirmMessageReceivedRequest(
|
352
|
+
node=node, run_id=run_id, message_object_id=msg_id
|
339
353
|
),
|
354
|
+
res_type=ConfirmMessageReceivedResponse,
|
355
|
+
api_path=PATH_CONFIRM_MESSAGE_RECEIVED,
|
340
356
|
)
|
341
357
|
except ValueError as e:
|
342
358
|
log(
|
@@ -377,59 +393,62 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
377
393
|
log(ERROR, "Invalid out message")
|
378
394
|
return
|
379
395
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
descendant_ids = all_object_ids[:-1] # All but the last object are descendants
|
385
|
-
|
386
|
-
# Serialize Message
|
387
|
-
message_proto = message_to_proto(message=remove_content_from_message(message))
|
388
|
-
req = PushMessagesRequest(
|
389
|
-
node=node,
|
390
|
-
messages_list=[message_proto],
|
391
|
-
msg_to_descendant_mapping={msg_id: ObjectIDs(object_ids=descendant_ids)},
|
392
|
-
)
|
396
|
+
with no_object_id_recompute():
|
397
|
+
# Get all nested objects
|
398
|
+
all_objects = get_all_nested_objects(message)
|
399
|
+
object_tree = get_object_tree(message)
|
393
400
|
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
401
|
+
# Serialize Message
|
402
|
+
message_proto = message_to_proto(
|
403
|
+
message=remove_content_from_message(message)
|
404
|
+
)
|
405
|
+
req = PushMessagesRequest(
|
406
|
+
node=node,
|
407
|
+
messages_list=[message_proto],
|
408
|
+
message_object_trees=[object_tree],
|
402
409
|
)
|
403
410
|
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
def fn(request: PushObjectRequest) -> PushObjectResponse:
|
408
|
-
res = _request(
|
409
|
-
req=request, res_type=PushObjectResponse, api_path=PATH_PUSH_OBJECT
|
410
|
-
)
|
411
|
-
if res is None:
|
412
|
-
raise ValueError("PushObjectResponse is None.")
|
413
|
-
return res
|
414
|
-
|
415
|
-
try:
|
416
|
-
push_objects(
|
417
|
-
all_objects,
|
418
|
-
push_object_fn=make_push_object_fn_rest(
|
419
|
-
push_object_rest=fn,
|
420
|
-
node=node,
|
421
|
-
run_id=message_proto.metadata.run_id,
|
422
|
-
),
|
423
|
-
object_ids_to_push=objs_to_push,
|
424
|
-
)
|
425
|
-
log(DEBUG, "Pushed %s objects to servicer.", len(objs_to_push))
|
426
|
-
except ValueError as e:
|
411
|
+
# Send the request
|
412
|
+
res = _request(req, PushMessagesResponse, PATH_PUSH_MESSAGES)
|
413
|
+
if res:
|
427
414
|
log(
|
428
|
-
|
429
|
-
"
|
430
|
-
|
415
|
+
INFO,
|
416
|
+
"[Node] POST /%s: success, created result %s",
|
417
|
+
PATH_PUSH_MESSAGES,
|
418
|
+
res.results, # pylint: disable=no-member
|
431
419
|
)
|
432
|
-
|
420
|
+
|
421
|
+
if res and res.objects_to_push:
|
422
|
+
objs_to_push = set(res.objects_to_push[message.object_id].object_ids)
|
423
|
+
|
424
|
+
def fn(request: PushObjectRequest) -> PushObjectResponse:
|
425
|
+
res = _request(
|
426
|
+
req=request,
|
427
|
+
res_type=PushObjectResponse,
|
428
|
+
api_path=PATH_PUSH_OBJECT,
|
429
|
+
)
|
430
|
+
if res is None:
|
431
|
+
raise ValueError("PushObjectResponse is None.")
|
432
|
+
return res
|
433
|
+
|
434
|
+
try:
|
435
|
+
push_objects(
|
436
|
+
all_objects,
|
437
|
+
push_object_fn=make_push_object_fn_rest(
|
438
|
+
push_object_rest=fn,
|
439
|
+
node=node,
|
440
|
+
run_id=message_proto.metadata.run_id,
|
441
|
+
),
|
442
|
+
object_ids_to_push=objs_to_push,
|
443
|
+
)
|
444
|
+
log(DEBUG, "Pushed %s objects to servicer.", len(objs_to_push))
|
445
|
+
except ValueError as e:
|
446
|
+
log(
|
447
|
+
ERROR,
|
448
|
+
"Pushing objects failed. Potential irrecoverable error: %s",
|
449
|
+
str(e),
|
450
|
+
)
|
451
|
+
log(ERROR, str(e))
|
433
452
|
|
434
453
|
# Cleanup
|
435
454
|
metadata = None
|
flwr/common/constant.py
CHANGED
@@ -150,6 +150,10 @@ PULL_INITIAL_BACKOFF = 1 # Initial backoff time for pulling objects
|
|
150
150
|
PULL_BACKOFF_CAP = 10 # Maximum backoff time for pulling objects
|
151
151
|
|
152
152
|
|
153
|
+
# ExecServicer constants
|
154
|
+
RUN_ID_NOT_FOUND_MESSAGE = "Run ID not found"
|
155
|
+
|
156
|
+
|
153
157
|
class MessageType:
|
154
158
|
"""Message type."""
|
155
159
|
|
flwr/common/inflatable.py
CHANGED
@@ -23,6 +23,8 @@ from collections.abc import Iterator
|
|
23
23
|
from contextlib import contextmanager
|
24
24
|
from typing import TypeVar, cast
|
25
25
|
|
26
|
+
from flwr.proto.message_pb2 import ObjectTree # pylint: disable=E0611
|
27
|
+
|
26
28
|
from .constant import HEAD_BODY_DIVIDER, HEAD_VALUE_DIVIDER
|
27
29
|
|
28
30
|
|
@@ -264,3 +266,25 @@ def get_all_nested_objects(obj: InflatableObject) -> dict[str, InflatableObject]
|
|
264
266
|
ret[obj.object_id] = obj
|
265
267
|
|
266
268
|
return ret
|
269
|
+
|
270
|
+
|
271
|
+
def get_object_tree(obj: InflatableObject) -> ObjectTree:
|
272
|
+
"""Get a tree representation of the InflatableObject."""
|
273
|
+
tree_children = []
|
274
|
+
if children := obj.children:
|
275
|
+
for child in children.values():
|
276
|
+
tree_children.append(get_object_tree(child))
|
277
|
+
return ObjectTree(object_id=obj.object_id, children=tree_children)
|
278
|
+
|
279
|
+
|
280
|
+
def iterate_object_tree(
|
281
|
+
tree: ObjectTree,
|
282
|
+
) -> Iterator[ObjectTree]:
|
283
|
+
"""Iterate over the object tree and yield object IDs.
|
284
|
+
|
285
|
+
This function performs a post-order traversal of the tree, yielding the object ID of
|
286
|
+
each node after all its children have been yielded.
|
287
|
+
"""
|
288
|
+
for child in tree.children:
|
289
|
+
yield from iterate_object_tree(child)
|
290
|
+
yield tree
|
flwr/common/serde.py
CHANGED
@@ -630,6 +630,7 @@ def run_to_proto(run: typing.Run) -> ProtoRun:
|
|
630
630
|
running_at=run.running_at,
|
631
631
|
finished_at=run.finished_at,
|
632
632
|
status=run_status_to_proto(run.status),
|
633
|
+
flwr_aid=run.flwr_aid,
|
633
634
|
)
|
634
635
|
return proto
|
635
636
|
|
@@ -647,6 +648,7 @@ def run_from_proto(run_proto: ProtoRun) -> typing.Run:
|
|
647
648
|
running_at=run_proto.running_at,
|
648
649
|
finished_at=run_proto.finished_at,
|
649
650
|
status=run_status_from_proto(run_proto.status),
|
651
|
+
flwr_aid=run_proto.flwr_aid,
|
650
652
|
)
|
651
653
|
return run
|
652
654
|
|
flwr/common/typing.py
CHANGED
@@ -230,6 +230,7 @@ class Run: # pylint: disable=too-many-instance-attributes
|
|
230
230
|
running_at: str
|
231
231
|
finished_at: str
|
232
232
|
status: RunStatus
|
233
|
+
flwr_aid: str
|
233
234
|
|
234
235
|
@classmethod
|
235
236
|
def create_empty(cls, run_id: int) -> "Run":
|
@@ -245,6 +246,7 @@ class Run: # pylint: disable=too-many-instance-attributes
|
|
245
246
|
running_at="",
|
246
247
|
finished_at="",
|
247
248
|
status=RunStatus(status="", sub_status="", details=""),
|
249
|
+
flwr_aid="",
|
248
250
|
)
|
249
251
|
|
250
252
|
|
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\"\x87\x02\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\x12L\n\x0fobjects_to_pull\x18\x03 \x03(\x0b\x32\x33.flwr.proto.PullMessagesResponse.ObjectsToPullEntry\x1aK\n\x12ObjectsToPullEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.flwr.proto.ObjectIDs:\x02\x38\x01\"\x97\
|
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\"\x87\x02\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\x12L\n\x0fobjects_to_pull\x18\x03 \x03(\x0b\x32\x33.flwr.proto.PullMessagesResponse.ObjectsToPullEntry\x1aK\n\x12ObjectsToPullEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.flwr.proto.ObjectIDs:\x02\x38\x01\"\x97\x01\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\x12\x34\n\x14message_object_trees\x18\x03 \x03(\x0b\x32\x16.flwr.proto.ObjectTree\"\xcb\x02\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\x12L\n\x0fobjects_to_push\x18\x03 \x03(\x0b\x32\x33.flwr.proto.PushMessagesResponse.ObjectsToPushEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\x1aK\n\x12ObjectsToPushEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.flwr.proto.ObjectIDs:\x02\x38\x01\"\x1e\n\tReconnect\x12\x11\n\treconnect\x18\x01 \x01(\x04\x32\xca\x06\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\x12q\n\x16\x43onfirmMessageReceived\x12).flwr.proto.ConfirmMessageReceivedRequest\x1a*.flwr.proto.ConfirmMessageReceivedResponse\"\x00\x62\x06proto3')
|
23
23
|
|
24
24
|
_globals = globals()
|
25
25
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
@@ -28,8 +28,6 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
28
28
|
DESCRIPTOR._options = None
|
29
29
|
_globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._options = None
|
30
30
|
_globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._serialized_options = b'8\001'
|
31
|
-
_globals['_PUSHMESSAGESREQUEST_MSGTODESCENDANTMAPPINGENTRY']._options = None
|
32
|
-
_globals['_PUSHMESSAGESREQUEST_MSGTODESCENDANTMAPPINGENTRY']._serialized_options = b'8\001'
|
33
31
|
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._options = None
|
34
32
|
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_options = b'8\001'
|
35
33
|
_globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._options = None
|
@@ -49,17 +47,15 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
49
47
|
_globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._serialized_start=602
|
50
48
|
_globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._serialized_end=677
|
51
49
|
_globals['_PUSHMESSAGESREQUEST']._serialized_start=680
|
52
|
-
_globals['_PUSHMESSAGESREQUEST']._serialized_end=
|
53
|
-
_globals['
|
54
|
-
_globals['
|
55
|
-
_globals['
|
56
|
-
_globals['
|
57
|
-
_globals['
|
58
|
-
_globals['
|
59
|
-
_globals['
|
60
|
-
_globals['
|
61
|
-
_globals['
|
62
|
-
_globals['
|
63
|
-
_globals['_FLEET']._serialized_start=1328
|
64
|
-
_globals['_FLEET']._serialized_end=2055
|
50
|
+
_globals['_PUSHMESSAGESREQUEST']._serialized_end=831
|
51
|
+
_globals['_PUSHMESSAGESRESPONSE']._serialized_start=834
|
52
|
+
_globals['_PUSHMESSAGESRESPONSE']._serialized_end=1165
|
53
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_start=1042
|
54
|
+
_globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_end=1088
|
55
|
+
_globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._serialized_start=1090
|
56
|
+
_globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._serialized_end=1165
|
57
|
+
_globals['_RECONNECT']._serialized_start=1167
|
58
|
+
_globals['_RECONNECT']._serialized_end=1197
|
59
|
+
_globals['_FLEET']._serialized_start=1200
|
60
|
+
_globals['_FLEET']._serialized_end=2042
|
65
61
|
# @@protoc_insertion_point(module_scope)
|
flwr/proto/fleet_pb2.pyi
CHANGED
@@ -115,38 +115,23 @@ global___PullMessagesResponse = PullMessagesResponse
|
|
115
115
|
class PushMessagesRequest(google.protobuf.message.Message):
|
116
116
|
"""PushMessages messages"""
|
117
117
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
118
|
-
class MsgToDescendantMappingEntry(google.protobuf.message.Message):
|
119
|
-
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
120
|
-
KEY_FIELD_NUMBER: builtins.int
|
121
|
-
VALUE_FIELD_NUMBER: builtins.int
|
122
|
-
key: typing.Text
|
123
|
-
@property
|
124
|
-
def value(self) -> flwr.proto.message_pb2.ObjectIDs: ...
|
125
|
-
def __init__(self,
|
126
|
-
*,
|
127
|
-
key: typing.Text = ...,
|
128
|
-
value: typing.Optional[flwr.proto.message_pb2.ObjectIDs] = ...,
|
129
|
-
) -> None: ...
|
130
|
-
def HasField(self, field_name: typing_extensions.Literal["value",b"value"]) -> builtins.bool: ...
|
131
|
-
def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
|
132
|
-
|
133
118
|
NODE_FIELD_NUMBER: builtins.int
|
134
119
|
MESSAGES_LIST_FIELD_NUMBER: builtins.int
|
135
|
-
|
120
|
+
MESSAGE_OBJECT_TREES_FIELD_NUMBER: builtins.int
|
136
121
|
@property
|
137
122
|
def node(self) -> flwr.proto.node_pb2.Node: ...
|
138
123
|
@property
|
139
124
|
def messages_list(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[flwr.proto.message_pb2.Message]: ...
|
140
125
|
@property
|
141
|
-
def
|
126
|
+
def message_object_trees(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[flwr.proto.message_pb2.ObjectTree]: ...
|
142
127
|
def __init__(self,
|
143
128
|
*,
|
144
129
|
node: typing.Optional[flwr.proto.node_pb2.Node] = ...,
|
145
130
|
messages_list: typing.Optional[typing.Iterable[flwr.proto.message_pb2.Message]] = ...,
|
146
|
-
|
131
|
+
message_object_trees: typing.Optional[typing.Iterable[flwr.proto.message_pb2.ObjectTree]] = ...,
|
147
132
|
) -> None: ...
|
148
133
|
def HasField(self, field_name: typing_extensions.Literal["node",b"node"]) -> builtins.bool: ...
|
149
|
-
def ClearField(self, field_name: typing_extensions.Literal["
|
134
|
+
def ClearField(self, field_name: typing_extensions.Literal["message_object_trees",b"message_object_trees","messages_list",b"messages_list","node",b"node"]) -> None: ...
|
150
135
|
global___PushMessagesRequest = PushMessagesRequest
|
151
136
|
|
152
137
|
class PushMessagesResponse(google.protobuf.message.Message):
|
flwr/proto/fleet_pb2_grpc.py
CHANGED
@@ -63,6 +63,11 @@ class FleetStub(object):
|
|
63
63
|
request_serializer=flwr_dot_proto_dot_message__pb2.PullObjectRequest.SerializeToString,
|
64
64
|
response_deserializer=flwr_dot_proto_dot_message__pb2.PullObjectResponse.FromString,
|
65
65
|
)
|
66
|
+
self.ConfirmMessageReceived = channel.unary_unary(
|
67
|
+
'/flwr.proto.Fleet/ConfirmMessageReceived',
|
68
|
+
request_serializer=flwr_dot_proto_dot_message__pb2.ConfirmMessageReceivedRequest.SerializeToString,
|
69
|
+
response_deserializer=flwr_dot_proto_dot_message__pb2.ConfirmMessageReceivedResponse.FromString,
|
70
|
+
)
|
66
71
|
|
67
72
|
|
68
73
|
class FleetServicer(object):
|
@@ -131,6 +136,13 @@ class FleetServicer(object):
|
|
131
136
|
context.set_details('Method not implemented!')
|
132
137
|
raise NotImplementedError('Method not implemented!')
|
133
138
|
|
139
|
+
def ConfirmMessageReceived(self, request, context):
|
140
|
+
"""Confirm Message Received
|
141
|
+
"""
|
142
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
143
|
+
context.set_details('Method not implemented!')
|
144
|
+
raise NotImplementedError('Method not implemented!')
|
145
|
+
|
134
146
|
|
135
147
|
def add_FleetServicer_to_server(servicer, server):
|
136
148
|
rpc_method_handlers = {
|
@@ -179,6 +191,11 @@ def add_FleetServicer_to_server(servicer, server):
|
|
179
191
|
request_deserializer=flwr_dot_proto_dot_message__pb2.PullObjectRequest.FromString,
|
180
192
|
response_serializer=flwr_dot_proto_dot_message__pb2.PullObjectResponse.SerializeToString,
|
181
193
|
),
|
194
|
+
'ConfirmMessageReceived': grpc.unary_unary_rpc_method_handler(
|
195
|
+
servicer.ConfirmMessageReceived,
|
196
|
+
request_deserializer=flwr_dot_proto_dot_message__pb2.ConfirmMessageReceivedRequest.FromString,
|
197
|
+
response_serializer=flwr_dot_proto_dot_message__pb2.ConfirmMessageReceivedResponse.SerializeToString,
|
198
|
+
),
|
182
199
|
}
|
183
200
|
generic_handler = grpc.method_handlers_generic_handler(
|
184
201
|
'flwr.proto.Fleet', rpc_method_handlers)
|
@@ -341,3 +358,20 @@ class Fleet(object):
|
|
341
358
|
flwr_dot_proto_dot_message__pb2.PullObjectResponse.FromString,
|
342
359
|
options, channel_credentials,
|
343
360
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
361
|
+
|
362
|
+
@staticmethod
|
363
|
+
def ConfirmMessageReceived(request,
|
364
|
+
target,
|
365
|
+
options=(),
|
366
|
+
channel_credentials=None,
|
367
|
+
call_credentials=None,
|
368
|
+
insecure=False,
|
369
|
+
compression=None,
|
370
|
+
wait_for_ready=None,
|
371
|
+
timeout=None,
|
372
|
+
metadata=None):
|
373
|
+
return grpc.experimental.unary_unary(request, target, '/flwr.proto.Fleet/ConfirmMessageReceived',
|
374
|
+
flwr_dot_proto_dot_message__pb2.ConfirmMessageReceivedRequest.SerializeToString,
|
375
|
+
flwr_dot_proto_dot_message__pb2.ConfirmMessageReceivedResponse.FromString,
|
376
|
+
options, channel_credentials,
|
377
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|