flwr-nightly 1.8.0.dev20240315__py3-none-any.whl → 1.11.0.dev20240813__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.

Files changed (237) hide show
  1. flwr/cli/app.py +7 -0
  2. flwr/cli/build.py +150 -0
  3. flwr/cli/config_utils.py +219 -0
  4. flwr/cli/example.py +3 -1
  5. flwr/cli/install.py +227 -0
  6. flwr/cli/new/new.py +179 -48
  7. flwr/cli/new/templates/app/.gitignore.tpl +160 -0
  8. flwr/cli/new/templates/app/README.flowertune.md.tpl +56 -0
  9. flwr/cli/new/templates/app/README.md.tpl +1 -5
  10. flwr/cli/new/templates/app/code/__init__.py.tpl +1 -1
  11. flwr/cli/new/templates/app/code/client.huggingface.py.tpl +65 -0
  12. flwr/cli/new/templates/app/code/client.jax.py.tpl +56 -0
  13. flwr/cli/new/templates/app/code/client.mlx.py.tpl +93 -0
  14. flwr/cli/new/templates/app/code/client.numpy.py.tpl +3 -2
  15. flwr/cli/new/templates/app/code/client.pytorch.py.tpl +23 -11
  16. flwr/cli/new/templates/app/code/client.sklearn.py.tpl +97 -0
  17. flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +60 -1
  18. flwr/cli/new/templates/app/code/flwr_tune/__init__.py +15 -0
  19. flwr/cli/new/templates/app/code/flwr_tune/app.py.tpl +89 -0
  20. flwr/cli/new/templates/app/code/flwr_tune/client.py.tpl +126 -0
  21. flwr/cli/new/templates/app/code/flwr_tune/config.yaml.tpl +34 -0
  22. flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +57 -0
  23. flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +59 -0
  24. flwr/cli/new/templates/app/code/flwr_tune/server.py.tpl +48 -0
  25. flwr/cli/new/templates/app/code/flwr_tune/static_config.yaml.tpl +11 -0
  26. flwr/cli/new/templates/app/code/server.huggingface.py.tpl +23 -0
  27. flwr/cli/new/templates/app/code/server.jax.py.tpl +20 -0
  28. flwr/cli/new/templates/app/code/server.mlx.py.tpl +20 -0
  29. flwr/cli/new/templates/app/code/server.numpy.py.tpl +17 -9
  30. flwr/cli/new/templates/app/code/server.pytorch.py.tpl +21 -18
  31. flwr/cli/new/templates/app/code/server.sklearn.py.tpl +24 -0
  32. flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +29 -1
  33. flwr/cli/new/templates/app/code/task.huggingface.py.tpl +99 -0
  34. flwr/cli/new/templates/app/code/task.jax.py.tpl +57 -0
  35. flwr/cli/new/templates/app/code/task.mlx.py.tpl +102 -0
  36. flwr/cli/new/templates/app/code/task.pytorch.py.tpl +28 -23
  37. flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +53 -0
  38. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +39 -0
  39. flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +38 -0
  40. flwr/cli/new/templates/app/pyproject.jax.toml.tpl +34 -0
  41. flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +39 -0
  42. flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +25 -12
  43. flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +29 -14
  44. flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +33 -0
  45. flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +29 -14
  46. flwr/cli/run/run.py +168 -17
  47. flwr/cli/utils.py +75 -4
  48. flwr/client/__init__.py +6 -1
  49. flwr/client/app.py +239 -248
  50. flwr/client/client_app.py +70 -9
  51. flwr/client/dpfedavg_numpy_client.py +1 -1
  52. flwr/client/grpc_adapter_client/__init__.py +15 -0
  53. flwr/client/grpc_adapter_client/connection.py +97 -0
  54. flwr/client/grpc_client/connection.py +18 -5
  55. flwr/client/grpc_rere_client/__init__.py +1 -1
  56. flwr/client/grpc_rere_client/client_interceptor.py +158 -0
  57. flwr/client/grpc_rere_client/connection.py +127 -33
  58. flwr/client/grpc_rere_client/grpc_adapter.py +140 -0
  59. flwr/client/heartbeat.py +74 -0
  60. flwr/client/message_handler/__init__.py +1 -1
  61. flwr/client/message_handler/message_handler.py +7 -7
  62. flwr/client/mod/__init__.py +5 -5
  63. flwr/client/mod/centraldp_mods.py +4 -2
  64. flwr/client/mod/comms_mods.py +4 -4
  65. flwr/client/mod/localdp_mod.py +9 -4
  66. flwr/client/mod/secure_aggregation/__init__.py +1 -1
  67. flwr/client/mod/secure_aggregation/secaggplus_mod.py +1 -1
  68. flwr/client/mod/utils.py +1 -1
  69. flwr/client/node_state.py +60 -10
  70. flwr/client/node_state_tests.py +4 -3
  71. flwr/client/rest_client/__init__.py +1 -1
  72. flwr/client/rest_client/connection.py +177 -157
  73. flwr/client/supernode/__init__.py +26 -0
  74. flwr/client/supernode/app.py +464 -0
  75. flwr/client/typing.py +1 -0
  76. flwr/common/__init__.py +13 -11
  77. flwr/common/address.py +1 -1
  78. flwr/common/config.py +193 -0
  79. flwr/common/constant.py +42 -1
  80. flwr/common/context.py +26 -1
  81. flwr/common/date.py +1 -1
  82. flwr/common/dp.py +1 -1
  83. flwr/common/grpc.py +6 -2
  84. flwr/common/logger.py +79 -8
  85. flwr/common/message.py +167 -105
  86. flwr/common/object_ref.py +126 -25
  87. flwr/common/record/__init__.py +1 -1
  88. flwr/common/record/parametersrecord.py +0 -1
  89. flwr/common/record/recordset.py +78 -27
  90. flwr/common/recordset_compat.py +8 -1
  91. flwr/common/retry_invoker.py +25 -13
  92. flwr/common/secure_aggregation/__init__.py +1 -1
  93. flwr/common/secure_aggregation/crypto/__init__.py +1 -1
  94. flwr/common/secure_aggregation/crypto/shamir.py +1 -1
  95. flwr/common/secure_aggregation/crypto/symmetric_encryption.py +21 -2
  96. flwr/common/secure_aggregation/ndarrays_arithmetic.py +1 -1
  97. flwr/common/secure_aggregation/quantization.py +1 -1
  98. flwr/common/secure_aggregation/secaggplus_constants.py +1 -1
  99. flwr/common/secure_aggregation/secaggplus_utils.py +1 -1
  100. flwr/common/serde.py +209 -3
  101. flwr/common/telemetry.py +25 -0
  102. flwr/common/typing.py +38 -0
  103. flwr/common/version.py +14 -0
  104. flwr/proto/clientappio_pb2.py +41 -0
  105. flwr/proto/clientappio_pb2.pyi +110 -0
  106. flwr/proto/clientappio_pb2_grpc.py +101 -0
  107. flwr/proto/clientappio_pb2_grpc.pyi +40 -0
  108. flwr/proto/common_pb2.py +36 -0
  109. flwr/proto/common_pb2.pyi +121 -0
  110. flwr/proto/common_pb2_grpc.py +4 -0
  111. flwr/proto/common_pb2_grpc.pyi +4 -0
  112. flwr/proto/driver_pb2.py +26 -19
  113. flwr/proto/driver_pb2.pyi +34 -0
  114. flwr/proto/driver_pb2_grpc.py +70 -0
  115. flwr/proto/driver_pb2_grpc.pyi +28 -0
  116. flwr/proto/exec_pb2.py +43 -0
  117. flwr/proto/exec_pb2.pyi +95 -0
  118. flwr/proto/exec_pb2_grpc.py +101 -0
  119. flwr/proto/exec_pb2_grpc.pyi +41 -0
  120. flwr/proto/fab_pb2.py +30 -0
  121. flwr/proto/fab_pb2.pyi +56 -0
  122. flwr/proto/fab_pb2_grpc.py +4 -0
  123. flwr/proto/fab_pb2_grpc.pyi +4 -0
  124. flwr/proto/fleet_pb2.py +29 -23
  125. flwr/proto/fleet_pb2.pyi +33 -0
  126. flwr/proto/fleet_pb2_grpc.py +102 -0
  127. flwr/proto/fleet_pb2_grpc.pyi +35 -0
  128. flwr/proto/grpcadapter_pb2.py +32 -0
  129. flwr/proto/grpcadapter_pb2.pyi +43 -0
  130. flwr/proto/grpcadapter_pb2_grpc.py +66 -0
  131. flwr/proto/grpcadapter_pb2_grpc.pyi +24 -0
  132. flwr/proto/message_pb2.py +41 -0
  133. flwr/proto/message_pb2.pyi +122 -0
  134. flwr/proto/message_pb2_grpc.py +4 -0
  135. flwr/proto/message_pb2_grpc.pyi +4 -0
  136. flwr/proto/run_pb2.py +35 -0
  137. flwr/proto/run_pb2.pyi +76 -0
  138. flwr/proto/run_pb2_grpc.py +4 -0
  139. flwr/proto/run_pb2_grpc.pyi +4 -0
  140. flwr/proto/task_pb2.py +7 -8
  141. flwr/proto/task_pb2.pyi +8 -5
  142. flwr/server/__init__.py +4 -8
  143. flwr/server/app.py +298 -350
  144. flwr/server/compat/app.py +6 -57
  145. flwr/server/compat/app_utils.py +5 -4
  146. flwr/server/compat/driver_client_proxy.py +29 -48
  147. flwr/server/compat/legacy_context.py +5 -4
  148. flwr/server/driver/__init__.py +2 -0
  149. flwr/server/driver/driver.py +22 -132
  150. flwr/server/driver/grpc_driver.py +224 -74
  151. flwr/server/driver/inmemory_driver.py +183 -0
  152. flwr/server/history.py +20 -20
  153. flwr/server/run_serverapp.py +121 -34
  154. flwr/server/server.py +11 -7
  155. flwr/server/server_app.py +59 -10
  156. flwr/server/serverapp_components.py +52 -0
  157. flwr/server/strategy/__init__.py +2 -2
  158. flwr/server/strategy/bulyan.py +1 -1
  159. flwr/server/strategy/dp_adaptive_clipping.py +3 -3
  160. flwr/server/strategy/dp_fixed_clipping.py +4 -3
  161. flwr/server/strategy/dpfedavg_adaptive.py +1 -1
  162. flwr/server/strategy/dpfedavg_fixed.py +1 -1
  163. flwr/server/strategy/fedadagrad.py +1 -1
  164. flwr/server/strategy/fedadam.py +1 -1
  165. flwr/server/strategy/fedavg_android.py +1 -1
  166. flwr/server/strategy/fedavgm.py +1 -1
  167. flwr/server/strategy/fedmedian.py +1 -1
  168. flwr/server/strategy/fedopt.py +1 -1
  169. flwr/server/strategy/fedprox.py +1 -1
  170. flwr/server/strategy/fedxgb_bagging.py +1 -1
  171. flwr/server/strategy/fedxgb_cyclic.py +1 -1
  172. flwr/server/strategy/fedxgb_nn_avg.py +1 -1
  173. flwr/server/strategy/fedyogi.py +1 -1
  174. flwr/server/strategy/krum.py +1 -1
  175. flwr/server/strategy/qfedavg.py +1 -1
  176. flwr/server/superlink/driver/__init__.py +1 -1
  177. flwr/server/superlink/driver/driver_grpc.py +1 -1
  178. flwr/server/superlink/driver/driver_servicer.py +51 -4
  179. flwr/server/superlink/ffs/__init__.py +24 -0
  180. flwr/server/superlink/ffs/disk_ffs.py +104 -0
  181. flwr/server/superlink/ffs/ffs.py +79 -0
  182. flwr/server/superlink/fleet/__init__.py +1 -1
  183. flwr/server/superlink/fleet/grpc_adapter/__init__.py +15 -0
  184. flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +131 -0
  185. flwr/server/superlink/fleet/grpc_bidi/__init__.py +1 -1
  186. flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -1
  187. flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +1 -1
  188. flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +1 -1
  189. flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +8 -2
  190. flwr/server/superlink/fleet/grpc_rere/__init__.py +1 -1
  191. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +30 -2
  192. flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +214 -0
  193. flwr/server/superlink/fleet/message_handler/__init__.py +1 -1
  194. flwr/server/superlink/fleet/message_handler/message_handler.py +42 -2
  195. flwr/server/superlink/fleet/rest_rere/__init__.py +1 -1
  196. flwr/server/superlink/fleet/rest_rere/rest_api.py +59 -1
  197. flwr/server/superlink/fleet/vce/backend/__init__.py +1 -1
  198. flwr/server/superlink/fleet/vce/backend/backend.py +5 -5
  199. flwr/server/superlink/fleet/vce/backend/raybackend.py +53 -56
  200. flwr/server/superlink/fleet/vce/vce_api.py +190 -127
  201. flwr/server/superlink/state/__init__.py +1 -1
  202. flwr/server/superlink/state/in_memory_state.py +159 -42
  203. flwr/server/superlink/state/sqlite_state.py +243 -39
  204. flwr/server/superlink/state/state.py +81 -6
  205. flwr/server/superlink/state/state_factory.py +11 -2
  206. flwr/server/superlink/state/utils.py +62 -0
  207. flwr/server/typing.py +2 -0
  208. flwr/server/utils/__init__.py +1 -1
  209. flwr/server/utils/tensorboard.py +1 -1
  210. flwr/server/utils/validator.py +23 -9
  211. flwr/server/workflow/default_workflows.py +67 -25
  212. flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +18 -6
  213. flwr/simulation/__init__.py +7 -4
  214. flwr/simulation/app.py +67 -36
  215. flwr/simulation/ray_transport/__init__.py +1 -1
  216. flwr/simulation/ray_transport/ray_actor.py +20 -46
  217. flwr/simulation/ray_transport/ray_client_proxy.py +36 -16
  218. flwr/simulation/run_simulation.py +308 -92
  219. flwr/superexec/__init__.py +21 -0
  220. flwr/superexec/app.py +184 -0
  221. flwr/superexec/deployment.py +185 -0
  222. flwr/superexec/exec_grpc.py +55 -0
  223. flwr/superexec/exec_servicer.py +70 -0
  224. flwr/superexec/executor.py +75 -0
  225. flwr/superexec/simulation.py +193 -0
  226. {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.11.0.dev20240813.dist-info}/METADATA +10 -6
  227. flwr_nightly-1.11.0.dev20240813.dist-info/RECORD +288 -0
  228. flwr_nightly-1.11.0.dev20240813.dist-info/entry_points.txt +10 -0
  229. flwr/cli/flower_toml.py +0 -140
  230. flwr/cli/new/templates/app/flower.toml.tpl +0 -13
  231. flwr/cli/new/templates/app/requirements.numpy.txt.tpl +0 -2
  232. flwr/cli/new/templates/app/requirements.pytorch.txt.tpl +0 -4
  233. flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl +0 -4
  234. flwr_nightly-1.8.0.dev20240315.dist-info/RECORD +0 -211
  235. flwr_nightly-1.8.0.dev20240315.dist-info/entry_points.txt +0 -9
  236. {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.11.0.dev20240813.dist-info}/LICENSE +0 -0
  237. {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.11.0.dev20240813.dist-info}/WHEEL +0 -0
