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.

@@ -15,9 +15,7 @@
15
15
  """Flower ServerApp process."""
16
16
 
17
17
  import argparse
18
- import sys
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 DriverAPI",
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
- "for a pending Run. If no pending run the process will exit. ",
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 = _try_obtain_certificates(args)
83
+ certificates = try_obtain_root_certificates(args, args.superlink)
109
84
 
110
85
  log(
111
86
  DEBUG,
112
- "Staring isolated `ServerApp` connected to SuperLink DriverAPI at %s",
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
- flwr_dir_=args.flwr_dir,
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
- flwr_dir_: Optional[str] = None,
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
- flwr_dir = get_flwr_dir(flwr_dir_)
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=flwr_dir, skip_prompt=True)
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(get_project_dir(fab_id, fab_version, fab.hash_str, flwr_dir))
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
- A dataclass instance containing three elements if `run_id` is valid:
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,
@@ -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.app import start_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
  ]