flwr 1.23.0__py3-none-any.whl → 1.24.0__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.
Files changed (292) hide show
  1. flwr/__init__.py +16 -5
  2. flwr/app/error.py +2 -2
  3. flwr/app/exception.py +3 -3
  4. flwr/cli/app.py +19 -0
  5. flwr/cli/app_cmd/__init__.py +23 -0
  6. flwr/cli/app_cmd/publish.py +285 -0
  7. flwr/cli/app_cmd/review.py +252 -0
  8. flwr/cli/auth_plugin/auth_plugin.py +4 -5
  9. flwr/cli/auth_plugin/noop_auth_plugin.py +54 -11
  10. flwr/cli/auth_plugin/oidc_cli_plugin.py +32 -9
  11. flwr/cli/build.py +60 -18
  12. flwr/cli/cli_account_auth_interceptor.py +24 -7
  13. flwr/cli/config_utils.py +101 -13
  14. flwr/cli/federation/__init__.py +24 -0
  15. flwr/cli/federation/ls.py +140 -0
  16. flwr/cli/federation/show.py +317 -0
  17. flwr/cli/install.py +91 -13
  18. flwr/cli/log.py +52 -9
  19. flwr/cli/login/login.py +7 -4
  20. flwr/cli/ls.py +170 -130
  21. flwr/cli/new/new.py +33 -50
  22. flwr/cli/new/templates/app/code/task.pytorch.py.tpl +1 -0
  23. flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +1 -1
  24. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +1 -1
  25. flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +1 -1
  26. flwr/cli/new/templates/app/pyproject.jax.toml.tpl +1 -1
  27. flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -1
  28. flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +1 -1
  29. flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +3 -3
  30. flwr/cli/new/templates/app/pyproject.pytorch_legacy_api.toml.tpl +1 -1
  31. flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
  32. flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +2 -2
  33. flwr/cli/new/templates/app/pyproject.xgboost.toml.tpl +1 -1
  34. flwr/cli/pull.py +10 -5
  35. flwr/cli/run/run.py +77 -30
  36. flwr/cli/run_utils.py +130 -0
  37. flwr/cli/stop.py +25 -7
  38. flwr/cli/supernode/ls.py +16 -8
  39. flwr/cli/supernode/register.py +9 -4
  40. flwr/cli/supernode/unregister.py +5 -3
  41. flwr/cli/utils.py +376 -16
  42. flwr/client/__init__.py +1 -1
  43. flwr/client/dpfedavg_numpy_client.py +4 -1
  44. flwr/client/grpc_adapter_client/connection.py +6 -7
  45. flwr/client/grpc_rere_client/connection.py +10 -11
  46. flwr/client/grpc_rere_client/grpc_adapter.py +6 -2
  47. flwr/client/grpc_rere_client/node_auth_client_interceptor.py +2 -1
  48. flwr/client/message_handler/message_handler.py +2 -2
  49. flwr/client/mod/secure_aggregation/secaggplus_mod.py +3 -3
  50. flwr/client/numpy_client.py +1 -1
  51. flwr/client/rest_client/connection.py +12 -14
  52. flwr/client/run_info_store.py +4 -5
  53. flwr/client/typing.py +1 -1
  54. flwr/clientapp/client_app.py +9 -10
  55. flwr/clientapp/mod/centraldp_mods.py +16 -17
  56. flwr/clientapp/mod/localdp_mod.py +8 -9
  57. flwr/clientapp/typing.py +1 -1
  58. flwr/clientapp/utils.py +3 -3
  59. flwr/common/address.py +1 -2
  60. flwr/common/args.py +3 -4
  61. flwr/common/config.py +13 -16
  62. flwr/common/constant.py +5 -2
  63. flwr/common/differential_privacy.py +3 -4
  64. flwr/common/event_log_plugin/event_log_plugin.py +3 -4
  65. flwr/common/exit/exit.py +15 -2
  66. flwr/common/exit/exit_code.py +19 -0
  67. flwr/common/exit/exit_handler.py +6 -2
  68. flwr/common/exit/signal_handler.py +5 -5
  69. flwr/common/grpc.py +6 -6
  70. flwr/common/inflatable_protobuf_utils.py +1 -1
  71. flwr/common/inflatable_utils.py +38 -21
  72. flwr/common/logger.py +19 -19
  73. flwr/common/message.py +4 -4
  74. flwr/common/object_ref.py +7 -7
  75. flwr/common/record/array.py +3 -3
  76. flwr/common/record/arrayrecord.py +18 -30
  77. flwr/common/record/configrecord.py +3 -3
  78. flwr/common/record/recorddict.py +5 -5
  79. flwr/common/record/typeddict.py +9 -2
  80. flwr/common/recorddict_compat.py +7 -10
  81. flwr/common/retry_invoker.py +20 -20
  82. flwr/common/secure_aggregation/ndarrays_arithmetic.py +3 -3
  83. flwr/common/serde.py +5 -4
  84. flwr/common/serde_utils.py +2 -2
  85. flwr/common/telemetry.py +9 -5
  86. flwr/common/typing.py +52 -37
  87. flwr/compat/client/app.py +38 -37
  88. flwr/compat/client/grpc_client/connection.py +11 -11
  89. flwr/compat/server/app.py +5 -6
  90. flwr/proto/appio_pb2.py +13 -3
  91. flwr/proto/appio_pb2.pyi +134 -65
  92. flwr/proto/appio_pb2_grpc.py +20 -0
  93. flwr/proto/appio_pb2_grpc.pyi +27 -0
  94. flwr/proto/clientappio_pb2.py +17 -7
  95. flwr/proto/clientappio_pb2.pyi +15 -0
  96. flwr/proto/clientappio_pb2_grpc.py +206 -40
  97. flwr/proto/clientappio_pb2_grpc.pyi +168 -53
  98. flwr/proto/control_pb2.py +71 -52
  99. flwr/proto/control_pb2.pyi +277 -111
  100. flwr/proto/control_pb2_grpc.py +249 -40
  101. flwr/proto/control_pb2_grpc.pyi +185 -52
  102. flwr/proto/error_pb2.py +13 -3
  103. flwr/proto/error_pb2.pyi +24 -6
  104. flwr/proto/error_pb2_grpc.py +20 -0
  105. flwr/proto/error_pb2_grpc.pyi +27 -0
  106. flwr/proto/fab_pb2.py +14 -4
  107. flwr/proto/fab_pb2.pyi +59 -31
  108. flwr/proto/fab_pb2_grpc.py +20 -0
  109. flwr/proto/fab_pb2_grpc.pyi +27 -0
  110. flwr/proto/federation_pb2.py +38 -0
  111. flwr/proto/federation_pb2.pyi +56 -0
  112. flwr/proto/federation_pb2_grpc.py +24 -0
  113. flwr/proto/federation_pb2_grpc.pyi +31 -0
  114. flwr/proto/fleet_pb2.py +14 -4
  115. flwr/proto/fleet_pb2.pyi +137 -61
  116. flwr/proto/fleet_pb2_grpc.py +189 -48
  117. flwr/proto/fleet_pb2_grpc.pyi +175 -61
  118. flwr/proto/grpcadapter_pb2.py +14 -4
  119. flwr/proto/grpcadapter_pb2.pyi +38 -16
  120. flwr/proto/grpcadapter_pb2_grpc.py +35 -4
  121. flwr/proto/grpcadapter_pb2_grpc.pyi +38 -7
  122. flwr/proto/heartbeat_pb2.py +17 -7
  123. flwr/proto/heartbeat_pb2.pyi +51 -22
  124. flwr/proto/heartbeat_pb2_grpc.py +20 -0
  125. flwr/proto/heartbeat_pb2_grpc.pyi +27 -0
  126. flwr/proto/log_pb2.py +13 -3
  127. flwr/proto/log_pb2.pyi +34 -11
  128. flwr/proto/log_pb2_grpc.py +20 -0
  129. flwr/proto/log_pb2_grpc.pyi +27 -0
  130. flwr/proto/message_pb2.py +15 -5
  131. flwr/proto/message_pb2.pyi +154 -86
  132. flwr/proto/message_pb2_grpc.py +20 -0
  133. flwr/proto/message_pb2_grpc.pyi +27 -0
  134. flwr/proto/node_pb2.py +15 -5
  135. flwr/proto/node_pb2.pyi +50 -25
  136. flwr/proto/node_pb2_grpc.py +20 -0
  137. flwr/proto/node_pb2_grpc.pyi +27 -0
  138. flwr/proto/recorddict_pb2.py +13 -3
  139. flwr/proto/recorddict_pb2.pyi +184 -107
  140. flwr/proto/recorddict_pb2_grpc.py +20 -0
  141. flwr/proto/recorddict_pb2_grpc.pyi +27 -0
  142. flwr/proto/run_pb2.py +40 -31
  143. flwr/proto/run_pb2.pyi +149 -84
  144. flwr/proto/run_pb2_grpc.py +20 -0
  145. flwr/proto/run_pb2_grpc.pyi +27 -0
  146. flwr/proto/serverappio_pb2.py +13 -3
  147. flwr/proto/serverappio_pb2.pyi +32 -8
  148. flwr/proto/serverappio_pb2_grpc.py +246 -65
  149. flwr/proto/serverappio_pb2_grpc.pyi +221 -85
  150. flwr/proto/simulationio_pb2.py +16 -8
  151. flwr/proto/simulationio_pb2.pyi +15 -0
  152. flwr/proto/simulationio_pb2_grpc.py +162 -41
  153. flwr/proto/simulationio_pb2_grpc.pyi +149 -55
  154. flwr/proto/transport_pb2.py +20 -10
  155. flwr/proto/transport_pb2.pyi +249 -160
  156. flwr/proto/transport_pb2_grpc.py +35 -4
  157. flwr/proto/transport_pb2_grpc.pyi +38 -8
  158. flwr/server/app.py +38 -17
  159. flwr/server/client_manager.py +4 -5
  160. flwr/server/client_proxy.py +10 -11
  161. flwr/server/compat/app.py +4 -5
  162. flwr/server/compat/app_utils.py +2 -1
  163. flwr/server/compat/grid_client_proxy.py +10 -12
  164. flwr/server/compat/legacy_context.py +3 -4
  165. flwr/server/fleet_event_log_interceptor.py +2 -1
  166. flwr/server/grid/grid.py +2 -3
  167. flwr/server/grid/grpc_grid.py +10 -8
  168. flwr/server/grid/inmemory_grid.py +4 -4
  169. flwr/server/run_serverapp.py +2 -3
  170. flwr/server/server.py +34 -39
  171. flwr/server/server_app.py +7 -8
  172. flwr/server/server_config.py +1 -2
  173. flwr/server/serverapp/app.py +34 -28
  174. flwr/server/serverapp_components.py +4 -5
  175. flwr/server/strategy/aggregate.py +9 -8
  176. flwr/server/strategy/bulyan.py +13 -11
  177. flwr/server/strategy/dp_adaptive_clipping.py +16 -20
  178. flwr/server/strategy/dp_fixed_clipping.py +12 -17
  179. flwr/server/strategy/dpfedavg_adaptive.py +3 -4
  180. flwr/server/strategy/dpfedavg_fixed.py +6 -10
  181. flwr/server/strategy/fault_tolerant_fedavg.py +14 -13
  182. flwr/server/strategy/fedadagrad.py +18 -14
  183. flwr/server/strategy/fedadam.py +16 -14
  184. flwr/server/strategy/fedavg.py +16 -17
  185. flwr/server/strategy/fedavg_android.py +15 -15
  186. flwr/server/strategy/fedavgm.py +21 -18
  187. flwr/server/strategy/fedmedian.py +2 -3
  188. flwr/server/strategy/fedopt.py +11 -10
  189. flwr/server/strategy/fedprox.py +10 -9
  190. flwr/server/strategy/fedtrimmedavg.py +12 -11
  191. flwr/server/strategy/fedxgb_bagging.py +13 -11
  192. flwr/server/strategy/fedxgb_cyclic.py +6 -6
  193. flwr/server/strategy/fedxgb_nn_avg.py +4 -4
  194. flwr/server/strategy/fedyogi.py +16 -14
  195. flwr/server/strategy/krum.py +12 -11
  196. flwr/server/strategy/qfedavg.py +16 -15
  197. flwr/server/strategy/strategy.py +6 -9
  198. flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +2 -1
  199. flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -2
  200. flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +3 -4
  201. flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +10 -12
  202. flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +1 -3
  203. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +4 -4
  204. flwr/server/superlink/fleet/grpc_rere/node_auth_server_interceptor.py +3 -2
  205. flwr/server/superlink/fleet/message_handler/message_handler.py +34 -28
  206. flwr/server/superlink/fleet/rest_rere/rest_api.py +2 -2
  207. flwr/server/superlink/fleet/vce/backend/backend.py +1 -1
  208. flwr/server/superlink/fleet/vce/backend/raybackend.py +5 -5
  209. flwr/server/superlink/fleet/vce/vce_api.py +15 -9
  210. flwr/server/superlink/linkstate/in_memory_linkstate.py +115 -150
  211. flwr/server/superlink/linkstate/linkstate.py +59 -43
  212. flwr/server/superlink/linkstate/linkstate_factory.py +22 -5
  213. flwr/server/superlink/linkstate/sqlite_linkstate.py +447 -438
  214. flwr/server/superlink/linkstate/utils.py +6 -6
  215. flwr/server/superlink/serverappio/serverappio_grpc.py +1 -2
  216. flwr/server/superlink/serverappio/serverappio_servicer.py +26 -21
  217. flwr/server/superlink/simulation/simulationio_grpc.py +1 -2
  218. flwr/server/superlink/simulation/simulationio_servicer.py +18 -13
  219. flwr/server/superlink/utils.py +4 -6
  220. flwr/server/typing.py +1 -1
  221. flwr/server/utils/tensorboard.py +15 -8
  222. flwr/server/workflow/default_workflows.py +5 -5
  223. flwr/server/workflow/secure_aggregation/secagg_workflow.py +2 -4
  224. flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +8 -8
  225. flwr/serverapp/strategy/bulyan.py +16 -15
  226. flwr/serverapp/strategy/dp_adaptive_clipping.py +12 -11
  227. flwr/serverapp/strategy/dp_fixed_clipping.py +11 -14
  228. flwr/serverapp/strategy/fedadagrad.py +10 -11
  229. flwr/serverapp/strategy/fedadam.py +10 -11
  230. flwr/serverapp/strategy/fedavg.py +9 -10
  231. flwr/serverapp/strategy/fedavgm.py +17 -16
  232. flwr/serverapp/strategy/fedmedian.py +2 -2
  233. flwr/serverapp/strategy/fedopt.py +10 -11
  234. flwr/serverapp/strategy/fedprox.py +7 -8
  235. flwr/serverapp/strategy/fedtrimmedavg.py +9 -9
  236. flwr/serverapp/strategy/fedxgb_bagging.py +3 -3
  237. flwr/serverapp/strategy/fedxgb_cyclic.py +9 -9
  238. flwr/serverapp/strategy/fedyogi.py +9 -11
  239. flwr/serverapp/strategy/krum.py +7 -7
  240. flwr/serverapp/strategy/multikrum.py +9 -9
  241. flwr/serverapp/strategy/qfedavg.py +17 -16
  242. flwr/serverapp/strategy/strategy.py +6 -9
  243. flwr/serverapp/strategy/strategy_utils.py +7 -8
  244. flwr/simulation/app.py +46 -42
  245. flwr/simulation/legacy_app.py +12 -12
  246. flwr/simulation/ray_transport/ray_actor.py +10 -11
  247. flwr/simulation/ray_transport/ray_client_proxy.py +11 -12
  248. flwr/simulation/run_simulation.py +43 -43
  249. flwr/simulation/simulationio_connection.py +4 -4
  250. flwr/supercore/cli/flower_superexec.py +3 -4
  251. flwr/supercore/constant.py +31 -1
  252. flwr/supercore/corestate/corestate.py +24 -3
  253. flwr/supercore/corestate/in_memory_corestate.py +138 -0
  254. flwr/supercore/corestate/sqlite_corestate.py +157 -0
  255. flwr/supercore/ffs/disk_ffs.py +1 -2
  256. flwr/supercore/ffs/ffs.py +1 -2
  257. flwr/supercore/ffs/ffs_factory.py +1 -2
  258. flwr/{common → supercore}/heartbeat.py +20 -25
  259. flwr/supercore/object_store/in_memory_object_store.py +1 -2
  260. flwr/supercore/object_store/object_store.py +1 -2
  261. flwr/supercore/object_store/object_store_factory.py +1 -2
  262. flwr/supercore/object_store/sqlite_object_store.py +8 -7
  263. flwr/supercore/primitives/asymmetric.py +1 -1
  264. flwr/supercore/primitives/asymmetric_ed25519.py +11 -1
  265. flwr/supercore/sqlite_mixin.py +37 -34
  266. flwr/supercore/superexec/plugin/base_exec_plugin.py +1 -2
  267. flwr/supercore/superexec/plugin/exec_plugin.py +3 -3
  268. flwr/supercore/superexec/run_superexec.py +9 -13
  269. flwr/superlink/artifact_provider/artifact_provider.py +1 -2
  270. flwr/superlink/auth_plugin/auth_plugin.py +6 -9
  271. flwr/superlink/auth_plugin/noop_auth_plugin.py +6 -9
  272. flwr/superlink/federation/__init__.py +24 -0
  273. flwr/superlink/federation/federation_manager.py +64 -0
  274. flwr/superlink/federation/noop_federation_manager.py +71 -0
  275. flwr/superlink/servicer/control/control_account_auth_interceptor.py +22 -13
  276. flwr/superlink/servicer/control/control_event_log_interceptor.py +7 -7
  277. flwr/superlink/servicer/control/control_grpc.py +5 -6
  278. flwr/superlink/servicer/control/control_license_interceptor.py +3 -3
  279. flwr/superlink/servicer/control/control_servicer.py +102 -18
  280. flwr/supernode/cli/flower_supernode.py +58 -3
  281. flwr/supernode/nodestate/in_memory_nodestate.py +60 -49
  282. flwr/supernode/nodestate/nodestate.py +7 -8
  283. flwr/supernode/nodestate/nodestate_factory.py +7 -4
  284. flwr/supernode/runtime/run_clientapp.py +41 -22
  285. flwr/supernode/servicer/clientappio/clientappio_servicer.py +40 -10
  286. flwr/supernode/start_client_internal.py +158 -42
  287. {flwr-1.23.0.dist-info → flwr-1.24.0.dist-info}/METADATA +8 -8
  288. flwr-1.24.0.dist-info/RECORD +454 -0
  289. flwr/supercore/object_store/utils.py +0 -43
  290. flwr-1.23.0.dist-info/RECORD +0 -439
  291. {flwr-1.23.0.dist-info → flwr-1.24.0.dist-info}/WHEEL +0 -0
  292. {flwr-1.23.0.dist-info → flwr-1.24.0.dist-info}/entry_points.txt +0 -0
