flwr-nightly 1.21.0.dev20250818__py3-none-any.whl → 1.21.0.dev20250820__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/common/exit/exit.py CHANGED
@@ -22,11 +22,14 @@ from logging import ERROR, INFO
22
22
  from typing import Any, NoReturn
23
23
 
24
24
  from flwr.common import EventType, event
25
+ from flwr.common.version import package_version
25
26
 
26
27
  from ..logger import log
27
28
  from .exit_code import EXIT_CODE_HELP
28
29
 
29
- HELP_PAGE_URL = "https://flower.ai/docs/framework/ref-exit-codes/"
30
+ HELP_PAGE_URL = (
31
+ f"https://flower.ai/docs/framework/v{package_version}/en/ref-exit-codes/"
32
+ )
30
33
 
31
34
 
32
35
  def flwr_exit(
@@ -34,18 +34,14 @@ class ExitCode:
34
34
  SUPERLINK_LICENSE_URL_INVALID = 103
35
35
  SUPERLINK_INVALID_ARGS = 104
36
36
 
37
- # ServerApp-specific exit codes (200-299)
38
-
39
37
  # SuperNode-specific exit codes (300-399)
40
38
  SUPERNODE_REST_ADDRESS_INVALID = 300
41
39
  SUPERNODE_NODE_AUTH_KEYS_REQUIRED = 301
42
40
  SUPERNODE_NODE_AUTH_KEYS_INVALID = 302
43
41
 
44
- # ClientApp-specific exit codes (400-499)
45
-
46
- # Simulation-specific exit codes (500-599)
42
+ # SuperExec-specific exit codes (400-499)
47
43
 
48
- # Common exit codes (600-)
44
+ # Common exit codes (600-699)
49
45
  COMMON_ADDRESS_INVALID = 600
50
46
  COMMON_MISSING_EXTRA_REST = 601
51
47
  COMMON_TLS_NOT_SUPPORTED = 602
@@ -80,7 +76,6 @@ EXIT_CODE_HELP = {
80
76
  "Invalid arguments provided to SuperLink. Use `--help` check for the correct "
81
77
  "usage. Alternatively, check the documentation."
82
78
  ),
83
- # ServerApp-specific exit codes (200-299)
84
79
  # SuperNode-specific exit codes (300-399)
85
80
  ExitCode.SUPERNODE_REST_ADDRESS_INVALID: (
86
81
  "When using the REST API, please provide `https://` or "
@@ -96,9 +91,8 @@ EXIT_CODE_HELP = {
96
91
  "Please ensure that the file path points to a valid private/public key "
97
92
  "file and try again."
98
93
  ),
99
- # ClientApp-specific exit codes (400-499)
100
- # Simulation-specific exit codes (500-599)
101
- # Common exit codes (600-)
94
+ # SuperExec-specific exit codes (400-499)
95
+ # Common exit codes (600-699)
102
96
  ExitCode.COMMON_ADDRESS_INVALID: (
103
97
  "Please provide a valid URL, IPv4 or IPv6 address."
104
98
  ),
flwr/common/logger.py CHANGED
@@ -132,13 +132,13 @@ if log_level := os.getenv("FLWR_LOG_LEVEL"):
132
132
  log_level = log_level.upper()
133
133
  try:
134
134
  is_debug = log_level == "DEBUG"
135
+ update_console_handler(level=log_level, timestamps=is_debug, colored=True)
135
136
  if is_debug:
136
137
  log(
137
138
  WARN,
138
139
  "DEBUG logs enabled. Do not use this in production, as it may expose "
139
140
  "sensitive details.",
140
141
  )
141
- update_console_handler(level=log_level, timestamps=is_debug, colored=True)
142
142
  except Exception: # pylint: disable=broad-exception-caught
143
143
  # Alert user but don't raise exception
144
144
  log(
flwr/server/app.py CHANGED
@@ -37,7 +37,7 @@ from flwr.common import GRPC_MAX_MESSAGE_LENGTH, EventType, event
37
37
  from flwr.common.address import parse_address
38
38
  from flwr.common.args import try_obtain_server_certificates
39
39
  from flwr.common.auth_plugin import ControlAuthPlugin, ControlAuthzPlugin
40
- from flwr.common.config import get_flwr_dir, parse_config_args
40
+ from flwr.common.config import get_flwr_dir
41
41
  from flwr.common.constant import (
42
42
  AUTH_TYPE_YAML_KEY,
43
43
  AUTHZ_TYPE_YAML_KEY,
@@ -71,7 +71,6 @@ from flwr.proto.grpcadapter_pb2_grpc import add_GrpcAdapterServicer_to_server
71
71
  from flwr.server.fleet_event_log_interceptor import FleetEventLogInterceptor
72
72
  from flwr.supercore.ffs import FfsFactory
73
73
  from flwr.supercore.object_store import ObjectStoreFactory
74
- from flwr.superlink.executor import load_executor
75
74
  from flwr.superlink.servicer.control import run_control_api_grpc
76
75
 
77
76
  from .superlink.fleet.grpc_adapter.grpc_adapter_servicer import GrpcAdapterServicer
@@ -136,6 +135,15 @@ def run_superlink() -> None:
136
135
  WARN, "The `--flwr-dir` option is currently not in use and will be ignored."
137
136
  )
138
137
 
138
+ # Detect if `--executor*` arguments were set
139
+ if args.executor or args.executor_dir or args.executor_config:
140
+ flwr_exit(
141
+ ExitCode.SUPERLINK_INVALID_ARGS,
142
+ "The arguments `--executor`, `--executor-dir`, and `--executor-config` are "
143
+ "deprecated and will be removed in a future release. To run SuperLink with "
144
+ "the SimulationIo API, please use `--simulation`.",
145
+ )
146
+
139
147
  # Detect if both Control API and Exec API addresses were set explicitly
140
148
  explicit_args = set()
141
149
  for arg in sys.argv[1:]:
@@ -198,26 +206,19 @@ def run_superlink() -> None:
198
206
  objectstore_factory = ObjectStoreFactory()
199
207
 
200
208
  # Start Control API
201
- executor = load_executor(args)
209
+ is_simulation = args.simulation
202
210
  control_server: grpc.Server = run_control_api_grpc(
203
211
  address=control_address,
204
212
  state_factory=state_factory,
205
213
  ffs_factory=ffs_factory,
206
214
  objectstore_factory=objectstore_factory,
207
- executor=executor,
208
215
  certificates=certificates,
209
- config=parse_config_args(
210
- [args.executor_config] if args.executor_config else args.executor_config
211
- ),
216
+ is_simulation=is_simulation,
212
217
  auth_plugin=auth_plugin,
213
218
  authz_plugin=authz_plugin,
214
219
  event_log_plugin=event_log_plugin,
215
220
  )
216
221
  grpc_servers = [control_server]
217
-
218
- # Determine Exec plugin
219
- # If simulation is used, don't start ServerAppIo and Fleet APIs
220
- is_simulation = executor.__class__.__qualname__ == "SimulationEngine"
221
222
  bckg_threads: list[threading.Thread] = []
222
223
 
223
224
  if is_simulation:
@@ -518,7 +519,9 @@ def _run_fleet_api_grpc_rere( # pylint: disable=R0913, R0917
518
519
  interceptors=interceptors,
519
520
  )
520
521
 
521
- log(INFO, "Flower ECE: Starting Fleet API (gRPC-rere) on %s", address)
522
+ log(
523
+ INFO, "Flower Deployment Runtime: Starting Fleet API (gRPC-rere) on %s", address
524
+ )
522
525
  fleet_grpc_server.start()
523
526
 
524
527
  return fleet_grpc_server
@@ -546,7 +549,11 @@ def _run_fleet_api_grpc_adapter(
546
549
  certificates=certificates,
547
550
  )
548
551
 
549
- log(INFO, "Flower ECE: Starting Fleet API (GrpcAdapter) on %s", address)
552
+ log(
553
+ INFO,
554
+ "Flower Deployment Runtime: Starting Fleet API (GrpcAdapter) on %s",
555
+ address,
556
+ )
550
557
  fleet_grpc_server.start()
551
558
 
552
559
  return fleet_grpc_server
@@ -741,20 +748,25 @@ def _add_args_control_api(parser: argparse.ArgumentParser) -> None:
741
748
  )
742
749
  parser.add_argument(
743
750
  "--executor",
744
- help="For example: `deployment:exec` or `project.package.module:wrapper.exec`. "
745
- "The default is `flwr.superexec.deployment:executor`",
746
- default="flwr.superexec.deployment:executor",
751
+ help="This argument is deprecated and will be removed in a future release.",
752
+ default=None,
747
753
  )
748
754
  parser.add_argument(
749
755
  "--executor-dir",
750
- help="The directory for the executor.",
751
- default=".",
756
+ help="This argument is deprecated and will be removed in a future release.",
757
+ default=None,
752
758
  )
753
759
  parser.add_argument(
754
760
  "--executor-config",
755
- help="Key-value pairs for the executor config, separated by spaces. "
756
- "For example:\n\n`--executor-config 'verbose=true "
757
- 'root-certificates="certificates/superlink-ca.crt"\'`',
761
+ help="This argument is deprecated and will be removed in a future release.",
762
+ default=None,
763
+ )
764
+ parser.add_argument(
765
+ "--simulation",
766
+ action="store_true",
767
+ default=False,
768
+ help="Launch the SimulationIo API server in place of "
769
+ "the ServerAppIo API server.",
758
770
  )
759
771
 
760
772
 
@@ -384,6 +384,7 @@ class GrpcGrid(Grid):
384
384
  """
385
385
  # Push messages
386
386
  msg_ids = set(self.push_messages(messages))
387
+ del messages
387
388
 
388
389
  # Pull messages
389
390
  end_time = time.time() + (timeout if timeout is not None else 0.0)
@@ -153,6 +153,7 @@ class InMemoryGrid(Grid):
153
153
  """
154
154
  # Push messages
155
155
  msg_ids = set(self.push_messages(messages))
156
+ del messages
156
157
 
157
158
  # Pull messages
158
159
  end_time = time.time() + (timeout if timeout is not None else 0.0)
@@ -16,7 +16,6 @@
16
16
 
17
17
 
18
18
  import argparse
19
- import gc
20
19
  from logging import DEBUG, ERROR, INFO
21
20
  from pathlib import Path
22
21
  from queue import Queue
@@ -65,7 +64,7 @@ from flwr.proto.run_pb2 import UpdateRunStatusRequest # pylint: disable=E0611
65
64
  from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
66
65
  from flwr.server.grid.grpc_grid import GrpcGrid
67
66
  from flwr.server.run_serverapp import run as run_
68
- from flwr.supercore.app_utils import simple_get_token, start_parent_process_monitor
67
+ from flwr.supercore.app_utils import start_parent_process_monitor
69
68
  from flwr.supercore.superexec.plugin import ServerAppExecPlugin
70
69
  from flwr.supercore.superexec.run_superexec import run_with_deprecation_warning
71
70
 
@@ -109,7 +108,6 @@ def flwr_serverapp() -> None:
109
108
  serverappio_api_address=args.serverappio_api_address,
110
109
  log_queue=log_queue,
111
110
  token=args.token,
112
- run_once=(args.token is not None) or args.run_once,
113
111
  flwr_dir=args.flwr_dir,
114
112
  certificates=None,
115
113
  parent_pid=args.parent_pid,
@@ -122,8 +120,7 @@ def flwr_serverapp() -> None:
122
120
  def run_serverapp( # pylint: disable=R0913, R0914, R0915, R0917, W0212
123
121
  serverappio_api_address: str,
124
122
  log_queue: Queue[Optional[str]],
125
- run_once: bool,
126
- token: Optional[str] = None,
123
+ token: str,
127
124
  flwr_dir: Optional[str] = None,
128
125
  certificates: Optional[bytes] = None,
129
126
  parent_pid: Optional[int] = None,
@@ -142,154 +139,133 @@ def run_serverapp( # pylint: disable=R0913, R0914, R0915, R0917, W0212
142
139
  heartbeat_sender = None
143
140
  grid = None
144
141
  context = None
145
- while True:
146
142
 
147
- try:
148
- # Initialize the GrpcGrid
149
- grid = GrpcGrid(
150
- serverappio_service_address=serverappio_api_address,
151
- root_certificates=certificates,
152
- )
143
+ try:
144
+ # Initialize the GrpcGrid
145
+ grid = GrpcGrid(
146
+ serverappio_service_address=serverappio_api_address,
147
+ root_certificates=certificates,
148
+ )
153
149
 
154
- # If token is not set, loop until token is received from SuperLink
155
- if token is None:
156
- log(DEBUG, "[flwr-serverapp] Request token")
157
- token = simple_get_token(grid._stub)
158
-
159
- # Pull ServerAppInputs from LinkState
160
- req = PullAppInputsRequest(token=token)
161
- log(DEBUG, "[flwr-serverapp] Pull ServerAppInputs")
162
- res: PullAppInputsResponse = grid._stub.PullAppInputs(req)
163
- context = context_from_proto(res.context)
164
- run = run_from_proto(res.run)
165
- fab = fab_from_proto(res.fab)
166
-
167
- hash_run_id = get_sha256_hash(run.run_id)
168
-
169
- grid.set_run(run.run_id)
170
-
171
- # Start log uploader for this run
172
- log_uploader = start_log_uploader(
173
- log_queue=log_queue,
174
- node_id=0,
175
- run_id=run.run_id,
176
- stub=grid._stub,
177
- )
150
+ # Pull ServerAppInputs from LinkState
151
+ req = PullAppInputsRequest(token=token)
152
+ log(DEBUG, "[flwr-serverapp] Pull ServerAppInputs")
153
+ res: PullAppInputsResponse = grid._stub.PullAppInputs(req)
154
+ context = context_from_proto(res.context)
155
+ run = run_from_proto(res.run)
156
+ fab = fab_from_proto(res.fab)
178
157
 
179
- log(DEBUG, "[flwr-serverapp] Start FAB installation.")
180
- install_from_fab(fab.content, flwr_dir=flwr_dir_, skip_prompt=True)
158
+ hash_run_id = get_sha256_hash(run.run_id)
181
159
 
182
- fab_id, fab_version = get_fab_metadata(fab.content)
160
+ grid.set_run(run.run_id)
183
161
 
184
- app_path = str(
185
- get_project_dir(fab_id, fab_version, fab.hash_str, flwr_dir_)
186
- )
187
- config = get_project_config(app_path)
162
+ # Start log uploader for this run
163
+ log_uploader = start_log_uploader(
164
+ log_queue=log_queue,
165
+ node_id=0,
166
+ run_id=run.run_id,
167
+ stub=grid._stub,
168
+ )
188
169
 
189
- # Obtain server app reference and the run config
190
- server_app_attr = config["tool"]["flwr"]["app"]["components"]["serverapp"]
191
- server_app_run_config = get_fused_config_from_dir(
192
- Path(app_path), run.override_config
193
- )
170
+ log(DEBUG, "[flwr-serverapp] Start FAB installation.")
171
+ install_from_fab(fab.content, flwr_dir=flwr_dir_, skip_prompt=True)
194
172
 
195
- # Update run_config in context
196
- context.run_config = server_app_run_config
173
+ fab_id, fab_version = get_fab_metadata(fab.content)
197
174
 
198
- log(
199
- DEBUG,
200
- "[flwr-serverapp] Will load ServerApp `%s` in %s",
201
- server_app_attr,
202
- app_path,
203
- )
175
+ app_path = str(get_project_dir(fab_id, fab_version, fab.hash_str, flwr_dir_))
176
+ config = get_project_config(app_path)
204
177
 
205
- # Change status to Running
206
- run_status_proto = run_status_to_proto(RunStatus(Status.RUNNING, "", ""))
207
- grid._stub.UpdateRunStatus(
208
- UpdateRunStatusRequest(run_id=run.run_id, run_status=run_status_proto)
209
- )
178
+ # Obtain server app reference and the run config
179
+ server_app_attr = config["tool"]["flwr"]["app"]["components"]["serverapp"]
180
+ server_app_run_config = get_fused_config_from_dir(
181
+ Path(app_path), run.override_config
182
+ )
210
183
 
211
- event(
212
- EventType.FLWR_SERVERAPP_RUN_ENTER,
213
- event_details={"run-id-hash": hash_run_id},
214
- )
184
+ # Update run_config in context
185
+ context.run_config = server_app_run_config
215
186
 
216
- # Set up heartbeat sender
217
- heartbeat_fn = get_grpc_app_heartbeat_fn(
218
- grid._stub,
219
- run.run_id,
220
- failure_message="Heartbeat failed unexpectedly. The SuperLink could "
221
- "not find the provided run ID, or the run status is invalid.",
222
- )
223
- heartbeat_sender = HeartbeatSender(heartbeat_fn)
224
- heartbeat_sender.start()
225
-
226
- # Load and run the ServerApp with the Grid
227
- updated_context = run_(
228
- grid=grid,
229
- server_app_dir=app_path,
230
- server_app_attr=server_app_attr,
231
- context=context,
232
- )
187
+ log(
188
+ DEBUG,
189
+ "[flwr-serverapp] Will load ServerApp `%s` in %s",
190
+ server_app_attr,
191
+ app_path,
192
+ )
233
193
 
234
- # Send resulting context
235
- context_proto = context_to_proto(updated_context)
236
- log(DEBUG, "[flwr-serverapp] Will push ServerAppOutputs")
237
- out_req = PushAppOutputsRequest(
238
- token=token, run_id=run.run_id, context=context_proto
239
- )
240
- _ = grid._stub.PushAppOutputs(out_req)
241
-
242
- run_status = RunStatus(Status.FINISHED, SubStatus.COMPLETED, "")
243
- except RunNotRunningException:
244
- log(INFO, "")
245
- log(INFO, "Run ID %s stopped.", run.run_id)
246
- log(INFO, "")
247
- run_status = None
248
- success = False
249
-
250
- except Exception as ex: # pylint: disable=broad-exception-caught
251
- exc_entity = "ServerApp"
252
- log(ERROR, "%s raised an exception", exc_entity, exc_info=ex)
253
- run_status = RunStatus(Status.FINISHED, SubStatus.FAILED, str(ex))
254
- success = False
255
-
256
- finally:
257
- # Stop heartbeat sender
258
- if heartbeat_sender:
259
- heartbeat_sender.stop()
260
- heartbeat_sender = None
261
-
262
- # Stop log uploader for this run and upload final logs
263
- if log_uploader:
264
- stop_log_uploader(log_queue, log_uploader)
265
- log_uploader = None
266
-
267
- # Update run status
268
- if run_status and grid:
269
- run_status_proto = run_status_to_proto(run_status)
270
- grid._stub.UpdateRunStatus(
271
- UpdateRunStatusRequest(
272
- run_id=run.run_id, run_status=run_status_proto
273
- )
274
- )
275
-
276
- # Close the Grpc connection
277
- if grid:
278
- grid.close()
279
-
280
- # Clean up the Context and the token
281
- context = None
282
- token = None
283
- gc.collect()
284
-
285
- event(
286
- EventType.FLWR_SERVERAPP_RUN_LEAVE,
287
- event_details={"run-id-hash": hash_run_id, "success": success},
194
+ # Change status to Running
195
+ run_status_proto = run_status_to_proto(RunStatus(Status.RUNNING, "", ""))
196
+ grid._stub.UpdateRunStatus(
197
+ UpdateRunStatusRequest(run_id=run.run_id, run_status=run_status_proto)
198
+ )
199
+
200
+ event(
201
+ EventType.FLWR_SERVERAPP_RUN_ENTER,
202
+ event_details={"run-id-hash": hash_run_id},
203
+ )
204
+
205
+ # Set up heartbeat sender
206
+ heartbeat_fn = get_grpc_app_heartbeat_fn(
207
+ grid._stub,
208
+ run.run_id,
209
+ failure_message="Heartbeat failed unexpectedly. The SuperLink could "
210
+ "not find the provided run ID, or the run status is invalid.",
211
+ )
212
+ heartbeat_sender = HeartbeatSender(heartbeat_fn)
213
+ heartbeat_sender.start()
214
+
215
+ # Load and run the ServerApp with the Grid
216
+ updated_context = run_(
217
+ grid=grid,
218
+ server_app_dir=app_path,
219
+ server_app_attr=server_app_attr,
220
+ context=context,
221
+ )
222
+
223
+ # Send resulting context
224
+ context_proto = context_to_proto(updated_context)
225
+ log(DEBUG, "[flwr-serverapp] Will push ServerAppOutputs")
226
+ out_req = PushAppOutputsRequest(
227
+ token=token, run_id=run.run_id, context=context_proto
228
+ )
229
+ _ = grid._stub.PushAppOutputs(out_req)
230
+
231
+ run_status = RunStatus(Status.FINISHED, SubStatus.COMPLETED, "")
232
+ except RunNotRunningException:
233
+ log(INFO, "")
234
+ log(INFO, "Run ID %s stopped.", run.run_id)
235
+ log(INFO, "")
236
+ run_status = None
237
+ success = False
238
+
239
+ except Exception as ex: # pylint: disable=broad-exception-caught
240
+ exc_entity = "ServerApp"
241
+ log(ERROR, "%s raised an exception", exc_entity, exc_info=ex)
242
+ run_status = RunStatus(Status.FINISHED, SubStatus.FAILED, str(ex))
243
+ success = False
244
+
245
+ finally:
246
+ # Stop heartbeat sender
247
+ if heartbeat_sender:
248
+ heartbeat_sender.stop()
249
+
250
+ # Stop log uploader for this run and upload final logs
251
+ if log_uploader:
252
+ stop_log_uploader(log_queue, log_uploader)
253
+
254
+ # Update run status
255
+ if run_status and grid:
256
+ run_status_proto = run_status_to_proto(run_status)
257
+ grid._stub.UpdateRunStatus(
258
+ UpdateRunStatusRequest(run_id=run.run_id, run_status=run_status_proto)
288
259
  )
289
260
 
290
- # Stop the loop if `flwr-serverapp` is expected to process a single run
291
- if run_once:
292
- break
261
+ # Close the Grpc connection
262
+ if grid:
263
+ grid.close()
264
+
265
+ event(
266
+ EventType.FLWR_SERVERAPP_RUN_LEAVE,
267
+ event_details={"run-id-hash": hash_run_id, "success": success},
268
+ )
293
269
 
294
270
 
295
271
  def _parse_args_run_flwr_serverapp() -> argparse.ArgumentParser:
@@ -58,7 +58,7 @@ def run_serverappio_api_grpc(
58
58
  certificates=certificates,
59
59
  )
60
60
 
61
- log(INFO, "Flower ECE: Starting ServerAppIo API (gRPC-rere) on %s", address)
61
+ log(INFO, "Flower Deployment Runtime: Starting ServerAppIo API on %s", address)
62
62
  serverappio_grpc_server.start()
63
63
 
64
64
  return serverappio_grpc_server