flwr 1.22.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 (301) 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 +34 -1
  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/__init__.py +15 -6
  9. flwr/cli/auth_plugin/auth_plugin.py +94 -0
  10. flwr/cli/auth_plugin/noop_auth_plugin.py +101 -0
  11. flwr/cli/auth_plugin/oidc_cli_plugin.py +46 -32
  12. flwr/cli/build.py +166 -53
  13. flwr/cli/{cli_user_auth_interceptor.py → cli_account_auth_interceptor.py} +29 -11
  14. flwr/cli/config_utils.py +101 -13
  15. flwr/cli/federation/__init__.py +24 -0
  16. flwr/cli/federation/ls.py +140 -0
  17. flwr/cli/federation/show.py +317 -0
  18. flwr/cli/install.py +91 -13
  19. flwr/cli/log.py +54 -11
  20. flwr/cli/login/login.py +41 -27
  21. flwr/cli/ls.py +177 -133
  22. flwr/cli/new/new.py +175 -40
  23. flwr/cli/new/templates/app/code/task.pytorch.py.tpl +1 -0
  24. flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +1 -1
  25. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +1 -1
  26. flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +1 -1
  27. flwr/cli/new/templates/app/pyproject.jax.toml.tpl +1 -1
  28. flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -1
  29. flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +1 -1
  30. flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +3 -3
  31. flwr/cli/new/templates/app/pyproject.pytorch_legacy_api.toml.tpl +1 -1
  32. flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
  33. flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +2 -2
  34. flwr/cli/new/templates/app/pyproject.xgboost.toml.tpl +1 -1
  35. flwr/cli/pull.py +12 -7
  36. flwr/cli/run/run.py +82 -31
  37. flwr/cli/run_utils.py +130 -0
  38. flwr/cli/stop.py +27 -9
  39. flwr/cli/supernode/__init__.py +25 -0
  40. flwr/cli/supernode/ls.py +268 -0
  41. flwr/cli/supernode/register.py +190 -0
  42. flwr/cli/supernode/unregister.py +140 -0
  43. flwr/cli/utils.py +464 -81
  44. flwr/client/__init__.py +2 -1
  45. flwr/client/dpfedavg_numpy_client.py +4 -1
  46. flwr/client/grpc_adapter_client/connection.py +12 -15
  47. flwr/client/grpc_rere_client/connection.py +68 -41
  48. flwr/client/grpc_rere_client/grpc_adapter.py +34 -14
  49. flwr/client/grpc_rere_client/{client_interceptor.py → node_auth_client_interceptor.py} +5 -7
  50. flwr/client/message_handler/message_handler.py +2 -2
  51. flwr/client/mod/secure_aggregation/secaggplus_mod.py +10 -8
  52. flwr/client/numpy_client.py +1 -1
  53. flwr/client/rest_client/connection.py +94 -51
  54. flwr/client/run_info_store.py +4 -5
  55. flwr/client/typing.py +1 -1
  56. flwr/clientapp/__init__.py +1 -2
  57. flwr/{client → clientapp}/client_app.py +9 -10
  58. flwr/clientapp/mod/centraldp_mods.py +16 -17
  59. flwr/clientapp/mod/localdp_mod.py +8 -9
  60. flwr/clientapp/typing.py +1 -1
  61. flwr/{client/clientapp → clientapp}/utils.py +4 -4
  62. flwr/common/address.py +1 -2
  63. flwr/common/args.py +3 -4
  64. flwr/common/config.py +13 -16
  65. flwr/common/constant.py +56 -13
  66. flwr/common/differential_privacy.py +3 -4
  67. flwr/common/event_log_plugin/event_log_plugin.py +3 -4
  68. flwr/common/exit/exit.py +15 -2
  69. flwr/common/exit/exit_code.py +39 -10
  70. flwr/common/exit/exit_handler.py +6 -2
  71. flwr/common/exit/signal_handler.py +5 -5
  72. flwr/common/grpc.py +6 -6
  73. flwr/common/inflatable_protobuf_utils.py +1 -1
  74. flwr/common/inflatable_utils.py +48 -31
  75. flwr/common/logger.py +19 -19
  76. flwr/common/message.py +4 -4
  77. flwr/common/object_ref.py +7 -7
  78. flwr/common/record/array.py +6 -6
  79. flwr/common/record/arrayrecord.py +18 -21
  80. flwr/common/record/configrecord.py +3 -3
  81. flwr/common/record/recorddict.py +5 -5
  82. flwr/common/record/typeddict.py +9 -2
  83. flwr/common/recorddict_compat.py +7 -10
  84. flwr/common/retry_invoker.py +20 -20
  85. flwr/common/secure_aggregation/crypto/symmetric_encryption.py +1 -89
  86. flwr/common/secure_aggregation/ndarrays_arithmetic.py +3 -3
  87. flwr/common/serde.py +9 -6
  88. flwr/common/serde_utils.py +2 -2
  89. flwr/common/telemetry.py +9 -5
  90. flwr/common/typing.py +59 -43
  91. flwr/compat/client/app.py +39 -38
  92. flwr/compat/client/grpc_client/connection.py +13 -13
  93. flwr/compat/server/app.py +5 -6
  94. flwr/proto/appio_pb2.py +13 -3
  95. flwr/proto/appio_pb2.pyi +134 -65
  96. flwr/proto/appio_pb2_grpc.py +20 -0
  97. flwr/proto/appio_pb2_grpc.pyi +27 -0
  98. flwr/proto/clientappio_pb2.py +17 -7
  99. flwr/proto/clientappio_pb2.pyi +15 -0
  100. flwr/proto/clientappio_pb2_grpc.py +206 -40
  101. flwr/proto/clientappio_pb2_grpc.pyi +168 -53
  102. flwr/proto/control_pb2.py +72 -40
  103. flwr/proto/control_pb2.pyi +319 -87
  104. flwr/proto/control_pb2_grpc.py +339 -28
  105. flwr/proto/control_pb2_grpc.pyi +209 -37
  106. flwr/proto/error_pb2.py +13 -3
  107. flwr/proto/error_pb2.pyi +24 -6
  108. flwr/proto/error_pb2_grpc.py +20 -0
  109. flwr/proto/error_pb2_grpc.pyi +27 -0
  110. flwr/proto/fab_pb2.py +24 -10
  111. flwr/proto/fab_pb2.pyi +68 -20
  112. flwr/proto/fab_pb2_grpc.py +20 -0
  113. flwr/proto/fab_pb2_grpc.pyi +27 -0
  114. flwr/proto/federation_pb2.py +38 -0
  115. flwr/proto/federation_pb2.pyi +56 -0
  116. flwr/proto/federation_pb2_grpc.py +24 -0
  117. flwr/proto/federation_pb2_grpc.pyi +31 -0
  118. flwr/proto/fleet_pb2.py +45 -27
  119. flwr/proto/fleet_pb2.pyi +186 -70
  120. flwr/proto/fleet_pb2_grpc.py +277 -66
  121. flwr/proto/fleet_pb2_grpc.pyi +201 -55
  122. flwr/proto/grpcadapter_pb2.py +14 -4
  123. flwr/proto/grpcadapter_pb2.pyi +38 -16
  124. flwr/proto/grpcadapter_pb2_grpc.py +35 -4
  125. flwr/proto/grpcadapter_pb2_grpc.pyi +38 -7
  126. flwr/proto/heartbeat_pb2.py +17 -7
  127. flwr/proto/heartbeat_pb2.pyi +51 -22
  128. flwr/proto/heartbeat_pb2_grpc.py +20 -0
  129. flwr/proto/heartbeat_pb2_grpc.pyi +27 -0
  130. flwr/proto/log_pb2.py +13 -3
  131. flwr/proto/log_pb2.pyi +34 -11
  132. flwr/proto/log_pb2_grpc.py +20 -0
  133. flwr/proto/log_pb2_grpc.pyi +27 -0
  134. flwr/proto/message_pb2.py +15 -5
  135. flwr/proto/message_pb2.pyi +154 -86
  136. flwr/proto/message_pb2_grpc.py +20 -0
  137. flwr/proto/message_pb2_grpc.pyi +27 -0
  138. flwr/proto/node_pb2.py +16 -4
  139. flwr/proto/node_pb2.pyi +77 -4
  140. flwr/proto/node_pb2_grpc.py +20 -0
  141. flwr/proto/node_pb2_grpc.pyi +27 -0
  142. flwr/proto/recorddict_pb2.py +13 -3
  143. flwr/proto/recorddict_pb2.pyi +184 -107
  144. flwr/proto/recorddict_pb2_grpc.py +20 -0
  145. flwr/proto/recorddict_pb2_grpc.pyi +27 -0
  146. flwr/proto/run_pb2.py +40 -31
  147. flwr/proto/run_pb2.pyi +149 -84
  148. flwr/proto/run_pb2_grpc.py +20 -0
  149. flwr/proto/run_pb2_grpc.pyi +27 -0
  150. flwr/proto/serverappio_pb2.py +13 -3
  151. flwr/proto/serverappio_pb2.pyi +32 -8
  152. flwr/proto/serverappio_pb2_grpc.py +246 -65
  153. flwr/proto/serverappio_pb2_grpc.pyi +221 -85
  154. flwr/proto/simulationio_pb2.py +16 -8
  155. flwr/proto/simulationio_pb2.pyi +15 -0
  156. flwr/proto/simulationio_pb2_grpc.py +162 -41
  157. flwr/proto/simulationio_pb2_grpc.pyi +149 -55
  158. flwr/proto/transport_pb2.py +20 -10
  159. flwr/proto/transport_pb2.pyi +249 -160
  160. flwr/proto/transport_pb2_grpc.py +35 -4
  161. flwr/proto/transport_pb2_grpc.pyi +38 -8
  162. flwr/server/app.py +173 -127
  163. flwr/server/client_manager.py +4 -5
  164. flwr/server/client_proxy.py +10 -11
  165. flwr/server/compat/app.py +4 -5
  166. flwr/server/compat/app_utils.py +2 -1
  167. flwr/server/compat/grid_client_proxy.py +10 -12
  168. flwr/server/compat/legacy_context.py +3 -4
  169. flwr/server/fleet_event_log_interceptor.py +2 -1
  170. flwr/server/grid/grid.py +2 -3
  171. flwr/server/grid/grpc_grid.py +10 -8
  172. flwr/server/grid/inmemory_grid.py +4 -4
  173. flwr/server/run_serverapp.py +2 -3
  174. flwr/server/server.py +34 -39
  175. flwr/server/server_app.py +7 -8
  176. flwr/server/server_config.py +1 -2
  177. flwr/server/serverapp/app.py +34 -28
  178. flwr/server/serverapp_components.py +4 -5
  179. flwr/server/strategy/aggregate.py +9 -8
  180. flwr/server/strategy/bulyan.py +13 -11
  181. flwr/server/strategy/dp_adaptive_clipping.py +16 -20
  182. flwr/server/strategy/dp_fixed_clipping.py +12 -17
  183. flwr/server/strategy/dpfedavg_adaptive.py +3 -4
  184. flwr/server/strategy/dpfedavg_fixed.py +6 -10
  185. flwr/server/strategy/fault_tolerant_fedavg.py +14 -13
  186. flwr/server/strategy/fedadagrad.py +18 -14
  187. flwr/server/strategy/fedadam.py +16 -14
  188. flwr/server/strategy/fedavg.py +16 -17
  189. flwr/server/strategy/fedavg_android.py +15 -15
  190. flwr/server/strategy/fedavgm.py +21 -18
  191. flwr/server/strategy/fedmedian.py +2 -3
  192. flwr/server/strategy/fedopt.py +11 -10
  193. flwr/server/strategy/fedprox.py +10 -9
  194. flwr/server/strategy/fedtrimmedavg.py +12 -11
  195. flwr/server/strategy/fedxgb_bagging.py +13 -11
  196. flwr/server/strategy/fedxgb_cyclic.py +6 -6
  197. flwr/server/strategy/fedxgb_nn_avg.py +4 -4
  198. flwr/server/strategy/fedyogi.py +16 -14
  199. flwr/server/strategy/krum.py +12 -11
  200. flwr/server/strategy/qfedavg.py +16 -15
  201. flwr/server/strategy/strategy.py +6 -9
  202. flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +19 -8
  203. flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -2
  204. flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +3 -4
  205. flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +10 -12
  206. flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +1 -3
  207. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +136 -42
  208. flwr/server/superlink/fleet/grpc_rere/{server_interceptor.py → node_auth_server_interceptor.py} +28 -51
  209. flwr/server/superlink/fleet/message_handler/message_handler.py +100 -49
  210. flwr/server/superlink/fleet/rest_rere/rest_api.py +54 -33
  211. flwr/server/superlink/fleet/vce/backend/backend.py +2 -2
  212. flwr/server/superlink/fleet/vce/backend/raybackend.py +6 -6
  213. flwr/server/superlink/fleet/vce/vce_api.py +32 -13
  214. flwr/server/superlink/linkstate/in_memory_linkstate.py +266 -207
  215. flwr/server/superlink/linkstate/linkstate.py +161 -62
  216. flwr/server/superlink/linkstate/linkstate_factory.py +24 -6
  217. flwr/server/superlink/linkstate/sqlite_linkstate.py +698 -638
  218. flwr/server/superlink/linkstate/utils.py +9 -60
  219. flwr/server/superlink/serverappio/serverappio_grpc.py +1 -2
  220. flwr/server/superlink/serverappio/serverappio_servicer.py +28 -23
  221. flwr/server/superlink/simulation/simulationio_grpc.py +1 -2
  222. flwr/server/superlink/simulation/simulationio_servicer.py +19 -14
  223. flwr/server/superlink/utils.py +4 -6
  224. flwr/server/typing.py +1 -1
  225. flwr/server/utils/tensorboard.py +15 -8
  226. flwr/server/utils/validator.py +2 -3
  227. flwr/server/workflow/default_workflows.py +5 -5
  228. flwr/server/workflow/secure_aggregation/secagg_workflow.py +2 -4
  229. flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +12 -10
  230. flwr/serverapp/strategy/bulyan.py +16 -15
  231. flwr/serverapp/strategy/dp_adaptive_clipping.py +12 -11
  232. flwr/serverapp/strategy/dp_fixed_clipping.py +11 -14
  233. flwr/serverapp/strategy/fedadagrad.py +10 -11
  234. flwr/serverapp/strategy/fedadam.py +10 -11
  235. flwr/serverapp/strategy/fedavg.py +9 -10
  236. flwr/serverapp/strategy/fedavgm.py +17 -16
  237. flwr/serverapp/strategy/fedmedian.py +2 -2
  238. flwr/serverapp/strategy/fedopt.py +10 -11
  239. flwr/serverapp/strategy/fedprox.py +7 -8
  240. flwr/serverapp/strategy/fedtrimmedavg.py +9 -9
  241. flwr/serverapp/strategy/fedxgb_bagging.py +3 -3
  242. flwr/serverapp/strategy/fedxgb_cyclic.py +9 -9
  243. flwr/serverapp/strategy/fedyogi.py +9 -11
  244. flwr/serverapp/strategy/krum.py +7 -7
  245. flwr/serverapp/strategy/multikrum.py +9 -9
  246. flwr/serverapp/strategy/qfedavg.py +17 -16
  247. flwr/serverapp/strategy/strategy.py +6 -9
  248. flwr/serverapp/strategy/strategy_utils.py +7 -8
  249. flwr/simulation/app.py +46 -42
  250. flwr/simulation/legacy_app.py +12 -12
  251. flwr/simulation/ray_transport/ray_actor.py +11 -12
  252. flwr/simulation/ray_transport/ray_client_proxy.py +12 -13
  253. flwr/simulation/run_simulation.py +44 -43
  254. flwr/simulation/simulationio_connection.py +4 -4
  255. flwr/supercore/cli/flower_superexec.py +3 -4
  256. flwr/supercore/constant.py +52 -0
  257. flwr/supercore/corestate/corestate.py +24 -3
  258. flwr/supercore/corestate/in_memory_corestate.py +138 -0
  259. flwr/supercore/corestate/sqlite_corestate.py +157 -0
  260. flwr/supercore/ffs/disk_ffs.py +1 -2
  261. flwr/supercore/ffs/ffs.py +1 -2
  262. flwr/supercore/ffs/ffs_factory.py +1 -2
  263. flwr/{common → supercore}/heartbeat.py +20 -25
  264. flwr/supercore/object_store/in_memory_object_store.py +1 -6
  265. flwr/supercore/object_store/object_store.py +1 -2
  266. flwr/supercore/object_store/object_store_factory.py +27 -8
  267. flwr/supercore/object_store/sqlite_object_store.py +253 -0
  268. flwr/{client/clientapp → supercore/primitives}/__init__.py +1 -1
  269. flwr/supercore/primitives/asymmetric.py +117 -0
  270. flwr/supercore/primitives/asymmetric_ed25519.py +175 -0
  271. flwr/supercore/sqlite_mixin.py +159 -0
  272. flwr/supercore/superexec/plugin/base_exec_plugin.py +1 -2
  273. flwr/supercore/superexec/plugin/exec_plugin.py +3 -3
  274. flwr/supercore/superexec/run_superexec.py +9 -13
  275. flwr/supercore/utils.py +20 -0
  276. flwr/superlink/artifact_provider/artifact_provider.py +1 -2
  277. flwr/{common → superlink}/auth_plugin/__init__.py +6 -6
  278. flwr/superlink/auth_plugin/auth_plugin.py +88 -0
  279. flwr/superlink/auth_plugin/noop_auth_plugin.py +84 -0
  280. flwr/superlink/federation/__init__.py +24 -0
  281. flwr/superlink/federation/federation_manager.py +64 -0
  282. flwr/superlink/federation/noop_federation_manager.py +71 -0
  283. flwr/superlink/servicer/control/{control_user_auth_interceptor.py → control_account_auth_interceptor.py} +41 -32
  284. flwr/superlink/servicer/control/control_event_log_interceptor.py +7 -7
  285. flwr/superlink/servicer/control/control_grpc.py +18 -17
  286. flwr/superlink/servicer/control/control_license_interceptor.py +3 -3
  287. flwr/superlink/servicer/control/control_servicer.py +239 -63
  288. flwr/supernode/cli/flower_supernode.py +74 -26
  289. flwr/supernode/nodestate/in_memory_nodestate.py +60 -49
  290. flwr/supernode/nodestate/nodestate.py +7 -8
  291. flwr/supernode/nodestate/nodestate_factory.py +7 -4
  292. flwr/supernode/runtime/run_clientapp.py +43 -24
  293. flwr/supernode/servicer/clientappio/clientappio_servicer.py +40 -10
  294. flwr/supernode/start_client_internal.py +175 -51
  295. {flwr-1.22.0.dist-info → flwr-1.24.0.dist-info}/METADATA +8 -8
  296. flwr-1.24.0.dist-info/RECORD +454 -0
  297. flwr/common/auth_plugin/auth_plugin.py +0 -149
  298. flwr/supercore/object_store/utils.py +0 -43
  299. flwr-1.22.0.dist-info/RECORD +0 -428
  300. {flwr-1.22.0.dist-info → flwr-1.24.0.dist-info}/WHEEL +0 -0
  301. {flwr-1.22.0.dist-info → flwr-1.24.0.dist-info}/entry_points.txt +0 -0
