flwr-nightly 1.13.0.dev20241109__py3-none-any.whl → 1.13.0.dev20241112__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 +37 -0
- flwr/cli/install.py +5 -3
- flwr/client/clientapp/app.py +21 -16
- flwr/client/supernode/app.py +2 -36
- flwr/common/args.py +148 -0
- flwr/common/logger.py +6 -2
- flwr/server/app.py +47 -76
- flwr/server/serverapp/app.py +15 -71
- flwr/server/superlink/linkstate/in_memory_linkstate.py +5 -0
- flwr/server/superlink/linkstate/linkstate.py +5 -4
- flwr/server/superlink/linkstate/sqlite_linkstate.py +8 -2
- flwr/server/superlink/linkstate/utils.py +11 -0
- flwr/simulation/__init__.py +3 -1
- flwr/simulation/app.py +245 -352
- flwr/simulation/legacy_app.py +382 -0
- flwr/superexec/simulation.py +43 -101
- {flwr_nightly-1.13.0.dev20241109.dist-info → flwr_nightly-1.13.0.dev20241112.dist-info}/METADATA +4 -2
- {flwr_nightly-1.13.0.dev20241109.dist-info → flwr_nightly-1.13.0.dev20241112.dist-info}/RECORD +21 -19
- {flwr_nightly-1.13.0.dev20241109.dist-info → flwr_nightly-1.13.0.dev20241112.dist-info}/entry_points.txt +1 -0
- {flwr_nightly-1.13.0.dev20241109.dist-info → flwr_nightly-1.13.0.dev20241112.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.13.0.dev20241109.dist-info → flwr_nightly-1.13.0.dev20241112.dist-info}/WHEEL +0 -0
flwr/server/serverapp/app.py
CHANGED
|
@@ -15,9 +15,7 @@
|
|
|
15
15
|
"""Flower ServerApp process."""
|
|
16
16
|
|
|
17
17
|
import argparse
|
|
18
|
-
import
|
|
19
|
-
from logging import DEBUG, ERROR, INFO, WARN
|
|
20
|
-
from os.path import isfile
|
|
18
|
+
from logging import DEBUG, ERROR, INFO
|
|
21
19
|
from pathlib import Path
|
|
22
20
|
from queue import Queue
|
|
23
21
|
from time import sleep
|
|
@@ -25,6 +23,7 @@ from typing import Optional
|
|
|
25
23
|
|
|
26
24
|
from flwr.cli.config_utils import get_fab_metadata
|
|
27
25
|
from flwr.cli.install import install_from_fab
|
|
26
|
+
from flwr.common.args import add_args_flwr_app_common, try_obtain_root_certificates
|
|
28
27
|
from flwr.common.config import (
|
|
29
28
|
get_flwr_dir,
|
|
30
29
|
get_fused_config_from_dir,
|
|
@@ -69,54 +68,30 @@ def flwr_serverapp() -> None:
|
|
|
69
68
|
parser.add_argument(
|
|
70
69
|
"--superlink",
|
|
71
70
|
type=str,
|
|
72
|
-
help="Address of SuperLink's
|
|
71
|
+
help="Address of SuperLink's ServerAppIo API",
|
|
73
72
|
)
|
|
74
73
|
parser.add_argument(
|
|
75
74
|
"--run-once",
|
|
76
75
|
action="store_true",
|
|
77
|
-
help="When set, this process will start a single ServerApp "
|
|
78
|
-
"
|
|
79
|
-
)
|
|
80
|
-
parser.add_argument(
|
|
81
|
-
"--flwr-dir",
|
|
82
|
-
default=None,
|
|
83
|
-
help="""The path containing installed Flower Apps.
|
|
84
|
-
By default, this value is equal to:
|
|
85
|
-
|
|
86
|
-
- `$FLWR_HOME/` if `$FLWR_HOME` is defined
|
|
87
|
-
- `$XDG_DATA_HOME/.flwr/` if `$XDG_DATA_HOME` is defined
|
|
88
|
-
- `$HOME/.flwr/` in all other cases
|
|
89
|
-
""",
|
|
90
|
-
)
|
|
91
|
-
parser.add_argument(
|
|
92
|
-
"--insecure",
|
|
93
|
-
action="store_true",
|
|
94
|
-
help="Run the server without HTTPS, regardless of whether certificate "
|
|
95
|
-
"paths are provided. By default, the server runs with HTTPS enabled. "
|
|
96
|
-
"Use this flag only if you understand the risks.",
|
|
97
|
-
)
|
|
98
|
-
parser.add_argument(
|
|
99
|
-
"--root-certificates",
|
|
100
|
-
metavar="ROOT_CERT",
|
|
101
|
-
type=str,
|
|
102
|
-
help="Specifies the path to the PEM-encoded root certificate file for "
|
|
103
|
-
"establishing secure HTTPS connections.",
|
|
76
|
+
help="When set, this process will start a single ServerApp for a pending Run. "
|
|
77
|
+
"If there is no pending Run, the process will exit.",
|
|
104
78
|
)
|
|
79
|
+
add_args_flwr_app_common(parser=parser)
|
|
105
80
|
args = parser.parse_args()
|
|
106
81
|
|
|
107
82
|
log(INFO, "Starting Flower ServerApp")
|
|
108
|
-
certificates =
|
|
83
|
+
certificates = try_obtain_root_certificates(args, args.superlink)
|
|
109
84
|
|
|
110
85
|
log(
|
|
111
86
|
DEBUG,
|
|
112
|
-
"
|
|
87
|
+
"Starting isolated `ServerApp` connected to SuperLink's ServerAppIo API at %s",
|
|
113
88
|
args.superlink,
|
|
114
89
|
)
|
|
115
90
|
run_serverapp(
|
|
116
91
|
superlink=args.superlink,
|
|
117
92
|
log_queue=log_queue,
|
|
118
93
|
run_once=args.run_once,
|
|
119
|
-
|
|
94
|
+
flwr_dir=args.flwr_dir,
|
|
120
95
|
certificates=certificates,
|
|
121
96
|
)
|
|
122
97
|
|
|
@@ -124,44 +99,11 @@ def flwr_serverapp() -> None:
|
|
|
124
99
|
restore_output()
|
|
125
100
|
|
|
126
101
|
|
|
127
|
-
def _try_obtain_certificates(
|
|
128
|
-
args: argparse.Namespace,
|
|
129
|
-
) -> Optional[bytes]:
|
|
130
|
-
|
|
131
|
-
if args.insecure:
|
|
132
|
-
if args.root_certificates is not None:
|
|
133
|
-
sys.exit(
|
|
134
|
-
"Conflicting options: The '--insecure' flag disables HTTPS, "
|
|
135
|
-
"but '--root-certificates' was also specified. Please remove "
|
|
136
|
-
"the '--root-certificates' option when running in insecure mode, "
|
|
137
|
-
"or omit '--insecure' to use HTTPS."
|
|
138
|
-
)
|
|
139
|
-
log(
|
|
140
|
-
WARN,
|
|
141
|
-
"Option `--insecure` was set. Starting insecure HTTP channel to %s.",
|
|
142
|
-
args.superlink,
|
|
143
|
-
)
|
|
144
|
-
root_certificates = None
|
|
145
|
-
else:
|
|
146
|
-
# Load the certificates if provided, or load the system certificates
|
|
147
|
-
if not isfile(args.root_certificates):
|
|
148
|
-
sys.exit("Path argument `--root-certificates` does not point to a file.")
|
|
149
|
-
root_certificates = Path(args.root_certificates).read_bytes()
|
|
150
|
-
log(
|
|
151
|
-
DEBUG,
|
|
152
|
-
"Starting secure HTTPS channel to %s "
|
|
153
|
-
"with the following certificates: %s.",
|
|
154
|
-
args.superlink,
|
|
155
|
-
args.root_certificates,
|
|
156
|
-
)
|
|
157
|
-
return root_certificates
|
|
158
|
-
|
|
159
|
-
|
|
160
102
|
def run_serverapp( # pylint: disable=R0914, disable=W0212
|
|
161
103
|
superlink: str,
|
|
162
104
|
log_queue: Queue[Optional[str]],
|
|
163
105
|
run_once: bool,
|
|
164
|
-
|
|
106
|
+
flwr_dir: Optional[str] = None,
|
|
165
107
|
certificates: Optional[bytes] = None,
|
|
166
108
|
) -> None:
|
|
167
109
|
"""Run Flower ServerApp process."""
|
|
@@ -171,7 +113,7 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212
|
|
|
171
113
|
)
|
|
172
114
|
|
|
173
115
|
# Resolve directory where FABs are installed
|
|
174
|
-
|
|
116
|
+
flwr_dir_ = get_flwr_dir(flwr_dir)
|
|
175
117
|
log_uploader = None
|
|
176
118
|
|
|
177
119
|
while True:
|
|
@@ -200,11 +142,13 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212
|
|
|
200
142
|
)
|
|
201
143
|
|
|
202
144
|
log(DEBUG, "ServerApp process starts FAB installation.")
|
|
203
|
-
install_from_fab(fab.content, flwr_dir=
|
|
145
|
+
install_from_fab(fab.content, flwr_dir=flwr_dir_, skip_prompt=True)
|
|
204
146
|
|
|
205
147
|
fab_id, fab_version = get_fab_metadata(fab.content)
|
|
206
148
|
|
|
207
|
-
app_path = str(
|
|
149
|
+
app_path = str(
|
|
150
|
+
get_project_dir(fab_id, fab_version, fab.hash_str, flwr_dir_)
|
|
151
|
+
)
|
|
208
152
|
config = get_project_config(app_path)
|
|
209
153
|
|
|
210
154
|
# Obtain server app reference and the run config
|
|
@@ -435,6 +435,11 @@ class InMemoryLinkState(LinkState): # pylint: disable=R0902,R0904
|
|
|
435
435
|
"""Retrieve all currently stored `node_public_keys` as a set."""
|
|
436
436
|
return self.node_public_keys
|
|
437
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
|
+
|
|
438
443
|
def get_run(self, run_id: int) -> Optional[Run]:
|
|
439
444
|
"""Retrieve information about the run with the specified `run_id`."""
|
|
440
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
|
|
@@ -902,6 +902,12 @@ class SqliteLinkState(LinkState): # pylint: disable=R0904
|
|
|
902
902
|
result: set[bytes] = {row["public_key"] for row in rows}
|
|
903
903
|
return result
|
|
904
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
|
+
|
|
905
911
|
def get_run(self, run_id: int) -> Optional[Run]:
|
|
906
912
|
"""Retrieve information about the run with the specified `run_id`."""
|
|
907
913
|
# Convert the uint64 value to sint64 for SQLite
|
|
@@ -1249,10 +1255,10 @@ def dict_to_task_res(task_dict: dict[str, Any]) -> TaskRes:
|
|
|
1249
1255
|
def determine_run_status(row: dict[str, Any]) -> str:
|
|
1250
1256
|
"""Determine the status of the run based on timestamp fields."""
|
|
1251
1257
|
if row["pending_at"]:
|
|
1258
|
+
if row["finished_at"]:
|
|
1259
|
+
return Status.FINISHED
|
|
1252
1260
|
if row["starting_at"]:
|
|
1253
1261
|
if row["running_at"]:
|
|
1254
|
-
if row["finished_at"]:
|
|
1255
|
-
return Status.FINISHED
|
|
1256
1262
|
return Status.RUNNING
|
|
1257
1263
|
return Status.STARTING
|
|
1258
1264
|
return Status.PENDING
|
|
@@ -34,6 +34,9 @@ VALID_RUN_STATUS_TRANSITIONS = {
|
|
|
34
34
|
(Status.PENDING, Status.STARTING),
|
|
35
35
|
(Status.STARTING, Status.RUNNING),
|
|
36
36
|
(Status.RUNNING, Status.FINISHED),
|
|
37
|
+
# Any non-FINISHED status can transition to FINISHED
|
|
38
|
+
(Status.PENDING, Status.FINISHED),
|
|
39
|
+
(Status.STARTING, Status.FINISHED),
|
|
37
40
|
}
|
|
38
41
|
VALID_RUN_SUB_STATUSES = {
|
|
39
42
|
SubStatus.COMPLETED,
|
|
@@ -170,6 +173,14 @@ def is_valid_transition(current_status: RunStatus, new_status: RunStatus) -> boo
|
|
|
170
173
|
bool
|
|
171
174
|
True if the transition is valid, False otherwise.
|
|
172
175
|
"""
|
|
176
|
+
# Transition to FINISHED from a non-RUNNING status is only allowed
|
|
177
|
+
# if the sub-status is not COMPLETED
|
|
178
|
+
if (
|
|
179
|
+
current_status.status in [Status.PENDING, Status.STARTING]
|
|
180
|
+
and new_status.status == Status.FINISHED
|
|
181
|
+
):
|
|
182
|
+
return new_status.sub_status != SubStatus.COMPLETED
|
|
183
|
+
|
|
173
184
|
return (
|
|
174
185
|
current_status.status,
|
|
175
186
|
new_status.status,
|
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
|
]
|