flwr-nightly 1.19.0.dev20250527__py3-none-any.whl → 1.19.0.dev20250528__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/log.py +3 -3
- flwr/cli/login/login.py +3 -7
- flwr/cli/ls.py +3 -3
- flwr/cli/run/run.py +2 -6
- flwr/cli/stop.py +2 -2
- flwr/cli/utils.py +5 -4
- flwr/client/grpc_rere_client/connection.py +2 -0
- flwr/client/message_handler/message_handler.py +1 -1
- flwr/common/inflatable.py +33 -2
- flwr/common/record/array.py +38 -1
- flwr/common/record/arrayrecord.py +34 -0
- flwr/common/serde.py +6 -1
- flwr/server/grid/grpc_grid.py +2 -1
- flwr/server/grid/inmemory_grid.py +5 -4
- flwr/server/superlink/fleet/message_handler/message_handler.py +1 -2
- flwr/server/superlink/fleet/vce/vce_api.py +3 -0
- flwr/server/superlink/linkstate/in_memory_linkstate.py +14 -25
- flwr/server/superlink/linkstate/linkstate.py +9 -10
- flwr/server/superlink/linkstate/sqlite_linkstate.py +11 -21
- flwr/server/superlink/linkstate/utils.py +23 -23
- flwr/server/superlink/serverappio/serverappio_servicer.py +6 -10
- flwr/server/utils/validator.py +2 -2
- flwr/supercore/object_store/in_memory_object_store.py +30 -4
- flwr/supercore/object_store/object_store.py +48 -1
- flwr/superexec/exec_servicer.py +1 -2
- {flwr_nightly-1.19.0.dev20250527.dist-info → flwr_nightly-1.19.0.dev20250528.dist-info}/METADATA +1 -1
- {flwr_nightly-1.19.0.dev20250527.dist-info → flwr_nightly-1.19.0.dev20250528.dist-info}/RECORD +29 -29
- {flwr_nightly-1.19.0.dev20250527.dist-info → flwr_nightly-1.19.0.dev20250528.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.19.0.dev20250527.dist-info → flwr_nightly-1.19.0.dev20250528.dist-info}/entry_points.txt +0 -0
flwr/cli/log.py
CHANGED
@@ -35,7 +35,7 @@ from flwr.common.logger import log as logger
|
|
35
35
|
from flwr.proto.exec_pb2 import StreamLogsRequest # pylint: disable=E0611
|
36
36
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
37
37
|
|
38
|
-
from .utils import init_channel, try_obtain_cli_auth_plugin
|
38
|
+
from .utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
|
39
39
|
|
40
40
|
|
41
41
|
class AllLogsRetrieved(BaseException):
|
@@ -95,7 +95,7 @@ def stream_logs(
|
|
95
95
|
latest_timestamp = 0.0
|
96
96
|
res = None
|
97
97
|
try:
|
98
|
-
with
|
98
|
+
with flwr_cli_grpc_exc_handler():
|
99
99
|
for res in stub.StreamLogs(req, timeout=duration):
|
100
100
|
print(res.log_output, end="")
|
101
101
|
raise AllLogsRetrieved()
|
@@ -116,7 +116,7 @@ def print_logs(run_id: int, channel: grpc.Channel, timeout: int) -> None:
|
|
116
116
|
req = StreamLogsRequest(run_id=run_id, after_timestamp=0.0)
|
117
117
|
|
118
118
|
try:
|
119
|
-
with
|
119
|
+
with flwr_cli_grpc_exc_handler():
|
120
120
|
# Enforce timeout for graceful exit
|
121
121
|
for res in stub.StreamLogs(req, timeout=timeout):
|
122
122
|
print(res.log_output)
|
flwr/cli/login/login.py
CHANGED
@@ -35,11 +35,7 @@ from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
|
|
35
35
|
)
|
36
36
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
37
37
|
|
38
|
-
from ..utils import
|
39
|
-
init_channel,
|
40
|
-
try_obtain_cli_auth_plugin,
|
41
|
-
unauthenticated_exc_handler,
|
42
|
-
)
|
38
|
+
from ..utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
|
43
39
|
|
44
40
|
|
45
41
|
def login( # pylint: disable=R0914
|
@@ -96,7 +92,7 @@ def login( # pylint: disable=R0914
|
|
96
92
|
stub = ExecStub(channel)
|
97
93
|
|
98
94
|
login_request = GetLoginDetailsRequest()
|
99
|
-
with
|
95
|
+
with flwr_cli_grpc_exc_handler():
|
100
96
|
login_response: GetLoginDetailsResponse = stub.GetLoginDetails(login_request)
|
101
97
|
|
102
98
|
# Get the auth plugin
|
@@ -120,7 +116,7 @@ def login( # pylint: disable=R0914
|
|
120
116
|
expires_in=login_response.expires_in,
|
121
117
|
interval=login_response.interval,
|
122
118
|
)
|
123
|
-
with
|
119
|
+
with flwr_cli_grpc_exc_handler():
|
124
120
|
credentials = auth_plugin.login(details, stub)
|
125
121
|
|
126
122
|
# Store the tokens
|
flwr/cli/ls.py
CHANGED
@@ -44,7 +44,7 @@ from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
|
|
44
44
|
)
|
45
45
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
46
46
|
|
47
|
-
from .utils import init_channel, try_obtain_cli_auth_plugin
|
47
|
+
from .utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
|
48
48
|
|
49
49
|
_RunListType = tuple[int, str, str, str, str, str, str, str, str]
|
50
50
|
|
@@ -305,7 +305,7 @@ def _list_runs(
|
|
305
305
|
output_format: str = CliOutputFormat.DEFAULT,
|
306
306
|
) -> None:
|
307
307
|
"""List all runs."""
|
308
|
-
with
|
308
|
+
with flwr_cli_grpc_exc_handler():
|
309
309
|
res: ListRunsResponse = stub.ListRuns(ListRunsRequest())
|
310
310
|
run_dict = {run_id: run_from_proto(proto) for run_id, proto in res.run_dict.items()}
|
311
311
|
|
@@ -322,7 +322,7 @@ def _display_one_run(
|
|
322
322
|
output_format: str = CliOutputFormat.DEFAULT,
|
323
323
|
) -> None:
|
324
324
|
"""Display information about a specific run."""
|
325
|
-
with
|
325
|
+
with flwr_cli_grpc_exc_handler():
|
326
326
|
res: ListRunsResponse = stub.ListRuns(ListRunsRequest(run_id=run_id))
|
327
327
|
if not res.run_dict:
|
328
328
|
raise ValueError(f"Run ID {run_id} not found")
|
flwr/cli/run/run.py
CHANGED
@@ -45,11 +45,7 @@ from flwr.proto.exec_pb2 import StartRunRequest # pylint: disable=E0611
|
|
45
45
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
46
46
|
|
47
47
|
from ..log import start_stream
|
48
|
-
from ..utils import
|
49
|
-
init_channel,
|
50
|
-
try_obtain_cli_auth_plugin,
|
51
|
-
unauthenticated_exc_handler,
|
52
|
-
)
|
48
|
+
from ..utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
|
53
49
|
|
54
50
|
CONN_REFRESH_PERIOD = 60 # Connection refresh period for log streaming (seconds)
|
55
51
|
|
@@ -172,7 +168,7 @@ def _run_with_exec_api(
|
|
172
168
|
override_config=user_config_to_proto(parse_config_args(config_overrides)),
|
173
169
|
federation_options=config_record_to_proto(c_record),
|
174
170
|
)
|
175
|
-
with
|
171
|
+
with flwr_cli_grpc_exc_handler():
|
176
172
|
res = stub.StartRun(req)
|
177
173
|
|
178
174
|
if res.HasField("run_id"):
|
flwr/cli/stop.py
CHANGED
@@ -35,7 +35,7 @@ from flwr.common.logger import print_json_error, redirect_output, restore_output
|
|
35
35
|
from flwr.proto.exec_pb2 import StopRunRequest, StopRunResponse # pylint: disable=E0611
|
36
36
|
from flwr.proto.exec_pb2_grpc import ExecStub
|
37
37
|
|
38
|
-
from .utils import init_channel, try_obtain_cli_auth_plugin
|
38
|
+
from .utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
|
39
39
|
|
40
40
|
|
41
41
|
def stop( # pylint: disable=R0914
|
@@ -122,7 +122,7 @@ def stop( # pylint: disable=R0914
|
|
122
122
|
|
123
123
|
def _stop_run(stub: ExecStub, run_id: int, output_format: str) -> None:
|
124
124
|
"""Stop a run."""
|
125
|
-
with
|
125
|
+
with flwr_cli_grpc_exc_handler():
|
126
126
|
response: StopRunResponse = stub.StopRun(request=StopRunRequest(run_id=run_id))
|
127
127
|
if response.success:
|
128
128
|
typer.secho(f"✅ Run {run_id} successfully stopped.", fg=typer.colors.GREEN)
|
flwr/cli/utils.py
CHANGED
@@ -288,11 +288,12 @@ def init_channel(
|
|
288
288
|
|
289
289
|
|
290
290
|
@contextmanager
|
291
|
-
def
|
292
|
-
"""Context manager to handle gRPC
|
291
|
+
def flwr_cli_grpc_exc_handler() -> Iterator[None]:
|
292
|
+
"""Context manager to handle specific gRPC errors.
|
293
293
|
|
294
|
-
It catches grpc.RpcError exceptions with UNAUTHENTICATED
|
295
|
-
and exits the application. All other exceptions will be allowed to
|
294
|
+
It catches grpc.RpcError exceptions with UNAUTHENTICATED and UNIMPLEMENTED statuses,
|
295
|
+
informs the user, and exits the application. All other exceptions will be allowed to
|
296
|
+
escape.
|
296
297
|
"""
|
297
298
|
try:
|
298
299
|
yield
|
@@ -279,6 +279,8 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
279
279
|
log(ERROR, "No current message")
|
280
280
|
return
|
281
281
|
|
282
|
+
# Set message_id
|
283
|
+
message.metadata.__dict__["_message_id"] = message.object_id
|
282
284
|
# Validate out message
|
283
285
|
if not validate_out_message(message, metadata):
|
284
286
|
log(ERROR, "Invalid out message")
|
@@ -164,7 +164,7 @@ def validate_out_message(out_message: Message, in_message_metadata: Metadata) ->
|
|
164
164
|
in_meta = in_message_metadata
|
165
165
|
if ( # pylint: disable-next=too-many-boolean-expressions
|
166
166
|
out_meta.run_id == in_meta.run_id
|
167
|
-
and out_meta.message_id ==
|
167
|
+
and out_meta.message_id == out_message.object_id # Should match the object id
|
168
168
|
and out_meta.src_node_id == in_meta.dst_node_id
|
169
169
|
and out_meta.dst_node_id == in_meta.src_node_id
|
170
170
|
and out_meta.reply_to_message_id == in_meta.message_id
|
flwr/common/inflatable.py
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
20
|
import hashlib
|
21
|
-
from typing import TypeVar
|
21
|
+
from typing import TypeVar, cast
|
22
22
|
|
23
23
|
from .constant import HEAD_BODY_DIVIDER, HEAD_VALUE_DIVIDER
|
24
24
|
|
@@ -55,13 +55,24 @@ class InflatableObject:
|
|
55
55
|
@property
|
56
56
|
def object_id(self) -> str:
|
57
57
|
"""Get object_id."""
|
58
|
-
|
58
|
+
if self.is_dirty or "_object_id" not in self.__dict__:
|
59
|
+
self.__dict__["_object_id"] = get_object_id(self.deflate())
|
60
|
+
return cast(str, self.__dict__["_object_id"])
|
59
61
|
|
60
62
|
@property
|
61
63
|
def children(self) -> dict[str, InflatableObject] | None:
|
62
64
|
"""Get all child objects as a dictionary or None if there are no children."""
|
63
65
|
return None
|
64
66
|
|
67
|
+
@property
|
68
|
+
def is_dirty(self) -> bool:
|
69
|
+
"""Check if the object is dirty after the last deflation.
|
70
|
+
|
71
|
+
An object is considered dirty if its content has changed since the last its
|
72
|
+
object ID was computed.
|
73
|
+
"""
|
74
|
+
return True
|
75
|
+
|
65
76
|
|
66
77
|
T = TypeVar("T", bound=InflatableObject)
|
67
78
|
|
@@ -178,3 +189,23 @@ def get_object_head_values_from_object_content(
|
|
178
189
|
obj_type, children_str, body_len = head.split(HEAD_VALUE_DIVIDER)
|
179
190
|
children_ids = children_str.split(",") if children_str else []
|
180
191
|
return obj_type, children_ids, int(body_len)
|
192
|
+
|
193
|
+
|
194
|
+
def _get_descendants_object_ids_recursively(obj: InflatableObject) -> set[str]:
|
195
|
+
|
196
|
+
descendants: set[str] = set()
|
197
|
+
if children := obj.children:
|
198
|
+
for child in children.values():
|
199
|
+
descendants |= _get_descendants_object_ids_recursively(child)
|
200
|
+
|
201
|
+
descendants.add(obj.object_id)
|
202
|
+
|
203
|
+
return descendants
|
204
|
+
|
205
|
+
|
206
|
+
def get_desdendant_object_ids(obj: InflatableObject) -> set[str]:
|
207
|
+
"""Get a set of object IDs of all descendants."""
|
208
|
+
descendants = _get_descendants_object_ids_recursively(obj)
|
209
|
+
# Exclude Object ID of parent object
|
210
|
+
descendants.discard(obj.object_id)
|
211
|
+
return descendants
|
flwr/common/record/array.py
CHANGED
@@ -107,10 +107,21 @@ class Array(InflatableObject):
|
|
107
107
|
"""
|
108
108
|
|
109
109
|
dtype: str
|
110
|
-
shape: list[int]
|
111
110
|
stype: str
|
112
111
|
data: bytes
|
113
112
|
|
113
|
+
@property
|
114
|
+
def shape(self) -> list[int]:
|
115
|
+
"""Get the shape of the array."""
|
116
|
+
self.is_dirty = True # Mark as dirty when shape is accessed
|
117
|
+
return cast(list[int], self.__dict__["_shape"])
|
118
|
+
|
119
|
+
@shape.setter
|
120
|
+
def shape(self, value: list[int]) -> None:
|
121
|
+
"""Set the shape of the array."""
|
122
|
+
self.is_dirty = True # Mark as dirty when shape is set
|
123
|
+
self.__dict__["_shape"] = value
|
124
|
+
|
114
125
|
@overload
|
115
126
|
def __init__( # noqa: E704
|
116
127
|
self, dtype: str, shape: list[int], stype: str, data: bytes
|
@@ -295,3 +306,29 @@ class Array(InflatableObject):
|
|
295
306
|
stype=proto_array.stype,
|
296
307
|
data=proto_array.data,
|
297
308
|
)
|
309
|
+
|
310
|
+
@property
|
311
|
+
def object_id(self) -> str:
|
312
|
+
"""Get object ID."""
|
313
|
+
ret = super().object_id
|
314
|
+
self.is_dirty = False # Reset dirty flag
|
315
|
+
return ret
|
316
|
+
|
317
|
+
@property
|
318
|
+
def is_dirty(self) -> bool:
|
319
|
+
"""Check if the object is dirty after the last deflation."""
|
320
|
+
if "_is_dirty" not in self.__dict__:
|
321
|
+
self.__dict__["_is_dirty"] = True
|
322
|
+
return cast(bool, self.__dict__["_is_dirty"])
|
323
|
+
|
324
|
+
@is_dirty.setter
|
325
|
+
def is_dirty(self, value: bool) -> None:
|
326
|
+
"""Set the dirty flag."""
|
327
|
+
self.__dict__["_is_dirty"] = value
|
328
|
+
|
329
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
330
|
+
"""Set attribute with special handling for dirty state."""
|
331
|
+
if name in ("dtype", "stype", "data"):
|
332
|
+
# Mark as dirty if any of the main attributes are set
|
333
|
+
self.is_dirty = True
|
334
|
+
super().__setattr__(name, value)
|
@@ -429,6 +429,40 @@ class ArrayRecord(TypedDict[str, Array], InflatableObject):
|
|
429
429
|
)
|
430
430
|
)
|
431
431
|
|
432
|
+
@property
|
433
|
+
def object_id(self) -> str:
|
434
|
+
"""Get object ID."""
|
435
|
+
ret = super().object_id
|
436
|
+
self.is_dirty = False # Reset dirty flag
|
437
|
+
return ret
|
438
|
+
|
439
|
+
@property
|
440
|
+
def is_dirty(self) -> bool:
|
441
|
+
"""Check if the object is dirty after the last deflation."""
|
442
|
+
if "_is_dirty" not in self.__dict__:
|
443
|
+
self.__dict__["_is_dirty"] = True
|
444
|
+
|
445
|
+
if not self.__dict__["_is_dirty"]:
|
446
|
+
if any(v.is_dirty for v in self.values()):
|
447
|
+
# If any Array is dirty, mark the record as dirty
|
448
|
+
self.__dict__["_is_dirty"] = True
|
449
|
+
return cast(bool, self.__dict__["_is_dirty"])
|
450
|
+
|
451
|
+
@is_dirty.setter
|
452
|
+
def is_dirty(self, value: bool) -> None:
|
453
|
+
"""Set the dirty flag."""
|
454
|
+
self.__dict__["_is_dirty"] = value
|
455
|
+
|
456
|
+
def __setitem__(self, key: str, value: Array) -> None:
|
457
|
+
"""Set item and mark the record as dirty."""
|
458
|
+
self.is_dirty = True # Mark as dirty when setting an item
|
459
|
+
super().__setitem__(key, value)
|
460
|
+
|
461
|
+
def __delitem__(self, key: str) -> None:
|
462
|
+
"""Delete item and mark the record as dirty."""
|
463
|
+
self.is_dirty = True # Mark as dirty when deleting an item
|
464
|
+
super().__delitem__(key)
|
465
|
+
|
432
466
|
|
433
467
|
class ParametersRecord(ArrayRecord):
|
434
468
|
"""Deprecated class ``ParametersRecord``, use ``ArrayRecord`` instead.
|
flwr/common/serde.py
CHANGED
@@ -378,7 +378,12 @@ def scalar_from_proto(scalar_msg: Scalar) -> typing.Scalar:
|
|
378
378
|
|
379
379
|
def array_to_proto(array: Array) -> ProtoArray:
|
380
380
|
"""Serialize Array to ProtoBuf."""
|
381
|
-
return ProtoArray(
|
381
|
+
return ProtoArray(
|
382
|
+
dtype=array.dtype,
|
383
|
+
shape=array.shape,
|
384
|
+
stype=array.stype,
|
385
|
+
data=array.data,
|
386
|
+
)
|
382
387
|
|
383
388
|
|
384
389
|
def array_from_proto(array_proto: ProtoArray) -> Array:
|
flwr/server/grid/grpc_grid.py
CHANGED
@@ -163,7 +163,7 @@ class GrpcGrid(Grid):
|
|
163
163
|
def _check_message(self, message: Message) -> None:
|
164
164
|
# Check if the message is valid
|
165
165
|
if not (
|
166
|
-
message.metadata.message_id
|
166
|
+
message.metadata.message_id != ""
|
167
167
|
and message.metadata.reply_to_message_id == ""
|
168
168
|
and message.metadata.ttl > 0
|
169
169
|
):
|
@@ -211,6 +211,7 @@ class GrpcGrid(Grid):
|
|
211
211
|
# Populate metadata
|
212
212
|
msg.metadata.__dict__["_run_id"] = run_id
|
213
213
|
msg.metadata.__dict__["_src_node_id"] = self.node.node_id
|
214
|
+
msg.metadata.__dict__["_message_id"] = msg.object_id
|
214
215
|
# Check message
|
215
216
|
self._check_message(msg)
|
216
217
|
# Convert to proto
|
@@ -18,7 +18,7 @@
|
|
18
18
|
import time
|
19
19
|
from collections.abc import Iterable
|
20
20
|
from typing import Optional, cast
|
21
|
-
from uuid import
|
21
|
+
from uuid import uuid4
|
22
22
|
|
23
23
|
from flwr.common import Message, RecordDict
|
24
24
|
from flwr.common.constant import SUPERLINK_NODE_ID
|
@@ -56,7 +56,7 @@ class InMemoryGrid(Grid):
|
|
56
56
|
def _check_message(self, message: Message) -> None:
|
57
57
|
# Check if the message is valid
|
58
58
|
if not (
|
59
|
-
message.metadata.message_id
|
59
|
+
message.metadata.message_id != ""
|
60
60
|
and message.metadata.reply_to_message_id == ""
|
61
61
|
and message.metadata.ttl > 0
|
62
62
|
and message.metadata.delivered_at == ""
|
@@ -111,6 +111,7 @@ class InMemoryGrid(Grid):
|
|
111
111
|
# Populate metadata
|
112
112
|
msg.metadata.__dict__["_run_id"] = cast(Run, self._run).run_id
|
113
113
|
msg.metadata.__dict__["_src_node_id"] = self.node.node_id
|
114
|
+
msg.metadata.__dict__["_message_id"] = str(uuid4())
|
114
115
|
# Check message
|
115
116
|
self._check_message(msg)
|
116
117
|
# Store in state
|
@@ -126,12 +127,12 @@ class InMemoryGrid(Grid):
|
|
126
127
|
This method is used to collect messages from the SuperLink that correspond to a
|
127
128
|
set of given message IDs.
|
128
129
|
"""
|
129
|
-
msg_ids =
|
130
|
+
msg_ids = set(message_ids)
|
130
131
|
# Pull Messages
|
131
132
|
message_res_list = self.state.get_message_res(message_ids=msg_ids)
|
132
133
|
# Get IDs of Messages these replies are for
|
133
134
|
message_ins_ids_to_delete = {
|
134
|
-
|
135
|
+
msg_res.metadata.reply_to_message_id for msg_res in message_res_list
|
135
136
|
}
|
136
137
|
# Delete
|
137
138
|
self.state.delete_messages(message_ins_ids=message_ins_ids_to_delete)
|
@@ -16,7 +16,6 @@
|
|
16
16
|
|
17
17
|
|
18
18
|
from typing import Optional
|
19
|
-
from uuid import UUID
|
20
19
|
|
21
20
|
from flwr.common import Message
|
22
21
|
from flwr.common.constant import Status
|
@@ -122,7 +121,7 @@ def push_messages(
|
|
122
121
|
raise InvalidRunStatusException(abort_msg)
|
123
122
|
|
124
123
|
# Store Message in State
|
125
|
-
message_id: Optional[
|
124
|
+
message_id: Optional[str] = state.store_message_res(message=msg)
|
126
125
|
|
127
126
|
# Build response
|
128
127
|
response = PushMessagesResponse(
|
@@ -25,6 +25,7 @@ from pathlib import Path
|
|
25
25
|
from queue import Empty, Queue
|
26
26
|
from time import sleep
|
27
27
|
from typing import Callable, Optional
|
28
|
+
from uuid import uuid4
|
28
29
|
|
29
30
|
from flwr.app.error import Error
|
30
31
|
from flwr.client.client_app import ClientApp, ClientAppException, LoadClientAppError
|
@@ -134,6 +135,8 @@ def worker(
|
|
134
135
|
|
135
136
|
finally:
|
136
137
|
if out_mssg:
|
138
|
+
# Assign a message_id
|
139
|
+
out_mssg.metadata.__dict__["_message_id"] = str(uuid4())
|
137
140
|
# Store reply Messages in state
|
138
141
|
messageres_queue.put(out_mssg)
|
139
142
|
|
@@ -21,7 +21,6 @@ from bisect import bisect_right
|
|
21
21
|
from dataclasses import dataclass, field
|
22
22
|
from logging import ERROR, WARNING
|
23
23
|
from typing import Optional
|
24
|
-
from uuid import UUID, uuid4
|
25
24
|
|
26
25
|
from flwr.common import Context, Message, log, now
|
27
26
|
from flwr.common.constant import (
|
@@ -76,15 +75,15 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
76
75
|
self.run_ids: dict[int, RunRecord] = {}
|
77
76
|
self.contexts: dict[int, Context] = {}
|
78
77
|
self.federation_options: dict[int, ConfigRecord] = {}
|
79
|
-
self.message_ins_store: dict[
|
80
|
-
self.message_res_store: dict[
|
81
|
-
self.message_ins_id_to_message_res_id: dict[
|
78
|
+
self.message_ins_store: dict[str, Message] = {}
|
79
|
+
self.message_res_store: dict[str, Message] = {}
|
80
|
+
self.message_ins_id_to_message_res_id: dict[str, str] = {}
|
82
81
|
|
83
82
|
self.node_public_keys: set[bytes] = set()
|
84
83
|
|
85
84
|
self.lock = threading.RLock()
|
86
85
|
|
87
|
-
def store_message_ins(self, message: Message) -> Optional[
|
86
|
+
def store_message_ins(self, message: Message) -> Optional[str]:
|
88
87
|
"""Store one Message."""
|
89
88
|
# Validate message
|
90
89
|
errors = validate_message(message, is_reply_message=False)
|
@@ -112,12 +111,7 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
112
111
|
)
|
113
112
|
return None
|
114
113
|
|
115
|
-
|
116
|
-
message_id = uuid4()
|
117
|
-
|
118
|
-
# Store Message
|
119
|
-
# pylint: disable-next=W0212
|
120
|
-
message.metadata._message_id = str(message_id) # type: ignore
|
114
|
+
message_id = message.metadata.message_id
|
121
115
|
with self.lock:
|
122
116
|
self.message_ins_store[message_id] = message
|
123
117
|
|
@@ -153,7 +147,7 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
153
147
|
return message_ins_list
|
154
148
|
|
155
149
|
# pylint: disable=R0911
|
156
|
-
def store_message_res(self, message: Message) -> Optional[
|
150
|
+
def store_message_res(self, message: Message) -> Optional[str]:
|
157
151
|
"""Store one Message."""
|
158
152
|
# Validate message
|
159
153
|
errors = validate_message(message, is_reply_message=True)
|
@@ -165,7 +159,7 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
165
159
|
with self.lock:
|
166
160
|
# Check if the Message it is replying to exists and is valid
|
167
161
|
msg_ins_id = res_metadata.reply_to_message_id
|
168
|
-
msg_ins = self.message_ins_store.get(
|
162
|
+
msg_ins = self.message_ins_store.get(msg_ins_id)
|
169
163
|
|
170
164
|
# Ensure that dst_node_id of original Message matches the src_node_id of
|
171
165
|
# reply Message.
|
@@ -220,22 +214,17 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
220
214
|
log(ERROR, "`metadata.run_id` is invalid")
|
221
215
|
return None
|
222
216
|
|
223
|
-
|
224
|
-
message_id = uuid4()
|
225
|
-
|
226
|
-
# Store Message
|
227
|
-
# pylint: disable-next=W0212
|
228
|
-
message.metadata._message_id = str(message_id) # type: ignore
|
217
|
+
message_id = message.metadata.message_id
|
229
218
|
with self.lock:
|
230
219
|
self.message_res_store[message_id] = message
|
231
|
-
self.message_ins_id_to_message_res_id[
|
220
|
+
self.message_ins_id_to_message_res_id[msg_ins_id] = message_id
|
232
221
|
|
233
222
|
# Return the new message_id
|
234
223
|
return message_id
|
235
224
|
|
236
|
-
def get_message_res(self, message_ids: set[
|
225
|
+
def get_message_res(self, message_ids: set[str]) -> list[Message]:
|
237
226
|
"""Get reply Messages for the given Message IDs."""
|
238
|
-
ret: dict[
|
227
|
+
ret: dict[str, Message] = {}
|
239
228
|
|
240
229
|
with self.lock:
|
241
230
|
current = time.time()
|
@@ -287,7 +276,7 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
287
276
|
|
288
277
|
return list(ret.values())
|
289
278
|
|
290
|
-
def delete_messages(self, message_ins_ids: set[
|
279
|
+
def delete_messages(self, message_ins_ids: set[str]) -> None:
|
291
280
|
"""Delete a Message and its reply based on provided Message IDs."""
|
292
281
|
if not message_ins_ids:
|
293
282
|
return
|
@@ -304,9 +293,9 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
304
293
|
)
|
305
294
|
del self.message_res_store[message_res_id]
|
306
295
|
|
307
|
-
def get_message_ids_from_run_id(self, run_id: int) -> set[
|
296
|
+
def get_message_ids_from_run_id(self, run_id: int) -> set[str]:
|
308
297
|
"""Get all instruction Message IDs for the given run_id."""
|
309
|
-
message_id_list: set[
|
298
|
+
message_id_list: set[str] = set()
|
310
299
|
with self.lock:
|
311
300
|
for message_id, message in self.message_ins_store.items():
|
312
301
|
if message.metadata.run_id == run_id:
|
@@ -17,7 +17,6 @@
|
|
17
17
|
|
18
18
|
import abc
|
19
19
|
from typing import Optional
|
20
|
-
from uuid import UUID
|
21
20
|
|
22
21
|
from flwr.common import Context, Message
|
23
22
|
from flwr.common.record import ConfigRecord
|
@@ -28,13 +27,13 @@ class LinkState(abc.ABC): # pylint: disable=R0904
|
|
28
27
|
"""Abstract LinkState."""
|
29
28
|
|
30
29
|
@abc.abstractmethod
|
31
|
-
def store_message_ins(self, message: Message) -> Optional[
|
30
|
+
def store_message_ins(self, message: Message) -> Optional[str]:
|
32
31
|
"""Store one Message.
|
33
32
|
|
34
33
|
Usually, the ServerAppIo API calls this to schedule instructions.
|
35
34
|
|
36
35
|
Stores the value of the `message` in the link state and, if successful,
|
37
|
-
returns the `message_id` (
|
36
|
+
returns the `message_id` (str) of the `message`. If, for any reason,
|
38
37
|
storing the `message` fails, `None` is returned.
|
39
38
|
|
40
39
|
Constraints
|
@@ -61,12 +60,12 @@ class LinkState(abc.ABC): # pylint: disable=R0904
|
|
61
60
|
"""
|
62
61
|
|
63
62
|
@abc.abstractmethod
|
64
|
-
def store_message_res(self, message: Message) -> Optional[
|
63
|
+
def store_message_res(self, message: Message) -> Optional[str]:
|
65
64
|
"""Store one Message.
|
66
65
|
|
67
66
|
Usually, the Fleet API calls this for Nodes returning results.
|
68
67
|
|
69
|
-
Stores the Message and, if successful, returns the `message_id` (
|
68
|
+
Stores the Message and, if successful, returns the `message_id` (str) of
|
70
69
|
the `message`. If storing the `message` fails, `None` is returned.
|
71
70
|
|
72
71
|
Constraints
|
@@ -78,7 +77,7 @@ class LinkState(abc.ABC): # pylint: disable=R0904
|
|
78
77
|
"""
|
79
78
|
|
80
79
|
@abc.abstractmethod
|
81
|
-
def get_message_res(self, message_ids: set[
|
80
|
+
def get_message_res(self, message_ids: set[str]) -> list[Message]:
|
82
81
|
"""Get reply Messages for the given Message IDs.
|
83
82
|
|
84
83
|
This method is typically called by the ServerAppIo API to obtain
|
@@ -94,7 +93,7 @@ class LinkState(abc.ABC): # pylint: disable=R0904
|
|
94
93
|
|
95
94
|
Parameters
|
96
95
|
----------
|
97
|
-
message_ids : set[
|
96
|
+
message_ids : set[str]
|
98
97
|
A set of Message IDs used to retrieve reply Messages responding to them.
|
99
98
|
|
100
99
|
Returns
|
@@ -113,18 +112,18 @@ class LinkState(abc.ABC): # pylint: disable=R0904
|
|
113
112
|
"""Calculate the number of reply Messages in store."""
|
114
113
|
|
115
114
|
@abc.abstractmethod
|
116
|
-
def delete_messages(self, message_ins_ids: set[
|
115
|
+
def delete_messages(self, message_ins_ids: set[str]) -> None:
|
117
116
|
"""Delete a Message and its reply based on provided Message IDs.
|
118
117
|
|
119
118
|
Parameters
|
120
119
|
----------
|
121
|
-
message_ins_ids : set[
|
120
|
+
message_ins_ids : set[str]
|
122
121
|
A set of Message IDs. For each ID in the set, the corresponding
|
123
122
|
Message and its associated reply Message will be deleted.
|
124
123
|
"""
|
125
124
|
|
126
125
|
@abc.abstractmethod
|
127
|
-
def get_message_ids_from_run_id(self, run_id: int) -> set[
|
126
|
+
def get_message_ids_from_run_id(self, run_id: int) -> set[str]:
|
128
127
|
"""Get all instruction Message IDs for the given run_id."""
|
129
128
|
|
130
129
|
@abc.abstractmethod
|
@@ -24,7 +24,6 @@ import time
|
|
24
24
|
from collections.abc import Sequence
|
25
25
|
from logging import DEBUG, ERROR, WARNING
|
26
26
|
from typing import Any, Optional, Union, cast
|
27
|
-
from uuid import UUID, uuid4
|
28
27
|
|
29
28
|
from flwr.common import Context, Message, Metadata, log, now
|
30
29
|
from flwr.common.constant import (
|
@@ -251,19 +250,15 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
251
250
|
|
252
251
|
return result
|
253
252
|
|
254
|
-
def store_message_ins(self, message: Message) -> Optional[
|
253
|
+
def store_message_ins(self, message: Message) -> Optional[str]:
|
255
254
|
"""Store one Message."""
|
256
255
|
# Validate message
|
257
256
|
errors = validate_message(message=message, is_reply_message=False)
|
258
257
|
if any(errors):
|
259
258
|
log(ERROR, errors)
|
260
259
|
return None
|
261
|
-
# Create message_id
|
262
|
-
message_id = uuid4()
|
263
260
|
|
264
261
|
# Store Message
|
265
|
-
# pylint: disable-next=W0212
|
266
|
-
message.metadata._message_id = str(message_id) # type: ignore
|
267
262
|
data = (message_to_dict(message),)
|
268
263
|
|
269
264
|
# Convert values from uint64 to sint64 for SQLite
|
@@ -303,7 +298,7 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
303
298
|
# This may need to be changed in the future version with more integrity checks.
|
304
299
|
self.query(query, data)
|
305
300
|
|
306
|
-
return message_id
|
301
|
+
return message.metadata.message_id
|
307
302
|
|
308
303
|
def get_message_ins(self, node_id: int, limit: Optional[int]) -> list[Message]:
|
309
304
|
"""Get all Messages that have not been delivered yet."""
|
@@ -366,7 +361,7 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
366
361
|
|
367
362
|
return result
|
368
363
|
|
369
|
-
def store_message_res(self, message: Message) -> Optional[
|
364
|
+
def store_message_res(self, message: Message) -> Optional[str]:
|
370
365
|
"""Store one Message."""
|
371
366
|
# Validate message
|
372
367
|
errors = validate_message(message=message, is_reply_message=True)
|
@@ -418,12 +413,7 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
418
413
|
)
|
419
414
|
return None
|
420
415
|
|
421
|
-
# Create message_id
|
422
|
-
message_id = uuid4()
|
423
|
-
|
424
416
|
# Store Message
|
425
|
-
# pylint: disable-next=W0212
|
426
|
-
message.metadata._message_id = str(message_id) # type: ignore
|
427
417
|
data = (message_to_dict(message),)
|
428
418
|
|
429
419
|
# Convert values from uint64 to sint64 for SQLite
|
@@ -442,12 +432,12 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
442
432
|
log(ERROR, "`run` is invalid")
|
443
433
|
return None
|
444
434
|
|
445
|
-
return message_id
|
435
|
+
return message.metadata.message_id
|
446
436
|
|
447
|
-
def get_message_res(self, message_ids: set[
|
437
|
+
def get_message_res(self, message_ids: set[str]) -> list[Message]:
|
448
438
|
"""Get reply Messages for the given Message IDs."""
|
449
439
|
# pylint: disable-msg=too-many-locals
|
450
|
-
ret: dict[
|
440
|
+
ret: dict[str, Message] = {}
|
451
441
|
|
452
442
|
# Verify Message IDs
|
453
443
|
current = time.time()
|
@@ -457,12 +447,12 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
457
447
|
WHERE message_id IN ({",".join(["?"] * len(message_ids))});
|
458
448
|
"""
|
459
449
|
rows = self.query(query, tuple(str(message_id) for message_id in message_ids))
|
460
|
-
found_message_ins_dict: dict[
|
450
|
+
found_message_ins_dict: dict[str, Message] = {}
|
461
451
|
for row in rows:
|
462
452
|
convert_sint64_values_in_dict_to_uint64(
|
463
453
|
row, ["run_id", "src_node_id", "dst_node_id"]
|
464
454
|
)
|
465
|
-
found_message_ins_dict[
|
455
|
+
found_message_ins_dict[row["message_id"]] = dict_to_message(row)
|
466
456
|
|
467
457
|
ret = verify_message_ids(
|
468
458
|
inquired_message_ids=message_ids,
|
@@ -551,7 +541,7 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
551
541
|
result: dict[str, int] = rows[0]
|
552
542
|
return result["num"]
|
553
543
|
|
554
|
-
def delete_messages(self, message_ins_ids: set[
|
544
|
+
def delete_messages(self, message_ins_ids: set[str]) -> None:
|
555
545
|
"""Delete a Message and its reply based on provided Message IDs."""
|
556
546
|
if not message_ins_ids:
|
557
547
|
return
|
@@ -577,7 +567,7 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
577
567
|
self.conn.execute(query_1, data)
|
578
568
|
self.conn.execute(query_2, data)
|
579
569
|
|
580
|
-
def get_message_ids_from_run_id(self, run_id: int) -> set[
|
570
|
+
def get_message_ids_from_run_id(self, run_id: int) -> set[str]:
|
581
571
|
"""Get all instruction Message IDs for the given run_id."""
|
582
572
|
if self.conn is None:
|
583
573
|
raise AttributeError("LinkState not initialized")
|
@@ -594,7 +584,7 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
594
584
|
with self.conn:
|
595
585
|
rows = self.conn.execute(query, data).fetchall()
|
596
586
|
|
597
|
-
return {
|
587
|
+
return {row["message_id"] for row in rows}
|
598
588
|
|
599
589
|
def create_node(self, heartbeat_interval: float) -> int:
|
600
590
|
"""Create, store in the link state, and return `node_id`."""
|
@@ -17,7 +17,7 @@
|
|
17
17
|
|
18
18
|
from os import urandom
|
19
19
|
from typing import Optional
|
20
|
-
from uuid import
|
20
|
+
from uuid import uuid4
|
21
21
|
|
22
22
|
from flwr.common import ConfigRecord, Context, Error, Message, Metadata, now, serde
|
23
23
|
from flwr.common.constant import (
|
@@ -273,7 +273,7 @@ def create_message_error_unavailable_res_message(
|
|
273
273
|
)
|
274
274
|
|
275
275
|
|
276
|
-
def create_message_error_unavailable_ins_message(reply_to_message_id:
|
276
|
+
def create_message_error_unavailable_ins_message(reply_to_message_id: str) -> Message:
|
277
277
|
"""Error to indicate that the enquired Message had expired before reply arrived or
|
278
278
|
that it isn't found."""
|
279
279
|
metadata = Metadata(
|
@@ -281,7 +281,7 @@ def create_message_error_unavailable_ins_message(reply_to_message_id: UUID) -> M
|
|
281
281
|
message_id=str(uuid4()),
|
282
282
|
src_node_id=SUPERLINK_NODE_ID,
|
283
283
|
dst_node_id=SUPERLINK_NODE_ID,
|
284
|
-
reply_to_message_id=
|
284
|
+
reply_to_message_id=reply_to_message_id,
|
285
285
|
group_id="", # Unknown
|
286
286
|
message_type=MessageType.SYSTEM,
|
287
287
|
created_at=now().timestamp(),
|
@@ -303,18 +303,18 @@ def message_ttl_has_expired(message_metadata: Metadata, current_time: float) ->
|
|
303
303
|
|
304
304
|
|
305
305
|
def verify_message_ids(
|
306
|
-
inquired_message_ids: set[
|
307
|
-
found_message_ins_dict: dict[
|
306
|
+
inquired_message_ids: set[str],
|
307
|
+
found_message_ins_dict: dict[str, Message],
|
308
308
|
current_time: Optional[float] = None,
|
309
309
|
update_set: bool = True,
|
310
|
-
) -> dict[
|
310
|
+
) -> dict[str, Message]:
|
311
311
|
"""Verify found Messages and generate error Messages for invalid ones.
|
312
312
|
|
313
313
|
Parameters
|
314
314
|
----------
|
315
|
-
inquired_message_ids : set[
|
315
|
+
inquired_message_ids : set[str]
|
316
316
|
Set of Message IDs for which to generate error Message if invalid.
|
317
|
-
found_message_ins_dict : dict[
|
317
|
+
found_message_ins_dict : dict[str, Message]
|
318
318
|
Dictionary containing all found Message indexed by their IDs.
|
319
319
|
current_time : Optional[float] (default: None)
|
320
320
|
The current time to check for expiration. If set to `None`, the current time
|
@@ -325,7 +325,7 @@ def verify_message_ids(
|
|
325
325
|
|
326
326
|
Returns
|
327
327
|
-------
|
328
|
-
dict[
|
328
|
+
dict[str, Message]
|
329
329
|
A dictionary of error Message indexed by the corresponding ID of the message
|
330
330
|
they are a reply of.
|
331
331
|
"""
|
@@ -345,19 +345,19 @@ def verify_message_ids(
|
|
345
345
|
|
346
346
|
|
347
347
|
def verify_found_message_replies(
|
348
|
-
inquired_message_ids: set[
|
349
|
-
found_message_ins_dict: dict[
|
348
|
+
inquired_message_ids: set[str],
|
349
|
+
found_message_ins_dict: dict[str, Message],
|
350
350
|
found_message_res_list: list[Message],
|
351
351
|
current_time: Optional[float] = None,
|
352
352
|
update_set: bool = True,
|
353
|
-
) -> dict[
|
353
|
+
) -> dict[str, Message]:
|
354
354
|
"""Verify found Message replies and generate error Message for invalid ones.
|
355
355
|
|
356
356
|
Parameters
|
357
357
|
----------
|
358
|
-
inquired_message_ids : set[
|
358
|
+
inquired_message_ids : set[str]
|
359
359
|
Set of Message IDs for which to generate error Message if invalid.
|
360
|
-
found_message_ins_dict : dict[
|
360
|
+
found_message_ins_dict : dict[str, Message]
|
361
361
|
Dictionary containing all found instruction Messages indexed by their IDs.
|
362
362
|
found_message_res_list : dict[Message, Message]
|
363
363
|
List of found Message to be verified.
|
@@ -370,13 +370,13 @@ def verify_found_message_replies(
|
|
370
370
|
|
371
371
|
Returns
|
372
372
|
-------
|
373
|
-
dict[
|
373
|
+
dict[str, Message]
|
374
374
|
A dictionary of Message indexed by the corresponding Message ID.
|
375
375
|
"""
|
376
|
-
ret_dict: dict[
|
376
|
+
ret_dict: dict[str, Message] = {}
|
377
377
|
current = current_time if current_time else now().timestamp()
|
378
378
|
for message_res in found_message_res_list:
|
379
|
-
message_ins_id =
|
379
|
+
message_ins_id = message_res.metadata.reply_to_message_id
|
380
380
|
if update_set:
|
381
381
|
inquired_message_ids.remove(message_ins_id)
|
382
382
|
# Check if the reply Message has expired
|
@@ -390,21 +390,21 @@ def verify_found_message_replies(
|
|
390
390
|
|
391
391
|
|
392
392
|
def check_node_availability_for_in_message(
|
393
|
-
inquired_in_message_ids: set[
|
394
|
-
found_in_message_dict: dict[
|
393
|
+
inquired_in_message_ids: set[str],
|
394
|
+
found_in_message_dict: dict[str, Message],
|
395
395
|
node_id_to_online_until: dict[int, float],
|
396
396
|
current_time: Optional[float] = None,
|
397
397
|
update_set: bool = True,
|
398
|
-
) -> dict[
|
398
|
+
) -> dict[str, Message]:
|
399
399
|
"""Check node availability for given Message and generate error reply Message if
|
400
400
|
unavailable. A Message error indicating node unavailability will be generated for
|
401
401
|
each given Message whose destination node is offline or non-existent.
|
402
402
|
|
403
403
|
Parameters
|
404
404
|
----------
|
405
|
-
inquired_in_message_ids : set[
|
405
|
+
inquired_in_message_ids : set[str]
|
406
406
|
Set of Message IDs for which to check destination node availability.
|
407
|
-
found_in_message_dict : dict[
|
407
|
+
found_in_message_dict : dict[str, Message]
|
408
408
|
Dictionary containing all found Message indexed by their IDs.
|
409
409
|
node_id_to_online_until : dict[int, float]
|
410
410
|
Dictionary mapping node IDs to their online-until timestamps.
|
@@ -417,7 +417,7 @@ def check_node_availability_for_in_message(
|
|
417
417
|
|
418
418
|
Returns
|
419
419
|
-------
|
420
|
-
dict[
|
420
|
+
dict[str, Message]
|
421
421
|
A dictionary of error Message indexed by the corresponding Message ID.
|
422
422
|
"""
|
423
423
|
ret_dict = {}
|
@@ -18,7 +18,6 @@
|
|
18
18
|
import threading
|
19
19
|
from logging import DEBUG, INFO
|
20
20
|
from typing import Optional
|
21
|
-
from uuid import UUID
|
22
21
|
|
23
22
|
import grpc
|
24
23
|
|
@@ -140,7 +139,7 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
|
140
139
|
request_name="PushMessages",
|
141
140
|
detail="`messages_list` must not be empty",
|
142
141
|
)
|
143
|
-
message_ids: list[Optional[
|
142
|
+
message_ids: list[Optional[str]] = []
|
144
143
|
while request.messages_list:
|
145
144
|
message_proto = request.messages_list.pop(0)
|
146
145
|
message = message_from_proto(message_proto=message_proto)
|
@@ -156,7 +155,7 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
|
156
155
|
detail="`Message.metadata` has mismatched `run_id`",
|
157
156
|
)
|
158
157
|
# Store
|
159
|
-
message_id: Optional[
|
158
|
+
message_id: Optional[str] = state.store_message_ins(message=message)
|
160
159
|
message_ids.append(message_id)
|
161
160
|
|
162
161
|
return PushInsMessagesResponse(
|
@@ -182,17 +181,14 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
|
|
182
181
|
context,
|
183
182
|
)
|
184
183
|
|
185
|
-
# Convert each message_id str to UUID
|
186
|
-
message_ids: set[UUID] = {
|
187
|
-
UUID(message_id) for message_id in request.message_ids
|
188
|
-
}
|
189
|
-
|
190
184
|
# Read from state
|
191
|
-
messages_res: list[Message] = state.get_message_res(
|
185
|
+
messages_res: list[Message] = state.get_message_res(
|
186
|
+
message_ids=set(request.message_ids)
|
187
|
+
)
|
192
188
|
|
193
189
|
# Delete the instruction Messages and their replies if found
|
194
190
|
message_ins_ids_to_delete = {
|
195
|
-
|
191
|
+
msg_res.metadata.reply_to_message_id for msg_res in messages_res
|
196
192
|
}
|
197
193
|
|
198
194
|
state.delete_messages(message_ins_ids=message_ins_ids_to_delete)
|
flwr/server/utils/validator.py
CHANGED
@@ -27,8 +27,8 @@ def validate_message(message: Message, is_reply_message: bool) -> list[str]:
|
|
27
27
|
validation_errors = []
|
28
28
|
metadata = message.metadata
|
29
29
|
|
30
|
-
if metadata.message_id
|
31
|
-
validation_errors.append("
|
30
|
+
if metadata.message_id == "":
|
31
|
+
validation_errors.append("empty `metadata.message_id`")
|
32
32
|
|
33
33
|
# Created/delivered/TTL/Pushed
|
34
34
|
if (
|
@@ -28,12 +28,27 @@ class InMemoryObjectStore(ObjectStore):
|
|
28
28
|
def __init__(self, verify: bool = True) -> None:
|
29
29
|
self.verify = verify
|
30
30
|
self.store: dict[str, bytes] = {}
|
31
|
+
# Mapping the Object ID of a message to the list of children object IDs
|
32
|
+
self.msg_children_objects_mapping: dict[str, list[str]] = {}
|
33
|
+
|
34
|
+
def preregister(self, object_ids: list[str]) -> list[str]:
|
35
|
+
"""Identify and preregister missing objects."""
|
36
|
+
new_objects = []
|
37
|
+
for obj_id in object_ids:
|
38
|
+
# Verify object ID format (must be a valid sha256 hash)
|
39
|
+
if not is_valid_sha256_hash(obj_id):
|
40
|
+
raise ValueError(f"Invalid object ID format: {obj_id}")
|
41
|
+
if obj_id not in self.store:
|
42
|
+
self.store[obj_id] = b""
|
43
|
+
new_objects.append(obj_id)
|
44
|
+
|
45
|
+
return new_objects
|
31
46
|
|
32
47
|
def put(self, object_id: str, object_content: bytes) -> None:
|
33
48
|
"""Put an object into the store."""
|
34
|
-
#
|
35
|
-
if not
|
36
|
-
raise
|
49
|
+
# Only allow adding the object if it has been preregistered
|
50
|
+
if object_id not in self.store:
|
51
|
+
raise KeyError(f"Object with id {object_id} was not preregistered.")
|
37
52
|
|
38
53
|
# Verify object_id and object_content match
|
39
54
|
if self.verify:
|
@@ -42,11 +57,22 @@ class InMemoryObjectStore(ObjectStore):
|
|
42
57
|
raise ValueError(f"Object ID {object_id} does not match content hash")
|
43
58
|
|
44
59
|
# Return if object is already present in the store
|
45
|
-
if object_id
|
60
|
+
if self.store[object_id] != b"":
|
46
61
|
return
|
47
62
|
|
48
63
|
self.store[object_id] = object_content
|
49
64
|
|
65
|
+
def set_message_descendant_ids(
|
66
|
+
self, msg_object_id: str, descendant_ids: list[str]
|
67
|
+
) -> None:
|
68
|
+
"""Store the mapping from a ``Message`` object ID to the object IDs of its
|
69
|
+
descendants."""
|
70
|
+
self.msg_children_objects_mapping[msg_object_id] = descendant_ids
|
71
|
+
|
72
|
+
def get_message_descendant_ids(self, msg_object_id: str) -> list[str]:
|
73
|
+
"""Retrieve the object IDs of all descendants of a given Message."""
|
74
|
+
return self.msg_children_objects_mapping[msg_object_id]
|
75
|
+
|
50
76
|
def get(self, object_id: str) -> Optional[bytes]:
|
51
77
|
"""Get an object from the store."""
|
52
78
|
return self.store.get(object_id)
|
@@ -26,6 +26,23 @@ class ObjectStore(abc.ABC):
|
|
26
26
|
delete objects identified by object IDs.
|
27
27
|
"""
|
28
28
|
|
29
|
+
@abc.abstractmethod
|
30
|
+
def preregister(self, object_ids: list[str]) -> list[str]:
|
31
|
+
"""Identify and preregister missing objects in the `ObjectStore`.
|
32
|
+
|
33
|
+
Parameters
|
34
|
+
----------
|
35
|
+
object_ids : list[str]
|
36
|
+
A list of object IDs to check against the store. Any object ID not already
|
37
|
+
present will be preregistered.
|
38
|
+
|
39
|
+
Returns
|
40
|
+
-------
|
41
|
+
list[str]
|
42
|
+
A list of object IDs that were not present in the `ObjectStore` and have now
|
43
|
+
been preregistered.
|
44
|
+
"""
|
45
|
+
|
29
46
|
@abc.abstractmethod
|
30
47
|
def put(self, object_id: str, object_content: bytes) -> None:
|
31
48
|
"""Put an object into the store.
|
@@ -33,7 +50,7 @@ class ObjectStore(abc.ABC):
|
|
33
50
|
Parameters
|
34
51
|
----------
|
35
52
|
object_id : str
|
36
|
-
The object_id under which to store the object.
|
53
|
+
The object_id under which to store the object. Must be preregistered.
|
37
54
|
object_content : bytes
|
38
55
|
The deflated object to store.
|
39
56
|
"""
|
@@ -70,6 +87,36 @@ class ObjectStore(abc.ABC):
|
|
70
87
|
This method should remove all objects from the store.
|
71
88
|
"""
|
72
89
|
|
90
|
+
@abc.abstractmethod
|
91
|
+
def set_message_descendant_ids(
|
92
|
+
self, msg_object_id: str, descendant_ids: list[str]
|
93
|
+
) -> None:
|
94
|
+
"""Store the mapping from a ``Message`` object ID to the object IDs of its
|
95
|
+
descendants.
|
96
|
+
|
97
|
+
Parameters
|
98
|
+
----------
|
99
|
+
msg_object_id : str
|
100
|
+
The object ID of the ``Message``.
|
101
|
+
descendant_ids : list[str]
|
102
|
+
A list of object IDs representing all descendant objects of the ``Message``.
|
103
|
+
"""
|
104
|
+
|
105
|
+
@abc.abstractmethod
|
106
|
+
def get_message_descendant_ids(self, msg_object_id: str) -> list[str]:
|
107
|
+
"""Retrieve the object IDs of all descendants of a given ``Message``.
|
108
|
+
|
109
|
+
Parameters
|
110
|
+
----------
|
111
|
+
msg_object_id : str
|
112
|
+
The object ID of the ``Message``.
|
113
|
+
|
114
|
+
Returns
|
115
|
+
-------
|
116
|
+
list[str]
|
117
|
+
A list of object IDs of all descendant objects of the ``Message``.
|
118
|
+
"""
|
119
|
+
|
73
120
|
@abc.abstractmethod
|
74
121
|
def __contains__(self, object_id: str) -> bool:
|
75
122
|
"""Check if an object_id is in the store.
|
flwr/superexec/exec_servicer.py
CHANGED
@@ -19,7 +19,6 @@ import time
|
|
19
19
|
from collections.abc import Generator
|
20
20
|
from logging import ERROR, INFO
|
21
21
|
from typing import Any, Optional
|
22
|
-
from uuid import UUID
|
23
22
|
|
24
23
|
import grpc
|
25
24
|
|
@@ -163,7 +162,7 @@ class ExecServicer(exec_pb2_grpc.ExecServicer):
|
|
163
162
|
)
|
164
163
|
|
165
164
|
if update_success:
|
166
|
-
message_ids: set[
|
165
|
+
message_ids: set[str] = state.get_message_ids_from_run_id(request.run_id)
|
167
166
|
|
168
167
|
# Delete Messages and their replies for the `run_id`
|
169
168
|
state.delete_messages(message_ids)
|
{flwr_nightly-1.19.0.dev20250527.dist-info → flwr_nightly-1.19.0.dev20250528.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: flwr-nightly
|
3
|
-
Version: 1.19.0.
|
3
|
+
Version: 1.19.0.dev20250528
|
4
4
|
Summary: Flower: A Friendly Federated AI Framework
|
5
5
|
License: Apache-2.0
|
6
6
|
Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
|
{flwr_nightly-1.19.0.dev20250527.dist-info → flwr_nightly-1.19.0.dev20250528.dist-info}/RECORD
RENAMED
@@ -12,10 +12,10 @@ flwr/cli/config_utils.py,sha256=IAVn2uWTXpN72YYt7raLtwp8ziwZugUKSURpc471VzU,9123
|
|
12
12
|
flwr/cli/constant.py,sha256=g7Ad7o3DJDkJNrWS0T3SSJETWSTkkVJWGpLM8zlbpcY,1289
|
13
13
|
flwr/cli/example.py,sha256=SNTorkKPrx1rOryGREUyZu8TcOc1-vFv1zEddaysdY0,2216
|
14
14
|
flwr/cli/install.py,sha256=Jr883qR7qssVpUr3hEOEcLK-dfW67Rsve3lZchjA9RU,8180
|
15
|
-
flwr/cli/log.py,sha256=
|
15
|
+
flwr/cli/log.py,sha256=CKh5l2nnpognDy3lSubrlYX2-gNJ0qa-UFGVPRKS_YQ,6523
|
16
16
|
flwr/cli/login/__init__.py,sha256=B1SXKU3HCQhWfFDMJhlC7FOl8UsvH4mxysxeBnrfyUE,800
|
17
|
-
flwr/cli/login/login.py,sha256=
|
18
|
-
flwr/cli/ls.py,sha256=
|
17
|
+
flwr/cli/login/login.py,sha256=pDkx5o4XBFBi7aGp_0Ys2FUMKmcWjzwWdoQRumXUsd8,4297
|
18
|
+
flwr/cli/ls.py,sha256=RpOR6tEyu5TWWMIAUa23cxuKH3yfBoki7UQigpIT3TY,11427
|
19
19
|
flwr/cli/new/__init__.py,sha256=QA1E2QtzPvFCjLTUHnFnJbufuFiGyT_0Y53Wpbvg1F0,790
|
20
20
|
flwr/cli/new/new.py,sha256=2e4ACJqeZ0W0_FyksQTi7PEzQpXT8KRpBPthFoac6zQ,9917
|
21
21
|
flwr/cli/new/templates/__init__.py,sha256=FpjWCfIySU2DB4kh0HOXLAjlZNNFDTVU4w3HoE2TzcI,725
|
@@ -71,9 +71,9 @@ flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl,sha256=dckyBDmvBHbPNB5LQhX
|
|
71
71
|
flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl,sha256=F93FdohqSBzcdFanew33V8bBeC3s9r3IaV8tfd4zw-E,686
|
72
72
|
flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=7aOtbvAAnVXyTEYLsg_LtxDRQD16XUjRmnENgAWyiMs,710
|
73
73
|
flwr/cli/run/__init__.py,sha256=RPyB7KbYTFl6YRiilCch6oezxrLQrl1kijV7BMGkLbA,790
|
74
|
-
flwr/cli/run/run.py,sha256=
|
75
|
-
flwr/cli/stop.py,sha256=
|
76
|
-
flwr/cli/utils.py,sha256=
|
74
|
+
flwr/cli/run/run.py,sha256=U_EHebzwiH8Lszm40oJM8a2I0vaiu1Iizci_GHSl25Y,8211
|
75
|
+
flwr/cli/stop.py,sha256=l8DcRkA---CESVJgc7iTHLWIBAPGxWIfoem8qSU3lZQ,4972
|
76
|
+
flwr/cli/utils.py,sha256=oHEP82x4mm0HpT4ZmMg9IU_JPzjSlRNp8BAl3pH_3n4,11222
|
77
77
|
flwr/client/__init__.py,sha256=boIhKaK6I977zrILmoTutNx94x5jB0e6F1gnAjaRJnI,1250
|
78
78
|
flwr/client/client.py,sha256=3HAchxvknKG9jYbB7swNyDj-e5vUWDuMKoLvbT7jCVM,7895
|
79
79
|
flwr/client/client_app.py,sha256=zVhi-l3chAb06ozFsKwix3hU_RpOLjST13Ha50AVIPE,16918
|
@@ -86,10 +86,10 @@ flwr/client/grpc_adapter_client/__init__.py,sha256=RQWP5mFPROLHKgombiRvPXVWSoVrQ
|
|
86
86
|
flwr/client/grpc_adapter_client/connection.py,sha256=aj5tTYyE8z2hQLXPPydsJiz8gBDIWLUhfWvqYkAL1L4,3966
|
87
87
|
flwr/client/grpc_rere_client/__init__.py,sha256=i7iS0Lt8B7q0E2L72e4F_YrKm6ClRKnd71PNA6PW2O0,752
|
88
88
|
flwr/client/grpc_rere_client/client_interceptor.py,sha256=zFaVHw6AxeNO-7eCKKb-RxrPa7zbM5Z-2-1Efc4adQY,2451
|
89
|
-
flwr/client/grpc_rere_client/connection.py,sha256=
|
89
|
+
flwr/client/grpc_rere_client/connection.py,sha256=slRDCax2CTwVURURUf8qV9Ph4eDuf67XVLB77PuV9fE,12118
|
90
90
|
flwr/client/grpc_rere_client/grpc_adapter.py,sha256=JvMZ7vCFTaTEo6AzKYh3zDmeQAU7VSjdysbC6t3ufWg,6351
|
91
91
|
flwr/client/message_handler/__init__.py,sha256=0lyljDVqre3WljiZbPcwCCf8GiIaSVI_yo_ylEyPwSE,719
|
92
|
-
flwr/client/message_handler/message_handler.py,sha256
|
92
|
+
flwr/client/message_handler/message_handler.py,sha256=X9SXX6et97Lw9_DGD93HKsEBGNjXClcFgc_5aLK0oiU,6541
|
93
93
|
flwr/client/mod/__init__.py,sha256=AtV4Y5UGuYqJdTg7bJ--KtfOZUYLGDPMy616LvtP5W4,1151
|
94
94
|
flwr/client/mod/centraldp_mods.py,sha256=ha5j0vDT7Mi8Ke5iz-hMn3H_H1jnXW10EswoyKYrRag,5422
|
95
95
|
flwr/client/mod/comms_mods.py,sha256=zfypvalPdVQ7aWwbsTYEYf0T0hv6aU3VO1eOCb9Uj9A,2387
|
@@ -124,7 +124,7 @@ flwr/common/exit/exit_code.py,sha256=PNEnCrZfOILjfDAFu5m-2YWEJBrk97xglq4zCUlqV7E
|
|
124
124
|
flwr/common/exit_handlers.py,sha256=MEk5_savTLphn-6lW57UQlos-XrFA39XEBn-OF1vXXg,3174
|
125
125
|
flwr/common/grpc.py,sha256=manTaHaPiyYngUq1ErZvvV2B2GxlXUUUGRy3jc3TBIQ,9798
|
126
126
|
flwr/common/heartbeat.py,sha256=SyEpNDnmJ0lni0cWO67rcoJVKasCLmkNHm3dKLeNrLU,5749
|
127
|
-
flwr/common/inflatable.py,sha256=
|
127
|
+
flwr/common/inflatable.py,sha256=vBDlaJlgF6sryjglhFcr22zylROmPFwM7QLjVV7XbtU,6837
|
128
128
|
flwr/common/inflatable_grpc_utils.py,sha256=On_RT8cYChwE3-1MlY21s_cVXgYCGeKTONRafm-rmEk,3432
|
129
129
|
flwr/common/logger.py,sha256=JbRf6E2vQxXzpDBq1T8IDUJo_usu3gjWEBPQ6uKcmdg,13049
|
130
130
|
flwr/common/message.py,sha256=onc0stpXk26P9d__AfSTde1BUVN0Z9Ofw85m0kyS9pY,19225
|
@@ -132,8 +132,8 @@ flwr/common/object_ref.py,sha256=p3SfTeqo3Aj16SkB-vsnNn01zswOPdGNBitcbRnqmUk,913
|
|
132
132
|
flwr/common/parameter.py,sha256=UVw6sOgehEFhFs4uUCMl2kfVq1PD6ncmWgPLMsZPKPE,2095
|
133
133
|
flwr/common/pyproject.py,sha256=2SU6yJW7059SbMXgzjOdK1GZRWO6AixDH7BmdxbMvHI,1386
|
134
134
|
flwr/common/record/__init__.py,sha256=cNGccdDoxttqgnUgyKRIqLWULjW-NaSmOufVxtXq-sw,1197
|
135
|
-
flwr/common/record/array.py,sha256=
|
136
|
-
flwr/common/record/arrayrecord.py,sha256=
|
135
|
+
flwr/common/record/array.py,sha256=XtM-ooMPfpyc4RpR6gxZUHmr1xVCtl2HPL-fWyCzzCo,12140
|
136
|
+
flwr/common/record/arrayrecord.py,sha256=vUNVBlHA_HsbsTdB9eom49abfPYrKHQNW9Ac0UCazTo,18007
|
137
137
|
flwr/common/record/configrecord.py,sha256=nDoIc_-vh7XUx2BuojenpcqSgM2XxD4NyGFAYpmXabM,9652
|
138
138
|
flwr/common/record/conversion_utils.py,sha256=wbNCzy7oAqaA3-arhls_EqRZYXRC4YrWIoE-Gy82fJ0,1191
|
139
139
|
flwr/common/record/metricrecord.py,sha256=Gxl9TdVpMAHg6pNN2SxB-as8iPDnPx398KEhORU4n3A,8839
|
@@ -149,7 +149,7 @@ flwr/common/secure_aggregation/ndarrays_arithmetic.py,sha256=TrggOlizlny3V2KS7-3
|
|
149
149
|
flwr/common/secure_aggregation/quantization.py,sha256=ssFZpiRyj9ltIh0Ai3vGkDqWFO4SoqgoD1mDU9XqMEM,2400
|
150
150
|
flwr/common/secure_aggregation/secaggplus_constants.py,sha256=dGYhWOBMMDJcQH4_tQNC8-Efqm-ecEUNN9ANz59UnCk,2182
|
151
151
|
flwr/common/secure_aggregation/secaggplus_utils.py,sha256=E_xU-Zd45daO1em7M6C2wOjFXVtJf-6tl7fp-7xq1wo,3214
|
152
|
-
flwr/common/serde.py,sha256=
|
152
|
+
flwr/common/serde.py,sha256=KpEaiOZGpMce4CGPkZ6HrWRj4qheYi-MC18HXDKeycM,22378
|
153
153
|
flwr/common/serde_utils.py,sha256=zF99EnqTNhEd3Xh3tYy2bZ44_8B-QfwNqsuP7vfLVDs,5735
|
154
154
|
flwr/common/telemetry.py,sha256=jF47v0SbnBd43XamHtl3wKxs3knFUY2p77cm_2lzZ8M,8762
|
155
155
|
flwr/common/typing.py,sha256=97QRfRRS7sQnjkAI5FDZ01-38oQUSz4i1qqewQmBWRg,6886
|
@@ -238,8 +238,8 @@ flwr/server/criterion.py,sha256=G4e-6B48Pc7d5rmGVUpIzNKb6UF88O3VmTRuUltgjzM,1061
|
|
238
238
|
flwr/server/fleet_event_log_interceptor.py,sha256=AkL7Y5d3xm2vRhL3ahmEVVoOvAP7PA7dRgB-je4v-Ys,3774
|
239
239
|
flwr/server/grid/__init__.py,sha256=aWZHezoR2UGMJISB_gPMCm2N_2GSbm97A3lAp7ruhRQ,888
|
240
240
|
flwr/server/grid/grid.py,sha256=naGCYt5J6dnmUvrcGkdNyKPe3MBd-0awGm1ALmgahqY,6625
|
241
|
-
flwr/server/grid/grpc_grid.py,sha256=
|
242
|
-
flwr/server/grid/inmemory_grid.py,sha256=
|
241
|
+
flwr/server/grid/grpc_grid.py,sha256=PE_ZMYcqZOntFVurIc9aoD-DwUofVIyNTY2vKsx1U-M,11204
|
242
|
+
flwr/server/grid/inmemory_grid.py,sha256=RjejYT-d-hHuTs1KSs_5wvOdAWKLus8w5_UAcnGt4iw,6168
|
243
243
|
flwr/server/history.py,sha256=cCkFhBN4GoHsYYNk5GG1Y089eKJh2DH_ZJbYPwLaGyk,5026
|
244
244
|
flwr/server/run_serverapp.py,sha256=v0p6jXj2dFxlRUdoEeF1mnaFd9XRQi6dZCflPY6d3qI,2063
|
245
245
|
flwr/server/server.py,sha256=39m4FSN2T-uVA-no9nstN0eWW0co-IUUAIMmpd3V7Jc,17893
|
@@ -289,23 +289,23 @@ flwr/server/superlink/fleet/grpc_rere/__init__.py,sha256=ahDJJ1e-lDxBpeBMgPk7YZt
|
|
289
289
|
flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=--Xfd3FqBUIKHHQ1oS53Zal3rqqxrCORcpbFQeGSDlY,7081
|
290
290
|
flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=DrHubsaLgJCwCeeJPYogQTiP0xYqjxwnT9rh7OP7BoU,6984
|
291
291
|
flwr/server/superlink/fleet/message_handler/__init__.py,sha256=fHsRV0KvJ8HtgSA4_YBsEzuhJLjO8p6xx4aCY2oE1p4,731
|
292
|
-
flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=
|
292
|
+
flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=fyckLUyumpApwcMM3Cme8sLBL8BHQN0-yltd3ngl9D4,5404
|
293
293
|
flwr/server/superlink/fleet/rest_rere/__init__.py,sha256=Lzc93nA7tDqoy-zRUaPG316oqFiZX1HUCL5ELaXY_xw,735
|
294
294
|
flwr/server/superlink/fleet/rest_rere/rest_api.py,sha256=s6SNp_z-Uyr4tT4C5PqSbeJySfvsdK1SIczwwxrljO8,6923
|
295
295
|
flwr/server/superlink/fleet/vce/__init__.py,sha256=XOKbAWOzlCqEOQ3M2cBYkH7HKA7PxlbCJMunt-ty-DY,784
|
296
296
|
flwr/server/superlink/fleet/vce/backend/__init__.py,sha256=PPH89Yqd1XKm-sRJN6R0WQlKT_b4v54Kzl2yzHAFzM8,1437
|
297
297
|
flwr/server/superlink/fleet/vce/backend/backend.py,sha256=-wDHjgAy5mrfEgXj0GxkJI7lhEbgSUyPwmNAf9ZcDzc,2193
|
298
298
|
flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=Hx9hxL7lju1_VJoAwkhBOGerZ3628u0P1zgkPhGWRPY,7154
|
299
|
-
flwr/server/superlink/fleet/vce/vce_api.py,sha256=
|
299
|
+
flwr/server/superlink/fleet/vce/vce_api.py,sha256=xSjQbBYHmUTinw7Q_-UxqR7qt07kqj9FCSpPYRsUKf8,12909
|
300
300
|
flwr/server/superlink/linkstate/__init__.py,sha256=OtsgvDTnZLU3k0sUbkHbqoVwW6ql2FDmb6uT6DbNkZo,1064
|
301
|
-
flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=
|
302
|
-
flwr/server/superlink/linkstate/linkstate.py,sha256=
|
301
|
+
flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=rw3h5cbF-T_9DNDM-f0WOrGy8yLEzzgsN3qeD0qUoR4,25592
|
302
|
+
flwr/server/superlink/linkstate/linkstate.py,sha256=Jrgm1biGDkQZVGuecrgJSf4laWZ1WeBbScA-Zs7Gc3Y,13069
|
303
303
|
flwr/server/superlink/linkstate/linkstate_factory.py,sha256=8RlosqSpKOoD_vhUUQPY0jtE3A84GeF96Z7sWNkRRcA,2069
|
304
|
-
flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=
|
305
|
-
flwr/server/superlink/linkstate/utils.py,sha256=
|
304
|
+
flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=sHJPK1w0tP0m2WCXH2F9lGxGyI3wBniPUBono30vwMY,43242
|
305
|
+
flwr/server/superlink/linkstate/utils.py,sha256=i93ZXBPHR27YCPkTBLX0-LP-zKOxV4L-qi7spoBxJXE,15345
|
306
306
|
flwr/server/superlink/serverappio/__init__.py,sha256=Fy4zJuoccZe5mZSEIpOmQvU6YeXFBa1M4eZuXXmJcn8,717
|
307
307
|
flwr/server/superlink/serverappio/serverappio_grpc.py,sha256=6-FUUt0GiLcBPljj8bBrUNeAITUoDQOLzaMihKo52hg,2326
|
308
|
-
flwr/server/superlink/serverappio/serverappio_servicer.py,sha256
|
308
|
+
flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=-d4XUmSbtalTIENQzh84Mj21KDoaq51pxWrrrSa5Ts8,13826
|
309
309
|
flwr/server/superlink/simulation/__init__.py,sha256=Ry8DrNaZCMcQXvUc4FoCN2m3dvUQgWjasfp015o3Ec4,718
|
310
310
|
flwr/server/superlink/simulation/simulationio_grpc.py,sha256=0l0F-UjYEk6W7HZmI28PbJQLFxSi_vBHRkdchgdaSMQ,2224
|
311
311
|
flwr/server/superlink/simulation/simulationio_servicer.py,sha256=aJezU8RSJswcmWm7Eoy0BqsU13jrcfuFwX3ljm-cORM,7719
|
@@ -313,7 +313,7 @@ flwr/server/superlink/utils.py,sha256=BpKJ8IQBzJ8nLfTD5plBA_Y9re5hIS2gQ_40fc-zno
|
|
313
313
|
flwr/server/typing.py,sha256=LvO6gq7H6TAWhA9JFx0WyqHxU7FycyvhSsLjBLPgpts,1011
|
314
314
|
flwr/server/utils/__init__.py,sha256=U4gM84-uUFddarODDQkO6SjNUuGhFcsHJZMjSEbezkU,884
|
315
315
|
flwr/server/utils/tensorboard.py,sha256=3z3MeF0cu_U6ghNgRd0UQ5bunyDQKxCLpIpEdGMoCJ0,5466
|
316
|
-
flwr/server/utils/validator.py,sha256=
|
316
|
+
flwr/server/utils/validator.py,sha256=_dFb6_aAqWSiTgFuR10p8PPRI1ojwf0GFXuT8kLL2H8,3612
|
317
317
|
flwr/server/workflow/__init__.py,sha256=N8G_xCBVrlV39Eov56bwImKMUTsqsaEoTCFYIQ0q8Bg,902
|
318
318
|
flwr/server/workflow/constant.py,sha256=4t2MTvOJUlByJfuD9yZjl8Xn5SwBJQDBi15DphztXe8,1082
|
319
319
|
flwr/server/workflow/default_workflows.py,sha256=RlD26dXbSksY-23f3ZspnN1YU1DOhDYOchMTEQvqFrM,13900
|
@@ -332,15 +332,15 @@ flwr/simulation/run_simulation.py,sha256=Nvw_6hI71aE2nU95_tt1F9VSo3OJWrvA97e3XZu
|
|
332
332
|
flwr/simulation/simulationio_connection.py,sha256=mzS1C6EEREwQDPceDo30anAasmTDLb9qqV2tXlBhOUA,3494
|
333
333
|
flwr/supercore/__init__.py,sha256=pqkFoow_E6UhbBlhmoD1gmTH-33yJRhBsIZqxRPFZ7U,755
|
334
334
|
flwr/supercore/object_store/__init__.py,sha256=7dvl-iNyZjEla9lLijc6Hn6HbdxXwsiA_ktF7PCYcSY,861
|
335
|
-
flwr/supercore/object_store/in_memory_object_store.py,sha256=
|
336
|
-
flwr/supercore/object_store/object_store.py,sha256=
|
335
|
+
flwr/supercore/object_store/in_memory_object_store.py,sha256=3q-v9_XRye0adQteDwckRpnVUGVbMZeSA4T326OTNO0,3579
|
336
|
+
flwr/supercore/object_store/object_store.py,sha256=f627VkRmBl6HFt4gyC3lMka0_uemF_NaysAjkDGsEyY,3951
|
337
337
|
flwr/supercore/object_store/object_store_factory.py,sha256=QVwE2ywi7vsj2iKfvWWnNw3N_I7Rz91NUt2RpcbJ7iM,1527
|
338
338
|
flwr/superexec/__init__.py,sha256=YFqER0IJc1XEWfsX6AxZ9LSRq0sawPYrNYki-brvTIc,715
|
339
339
|
flwr/superexec/app.py,sha256=U2jjOHb2LGWoU7vrl9_czTzre9O2mPxu3CPGUZ86sK4,1465
|
340
340
|
flwr/superexec/deployment.py,sha256=2wBBZgdNAn1Ik1M3HGg4t23CV8oZqzDz1zkOBzHjZLE,6734
|
341
341
|
flwr/superexec/exec_event_log_interceptor.py,sha256=IlQ_w-GpGNMJ4g1gTI3H4LHfWli1-8O7a2-pCqB3yeA,5753
|
342
342
|
flwr/superexec/exec_grpc.py,sha256=KMaiPcg_wVM_cn_VPzrSP8AKVqGndOuei9XdHgy86tU,3252
|
343
|
-
flwr/superexec/exec_servicer.py,sha256=
|
343
|
+
flwr/superexec/exec_servicer.py,sha256=nSqAzrWDQFQm9xE6oejoFZqgWhPchbdkC2mCMrWTbhE,8324
|
344
344
|
flwr/superexec/exec_user_auth_interceptor.py,sha256=iqygALkOMBUu_s_R9G0mFThZA7HTUzuXCLgxLCefiwI,4440
|
345
345
|
flwr/superexec/executor.py,sha256=M5ucqSE53jfRtuCNf59WFLqQvA1Mln4741TySeZE7qQ,3112
|
346
346
|
flwr/superexec/simulation.py,sha256=j6YwUvBN7EQ09ID7MYOCVZ70PGbuyBy8f9bXU0EszEM,4088
|
@@ -353,7 +353,7 @@ flwr/supernode/nodestate/in_memory_nodestate.py,sha256=brV7TMMzS93tXk6ntpoYjtPK5
|
|
353
353
|
flwr/supernode/nodestate/nodestate.py,sha256=-LAjZOnS7VyHC05ll3b31cYDjwAt6l4WmYt7duVLRKk,1024
|
354
354
|
flwr/supernode/nodestate/nodestate_factory.py,sha256=UYTDCcwK_baHUmkzkJDxL0UEqvtTfOMlQRrROMCd0Xo,1430
|
355
355
|
flwr/supernode/start_client_internal.py,sha256=4z9qtwT7ZwNwahpX1SRfuaoYw1HCICPFUvjPBLHgsA0,18806
|
356
|
-
flwr_nightly-1.19.0.
|
357
|
-
flwr_nightly-1.19.0.
|
358
|
-
flwr_nightly-1.19.0.
|
359
|
-
flwr_nightly-1.19.0.
|
356
|
+
flwr_nightly-1.19.0.dev20250528.dist-info/METADATA,sha256=S54bdEeqV_WTys7Xz7TbQmS0ynnkV9MKfYY9AWIO8M4,15910
|
357
|
+
flwr_nightly-1.19.0.dev20250528.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
358
|
+
flwr_nightly-1.19.0.dev20250528.dist-info/entry_points.txt,sha256=08k99PaHg3Wr6W49rFXYtjmgcfIdpFLNeu6O0bXDYnU,370
|
359
|
+
flwr_nightly-1.19.0.dev20250528.dist-info/RECORD,,
|
{flwr_nightly-1.19.0.dev20250527.dist-info → flwr_nightly-1.19.0.dev20250528.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|