@@ -1,9 +1,29 @@
1
1
  # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
2
  """Client and server classes corresponding to protobuf-defined services."""
3
3
  import grpc
4
+ import warnings
4
5
 
5
6
  from flwr.proto import transport_pb2 as flwr_dot_proto_dot_transport__pb2
6
7
 
8
+ GRPC_GENERATED_VERSION = '1.70.0'
9
+ GRPC_VERSION = grpc.__version__
10
+ _version_not_supported = False
11
+
12
+ try:
13
+ from grpc._utilities import first_version_is_lower
14
+ _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
15
+ except ImportError:
16
+ _version_not_supported = True
17
+
18
+ if _version_not_supported:
19
+ raise RuntimeError(
20
+ f'The grpc package installed is at version {GRPC_VERSION},'
21
+ + f' but the generated code in flwr/proto/transport_pb2_grpc.py depends on'
22
+ + f' grpcio>={GRPC_GENERATED_VERSION}.'
23
+ + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
24
+ + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
25
+ )
26
+
7
27
 
8
28
  class FlowerServiceStub(object):
9
29
  """Missing associated documentation comment in .proto file."""
@@ -18,7 +38,7 @@ class FlowerServiceStub(object):
18
38
  '/flwr.proto.FlowerService/Join',
19
39
  request_serializer=flwr_dot_proto_dot_transport__pb2.ClientMessage.SerializeToString,