@@ -22,16 +22,32 @@ from pathlib import Path
22
22
  from typing import Optional
23
23
 
24
24
  from flwr.common import Context, EventType, RecordSet, event
25
- from flwr.common.logger import log, update_console_handler
25
+ from flwr.common.config import (
26
+ get_flwr_dir,
27
+ get_fused_config_from_dir,
28
+ get_metadata_from_config,
29
+ get_project_config,
30
+ get_project_dir,
31
+ )
32
+ from flwr.common.logger import log, update_console_handler, warn_deprecated_feature
26
33
  from flwr.common.object_ref import load_app
34
+ from flwr.common.typing import UserConfig
35
+ from flwr.proto.driver_pb2 import ( # pylint: disable=E0611
36
+ CreateRunRequest,
37
+ CreateRunResponse,
38
+ )
27
39
 
28
- from .driver.driver import Driver
40
+ from .driver import Driver
41
+ from .driver.grpc_driver import GrpcDriver
29
42
  from .server_app import LoadServerAppError, ServerApp
30
43
 
44
+ ADDRESS_DRIVER_API = "0.0.0.0:9091"
45
+
31
46
 
32
47
  def run(
33
48
  driver: Driver,
34
49
  server_app_dir: str,
50
+ server_app_run_config: UserConfig,
35
51
  server_app_attr: Optional[str] = None,
36
52
  loaded_server_app: Optional[ServerApp] = None,
37
53
  ) -> None:
@@ -39,16 +55,15 @@ def run(
39
55
  if not (server_app_attr is None) ^ (loaded_server_app is None):
40
56
  raise ValueError(
41
57
  "Either `server_app_attr` or `loaded_server_app` should be set "
42
- "but not both. "
58
+ "but not both."
43
59
  )
44
60
 
45
- if server_app_dir is not None:
46
- sys.path.insert(0, server_app_dir)
47
-
48
61
  # Load ServerApp if needed
49
62
  def _load() -> ServerApp:
50
63
  if server_app_attr:
51
- server_app: ServerApp = load_app(server_app_attr, LoadServerAppError)
64
+ server_app: ServerApp = load_app(
65
+ server_app_attr, LoadServerAppError, server_app_dir
66
+ )
52
67
 
53
68
  if not isinstance(server_app, ServerApp):
54
69
  raise LoadServerAppError(
@@ -62,7 +77,9 @@ def run(
62
77
  server_app = _load()
63
78
 
64
79
  # Initialize Context
65
- context = Context(state=RecordSet())
80
+ context = Context(
81
+ node_id=0, node_config={}, state=RecordSet(), run_config=server_app_run_config
82
+ )
66
83
 
67
84
  # Call ServerApp
68
85
  server_app(driver=driver, context=context)
@@ -70,12 +87,29 @@ def run(
70
87
  log(DEBUG, "ServerApp finished running.")
71
88
 
72
89
 
73
- def run_server_app() -> None:
90
+ def run_server_app() -> None: # pylint: disable=too-many-branches
74
91
  """Run Flower server app."""
75
92
  event(EventType.RUN_SERVER_APP_ENTER)
76
93
 
77
94
  args = _parse_args_run_server_app().parse_args()
78
95
 
96
+ if args.server != ADDRESS_DRIVER_API:
97
+ warn = "Passing flag --server is deprecated. Use --superlink instead."
98
+ warn_deprecated_feature(warn)
99
+
100
+ if args.superlink != ADDRESS_DRIVER_API:
101
+ # if `--superlink` also passed, then
102
+ # warn user that this argument overrides what was passed with `--server`
103
+ log(
104
+ WARN,
105
+ "Both `--server` and `--superlink` were passed. "
106
+ "`--server` will be ignored. Connecting to the Superlink Driver API "
107
+ "at %s.",
108
+ args.superlink,
109
+ )
110
+ else:
111
+ args.superlink = args.server
112
+
79
113
  update_console_handler(
80
114
  level=DEBUG if args.verbose else INFO,
81
115
  timestamps=args.verbose,
@@ -95,7 +129,7 @@ def run_server_app() -> None:
95
129
  WARN,
96
130
  "Option `--insecure` was set. "
97
131
  "Starting insecure HTTP client connected to %s.",
98
- args.server,
132
+ args.superlink,
99
133
  )
100
134
  root_certificates = None
101
135
  else:
@@ -109,34 +143,69 @@ def run_server_app() -> None:
109
143
  DEBUG,
110
144
  "Starting secure HTTPS client connected to %s "
111
145
  "with the following certificates: %s.",
112
- args.server,
146
+ args.superlink,
113
147
  cert_path,
114
148
  )
115
149
 
116
- log(
117
- DEBUG,
118
- "Flower will load ServerApp `%s`",
119
- getattr(args, "server-app"),
150
+ app_path: Optional[str] = args.app
151
+ if not (app_path is None) ^ (args.run_id is None):
152
+ raise sys.exit(
153
+ "Please provide either a Flower App path or a Run ID, but not both. "
154
+ "For more details, use: ``flower-server-app -h``"
155
+ )
156
+
157
+ # Initialize GrpcDriver
158
+ if app_path is None:
159
+ # User provided `--run-id`, but not `app_dir`
160
+ driver = GrpcDriver(
161
+ run_id=args.run_id,
162
+ driver_service_address=args.superlink,
163
+ root_certificates=root_certificates,
164
+ )
165
+ flwr_dir = get_flwr_dir(args.flwr_dir)
166
+ run_ = driver.run
167
+ app_path = str(get_project_dir(run_.fab_id, run_.fab_version, flwr_dir))
168
+ config = get_project_config(app_path)
169
+ else:
170
+ # User provided `app_dir`, but not `--run-id`
171
+ # Create run if run_id is not provided
172
+ driver = GrpcDriver(
173
+ run_id=0, # Will be overwritten
174
+ driver_service_address=args.superlink,
175
+ root_certificates=root_certificates,
176
+ )
177
+ # Load config from the project directory
178
+ config = get_project_config(app_path)
179
+ fab_version, fab_id = get_metadata_from_config(config)
180
+
181
+ # Create run
182
+ req = CreateRunRequest(fab_id=fab_id, fab_version=fab_version)
183
+ res: CreateRunResponse = driver._stub.CreateRun(req) # pylint: disable=W0212
184
+ # Overwrite driver._run_id
185
+ driver._run_id = res.run_id # pylint: disable=W0212
186
+
187
+ # Obtain server app reference and the run config
188
+ server_app_attr = config["tool"]["flwr"]["app"]["components"]["serverapp"]
189
+ server_app_run_config = get_fused_config_from_dir(
190
+ Path(app_path), driver.run.override_config
120
191
  )
121
192
 
193
+ log(DEBUG, "Flower will load ServerApp `%s` in %s", server_app_attr, app_path)
194
+
122
195
  log(
123
196
  DEBUG,
124
197
  "root_certificates: `%s`",
125
198
  root_certificates,
126
199
  )
127
200
 
128
- server_app_dir = args.dir
129
- server_app_attr = getattr(args, "server-app")
130
-
131
- # Initialize Driver
132
- driver = Driver(
133
- driver_service_address=args.server,
134
- root_certificates=root_certificates,
201
+ # Run the ServerApp with the Driver
202
+ run(
203
+ driver=driver,
204
+ server_app_dir=app_path,
205
+ server_app_run_config=server_app_run_config,
206
+ server_app_attr=server_app_attr,
135
207
  )
136
208
 
137
- # Run the Server App with the Driver
138
- run(driver=driver, server_app_dir=server_app_dir, server_app_attr=server_app_attr)
139
-
140
209
  # Clean up
141
210
  driver.close()
142
211
 
@@ -150,13 +219,16 @@ def _parse_args_run_server_app() -> argparse.ArgumentParser:
150
219
  )
151
220
 
152
221
  parser.add_argument(
153
- "server-app",
154
- help="For example: `server:app` or `project.package.module:wrapper.app`",
222
+ "app",
223
+ nargs="?",
224
+ default=None,
225
+ help="Load and run the `ServerApp` from the specified Flower App path. "
226
+ "The `pyproject.toml` file must be located in the root of this path.",
155
227
  )
156
228
  parser.add_argument(
157
229
  "--insecure",
158
230
  action="store_true",
159
- help="Run the server app without HTTPS. By default, the app runs with "
231
+ help="Run the `ServerApp` without HTTPS. By default, the app runs with "
160
232
  "HTTPS enabled. Use this flag only if you understand the risks.",
161
233
  )
162
234
  parser.add_argument(
@@ -173,15 +245,30 @@ def _parse_args_run_server_app() -> argparse.ArgumentParser:
173
245
  )
174
246
  parser.add_argument(
175
247
  "--server",
176
- default="0.0.0.0:9091",
248
+ default=ADDRESS_DRIVER_API,
177
249
  help="Server address",
178
250
  )
179
251
  parser.add_argument(
180
- "--dir",
181
- default="",
182
- help="Add specified directory to the PYTHONPATH and load Flower "
183
- "app from there."
184
- " Default: current working directory.",
252
+ "--superlink",
253
+ default=ADDRESS_DRIVER_API,
254
+ help="SuperLink Driver API (gRPC-rere) address (IPv4, IPv6, or a domain name)",
255
+ )
256
+ parser.add_argument(
257
+ "--run-id",
258
+ default=None,
259
+ type=int,
260
+ help="The identifier of the run.",
261
+ )
262
+ parser.add_argument(
263
+ "--flwr-dir",
264
+ default=None,
265
+ help="""The path containing installed Flower Apps.
266
+ By default, this value is equal to:
267
+
268
+ - `$FLWR_HOME/` if `$FLWR_HOME` is defined
269
+ - `$XDG_DATA_HOME/.flwr/` if `$XDG_DATA_HOME` is defined
270
+ - `$HOME/.flwr/` in all other cases
271
+ """,
185
272
  )
186
273
 
187
274
  return parser
flwr/server/server.py CHANGED
@@ -282,7 +282,14 @@ class Server:
282
282
  get_parameters_res = random_client.get_parameters(
283
283
  ins=ins, timeout=timeout, group_id=server_round
284
284
  )
285
- log(INFO, "Received initial parameters from one random client")
285
+ if get_parameters_res.status.code == Code.OK:
286
+ log(INFO, "Received initial parameters from one random client")
287
+ else:
288
+ log(
289
+ WARN,
290
+ "Failed to receive initial parameters from the client."
291
+ " Empty initial parameters will be used.",
292
+ )
286
293
  return get_parameters_res.parameters
287
294
 
288
295
 
@@ -486,12 +493,9 @@ def run_fl(
486
493
 
487
494
  log(INFO, "")
488
495
  log(INFO, "[SUMMARY]")
489
- log(INFO, "Run finished %s rounds in %.2fs", config.num_rounds, elapsed_time)
490
- for idx, line in enumerate(io.StringIO(str(hist))):
491
- if idx == 0:
492
- log(INFO, "%s", line.strip("\n"))
493
- else:
494
- log(INFO, "\t%s", line.strip("\n"))
496
+ log(INFO, "Run finished %s round(s) in %.2fs", config.num_rounds, elapsed_time)
497
+ for line in io.StringIO(str(hist)):
498
+ log(INFO, "\t%s", line.strip("\n"))
495
499
  log(INFO, "")
496
500
 
497
501
  # Graceful shutdown
flwr/server/server_app.py CHANGED
@@ -17,7 +17,11 @@
17
17
 
18
18
  from typing import Callable, Optional
19
19
 
20
- from flwr.common import Context, RecordSet
20
+ from flwr.common import Context
21
+ from flwr.common.logger import (
22
+ warn_deprecated_feature_with_example,
23
+ warn_preview_feature,
24
+ )
21
25
  from flwr.server.strategy import Strategy
22
26
 
23
27
  from .client_manager import ClientManager
@@ -25,7 +29,20 @@ from .compat import start_driver
25
29
  from .driver import Driver
26
30
  from .server import Server
27
31
  from .server_config import ServerConfig
28
- from .typing import ServerAppCallable
32
+ from .typing import ServerAppCallable, ServerFn
33
+
34
+ SERVER_FN_USAGE_EXAMPLE = """
35
+
36
+ def server_fn(context: Context):
37
+ server_config = ServerConfig(num_rounds=3)
38
+ strategy = FedAvg()
39
+ return ServerAppComponents(
40
+ strategy=strategy,
41
+ server_config=server_config,
42
+ )
43
+
44
+ app = ServerApp(server_fn=server_fn)
45
+ """
29
46
 
30
47
 
31
48
  class ServerApp:
@@ -35,13 +52,15 @@ class ServerApp:
35
52
  --------
36
53
  Use the `ServerApp` with an existing `Strategy`:
37
54
 
38
- >>> server_config = ServerConfig(num_rounds=3)
39
- >>> strategy = FedAvg()
55
+ >>> def server_fn(context: Context):
56
+ >>> server_config = ServerConfig(num_rounds=3)
57
+ >>> strategy = FedAvg()
58
+ >>> return ServerAppComponents(
59
+ >>> strategy=strategy,
60
+ >>> server_config=server_config,
61
+ >>> )
40
62
  >>>
41
- >>> app = ServerApp()
42
- >>> server_config=server_config,
43
- >>> strategy=strategy,
44
- >>> )
63
+ >>> app = ServerApp(server_fn=server_fn)
45
64
 
46
65
  Use the `ServerApp` with a custom main function:
47
66
 
@@ -52,23 +71,52 @@ class ServerApp:
52
71
  >>> print("ServerApp running")
53
72
  """
54
73
 
74
+ # pylint: disable=too-many-arguments
55
75
  def __init__(
56
76
  self,
57
77
  server: Optional[Server] = None,
58
78
  config: Optional[ServerConfig] = None,
59
79
  strategy: Optional[Strategy] = None,
60
80
  client_manager: Optional[ClientManager] = None,
81
+ server_fn: Optional[ServerFn] = None,
61
82
  ) -> None:
83
+ if any([server, config, strategy, client_manager]):
84
+ warn_deprecated_feature_with_example(
85
+ deprecation_message="Passing either `server`, `config`, `strategy` or "
86
+ "`client_manager` directly to the ServerApp "
87
+ "constructor is deprecated.",
88
+ example_message="Pass `ServerApp` arguments wrapped "
89
+ "in a `flwr.server.ServerAppComponents` object that gets "
90
+ "returned by a function passed as the `server_fn` argument "
91
+ "to the `ServerApp` constructor. For example: ",
92
+ code_example=SERVER_FN_USAGE_EXAMPLE,
93
+ )
94
+
95
+ if server_fn:
96
+ raise ValueError(
97
+ "Passing `server_fn` is incompatible with passing the "
98
+ "other arguments (now deprecated) to ServerApp. "
99
+ "Use `server_fn` exclusively."
100
+ )
101
+
62
102
  self._server = server
63
103
  self._config = config
64
104
  self._strategy = strategy
65
105
  self._client_manager = client_manager
106
+ self._server_fn = server_fn
66
107
  self._main: Optional[ServerAppCallable] = None
67
108
 
68
109
  def __call__(self, driver: Driver, context: Context) -> None:
69
110
  """Execute `ServerApp`."""
70
111
  # Compatibility mode
71
112
  if not self._main:
113
+ if self._server_fn:
114
+ # Execute server_fn()
115
+ components = self._server_fn(context)
116
+ self._server = components.server
117
+ self._config = components.config
118
+ self._strategy = components.strategy
119
+ self._client_manager = components.client_manager
72
120
  start_driver(
73
121
  server=self._server,
74
122
  config=self._config,
@@ -79,7 +127,6 @@ class ServerApp:
79
127
  return
80
128
 
81
129
  # New execution mode
82
- context = Context(state=RecordSet())
83
130
  self._main(driver, context)
84
131
 
85
132
  def main(self) -> Callable[[ServerAppCallable], ServerAppCallable]:
@@ -105,7 +152,7 @@ class ServerApp:
105
152
  >>> server_config = ServerConfig(num_rounds=3)
106
153
  >>> strategy = FedAvg()
107
154
  >>>
108
- >>> app = ServerApp()
155
+ >>> app = ServerApp(
109
156
  >>> server_config=server_config,
110
157
  >>> strategy=strategy,
111
158
  >>> )
@@ -120,6 +167,8 @@ class ServerApp:
120
167
  """,
121
168
  )
122
169
 
170
+ warn_preview_feature("ServerApp-register-main-function")
171
+
123
172
  # Register provided function with the ServerApp object
124
173
  self._main = main_fn
125
174
 
@@ -0,0 +1,52 @@
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
+ """ServerAppComponents for the ServerApp."""
16
+
17
+
18
+ from dataclasses import dataclass
19
+ from typing import Optional
20
+
21
+ from .client_manager import ClientManager
22
+ from .server import Server
23
+ from .server_config import ServerConfig
24
+ from .strategy import Strategy
25
+
26
+
27
+ @dataclass
28
+ class ServerAppComponents: # pylint: disable=too-many-instance-attributes
29
+ """Components to construct a ServerApp.
30
+
31
+ Parameters
32
+ ----------
33
+ server : Optional[Server] (default: None)
34
+ A server implementation, either `flwr.server.Server` or a subclass
35
+ thereof. If no instance is provided, one will be created internally.
36
+ config : Optional[ServerConfig] (default: None)
37
+ Currently supported values are `num_rounds` (int, default: 1) and
38
+ `round_timeout` in seconds (float, default: None).
39
+ strategy : Optional[Strategy] (default: None)
40
+ An implementation of the abstract base class
41
+ `flwr.server.strategy.Strategy`. If no strategy is provided, then
42
+ `flwr.server.strategy.FedAvg` will be used.
43
+ client_manager : Optional[ClientManager] (default: None)
44
+ An implementation of the class `flwr.server.ClientManager`. If no
45
+ implementation is provided, then `flwr.server.SimpleClientManager`
46
+ will be used.
47
+ """
48
+
49
+ server: Optional[Server] = None
50
+ config: Optional[ServerConfig] = None
51
+ strategy: Optional[Strategy] = None
52
+ client_manager: Optional[ClientManager] = None
@@ -53,9 +53,10 @@ __all__ = [
53
53
  "DPFedAvgAdaptive",
54
54
  "DPFedAvgFixed",
55
55
  "DifferentialPrivacyClientSideAdaptiveClipping",
56
- "DifferentialPrivacyServerSideAdaptiveClipping",
57
56
  "DifferentialPrivacyClientSideFixedClipping",
57
+ "DifferentialPrivacyServerSideAdaptiveClipping",
58
58
  "DifferentialPrivacyServerSideFixedClipping",
59
+ "FaultTolerantFedAvg",
59
60
  "FedAdagrad",
60
61
  "FedAdam",
61
62
  "FedAvg",
@@ -69,7 +70,6 @@ __all__ = [
69
70
  "FedXgbCyclic",
70
71
  "FedXgbNnAvg",
71
72
  "FedYogi",
72
- "FaultTolerantFedAvg",
73
73
  "Krum",
74
74
  "QFedAvg",
75
75
  "Strategy",
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2023 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -200,7 +200,7 @@ class DifferentialPrivacyServerSideAdaptiveClipping(Strategy):
200
200
 
201
201
  log(
202
202
  INFO,
203
- "aggregate_fit: parameters are clipped by value: %s.",
203
+ "aggregate_fit: parameters are clipped by value: %.4f.",
204
204
  self.clipping_norm,
205
205
  )
206
206
 
@@ -234,7 +234,7 @@ class DifferentialPrivacyServerSideAdaptiveClipping(Strategy):
234
234
  )
235
235
  log(
236
236
  INFO,
237
- "aggregate_fit: central DP noise with standard deviation: %s added to parameters.",
237
+ "aggregate_fit: central DP noise with %.4f stdev added",
238
238
  compute_stdv(
239
239
  self.noise_multiplier, self.clipping_norm, self.num_sampled_clients
240
240
  ),
@@ -424,7 +424,7 @@ class DifferentialPrivacyClientSideAdaptiveClipping(Strategy):
424
424
  )
425
425
  log(
426
426
  INFO,
427
- "aggregate_fit: central DP noise with standard deviation: %s added to parameters.",
427
+ "aggregate_fit: central DP noise with %.4f stdev added",
428
428
  compute_stdv(
429
429
  self.noise_multiplier, self.clipping_norm, self.num_sampled_clients
430
430
  ),
@@ -158,7 +158,7 @@ class DifferentialPrivacyServerSideFixedClipping(Strategy):
158
158
  )
159
159
  log(
160
160
  INFO,
161
- "aggregate_fit: parameters are clipped by value: %s.",
161
+ "aggregate_fit: parameters are clipped by value: %.4f.",
162
162
  self.clipping_norm,
163
163
  )
164
164
  # Convert back to parameters
@@ -180,7 +180,7 @@ class DifferentialPrivacyServerSideFixedClipping(Strategy):
180
180
 
181
181
  log(
182
182
  INFO,
183
- "aggregate_fit: central DP noise with standard deviation: %s added to parameters.",
183
+ "aggregate_fit: central DP noise with %.4f stdev added",
184
184
  compute_stdv(
185
185
  self.noise_multiplier, self.clipping_norm, self.num_sampled_clients
186
186
  ),
@@ -337,11 +337,12 @@ class DifferentialPrivacyClientSideFixedClipping(Strategy):
337
337
  )
338
338
  log(
339
339
  INFO,
340
- "aggregate_fit: central DP noise with standard deviation: %s added to parameters.",
340
+ "aggregate_fit: central DP noise with %.4f stdev added",
341
341
  compute_stdv(
342
342
  self.noise_multiplier, self.clipping_norm, self.num_sampled_clients
343
343
  ),
344
344
  )
345
+
345
346
  return aggregated_params, metrics
346
347
 
347
348
  def aggregate_evaluate(
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2022 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2022 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2021 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2021 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2021 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2022 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2022 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2021 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2023 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2023 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2023 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2023 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2021 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2022 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2020 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2021 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2022 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.