flwr-nightly 1.13.0.dev20241106__py3-none-any.whl → 1.13.0.dev20241111__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.
Potentially problematic release.
This version of flwr-nightly might be problematic. Click here for more details.
- flwr/cli/run/run.py +16 -5
- flwr/client/app.py +10 -6
- flwr/client/clientapp/app.py +21 -16
- flwr/client/nodestate/__init__.py +25 -0
- flwr/client/nodestate/in_memory_nodestate.py +38 -0
- flwr/client/nodestate/nodestate.py +30 -0
- flwr/client/nodestate/nodestate_factory.py +37 -0
- flwr/common/args.py +83 -0
- flwr/common/config.py +10 -0
- flwr/common/constant.py +0 -1
- flwr/common/logger.py +6 -2
- flwr/common/object_ref.py +47 -16
- flwr/common/typing.py +1 -1
- flwr/proto/exec_pb2.py +14 -17
- flwr/proto/exec_pb2.pyi +6 -20
- flwr/proto/run_pb2.py +32 -27
- flwr/proto/run_pb2.pyi +26 -0
- flwr/proto/simulationio_pb2.py +2 -2
- flwr/proto/simulationio_pb2_grpc.py +34 -0
- flwr/proto/simulationio_pb2_grpc.pyi +13 -0
- flwr/server/app.py +45 -20
- flwr/server/driver/driver.py +1 -1
- flwr/server/driver/grpc_driver.py +2 -6
- flwr/server/driver/inmemory_driver.py +1 -3
- flwr/server/run_serverapp.py +2 -2
- flwr/server/serverapp/app.py +16 -72
- flwr/server/strategy/aggregate.py +4 -4
- flwr/server/superlink/linkstate/in_memory_linkstate.py +5 -16
- flwr/server/superlink/linkstate/linkstate.py +5 -4
- flwr/server/superlink/linkstate/sqlite_linkstate.py +6 -15
- flwr/server/superlink/linkstate/utils.py +2 -33
- flwr/server/superlink/simulation/simulationio_servicer.py +22 -1
- flwr/simulation/__init__.py +3 -1
- flwr/simulation/app.py +273 -345
- flwr/simulation/legacy_app.py +382 -0
- flwr/simulation/run_simulation.py +1 -1
- flwr/superexec/deployment.py +1 -1
- flwr/superexec/exec_servicer.py +2 -2
- flwr/superexec/executor.py +4 -3
- flwr/superexec/simulation.py +44 -102
- {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241111.dist-info}/METADATA +5 -4
- {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241111.dist-info}/RECORD +45 -39
- {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241111.dist-info}/entry_points.txt +1 -0
- {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241111.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241111.dist-info}/WHEEL +0 -0
|
@@ -40,7 +40,6 @@ from .utils import (
|
|
|
40
40
|
generate_rand_int_from_bytes,
|
|
41
41
|
has_valid_sub_status,
|
|
42
42
|
is_valid_transition,
|
|
43
|
-
make_node_unavailable_taskres,
|
|
44
43
|
)
|
|
45
44
|
|
|
46
45
|
|
|
@@ -257,21 +256,6 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
|
257
256
|
task_res_list.append(task_res)
|
|
258
257
|
replied_task_ids.add(reply_to)
|
|
259
258
|
|
|
260
|
-
# Check if the node is offline
|
|
261
|
-
for task_id in task_ids - replied_task_ids:
|
|
262
|
-
task_ins = self.task_ins_store.get(task_id)
|
|
263
|
-
if task_ins is None:
|
|
264
|
-
continue
|
|
265
|
-
node_id = task_ins.task.consumer.node_id
|
|
266
|
-
online_until, _ = self.node_ids[node_id]
|
|
267
|
-
# Generate a TaskRes containing an error reply if the node is offline.
|
|
268
|
-
if online_until < time.time():
|
|
269
|
-
err_taskres = make_node_unavailable_taskres(
|
|
270
|
-
ref_taskins=task_ins,
|
|
271
|
-
)
|
|
272
|
-
self.task_res_store[UUID(err_taskres.task_id)] = err_taskres
|
|
273
|
-
task_res_list.append(err_taskres)
|
|
274
|
-
|
|
275
259
|
# Mark all of them as delivered
|
|
276
260
|
delivered_at = now().isoformat()
|
|
277
261
|
for task_res in task_res_list:
|
|
@@ -451,6 +435,11 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
|
451
435
|
"""Retrieve all currently stored `node_public_keys` as a set."""
|
|
452
436
|
return self.node_public_keys
|
|
453
437
|
|
|
438
|
+
def get_run_ids(self) -> set[int]:
|
|
439
|
+
"""Retrieve all run IDs."""
|
|
440
|
+
with self.lock:
|
|
441
|
+
return set(self.run_ids.keys())
|
|
442
|
+
|
|
454
443
|
def get_run(self, run_id: int) -> Optional[Run]:
|
|
455
444
|
"""Retrieve information about the run with the specified `run_id`."""
|
|
456
445
|
with self.lock:
|
|
@@ -163,6 +163,10 @@ class LinkState(abc.ABC): # pylint: disable=R0904
|
|
|
163
163
|
) -> int:
|
|
164
164
|
"""Create a new run for the specified `fab_hash`."""
|
|
165
165
|
|
|
166
|
+
@abc.abstractmethod
|
|
167
|
+
def get_run_ids(self) -> set[int]:
|
|
168
|
+
"""Retrieve all run IDs."""
|
|
169
|
+
|
|
166
170
|
@abc.abstractmethod
|
|
167
171
|
def get_run(self, run_id: int) -> Optional[Run]:
|
|
168
172
|
"""Retrieve information about the run with the specified `run_id`.
|
|
@@ -175,10 +179,7 @@ class LinkState(abc.ABC): # pylint: disable=R0904
|
|
|
175
179
|
Returns
|
|
176
180
|
-------
|
|
177
181
|
Optional[Run]
|
|
178
|
-
|
|
179
|
-
- `run_id`: The identifier of the run, same as the specified `run_id`.
|
|
180
|
-
- `fab_id`: The identifier of the FAB used in the specified run.
|
|
181
|
-
- `fab_version`: The version of the FAB used in the specified run.
|
|
182
|
+
The `Run` instance if found; otherwise, `None`.
|
|
182
183
|
"""
|
|
183
184
|
|
|
184
185
|
@abc.abstractmethod
|
|
@@ -57,7 +57,6 @@ from .utils import (
|
|
|
57
57
|
generate_rand_int_from_bytes,
|
|
58
58
|
has_valid_sub_status,
|
|
59
59
|
is_valid_transition,
|
|
60
|
-
make_node_unavailable_taskres,
|
|
61
60
|
)
|
|
62
61
|
|
|
63
62
|
SQL_CREATE_TABLE_NODE = """
|
|
@@ -640,20 +639,6 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
|
640
639
|
data = {f"id_{i}": str(node_id) for i, node_id in enumerate(offline_node_ids)}
|
|
641
640
|
task_ins_rows = self.query(query, data)
|
|
642
641
|
|
|
643
|
-
# Make TaskRes containing node unavailabe error
|
|
644
|
-
for row in task_ins_rows:
|
|
645
|
-
for row in rows:
|
|
646
|
-
# Convert values from sint64 to uint64
|
|
647
|
-
convert_sint64_values_in_dict_to_uint64(
|
|
648
|
-
row, ["run_id", "producer_node_id", "consumer_node_id"]
|
|
649
|
-
)
|
|
650
|
-
|
|
651
|
-
task_ins = dict_to_task_ins(row)
|
|
652
|
-
err_taskres = make_node_unavailable_taskres(
|
|
653
|
-
ref_taskins=task_ins,
|
|
654
|
-
)
|
|
655
|
-
result.append(err_taskres)
|
|
656
|
-
|
|
657
642
|
return result
|
|
658
643
|
|
|
659
644
|
def num_task_ins(self) -> int:
|
|
@@ -917,6 +902,12 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
|
917
902
|
result: set[bytes] = {row["public_key"] for row in rows}
|
|
918
903
|
return result
|
|
919
904
|
|
|
905
|
+
def get_run_ids(self) -> set[int]:
|
|
906
|
+
"""Retrieve all run IDs."""
|
|
907
|
+
query = "SELECT run_id FROM run;"
|
|
908
|
+
rows = self.query(query)
|
|
909
|
+
return {convert_sint64_to_uint64(row["run_id"]) for row in rows}
|
|
910
|
+
|
|
920
911
|
def get_run(self, run_id: int) -> Optional[Run]:
|
|
921
912
|
"""Retrieve information about the run with the specified `run_id`."""
|
|
922
913
|
# Convert the uint64 value to sint64 for SQLite
|
|
@@ -15,21 +15,15 @@
|
|
|
15
15
|
"""Utility functions for State."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
import time
|
|
19
|
-
from logging import ERROR
|
|
20
18
|
from os import urandom
|
|
21
|
-
from uuid import uuid4
|
|
22
19
|
|
|
23
|
-
from flwr.common import ConfigsRecord, Context,
|
|
24
|
-
from flwr.common.constant import
|
|
20
|
+
from flwr.common import ConfigsRecord, Context, serde
|
|
21
|
+
from flwr.common.constant import Status, SubStatus
|
|
25
22
|
from flwr.common.typing import RunStatus
|
|
26
|
-
from flwr.proto.error_pb2 import Error # pylint: disable=E0611
|
|
27
23
|
from flwr.proto.message_pb2 import Context as ProtoContext # pylint: disable=E0611
|
|
28
|
-
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
|
29
24
|
|
|
30
25
|
# pylint: disable=E0611
|
|
31
26
|
from flwr.proto.recordset_pb2 import ConfigsRecord as ProtoConfigsRecord
|
|
32
|
-
from flwr.proto.task_pb2 import Task, TaskIns, TaskRes # pylint: disable=E0611
|
|
33
27
|
|
|
34
28
|
NODE_UNAVAILABLE_ERROR_REASON = (
|
|
35
29
|
"Error: Node Unavailable - The destination node is currently unavailable. "
|
|
@@ -161,31 +155,6 @@ def configsrecord_from_bytes(configsrecord_bytes: bytes) -> ConfigsRecord:
|
|
|
161
155
|
)
|
|
162
156
|
|
|
163
157
|
|
|
164
|
-
def make_node_unavailable_taskres(ref_taskins: TaskIns) -> TaskRes:
|
|
165
|
-
"""Generate a TaskRes with a node unavailable error from a TaskIns."""
|
|
166
|
-
current_time = time.time()
|
|
167
|
-
ttl = ref_taskins.task.ttl - (current_time - ref_taskins.task.created_at)
|
|
168
|
-
if ttl < 0:
|
|
169
|
-
log(ERROR, "Creating TaskRes for TaskIns that exceeds its TTL.")
|
|
170
|
-
ttl = 0
|
|
171
|
-
return TaskRes(
|
|
172
|
-
task_id=str(uuid4()),
|
|
173
|
-
group_id=ref_taskins.group_id,
|
|
174
|
-
run_id=ref_taskins.run_id,
|
|
175
|
-
task=Task(
|
|
176
|
-
producer=Node(node_id=ref_taskins.task.consumer.node_id, anonymous=False),
|
|
177
|
-
consumer=Node(node_id=ref_taskins.task.producer.node_id, anonymous=False),
|
|
178
|
-
created_at=current_time,
|
|
179
|
-
ttl=ttl,
|
|
180
|
-
ancestry=[ref_taskins.task_id],
|
|
181
|
-
task_type=ref_taskins.task.task_type,
|
|
182
|
-
error=Error(
|
|
183
|
-
code=ErrorCode.NODE_UNAVAILABLE, reason=NODE_UNAVAILABLE_ERROR_REASON
|
|
184
|
-
),
|
|
185
|
-
),
|
|
186
|
-
)
|
|
187
|
-
|
|
188
|
-
|
|
189
158
|
def is_valid_transition(current_status: RunStatus, new_status: RunStatus) -> bool:
|
|
190
159
|
"""Check if a transition between two run statuses is valid.
|
|
191
160
|
|
|
@@ -23,6 +23,7 @@ from grpc import ServicerContext
|
|
|
23
23
|
from flwr.common.constant import Status
|
|
24
24
|
from flwr.common.logger import log
|
|
25
25
|
from flwr.common.serde import (
|
|
26
|
+
configs_record_to_proto,
|
|
26
27
|
context_from_proto,
|
|
27
28
|
context_to_proto,
|
|
28
29
|
fab_to_proto,
|
|
@@ -36,6 +37,8 @@ from flwr.proto.log_pb2 import ( # pylint: disable=E0611
|
|
|
36
37
|
PushLogsResponse,
|
|
37
38
|
)
|
|
38
39
|
from flwr.proto.run_pb2 import ( # pylint: disable=E0611
|
|
40
|
+
GetFederationOptionsRequest,
|
|
41
|
+
GetFederationOptionsResponse,
|
|
39
42
|
UpdateRunStatusRequest,
|
|
40
43
|
UpdateRunStatusResponse,
|
|
41
44
|
)
|
|
@@ -123,10 +126,28 @@ class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
|
123
126
|
self, request: PushLogsRequest, context: grpc.ServicerContext
|
|
124
127
|
) -> PushLogsResponse:
|
|
125
128
|
"""Push logs."""
|
|
126
|
-
log(DEBUG, "
|
|
129
|
+
log(DEBUG, "SimultionIoServicer.PushLogs")
|
|
127
130
|
state = self.state_factory.state()
|
|
128
131
|
|
|
129
132
|
# Add logs to LinkState
|
|
130
133
|
merged_logs = "".join(request.logs)
|
|
131
134
|
state.add_serverapp_log(request.run_id, merged_logs)
|
|
132
135
|
return PushLogsResponse()
|
|
136
|
+
|
|
137
|
+
def GetFederationOptions(
|
|
138
|
+
self, request: GetFederationOptionsRequest, context: ServicerContext
|
|
139
|
+
) -> GetFederationOptionsResponse:
|
|
140
|
+
"""Get Federation Options associated with a run."""
|
|
141
|
+
log(DEBUG, "SimultionIoServicer.GetFederationOptions")
|
|
142
|
+
state = self.state_factory.state()
|
|
143
|
+
|
|
144
|
+
federation_options = state.get_federation_options(request.run_id)
|
|
145
|
+
if federation_options is None:
|
|
146
|
+
context.abort(
|
|
147
|
+
grpc.StatusCode.FAILED_PRECONDITION,
|
|
148
|
+
"Expected federation options to be set, but none available.",
|
|
149
|
+
)
|
|
150
|
+
return GetFederationOptionsResponse()
|
|
151
|
+
return GetFederationOptionsResponse(
|
|
152
|
+
federation_options=configs_record_to_proto(federation_options)
|
|
153
|
+
)
|
flwr/simulation/__init__.py
CHANGED
|
@@ -17,13 +17,14 @@
|
|
|
17
17
|
|
|
18
18
|
import importlib
|
|
19
19
|
|
|
20
|
+
from flwr.simulation.app import run_simulation_process
|
|
20
21
|
from flwr.simulation.run_simulation import run_simulation
|
|
21
22
|
from flwr.simulation.simulationio_connection import SimulationIoConnection
|
|
22
23
|
|
|
23
24
|
is_ray_installed = importlib.util.find_spec("ray") is not None
|
|
24
25
|
|
|
25
26
|
if is_ray_installed:
|
|
26
|
-
from flwr.simulation.
|
|
27
|
+
from flwr.simulation.legacy_app import start_simulation
|
|
27
28
|
else:
|
|
28
29
|
RAY_IMPORT_ERROR: str = """Unable to import module `ray`.
|
|
29
30
|
|
|
@@ -40,5 +41,6 @@ To install the necessary dependencies, install `flwr` with the `simulation` extr
|
|
|
40
41
|
__all__ = [
|
|
41
42
|
"SimulationIoConnection",
|
|
42
43
|
"run_simulation",
|
|
44
|
+
"run_simulation_process",
|
|
43
45
|
"start_simulation",
|
|
44
46
|
]
|