20
40
  response_deserializer=flwr_dot_proto_dot_transport__pb2.ServerMessage.FromString,
21
- )
41
+ _registered_method=True)
22
42
 
23
43
 
24
44
  class FlowerServiceServicer(object):
@@ -42,6 +62,7 @@ def add_FlowerServiceServicer_to_server(servicer, server):
42
62
  generic_handler = grpc.method_handlers_generic_handler(
43
63
  'flwr.proto.FlowerService', rpc_method_handlers)
44
64
  server.add_generic_rpc_handlers((generic_handler,))
65
+ server.add_registered_method_handlers('flwr.proto.FlowerService', rpc_method_handlers)
45
66
 
46
67
 
47
68
  # This class is part of an EXPERIMENTAL API.
@@ -59,8 +80,18 @@ class FlowerService(object):
59
80
  wait_for_ready=None,
60
81
  timeout=None,
61
82
  metadata=None):
62
- return grpc.experimental.stream_stream(request_iterator, target, '/flwr.proto.FlowerService/Join',
83
+ return grpc.experimental.stream_stream(
84
+ request_iterator,
85
+ target,
86
+ '/flwr.proto.FlowerService/Join',
63
87
  flwr_dot_proto_dot_transport__pb2.ClientMessage.SerializeToString,
64
88
  flwr_dot_proto_dot_transport__pb2.ServerMessage.FromString,
65
- options, channel_credentials,
66
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
89
+ options,
90
+ channel_credentials,
91
+ insecure,
92
+ call_credentials,
93
+ compression,
94
+ wait_for_ready,
95
+ timeout,
96
+ metadata,
97
+ _registered_method=True)
@@ -1,25 +1,55 @@
1
1
  """
2
2
  @generated by mypy-protobuf. Do not edit manually!
3
3
  isort:skip_file
4
+ Copyright 2020 Flower Labs GmbH. All Rights Reserved.
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ ==============================================================================
4
18
  """
19
+
5
20
  import abc
21
+ import collections.abc
6
22
  import flwr.proto.transport_pb2
7
23
  import grpc
24
+ import grpc.aio
8
25
  import typing
9
26
 
27
+ _T = typing.TypeVar("_T")
28
+
29
+ class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ...
30
+
31
+ class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg]
32
+ ...
33
+
10
34
  class FlowerServiceStub:
11
- def __init__(self, channel: grpc.Channel) -> None: ...
35
+ def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ...
12
36
  Join: grpc.StreamStreamMultiCallable[
13
37
  flwr.proto.transport_pb2.ClientMessage,
14
- flwr.proto.transport_pb2.ServerMessage]
38
+ flwr.proto.transport_pb2.ServerMessage,
39
+ ]
15
40
 
41
+ class FlowerServiceAsyncStub:
42
+ Join: grpc.aio.StreamStreamMultiCallable[
43
+ flwr.proto.transport_pb2.ClientMessage,
44
+ flwr.proto.transport_pb2.ServerMessage,
45
+ ]
16
46
 
17
47
  class FlowerServiceServicer(metaclass=abc.ABCMeta):
18
48
  @abc.abstractmethod
19
- def Join(self,
20
- request_iterator: typing.Iterator[flwr.proto.transport_pb2.ClientMessage],
21
- context: grpc.ServicerContext,
22
- ) -> typing.Iterator[flwr.proto.transport_pb2.ServerMessage]: ...
23
-
49
+ def Join(
50
+ self,
51
+ request_iterator: _MaybeAsyncIterator[flwr.proto.transport_pb2.ClientMessage],
52
+ context: _ServicerContext,
53
+ ) -> typing.Union[collections.abc.Iterator[flwr.proto.transport_pb2.ServerMessage], collections.abc.AsyncIterator[flwr.proto.transport_pb2.ServerMessage]]: ...
24
54
 