flwr/cli/log.py CHANGED
@@ -18,7 +18,7 @@
18
18
  import time
19
19
  from logging import DEBUG, ERROR, INFO
20
20
  from pathlib import Path
21
- from typing import Annotated, Any, Optional, cast
21
+ from typing import Annotated, Any, cast
22
22
 
23
23
  import grpc
24
24
  import typer
@@ -35,17 +35,31 @@ from flwr.common.logger import log as logger
35
35
  from flwr.proto.control_pb2 import StreamLogsRequest # pylint: disable=E0611
36
36
  from flwr.proto.control_pb2_grpc import ControlStub
37
37
 
38
- from .utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
38
+ from .utils import flwr_cli_grpc_exc_handler, init_channel, load_cli_auth_plugin
39
39
 
40
40
 
41
41
  class AllLogsRetrieved(BaseException):
42
- """Raised when all logs are retrieved."""
42
+ """Exception raised when all available logs have been retrieved.
43
+
44
+ This exception is used internally to signal that the log stream has reached the end
45
+ and all logs have been successfully retrieved.
46
+ """
43
47
 
44
48
 
45
49
  def start_stream(
46
50
  run_id: int, channel: grpc.Channel, refresh_period: int = CONN_REFRESH_PERIOD
47
51
  ) -> None:
48
- """Start log streaming for a given run ID."""
52
+ """Start log streaming for a given run ID.
53
+
54
+ Parameters
55
+ ----------
56
+ run_id : int
57
+ The unique identifier of the run to stream logs from.
58
+ channel : grpc.Channel
59
+ The gRPC channel for communication.
60
+ refresh_period : int (default: CONN_REFRESH_PERIOD)
61
+ Connection refresh period in seconds.
62
+ """
49
63
  stub = ControlStub(channel)
50
64
  after_timestamp = 0.0
51
65
  try:
@@ -111,7 +125,17 @@ def stream_logs(
111
125
 
112
126
 
113
127
  def print_logs(run_id: int, channel: grpc.Channel, timeout: int) -> None:
114
- """Print logs from the beginning of a run."""
128
+ """Print logs from the beginning of a run.
129
+
130
+ Parameters
131
+ ----------
132
+ run_id : int
133
+ The unique identifier of the run to retrieve logs from.
134
+ channel : grpc.Channel
135
+ The gRPC channel for communication.
136
+ timeout : int
137
+ Timeout duration in seconds for the log retrieval request.
138
+ """
115
139
  stub = ControlStub(channel)
116
140
  req = StreamLogsRequest(run_id=run_id, after_timestamp=0.0)
117
141
 
@@ -143,11 +167,11 @@ def log(
143
167
  typer.Argument(help="Path of the Flower project to run"),
144
168
  ] = Path("."),
145
169
  federation: Annotated[
146
- Optional[str],
170
+ str | None,
147
171
  typer.Argument(help="Name of the federation to run the app on"),
148
172
  ] = None,
149
173
  federation_config_overrides: Annotated[
150
- Optional[list[str]],
174
+ list[str] | None,
151
175
  typer.Option(
152
176
  "--federation-config",
153
177
  help=FEDERATION_CONFIG_HELP_MESSAGE,
@@ -161,11 +185,15 @@ def log(
161
185
  ),
162
186
  ] = True,
163
187
  ) -> None:
164
- """Get logs from a Flower project run."""
188
+ """Get logs from a run.
189
+
190
+ Retrieve and display logs from a Flower run. Logs can be streamed in real-time (with
191
+ --stream) or printed once (with --show).
192
+ """
165
193
  typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
166
194
 
167
195
  pyproject_path = app / "pyproject.toml" if app else None
168
- config, errors, warnings = load_and_validate(path=pyproject_path)
196
+ config, errors, warnings = load_and_validate(pyproject_path, check_module=False)
169
197
  config = process_loaded_project_config(config, errors, warnings)
170
198
  federation, federation_config = validate_federation_in_project_config(
171
199
  federation, config, federation_config_overrides
@@ -175,7 +203,7 @@ def log(
175
203
  try:
176
204
  _log_with_control_api(app, federation, federation_config, run_id, stream)
177
205
  except Exception as err: # pylint: disable=broad-except
178
- typer.secho(str(err), fg=typer.colors.RED, bold=True)
206
+ typer.secho(str(err), fg=typer.colors.RED, bold=True, err=True)
179
207
  raise typer.Exit(code=1) from None
180
208
 
181
209
 
@@ -186,7 +214,22 @@ def _log_with_control_api(
186
214
  run_id: int,
187
215
  stream: bool,
188
216
  ) -> None:
189
- auth_plugin = try_obtain_cli_auth_plugin(app, federation, federation_config)
217
+ """Retrieve logs using the Control API.
218
+
219
+ Parameters
220
+ ----------
221
+ app : Path
222
+ Path to the Flower app directory.
223
+ federation : str
224
+ Name of the federation.
225
+ federation_config : dict[str, Any]
226
+ Federation configuration dictionary.
227
+ run_id : int
228
+ The unique identifier of the run to retrieve logs from.
229
+ stream : bool
230
+ If True, stream logs continuously; if False, print once.
231
+ """
232
+ auth_plugin = load_cli_auth_plugin(app, federation, federation_config)
190
233
  channel = init_channel(app, federation_config, auth_plugin)
191
234
 
192
235
  if stream:
flwr/cli/login/login.py CHANGED
@@ -16,10 +16,11 @@
16
16
 
17
17
 
18
18
  from pathlib import Path
19
- from typing import Annotated, Optional
19
+ from typing import Annotated
20
20
 
21
21
  import typer
22
22
 
23
+ from flwr.cli.auth_plugin import LoginError, NoOpCliAuthPlugin
23
24
  from flwr.cli.config_utils import (
24
25
  exit_if_no_address,
25
26
  get_insecure_flag,
@@ -28,14 +29,19 @@ from flwr.cli.config_utils import (
28
29
  validate_federation_in_project_config,
29
30
  )
30
31
  from flwr.cli.constant import FEDERATION_CONFIG_HELP_MESSAGE
31
- from flwr.common.typing import UserAuthLoginDetails
32
+ from flwr.common.typing import AccountAuthLoginDetails
32
33
  from flwr.proto.control_pb2 import ( # pylint: disable=E0611
33
34
  GetLoginDetailsRequest,
34
35
  GetLoginDetailsResponse,
35
36
  )
36
37
  from flwr.proto.control_pb2_grpc import ControlStub
37
38
 
38
- from ..utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
39
+ from ..utils import (
40
+ account_auth_enabled,
41
+ flwr_cli_grpc_exc_handler,
42
+ init_channel,
43
+ load_cli_auth_plugin,
44
+ )
39
45
 
40
46
 
41
47
  def login( # pylint: disable=R0914
@@ -44,11 +50,11 @@ def login( # pylint: disable=R0914
44
50
  typer.Argument(help="Path of the Flower App to run."),
45
51
  ] = Path("."),
46
52
  federation: Annotated[
47
- Optional[str],
53
+ str | None,
48
54
  typer.Argument(help="Name of the federation to login into."),
49
55
  ] = None,
50
56
  federation_config_overrides: Annotated[
51
- Optional[list[str]],
57
+ list[str] | None,
52
58
  typer.Option(
53
59
  "--federation-config",
54
60
  help=FEDERATION_CONFIG_HELP_MESSAGE,
@@ -59,7 +65,7 @@ def login( # pylint: disable=R0914
59
65
  typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
60
66
 
61
67
  pyproject_path = app / "pyproject.toml" if app else None
62
- config, errors, warnings = load_and_validate(path=pyproject_path)
68
+ config, errors, warnings = load_and_validate(pyproject_path, check_module=False)
63
69
 
64
70
  config = process_loaded_project_config(config, errors, warnings)
65
71
  federation, federation_config = validate_federation_in_project_config(
@@ -67,14 +73,16 @@ def login( # pylint: disable=R0914
67
73
  )
68
74
  exit_if_no_address(federation_config, "login")
69
75
 
70
- # Check if `enable-user-auth` is set to `true`
71
- if not federation_config.get("enable-user-auth", False):
76
+ # Check if `enable-account-auth` is set to `true`
77
+
78
+ if not account_auth_enabled(federation_config):
72
79
  typer.secho(
73
- f"❌ User authentication is not enabled for the federation '{federation}'. "
74
- "To enable it, set `enable-user-auth = true` in the federation "
75
- "configuration.",
80
+ "❌ Account authentication is not enabled for the federation "
81
+ f"'{federation}'. To enable it, set `enable-account-auth = true` "
82
+ "in the federation configuration.",
76
83
  fg=typer.colors.RED,
77
84
  bold=True,
85
+ err=True,
78
86
  )
79
87
  raise typer.Exit(code=1)
80
88
  # Check if insecure flag is set to `True`
@@ -85,10 +93,11 @@ def login( # pylint: disable=R0914
85
93
  "`true` in the federation configuration.",
86
94
  fg=typer.colors.RED,
87
95
  bold=True,
96
+ err=True,
88
97
  )
89
98
  raise typer.Exit(code=1)
90
99
 
91
- channel = init_channel(app, federation_config, None)
100
+ channel = init_channel(app, federation_config, NoOpCliAuthPlugin(Path()))
92
101
  stub = ControlStub(channel)
93
102
 
94
103
  login_request = GetLoginDetailsRequest()
@@ -96,28 +105,33 @@ def login( # pylint: disable=R0914
96
105
  login_response: GetLoginDetailsResponse = stub.GetLoginDetails(login_request)
97
106
 
98
107
  # Get the auth plugin
99
- auth_type = login_response.auth_type
100
- auth_plugin = try_obtain_cli_auth_plugin(
101
- app, federation, federation_config, auth_type
102
- )
103
- if auth_plugin is None:
104
- typer.secho(
105
- f'❌ Authentication type "{auth_type}" not found',
106
- fg=typer.colors.RED,
107
- bold=True,
108
- )
109
- raise typer.Exit(code=1)
108
+ authn_type = login_response.authn_type
109
+ auth_plugin = load_cli_auth_plugin(app, federation, federation_config, authn_type)
110
110
 
111
111
  # Login
112
- details = UserAuthLoginDetails(
113
- auth_type=login_response.auth_type,
112
+ details = AccountAuthLoginDetails(
113
+ authn_type=login_response.authn_type,
114
114
  device_code=login_response.device_code,
115
115
  verification_uri_complete=login_response.verification_uri_complete,
116
116
  expires_in=login_response.expires_in,
117
117
  interval=login_response.interval,
118
118
  )
119
- with flwr_cli_grpc_exc_handler():
120
- credentials = auth_plugin.login(details, stub)
119
+ try:
120
+ with flwr_cli_grpc_exc_handler():
121
+ credentials = auth_plugin.login(details, stub)
122
+ typer.secho(
123
+ "✅ Login successful.",
124
+ fg=typer.colors.GREEN,
125
+ bold=False,
126
+ )
127
+ except LoginError as e:
128
+ typer.secho(
129
+ f"❌ Login failed: {e.message}",
130
+ fg=typer.colors.RED,
131
+ bold=True,
132
+ err=True,
133
+ )
134
+ raise typer.Exit(code=1) from None
121
135
 
122
136
  # Store the tokens
123
137
  auth_plugin.store_tokens(credentials)