flwr-nightly 1.13.0.dev20241021__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/build.py +2 -2
- flwr/cli/config_utils.py +97 -0
- flwr/cli/log.py +63 -97
- flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +1 -0
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +1 -1
- flwr/cli/run/run.py +34 -88
- flwr/client/app.py +23 -20
- flwr/client/clientapp/app.py +22 -18
- 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/client/{node_state.py → run_info_store.py} +4 -3
- flwr/client/supernode/app.py +6 -8
- flwr/common/args.py +83 -0
- flwr/common/config.py +10 -0
- flwr/common/constant.py +39 -5
- flwr/common/context.py +9 -4
- flwr/common/date.py +3 -3
- flwr/common/logger.py +108 -1
- flwr/common/object_ref.py +47 -16
- flwr/common/serde.py +24 -0
- flwr/common/telemetry.py +0 -6
- flwr/common/typing.py +10 -1
- flwr/proto/exec_pb2.py +14 -17
- flwr/proto/exec_pb2.pyi +14 -22
- flwr/proto/log_pb2.py +29 -0
- flwr/proto/log_pb2.pyi +39 -0
- flwr/proto/log_pb2_grpc.py +4 -0
- flwr/proto/log_pb2_grpc.pyi +4 -0
- flwr/proto/message_pb2.py +8 -8
- flwr/proto/message_pb2.pyi +4 -1
- flwr/proto/run_pb2.py +32 -27
- flwr/proto/run_pb2.pyi +26 -0
- flwr/proto/serverappio_pb2.py +52 -0
- flwr/proto/{driver_pb2.pyi → serverappio_pb2.pyi} +54 -0
- flwr/proto/serverappio_pb2_grpc.py +376 -0
- flwr/proto/serverappio_pb2_grpc.pyi +147 -0
- flwr/proto/simulationio_pb2.py +38 -0
- flwr/proto/simulationio_pb2.pyi +65 -0
- flwr/proto/simulationio_pb2_grpc.py +205 -0
- flwr/proto/simulationio_pb2_grpc.pyi +81 -0
- flwr/server/app.py +272 -105
- flwr/server/driver/driver.py +15 -1
- flwr/server/driver/grpc_driver.py +25 -36
- flwr/server/driver/inmemory_driver.py +6 -16
- flwr/server/run_serverapp.py +29 -23
- flwr/server/{superlink/state → serverapp}/__init__.py +3 -9
- flwr/server/serverapp/app.py +214 -0
- flwr/server/strategy/aggregate.py +4 -4
- flwr/server/strategy/fedadam.py +11 -1
- flwr/server/superlink/driver/__init__.py +1 -1
- flwr/server/superlink/driver/{driver_grpc.py → serverappio_grpc.py} +19 -16
- flwr/server/superlink/driver/{driver_servicer.py → serverappio_servicer.py} +125 -39
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +4 -2
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +2 -2
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +4 -2
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +2 -2
- flwr/server/superlink/fleet/message_handler/message_handler.py +7 -7
- flwr/server/superlink/fleet/rest_rere/rest_api.py +7 -7
- flwr/server/superlink/fleet/vce/vce_api.py +23 -23
- flwr/server/superlink/linkstate/__init__.py +28 -0
- flwr/server/superlink/{state/in_memory_state.py → linkstate/in_memory_linkstate.py} +184 -36
- flwr/server/superlink/{state/state.py → linkstate/linkstate.py} +149 -19
- flwr/server/superlink/{state/state_factory.py → linkstate/linkstate_factory.py} +9 -9
- flwr/server/superlink/{state/sqlite_state.py → linkstate/sqlite_linkstate.py} +306 -65
- flwr/server/superlink/{state → linkstate}/utils.py +81 -30
- flwr/server/superlink/simulation/__init__.py +15 -0
- flwr/server/superlink/simulation/simulationio_grpc.py +65 -0
- flwr/server/superlink/simulation/simulationio_servicer.py +153 -0
- flwr/simulation/__init__.py +5 -1
- flwr/simulation/app.py +273 -345
- flwr/simulation/legacy_app.py +382 -0
- flwr/simulation/ray_transport/ray_client_proxy.py +2 -2
- flwr/simulation/run_simulation.py +57 -131
- flwr/simulation/simulationio_connection.py +86 -0
- flwr/superexec/app.py +6 -134
- flwr/superexec/deployment.py +61 -66
- flwr/superexec/exec_grpc.py +15 -8
- flwr/superexec/exec_servicer.py +36 -65
- flwr/superexec/executor.py +26 -7
- flwr/superexec/simulation.py +54 -107
- {flwr_nightly-1.13.0.dev20241021.dist-info → flwr_nightly-1.13.0.dev20241111.dist-info}/METADATA +5 -4
- {flwr_nightly-1.13.0.dev20241021.dist-info → flwr_nightly-1.13.0.dev20241111.dist-info}/RECORD +88 -69
- {flwr_nightly-1.13.0.dev20241021.dist-info → flwr_nightly-1.13.0.dev20241111.dist-info}/entry_points.txt +2 -0
- flwr/client/node_state_tests.py +0 -66
- flwr/proto/driver_pb2.py +0 -42
- flwr/proto/driver_pb2_grpc.py +0 -239
- flwr/proto/driver_pb2_grpc.pyi +0 -94
- {flwr_nightly-1.13.0.dev20241021.dist-info → flwr_nightly-1.13.0.dev20241111.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.13.0.dev20241021.dist-info → flwr_nightly-1.13.0.dev20241111.dist-info}/WHEEL +0 -0
|
@@ -15,22 +15,32 @@
|
|
|
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
|
|
24
|
-
from flwr.common.constant import
|
|
25
|
-
from flwr.
|
|
26
|
-
from flwr.proto.
|
|
27
|
-
|
|
20
|
+
from flwr.common import ConfigsRecord, Context, serde
|
|
21
|
+
from flwr.common.constant import Status, SubStatus
|
|
22
|
+
from flwr.common.typing import RunStatus
|
|
23
|
+
from flwr.proto.message_pb2 import Context as ProtoContext # pylint: disable=E0611
|
|
24
|
+
|
|
25
|
+
# pylint: disable=E0611
|
|
26
|
+
from flwr.proto.recordset_pb2 import ConfigsRecord as ProtoConfigsRecord
|
|
28
27
|
|
|
29
28
|
NODE_UNAVAILABLE_ERROR_REASON = (
|
|
30
29
|
"Error: Node Unavailable - The destination node is currently unavailable. "
|
|
31
30
|
"It exceeds the time limit specified in its last ping."
|
|
32
31
|
)
|
|
33
32
|
|
|
33
|
+
VALID_RUN_STATUS_TRANSITIONS = {
|
|
34
|
+
(Status.PENDING, Status.STARTING),
|
|
35
|
+
(Status.STARTING, Status.RUNNING),
|
|
36
|
+
(Status.RUNNING, Status.FINISHED),
|
|
37
|
+
}
|
|
38
|
+
VALID_RUN_SUB_STATUSES = {
|
|
39
|
+
SubStatus.COMPLETED,
|
|
40
|
+
SubStatus.FAILED,
|
|
41
|
+
SubStatus.STOPPED,
|
|
42
|
+
}
|
|
43
|
+
|
|
34
44
|
|
|
35
45
|
def generate_rand_int_from_bytes(num_bytes: int) -> int:
|
|
36
46
|
"""Generate a random unsigned integer from `num_bytes` bytes."""
|
|
@@ -123,26 +133,67 @@ def convert_sint64_values_in_dict_to_uint64(
|
|
|
123
133
|
data_dict[key] = convert_sint64_to_uint64(data_dict[key])
|
|
124
134
|
|
|
125
135
|
|
|
126
|
-
def
|
|
127
|
-
"""
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
code=ErrorCode.NODE_UNAVAILABLE, reason=NODE_UNAVAILABLE_ERROR_REASON
|
|
146
|
-
),
|
|
147
|
-
),
|
|
136
|
+
def context_to_bytes(context: Context) -> bytes:
|
|
137
|
+
"""Serialize `Context` to bytes."""
|
|
138
|
+
return serde.context_to_proto(context).SerializeToString()
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def context_from_bytes(context_bytes: bytes) -> Context:
|
|
142
|
+
"""Deserialize `Context` from bytes."""
|
|
143
|
+
return serde.context_from_proto(ProtoContext.FromString(context_bytes))
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def configsrecord_to_bytes(configs_record: ConfigsRecord) -> bytes:
|
|
147
|
+
"""Serialize a `ConfigsRecord` to bytes."""
|
|
148
|
+
return serde.configs_record_to_proto(configs_record).SerializeToString()
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def configsrecord_from_bytes(configsrecord_bytes: bytes) -> ConfigsRecord:
|
|
152
|
+
"""Deserialize `ConfigsRecord` from bytes."""
|
|
153
|
+
return serde.configs_record_from_proto(
|
|
154
|
+
ProtoConfigsRecord.FromString(configsrecord_bytes)
|
|
148
155
|
)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def is_valid_transition(current_status: RunStatus, new_status: RunStatus) -> bool:
|
|
159
|
+
"""Check if a transition between two run statuses is valid.
|
|
160
|
+
|
|
161
|
+
Parameters
|
|
162
|
+
----------
|
|
163
|
+
current_status : RunStatus
|
|
164
|
+
The current status of the run.
|
|
165
|
+
new_status : RunStatus
|
|
166
|
+
The new status to transition to.
|
|
167
|
+
|
|
168
|
+
Returns
|
|
169
|
+
-------
|
|
170
|
+
bool
|
|
171
|
+
True if the transition is valid, False otherwise.
|
|
172
|
+
"""
|
|
173
|
+
return (
|
|
174
|
+
current_status.status,
|
|
175
|
+
new_status.status,
|
|
176
|
+
) in VALID_RUN_STATUS_TRANSITIONS
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def has_valid_sub_status(status: RunStatus) -> bool:
|
|
180
|
+
"""Check if the 'sub_status' field of the given status is valid.
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
status : RunStatus
|
|
185
|
+
The status object to be checked.
|
|
186
|
+
|
|
187
|
+
Returns
|
|
188
|
+
-------
|
|
189
|
+
bool
|
|
190
|
+
True if the status object has a valid sub-status, False otherwise.
|
|
191
|
+
|
|
192
|
+
Notes
|
|
193
|
+
-----
|
|
194
|
+
Only an empty string (i.e., "") is considered a valid sub-status for
|
|
195
|
+
non-finished statuses. The sub-status of a finished status cannot be empty.
|
|
196
|
+
"""
|
|
197
|
+
if status.status == Status.FINISHED:
|
|
198
|
+
return status.sub_status in VALID_RUN_SUB_STATUSES
|
|
199
|
+
return status.sub_status == ""
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Flower SimulationIo service."""
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""SimulationIo gRPC API."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from logging import INFO
|
|
19
|
+
from typing import Optional
|
|
20
|
+
|
|
21
|
+
import grpc
|
|
22
|
+
|
|
23
|
+
from flwr.common import GRPC_MAX_MESSAGE_LENGTH
|
|
24
|
+
from flwr.common.logger import log
|
|
25
|
+
from flwr.proto.simulationio_pb2_grpc import ( # pylint: disable=E0611
|
|
26
|
+
add_SimulationIoServicer_to_server,
|
|
27
|
+
)
|
|
28
|
+
from flwr.server.superlink.ffs.ffs_factory import FfsFactory
|
|
29
|
+
from flwr.server.superlink.linkstate import LinkStateFactory
|
|
30
|
+
|
|
31
|
+
from ..fleet.grpc_bidi.grpc_server import generic_create_grpc_server
|
|
32
|
+
from .simulationio_servicer import SimulationIoServicer
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def run_simulationio_api_grpc(
|
|
36
|
+
address: str,
|
|
37
|
+
state_factory: LinkStateFactory,
|
|
38
|
+
ffs_factory: FfsFactory,
|
|
39
|
+
certificates: Optional[tuple[bytes, bytes, bytes]],
|
|
40
|
+
) -> grpc.Server:
|
|
41
|
+
"""Run SimulationIo API (gRPC, request-response)."""
|
|
42
|
+
# Create SimulationIo API gRPC server
|
|
43
|
+
simulationio_servicer: grpc.Server = SimulationIoServicer(
|
|
44
|
+
state_factory=state_factory,
|
|
45
|
+
ffs_factory=ffs_factory,
|
|
46
|
+
)
|
|
47
|
+
simulationio_add_servicer_to_server_fn = add_SimulationIoServicer_to_server
|
|
48
|
+
simulationio_grpc_server = generic_create_grpc_server(
|
|
49
|
+
servicer_and_add_fn=(
|
|
50
|
+
simulationio_servicer,
|
|
51
|
+
simulationio_add_servicer_to_server_fn,
|
|
52
|
+
),
|
|
53
|
+
server_address=address,
|
|
54
|
+
max_message_length=GRPC_MAX_MESSAGE_LENGTH,
|
|
55
|
+
certificates=certificates,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
log(
|
|
59
|
+
INFO,
|
|
60
|
+
"Flower Simulation Engine: Starting SimulationIo API on %s",
|
|
61
|
+
address,
|
|
62
|
+
)
|
|
63
|
+
simulationio_grpc_server.start()
|
|
64
|
+
|
|
65
|
+
return simulationio_grpc_server
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""SimulationIo API servicer."""
|
|
16
|
+
|
|
17
|
+
import threading
|
|
18
|
+
from logging import DEBUG, INFO
|
|
19
|
+
|
|
20
|
+
import grpc
|
|
21
|
+
from grpc import ServicerContext
|
|
22
|
+
|
|
23
|
+
from flwr.common.constant import Status
|
|
24
|
+
from flwr.common.logger import log
|
|
25
|
+
from flwr.common.serde import (
|
|
26
|
+
configs_record_to_proto,
|
|
27
|
+
context_from_proto,
|
|
28
|
+
context_to_proto,
|
|
29
|
+
fab_to_proto,
|
|
30
|
+
run_status_from_proto,
|
|
31
|
+
run_to_proto,
|
|
32
|
+
)
|
|
33
|
+
from flwr.common.typing import Fab, RunStatus
|
|
34
|
+
from flwr.proto import simulationio_pb2_grpc
|
|
35
|
+
from flwr.proto.log_pb2 import ( # pylint: disable=E0611
|
|
36
|
+
PushLogsRequest,
|
|
37
|
+
PushLogsResponse,
|
|
38
|
+
)
|
|
39
|
+
from flwr.proto.run_pb2 import ( # pylint: disable=E0611
|
|
40
|
+
GetFederationOptionsRequest,
|
|
41
|
+
GetFederationOptionsResponse,
|
|
42
|
+
UpdateRunStatusRequest,
|
|
43
|
+
UpdateRunStatusResponse,
|
|
44
|
+
)
|
|
45
|
+
from flwr.proto.simulationio_pb2 import ( # pylint: disable=E0611
|
|
46
|
+
PullSimulationInputsRequest,
|
|
47
|
+
PullSimulationInputsResponse,
|
|
48
|
+
PushSimulationOutputsRequest,
|
|
49
|
+
PushSimulationOutputsResponse,
|
|
50
|
+
)
|
|
51
|
+
from flwr.server.superlink.ffs.ffs_factory import FfsFactory
|
|
52
|
+
from flwr.server.superlink.linkstate import LinkStateFactory
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class SimulationIoServicer(simulationio_pb2_grpc.SimulationIoServicer):
|
|
56
|
+
"""SimulationIo API servicer."""
|
|
57
|
+
|
|
58
|
+
def __init__(
|
|
59
|
+
self, state_factory: LinkStateFactory, ffs_factory: FfsFactory
|
|
60
|
+
) -> None:
|
|
61
|
+
self.state_factory = state_factory
|
|
62
|
+
self.ffs_factory = ffs_factory
|
|
63
|
+
self.lock = threading.RLock()
|
|
64
|
+
|
|
65
|
+
def PullSimulationInputs(
|
|
66
|
+
self, request: PullSimulationInputsRequest, context: ServicerContext
|
|
67
|
+
) -> PullSimulationInputsResponse:
|
|
68
|
+
"""Pull SimultionIo process inputs."""
|
|
69
|
+
log(DEBUG, "SimultionIoServicer.SimultionIoInputs")
|
|
70
|
+
# Init access to LinkState and Ffs
|
|
71
|
+
state = self.state_factory.state()
|
|
72
|
+
ffs = self.ffs_factory.ffs()
|
|
73
|
+
|
|
74
|
+
# Lock access to LinkState, preventing obtaining the same pending run_id
|
|
75
|
+
with self.lock:
|
|
76
|
+
# Attempt getting the run_id of a pending run
|
|
77
|
+
run_id = state.get_pending_run_id()
|
|
78
|
+
# If there's no pending run, return an empty response
|
|
79
|
+
if run_id is None:
|
|
80
|
+
return PullSimulationInputsResponse()
|
|
81
|
+
|
|
82
|
+
# Retrieve Context, Run and Fab for the run_id
|
|
83
|
+
serverapp_ctxt = state.get_serverapp_context(run_id)
|
|
84
|
+
run = state.get_run(run_id)
|
|
85
|
+
fab = None
|
|
86
|
+
if run and run.fab_hash:
|
|
87
|
+
if result := ffs.get(run.fab_hash):
|
|
88
|
+
fab = Fab(run.fab_hash, result[0])
|
|
89
|
+
if run and fab and serverapp_ctxt:
|
|
90
|
+
# Update run status to STARTING
|
|
91
|
+
if state.update_run_status(run_id, RunStatus(Status.STARTING, "", "")):
|
|
92
|
+
log(INFO, "Starting run %d", run_id)
|
|
93
|
+
return PullSimulationInputsResponse(
|
|
94
|
+
context=context_to_proto(serverapp_ctxt),
|
|
95
|
+
run=run_to_proto(run),
|
|
96
|
+
fab=fab_to_proto(fab),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Raise an exception if the Run or Fab is not found,
|
|
100
|
+
# or if the status cannot be updated to STARTING
|
|
101
|
+
raise RuntimeError(f"Failed to start run {run_id}")
|
|
102
|
+
|
|
103
|
+
def PushSimulationOutputs(
|
|
104
|
+
self, request: PushSimulationOutputsRequest, context: ServicerContext
|
|
105
|
+
) -> PushSimulationOutputsResponse:
|
|
106
|
+
"""Push Simulation process outputs."""
|
|
107
|
+
log(DEBUG, "SimultionIoServicer.PushSimulationOutputs")
|
|
108
|
+
state = self.state_factory.state()
|
|
109
|
+
state.set_serverapp_context(request.run_id, context_from_proto(request.context))
|
|
110
|
+
return PushSimulationOutputsResponse()
|
|
111
|
+
|
|
112
|
+
def UpdateRunStatus(
|
|
113
|
+
self, request: UpdateRunStatusRequest, context: grpc.ServicerContext
|
|
114
|
+
) -> UpdateRunStatusResponse:
|
|
115
|
+
"""Update the status of a run."""
|
|
116
|
+
log(DEBUG, "SimultionIoServicer.UpdateRunStatus")
|
|
117
|
+
state = self.state_factory.state()
|
|
118
|
+
|
|
119
|
+
# Update the run status
|
|
120
|
+
state.update_run_status(
|
|
121
|
+
run_id=request.run_id, new_status=run_status_from_proto(request.run_status)
|
|
122
|
+
)
|
|
123
|
+
return UpdateRunStatusResponse()
|
|
124
|
+
|
|
125
|
+
def PushLogs(
|
|
126
|
+
self, request: PushLogsRequest, context: grpc.ServicerContext
|
|
127
|
+
) -> PushLogsResponse:
|
|
128
|
+
"""Push logs."""
|
|
129
|
+
log(DEBUG, "SimultionIoServicer.PushLogs")
|
|
130
|
+
state = self.state_factory.state()
|
|
131
|
+
|
|
132
|
+
# Add logs to LinkState
|
|
133
|
+
merged_logs = "".join(request.logs)
|
|
134
|
+
state.add_serverapp_log(request.run_id, merged_logs)
|
|
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,12 +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
|
|
22
|
+
from flwr.simulation.simulationio_connection import SimulationIoConnection
|
|
21
23
|
|
|
22
24
|
is_ray_installed = importlib.util.find_spec("ray") is not None
|
|
23
25
|
|
|
24
26
|
if is_ray_installed:
|
|
25
|
-
from flwr.simulation.
|
|
27
|
+
from flwr.simulation.legacy_app import start_simulation
|
|
26
28
|
else:
|
|
27
29
|
RAY_IMPORT_ERROR: str = """Unable to import module `ray`.
|
|
28
30
|
|
|
@@ -37,6 +39,8 @@ To install the necessary dependencies, install `flwr` with the `simulation` extr
|
|
|
37
39
|
|
|
38
40
|
|
|
39
41
|
__all__ = [
|
|
42
|
+
"SimulationIoConnection",
|
|
40
43
|
"run_simulation",
|
|
44
|
+
"run_simulation_process",
|
|
41
45
|
"start_simulation",
|
|
42
46
|
]
|