25
- def add_FlowerServiceServicer_to_server(servicer: FlowerServiceServicer, server: grpc.Server) -> None: ...
55
+ def add_FlowerServiceServicer_to_server(servicer: FlowerServiceServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ...
flwr/server/app.py CHANGED
@@ -21,11 +21,11 @@ import os
21
21
  import subprocess
22
22
  import sys
23
23
  import threading
24
- from collections.abc import Sequence
24
+ from collections.abc import Callable, Sequence
25
25
  from logging import INFO, WARN
26
26
  from pathlib import Path
27
27
  from time import sleep
28
- from typing import Callable, Optional, TypeVar, cast
28
+ from typing import TypeVar, cast
29
29
 
30
30
  import grpc
31
31
  import yaml
@@ -75,6 +75,7 @@ from flwr.superlink.auth_plugin import (
75
75
  NoOpControlAuthnPlugin,
76
76
  NoOpControlAuthzPlugin,
77
77
  )
78
+ from flwr.superlink.federation import FederationManager, NoOpFederationManager
78
79
  from flwr.superlink.servicer.control import run_control_api_grpc
79
80
 
80
81
  from .superlink.fleet.grpc_adapter.grpc_adapter_servicer import GrpcAdapterServicer
@@ -97,6 +98,7 @@ try:
97
98
  get_control_authz_ee_plugins,
98
99
  get_control_event_log_writer_plugins,
99
100
  get_ee_artifact_provider,
101
+ get_ee_federation_manager,
100
102
  get_fleet_event_log_writer_plugins,
101
103
  )
102
104
  except ImportError:
@@ -129,6 +131,11 @@ except ImportError:
129
131
  """Return all Control API authorization plugins for EE."""
130
132
  return {}
131
133
 
134
+ # pylint: disable-next=unused-argument
135
+ def get_ee_federation_manager(config_path: str) -> FederationManager:
136
+ """Return the EE FederationManager."""
137
+ raise NotImplementedError("No federation manager is currently supported.")
138
+
132
139
 
133
140
  def get_control_authn_plugins() -> dict[str, type[ControlAuthnPlugin]]:
134
141
  """Return all Control API authentication plugins."""
@@ -142,6 +149,14 @@ def get_control_authz_plugins() -> dict[str, type[ControlAuthzPlugin]]:
142
149
  return ee_dict | {AuthzType.NOOP: NoOpControlAuthzPlugin}
143
150
 
144
151
 
152
+ def get_federation_manager(config_path: str | None = None) -> FederationManager:
153
+ """Return the FederationManager."""
154
+ if config_path is None:
155
+ return NoOpFederationManager()
156
+ federation_manager: FederationManager = get_ee_federation_manager(config_path)
157
+ return federation_manager
158
+
159
+
145
160
  # pylint: disable=too-many-branches, too-many-locals, too-many-statements
146
161
  def run_superlink() -> None:
147
162
  """Run Flower SuperLink (ServerAppIo API and Fleet API)."""
@@ -209,9 +224,9 @@ def run_superlink() -> None:
209
224
  # provided
210
225
  verify_tls_cert = not getattr(args, "disable_oidc_tls_cert_verification", None)
211
226
 
212
- authn_plugin: Optional[ControlAuthnPlugin] = None
213
- authz_plugin: Optional[ControlAuthzPlugin] = None
214
- event_log_plugin: Optional[EventLogWriterPlugin] = None
227
+ authn_plugin: ControlAuthnPlugin | None = None
228
+ authz_plugin: ControlAuthzPlugin | None = None
229
+ event_log_plugin: EventLogWriterPlugin | None = None
215
230
  # Load the auth plugin if the args.account_auth_config is provided
216
231
  if cfg_path := getattr(args, "user_auth_config", None):
217
232
  log(
@@ -281,15 +296,21 @@ def run_superlink() -> None:
281
296
  f" to the Flower documentation for more information: {url_v}{page}",
282
297
  )
283
298
 
299
+ # Load Federation Manager
300
+ fed_config_path = getattr(args, "federations_config", None)
301
+ federation_manager = get_federation_manager(fed_config_path)
302
+
303
+ # Initialize ObjectStoreFactory
304
+ objectstore_factory = ObjectStoreFactory(args.database)
305
+
284
306
  # Initialize StateFactory
285
- state_factory = LinkStateFactory(args.database)
307
+ state_factory = LinkStateFactory(
308
+ args.database, federation_manager, objectstore_factory
309
+ )
286
310
 
287
311
  # Initialize FfsFactory
288
312
  ffs_factory = FfsFactory(args.storage_dir)
289
313
 
290
- # Initialize ObjectStoreFactory
291
- objectstore_factory = ObjectStoreFactory(args.database)
292
-
293
314
  # Start Control API
294
315
  is_simulation = args.simulation
295
316
  control_server: grpc.Server = run_control_api_grpc(
@@ -458,7 +479,7 @@ def _format_address(address: str) -> tuple[str, str, int]:
458
479
 
459
480
 
460
481
  def _load_control_auth_plugins(
461
- config_path: Optional[str], verify_tls_cert: bool
482
+ config_path: str | None, verify_tls_cert: bool
462
483
  ) -> tuple[ControlAuthnPlugin, ControlAuthzPlugin]:
463
484
  """Obtain Control API authentication and authorization plugins."""
464
485
  # Load NoOp plugins if no config path is provided
@@ -517,7 +538,7 @@ def _load_control_auth_plugins(
517
538
  return authn_plugin, authz_plugin
518
539
 
519
540
 
520
- def _try_obtain_control_event_log_writer_plugin() -> Optional[EventLogWriterPlugin]:
541
+ def _try_obtain_control_event_log_writer_plugin() -> EventLogWriterPlugin | None:
521
542
  """Return an instance of the event log writer plugin."""
522
543
  try:
523
544
  all_plugins: dict[str, type[EventLogWriterPlugin]] = (
@@ -531,7 +552,7 @@ def _try_obtain_control_event_log_writer_plugin() -> Optional[EventLogWriterPlug
531
552
  sys.exit("No event log writer plugins are currently supported.")
532
553
 
533
554
 
534
- def _try_obtain_fleet_event_log_writer_plugin() -> Optional[EventLogWriterPlugin]:
555
+ def _try_obtain_fleet_event_log_writer_plugin() -> EventLogWriterPlugin | None:
535
556
  """Return an instance of the Fleet Servicer event log writer plugin."""
536
557
  try:
537
558
  all_plugins: dict[str, type[EventLogWriterPlugin]] = (
@@ -551,8 +572,8 @@ def _run_fleet_api_grpc_rere( # pylint: disable=R0913, R0917
551
572
  ffs_factory: FfsFactory,
552
573
  objectstore_factory: ObjectStoreFactory,
553
574
  enable_supernode_auth: bool,
554
- certificates: Optional[tuple[bytes, bytes, bytes]],
555
- interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None,
575
+ certificates: tuple[bytes, bytes, bytes] | None,
576
+ interceptors: Sequence[grpc.ServerInterceptor] | None = None,
556
577
  ) -> grpc.Server:
557
578
  """Run Fleet API (gRPC, request-response)."""
558
579
  # Create Fleet API gRPC server
@@ -585,7 +606,7 @@ def _run_fleet_api_grpc_adapter(
585
606
  state_factory: LinkStateFactory,
586
607
  ffs_factory: FfsFactory,
587
608
  objectstore_factory: ObjectStoreFactory,
588
- certificates: Optional[tuple[bytes, bytes, bytes]],
609
+ certificates: tuple[bytes, bytes, bytes] | None,
589
610
  ) -> grpc.Server:
590
611
  """Run Fleet API (GrpcAdapter)."""
591
612
  # Create Fleet API gRPC server
@@ -618,8 +639,8 @@ def _run_fleet_api_grpc_adapter(
618
639
  def _run_fleet_api_rest(
619
640
  host: str,
620
641
  port: int,
621
- ssl_keyfile: Optional[str],
622
- ssl_certfile: Optional[str],
642
+ ssl_keyfile: str | None,
643
+ ssl_certfile: str | None,
623
644
  state_factory: LinkStateFactory,
624
645
  ffs_factory: FfsFactory,
625
646
  objectstore_factory: ObjectStoreFactory,
@@ -19,7 +19,6 @@ import random
19
19
  import threading
20
20
  from abc import ABC, abstractmethod
21
21
  from logging import INFO
22
- from typing import Optional
23
22
 
24
23
  from flwr.common.logger import log
25
24
 
@@ -80,8 +79,8 @@ class ClientManager(ABC):
80
79
  def sample(
81
80
  self,
82
81
  num_clients: int,
83
- min_num_clients: Optional[int] = None,
84
- criterion: Optional[Criterion] = None,
82
+ min_num_clients: int | None = None,
83
+ criterion: Criterion | None = None,
85
84
  ) -> list[ClientProxy]:
86
85
  """Sample a number of Flower ClientProxy instances."""
87
86
 
@@ -179,8 +178,8 @@ class SimpleClientManager(ClientManager):
179
178
  def sample(
180
179
  self,
181
180
  num_clients: int,
182
- min_num_clients: Optional[int] = None,
183
- criterion: Optional[Criterion] = None,
181
+ min_num_clients: int | None = None,
182
+ criterion: Criterion | None = None,
184
183
  ) -> list[ClientProxy]:
185
184
  """Sample a number of Flower ClientProxy instances."""
186
185
  # Block until at least num_clients are connected.
@@ -16,7 +16,6 @@
16
16
 
17
17
 
18
18
  from abc import ABC, abstractmethod
19
- from typing import Optional
20
19
 
21
20
  from flwr.common import (
22
21
  DisconnectRes,
@@ -46,8 +45,8 @@ class ClientProxy(ABC):
46
45
  def get_properties(
47
46
  self,
48
47
  ins: GetPropertiesIns,
49
- timeout: Optional[float],
50
- group_id: Optional[int],
48
+ timeout: float | None,
49
+ group_id: int | None,
51
50
  ) -> GetPropertiesRes:
52
51
  """Return the client's properties."""
53
52
 
@@ -55,8 +54,8 @@ class ClientProxy(ABC):
55
54
  def get_parameters(
56
55
  self,
57
56
  ins: GetParametersIns,
58
- timeout: Optional[float],
59
- group_id: Optional[int],
57
+ timeout: float | None,
58
+ group_id: int | None,
60
59
  ) -> GetParametersRes:
61
60
  """Return the current local model parameters."""
62
61
 
@@ -64,8 +63,8 @@ class ClientProxy(ABC):
64
63
  def fit(
65
64
  self,
66
65
  ins: FitIns,
67
- timeout: Optional[float],
68
- group_id: Optional[int],
66
+ timeout: float | None,
67
+ group_id: int | None,
69
68
  ) -> FitRes:
70
69
  """Refine the provided parameters using the locally held dataset."""
71
70
 
@@ -73,8 +72,8 @@ class ClientProxy(ABC):
73
72
  def evaluate(
74
73
  self,
75
74
  ins: EvaluateIns,
76
- timeout: Optional[float],
77
- group_id: Optional[int],
75
+ timeout: float | None,
76
+ group_id: int | None,
78
77
  ) -> EvaluateRes:
79
78
  """Evaluate the provided parameters using the locally held dataset."""
80
79
 
@@ -82,7 +81,7 @@ class ClientProxy(ABC):
82
81
  def reconnect(
83
82
  self,
84
83
  ins: ReconnectIns,
85
- timeout: Optional[float],
86
- group_id: Optional[int],
84
+ timeout: float | None,
85
+ group_id: int | None,
87
86
  ) -> DisconnectRes:
88
87
  """Disconnect and (optionally) reconnect later."""
flwr/server/compat/app.py CHANGED
@@ -16,7 +16,6 @@
16
16
 
17
17
 
18
18
  from logging import INFO
19
- from typing import Optional
20
19
 
21
20
  from flwr.common.logger import log
22
21
  from flwr.server.client_manager import ClientManager
@@ -32,10 +31,10 @@ from .app_utils import start_update_client_manager_thread
32
31
  def start_grid( # pylint: disable=too-many-arguments, too-many-locals
33
32
  *,
34
33
  grid: Grid,
35
- server: Optional[Server] = None,
36
- config: Optional[ServerConfig] = None,
37
- strategy: Optional[Strategy] = None,
38
- client_manager: Optional[ClientManager] = None,
34
+ server: Server | None = None,
35
+ config: ServerConfig | None = None,
36
+ strategy: Strategy | None = None,
37
+ client_manager: ClientManager | None = None,
39
38
  ) -> History:
40
39
  """Start a Flower server.
41
40
 
@@ -16,7 +16,8 @@
16
16
 
17
17
 
18
18
  import threading
19
- from typing import Any, Callable
19
+ from collections.abc import Callable
20
+ from typing import Any
20
21
 
21
22
  from flwr.common.typing import RunNotRunningException
22
23
 
@@ -15,8 +15,6 @@
15
15
  """Flower ClientProxy implementation using Grid."""
16
16
 
17
17
 
18
- from typing import Optional
19
-
20
18
  from flwr import common
21
19
  from flwr.common import Message, MessageType, MessageTypeLegacy, RecordDict
22
20
  from flwr.common import recorddict_compat as compat
@@ -37,8 +35,8 @@ class GridClientProxy(ClientProxy):
37
35
  def get_properties(
38
36
  self,
39
37
  ins: common.GetPropertiesIns,
40
- timeout: Optional[float],
41
- group_id: Optional[int],
38
+ timeout: float | None,
39
+ group_id: int | None,
42
40
  ) -> common.GetPropertiesRes:
43
41
  """Return client's properties."""
44
42
  # Ins to RecordDict
@@ -53,8 +51,8 @@ class GridClientProxy(ClientProxy):
53
51
  def get_parameters(
54
52
  self,
55
53
  ins: common.GetParametersIns,
56
- timeout: Optional[float],
57
- group_id: Optional[int],
54
+ timeout: float | None,
55
+ group_id: int | None,
58
56
  ) -> common.GetParametersRes:
59
57
  """Return the current local model parameters."""
60
58
  # Ins to RecordDict
@@ -67,7 +65,7 @@ class GridClientProxy(ClientProxy):
67
65
  return compat.recorddict_to_getparametersres(in_recorddict, False)
68
66
 
69
67
  def fit(
70
- self, ins: common.FitIns, timeout: Optional[float], group_id: Optional[int]
68
+ self, ins: common.FitIns, timeout: float | None, group_id: int | None
71
69
  ) -> common.FitRes:
72
70
  """Train model parameters on the locally held dataset."""
73
71
  # Ins to RecordDict
@@ -80,7 +78,7 @@ class GridClientProxy(ClientProxy):
80
78
  return compat.recorddict_to_fitres(in_recorddict, keep_input=False)
81
79
 
82
80
  def evaluate(
83
- self, ins: common.EvaluateIns, timeout: Optional[float], group_id: Optional[int]
81
+ self, ins: common.EvaluateIns, timeout: float | None, group_id: int | None
84
82
  ) -> common.EvaluateRes:
85
83
  """Evaluate model parameters on the locally held dataset."""
86
84
  # Ins to RecordDict
@@ -95,8 +93,8 @@ class GridClientProxy(ClientProxy):
95
93
  def reconnect(
96
94
  self,
97
95
  ins: common.ReconnectIns,
98
- timeout: Optional[float],
99
- group_id: Optional[int],
96
+ timeout: float | None,
97
+ group_id: int | None,
100
98
  ) -> common.DisconnectRes:
101
99
  """Disconnect and (optionally) reconnect later."""
102
100
  return common.DisconnectRes(reason="") # Nothing to do here (yet)
@@ -105,8 +103,8 @@ class GridClientProxy(ClientProxy):
105
103
  self,
106
104
  recorddict: RecordDict,
107
105
  message_type: str,
108
- timeout: Optional[float],
109
- group_id: Optional[int],
106
+ timeout: float | None,
107
+ group_id: int | None,
110
108
  ) -> RecordDict:
111
109
 
112
110
  # Create message
@@ -16,7 +16,6 @@
16
16
 
17
17
 
18
18
  from dataclasses import dataclass
19
- from typing import Optional
20
19
 
21
20
  from flwr.common import Context
22
21
 
@@ -38,9 +37,9 @@ class LegacyContext(Context):
38
37
  def __init__( # pylint: disable=too-many-arguments
39
38
  self,
40
39
  context: Context,
41
- config: Optional[ServerConfig] = None,
42
- strategy: Optional[Strategy] = None,
43
- client_manager: Optional[ClientManager] = None,
40
+ config: ServerConfig | None = None,
41
+ strategy: Strategy | None = None,
42
+ client_manager: ClientManager | None = None,
44
43
  ) -> None:
45
44
  if config is None:
46
45
  config = ServerConfig()
@@ -15,7 +15,8 @@
15
15
  """Flower Fleet API event log interceptor."""
16
16
 
17
17
 
18
- from typing import Any, Callable, cast
18
+ from collections.abc import Callable
19
+ from typing import Any, cast
19
20
 
20
21
  import grpc
21
22
  from google.protobuf.message import Message as GrpcMessage
flwr/server/grid/grid.py CHANGED
@@ -17,7 +17,6 @@
17
17
 
18
18
  from abc import ABC, abstractmethod
19
19
  from collections.abc import Iterable
20
- from typing import Optional
21
20
 
22
21
  from flwr.common import Message, RecordDict
23
22
  from flwr.common.typing import Run
@@ -52,7 +51,7 @@ class Grid(ABC):
52
51
  message_type: str,
53
52
  dst_node_id: int,
54
53
  group_id: str,
55
- ttl: Optional[float] = None,
54
+ ttl: float | None = None,
56
55
  ) -> Message:
57
56
  """Create a new message with specified parameters.
58
57
 
@@ -130,7 +129,7 @@ class Grid(ABC):
130
129
  self,
131
130
  messages: Iterable[Message],
132
131
  *,
133
- timeout: Optional[float] = None,
132
+ timeout: float | None = None,
134
133
  ) -> Iterable[Message]:
135
134
  """Push messages to specified node IDs and pull the reply messages.
136
135
 
@@ -18,7 +18,7 @@
18
18
  import time
19
19
  from collections.abc import Iterable
20
20
  from logging import DEBUG, ERROR, WARNING
21
- from typing import Optional, cast
21
+ from typing import cast
22
22
 
23
23
  import grpc
24
24
 
@@ -119,13 +119,13 @@ class GrpcGrid(Grid):
119
119
  def __init__( # pylint: disable=too-many-arguments
120
120
  self,
121
121
  serverappio_service_address: str = SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS,
122
- root_certificates: Optional[bytes] = None,
122
+ root_certificates: bytes | None = None,
123
123
  ) -> None:
124
124
  self._addr = serverappio_service_address
125
125
  self._cert = root_certificates
126
- self._run: Optional[Run] = None
127
- self._grpc_stub: Optional[ServerAppIoStub] = None
128
- self._channel: Optional[grpc.Channel] = None
126
+ self._run: Run | None = None
127
+ self._grpc_stub: ServerAppIoStub | None = None
128
+ self._channel: grpc.Channel | None = None
129
129
  self.node = Node(node_id=SUPERLINK_NODE_ID)
130
130
  self._retry_invoker = _make_simple_grpc_retry_invoker()
131
131
  super().__init__()
@@ -200,7 +200,7 @@ class GrpcGrid(Grid):
200
200
  message_type: str,
201
201
  dst_node_id: int,
202
202
  group_id: str,
203
- ttl: Optional[float] = None,
203
+ ttl: float | None = None,
204
204
  ) -> Message:
205
205
  """Create a new message with specified parameters.
206
206
 
@@ -313,7 +313,9 @@ class GrpcGrid(Grid):
313
313
  )
314
314
  # Pull Messages from store
315
315
  inflated_msgs: list[Message] = []
316
- for msg_proto, msg_tree in zip(res.messages_list, res.message_object_trees):
316
+ for msg_proto, msg_tree in zip(
317
+ res.messages_list, res.message_object_trees, strict=True
318
+ ):
317
319
  msg_id = msg_proto.metadata.message_id
318
320
  try:
319
321
  all_object_contents = pull_objects(
@@ -376,7 +378,7 @@ class GrpcGrid(Grid):
376
378
  self,
377
379
  messages: Iterable[Message],
378
380
  *,
379
- timeout: Optional[float] = None,
381
+ timeout: float | None = None,
380
382
  ) -> Iterable[Message]:
381
383
  """Push messages to specified node IDs and pull the reply messages.
382
384
 
@@ -17,7 +17,7 @@
17
17
 
18
18
  import time
19
19
  from collections.abc import Iterable
20
- from typing import Optional, cast
20
+ from typing import cast
21
21
  from uuid import uuid4
22
22
 
23
23
  from flwr.common import Message, RecordDict
@@ -48,7 +48,7 @@ class InMemoryGrid(Grid):
48
48
  state_factory: LinkStateFactory,
49
49
  pull_interval: float = 0.1,
50
50
  ) -> None:
51
- self._run: Optional[Run] = None
51
+ self._run: Run | None = None
52
52
  self.state = state_factory.state()
53
53
  self.pull_interval = pull_interval
54
54
  self.node = Node(node_id=SUPERLINK_NODE_ID)
@@ -81,7 +81,7 @@ class InMemoryGrid(Grid):
81
81
  message_type: str,
82
82
  dst_node_id: int,
83
83
  group_id: str,
84
- ttl: Optional[float] = None,
84
+ ttl: float | None = None,
85
85
  ) -> Message:
86
86
  """Create a new message with specified parameters.
87
87
 
@@ -143,7 +143,7 @@ class InMemoryGrid(Grid):
143
143
  self,
144
144
  messages: Iterable[Message],
145
145
  *,
146
- timeout: Optional[float] = None,
146
+ timeout: float | None = None,
147
147
  ) -> Iterable[Message]:
148
148
  """Push messages to specified node IDs and pull the reply messages.
149
149
 
@@ -16,7 +16,6 @@
16
16
 
17
17
 
18
18
  from logging import DEBUG
19
- from typing import Optional
20
19
 
21
20
  from flwr.common import Context
22
21
  from flwr.common.logger import log
@@ -30,8 +29,8 @@ def run(
30
29
  grid: Grid,
31
30
  context: Context,
32
31
  server_app_dir: str,
33
- server_app_attr: Optional[str] = None,
34
- loaded_server_app: Optional[ServerApp] = None,
32
+ server_app_attr: str | None = None,
33
+ loaded_server_app: ServerApp | None = None,
35
34
  ) -> Context:
36
35
  """Run ServerApp with a given Grid."""
37
36
  if not (server_app_attr is None) ^ (loaded_server_app is None):