flwr-nightly 1.23.0.dev20250930__py3-none-any.whl → 1.26.0.dev20260121__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 (375) hide show
  1. flwr/__init__.py +17 -6
  2. flwr/app/__init__.py +4 -1
  3. flwr/app/error.py +2 -2
  4. flwr/app/exception.py +3 -3
  5. flwr/app/message_type.py +29 -0
  6. flwr/app/metadata.py +5 -2
  7. flwr/app/user_config.py +19 -0
  8. flwr/cli/app.py +62 -9
  9. flwr/cli/{new/templates/app/code → app_cmd}/__init__.py +9 -1
  10. flwr/cli/app_cmd/publish.py +285 -0
  11. flwr/cli/app_cmd/review.py +262 -0
  12. flwr/cli/auth_plugin/__init__.py +13 -6
  13. flwr/cli/auth_plugin/auth_plugin.py +26 -15
  14. flwr/cli/auth_plugin/noop_auth_plugin.py +101 -0
  15. flwr/cli/auth_plugin/oidc_cli_plugin.py +52 -32
  16. flwr/cli/build.py +166 -53
  17. flwr/cli/{cli_user_auth_interceptor.py → cli_account_auth_interceptor.py} +27 -10
  18. flwr/cli/config/__init__.py +21 -0
  19. flwr/cli/config/ls.py +104 -0
  20. flwr/cli/config_migration.py +300 -0
  21. flwr/cli/config_utils.py +154 -13
  22. flwr/cli/constant.py +67 -0
  23. flwr/cli/{new/templates/app/code/flwr_tune → federation}/__init__.py +8 -1
  24. flwr/cli/federation/ls.py +361 -0
  25. flwr/cli/flower_config.py +447 -0
  26. flwr/cli/install.py +91 -13
  27. flwr/cli/log.py +65 -36
  28. flwr/cli/login/login.py +41 -27
  29. flwr/cli/ls.py +232 -158
  30. flwr/cli/new/new.py +188 -244
  31. flwr/cli/pull.py +25 -34
  32. flwr/cli/run/run.py +106 -74
  33. flwr/cli/run_utils.py +148 -0
  34. flwr/cli/stop.py +46 -37
  35. flwr/cli/supernode/__init__.py +25 -0
  36. flwr/cli/supernode/ls.py +273 -0
  37. flwr/cli/supernode/register.py +190 -0
  38. flwr/cli/supernode/unregister.py +140 -0
  39. flwr/cli/typing.py +211 -0
  40. flwr/cli/utils.py +428 -80
  41. flwr/client/__init__.py +2 -1
  42. flwr/client/dpfedavg_numpy_client.py +4 -1
  43. flwr/client/grpc_adapter_client/connection.py +14 -17
  44. flwr/client/grpc_rere_client/connection.py +73 -43
  45. flwr/client/grpc_rere_client/grpc_adapter.py +35 -15
  46. flwr/client/grpc_rere_client/{client_interceptor.py → node_auth_client_interceptor.py} +5 -7
  47. flwr/client/message_handler/message_handler.py +4 -3
  48. flwr/client/mod/centraldp_mods.py +1 -1
  49. flwr/client/mod/localdp_mod.py +1 -1
  50. flwr/client/mod/secure_aggregation/secaggplus_mod.py +11 -9
  51. flwr/client/numpy_client.py +1 -1
  52. flwr/client/rest_client/connection.py +99 -54
  53. flwr/client/run_info_store.py +6 -6
  54. flwr/client/typing.py +1 -1
  55. flwr/clientapp/__init__.py +1 -2
  56. flwr/{client → clientapp}/client_app.py +11 -11
  57. flwr/clientapp/mod/centraldp_mods.py +16 -17
  58. flwr/clientapp/mod/localdp_mod.py +8 -9
  59. flwr/clientapp/typing.py +1 -1
  60. flwr/{client/clientapp → clientapp}/utils.py +4 -4
  61. flwr/common/__init__.py +3 -2
  62. flwr/common/args.py +3 -4
  63. flwr/common/config.py +15 -17
  64. flwr/common/constant.py +56 -28
  65. flwr/common/context.py +2 -1
  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 +16 -3
  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 +8 -7
  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 +5 -5
  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 +8 -5
  87. flwr/common/serde.py +22 -11
  88. flwr/common/serde_utils.py +2 -2
  89. flwr/common/telemetry.py +10 -6
  90. flwr/common/typing.py +65 -44
  91. flwr/compat/client/app.py +45 -47
  92. flwr/compat/client/grpc_client/connection.py +15 -14
  93. flwr/compat/common/constant.py +29 -0
  94. flwr/compat/server/app.py +6 -7
  95. flwr/proto/appio_pb2.py +13 -3
  96. flwr/proto/appio_pb2.pyi +134 -65
  97. flwr/proto/appio_pb2_grpc.py +20 -0
  98. flwr/proto/appio_pb2_grpc.pyi +27 -0
  99. flwr/proto/clientappio_pb2.py +17 -7
  100. flwr/proto/clientappio_pb2.pyi +15 -0
  101. flwr/proto/clientappio_pb2_grpc.py +206 -40
  102. flwr/proto/clientappio_pb2_grpc.pyi +168 -53
  103. flwr/proto/control_pb2.py +72 -40
  104. flwr/proto/control_pb2.pyi +319 -87
  105. flwr/proto/control_pb2_grpc.py +339 -28
  106. flwr/proto/control_pb2_grpc.pyi +209 -37
  107. flwr/proto/error_pb2.py +13 -3
  108. flwr/proto/error_pb2.pyi +24 -6
  109. flwr/proto/error_pb2_grpc.py +20 -0
  110. flwr/proto/error_pb2_grpc.pyi +27 -0
  111. flwr/proto/fab_pb2.py +24 -10
  112. flwr/proto/fab_pb2.pyi +68 -20
  113. flwr/proto/fab_pb2_grpc.py +20 -0
  114. flwr/proto/fab_pb2_grpc.pyi +27 -0
  115. flwr/proto/federation_pb2.py +38 -0
  116. flwr/proto/federation_pb2.pyi +56 -0
  117. flwr/proto/federation_pb2_grpc.py +24 -0
  118. flwr/proto/federation_pb2_grpc.pyi +31 -0
  119. flwr/proto/fleet_pb2.py +45 -27
  120. flwr/proto/fleet_pb2.pyi +190 -70
  121. flwr/proto/fleet_pb2_grpc.py +277 -66
  122. flwr/proto/fleet_pb2_grpc.pyi +201 -55
  123. flwr/proto/grpcadapter_pb2.py +14 -4
  124. flwr/proto/grpcadapter_pb2.pyi +38 -16
  125. flwr/proto/grpcadapter_pb2_grpc.py +35 -4
  126. flwr/proto/grpcadapter_pb2_grpc.pyi +38 -7
  127. flwr/proto/heartbeat_pb2.py +17 -7
  128. flwr/proto/heartbeat_pb2.pyi +51 -22
  129. flwr/proto/heartbeat_pb2_grpc.py +20 -0
  130. flwr/proto/heartbeat_pb2_grpc.pyi +27 -0
  131. flwr/proto/log_pb2.py +13 -3
  132. flwr/proto/log_pb2.pyi +34 -11
  133. flwr/proto/log_pb2_grpc.py +20 -0
  134. flwr/proto/log_pb2_grpc.pyi +27 -0
  135. flwr/proto/message_pb2.py +15 -5
  136. flwr/proto/message_pb2.pyi +154 -86
  137. flwr/proto/message_pb2_grpc.py +20 -0
  138. flwr/proto/message_pb2_grpc.pyi +27 -0
  139. flwr/proto/node_pb2.py +16 -4
  140. flwr/proto/node_pb2.pyi +77 -4
  141. flwr/proto/node_pb2_grpc.py +20 -0
  142. flwr/proto/node_pb2_grpc.pyi +27 -0
  143. flwr/proto/recorddict_pb2.py +13 -3
  144. flwr/proto/recorddict_pb2.pyi +184 -107
  145. flwr/proto/recorddict_pb2_grpc.py +20 -0
  146. flwr/proto/recorddict_pb2_grpc.pyi +27 -0
  147. flwr/proto/run_pb2.py +40 -31
  148. flwr/proto/run_pb2.pyi +158 -84
  149. flwr/proto/run_pb2_grpc.py +20 -0
  150. flwr/proto/run_pb2_grpc.pyi +27 -0
  151. flwr/proto/serverappio_pb2.py +13 -3
  152. flwr/proto/serverappio_pb2.pyi +32 -8
  153. flwr/proto/serverappio_pb2_grpc.py +246 -65
  154. flwr/proto/serverappio_pb2_grpc.pyi +221 -85
  155. flwr/proto/simulationio_pb2.py +16 -8
  156. flwr/proto/simulationio_pb2.pyi +15 -0
  157. flwr/proto/simulationio_pb2_grpc.py +162 -41
  158. flwr/proto/simulationio_pb2_grpc.pyi +149 -55
  159. flwr/proto/transport_pb2.py +20 -10
  160. flwr/proto/transport_pb2.pyi +249 -160
  161. flwr/proto/transport_pb2_grpc.py +35 -4
  162. flwr/proto/transport_pb2_grpc.pyi +38 -8
  163. flwr/server/app.py +175 -128
  164. flwr/server/client_manager.py +4 -5
  165. flwr/server/client_proxy.py +10 -11
  166. flwr/server/compat/app.py +4 -5
  167. flwr/server/compat/app_utils.py +2 -1
  168. flwr/server/compat/grid_client_proxy.py +12 -13
  169. flwr/server/compat/legacy_context.py +3 -4
  170. flwr/server/fleet_event_log_interceptor.py +2 -1
  171. flwr/server/grid/grid.py +2 -3
  172. flwr/server/grid/grpc_grid.py +12 -10
  173. flwr/server/grid/inmemory_grid.py +4 -4
  174. flwr/server/run_serverapp.py +2 -3
  175. flwr/server/server.py +34 -39
  176. flwr/server/server_app.py +7 -8
  177. flwr/server/server_config.py +1 -2
  178. flwr/server/serverapp/app.py +34 -28
  179. flwr/server/serverapp_components.py +4 -5
  180. flwr/server/strategy/aggregate.py +9 -8
  181. flwr/server/strategy/bulyan.py +13 -11
  182. flwr/server/strategy/dp_adaptive_clipping.py +16 -20
  183. flwr/server/strategy/dp_fixed_clipping.py +12 -17
  184. flwr/server/strategy/dpfedavg_adaptive.py +3 -4
  185. flwr/server/strategy/dpfedavg_fixed.py +6 -10
  186. flwr/server/strategy/fault_tolerant_fedavg.py +14 -13
  187. flwr/server/strategy/fedadagrad.py +18 -14
  188. flwr/server/strategy/fedadam.py +16 -14
  189. flwr/server/strategy/fedavg.py +16 -17
  190. flwr/server/strategy/fedavg_android.py +15 -15
  191. flwr/server/strategy/fedavgm.py +21 -18
  192. flwr/server/strategy/fedmedian.py +2 -3
  193. flwr/server/strategy/fedopt.py +11 -10
  194. flwr/server/strategy/fedprox.py +10 -9
  195. flwr/server/strategy/fedtrimmedavg.py +12 -11
  196. flwr/server/strategy/fedxgb_bagging.py +13 -11
  197. flwr/server/strategy/fedxgb_cyclic.py +6 -6
  198. flwr/server/strategy/fedxgb_nn_avg.py +4 -4
  199. flwr/server/strategy/fedyogi.py +16 -14
  200. flwr/server/strategy/krum.py +12 -11
  201. flwr/server/strategy/qfedavg.py +16 -15
  202. flwr/server/strategy/strategy.py +6 -9
  203. flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +20 -9
  204. flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -2
  205. flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +3 -4
  206. flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +10 -12
  207. flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +1 -3
  208. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +136 -42
  209. flwr/server/superlink/fleet/grpc_rere/{server_interceptor.py → node_auth_server_interceptor.py} +28 -50
  210. flwr/server/superlink/fleet/message_handler/message_handler.py +141 -51
  211. flwr/server/superlink/fleet/rest_rere/rest_api.py +54 -33
  212. flwr/server/superlink/fleet/vce/backend/backend.py +2 -2
  213. flwr/server/superlink/fleet/vce/backend/raybackend.py +6 -6
  214. flwr/server/superlink/fleet/vce/vce_api.py +32 -13
  215. flwr/server/superlink/linkstate/__init__.py +2 -0
  216. flwr/server/superlink/linkstate/in_memory_linkstate.py +293 -208
  217. flwr/server/superlink/linkstate/linkstate.py +176 -64
  218. flwr/server/superlink/linkstate/linkstate_factory.py +24 -6
  219. flwr/server/superlink/linkstate/sql_linkstate.py +221 -0
  220. flwr/server/superlink/linkstate/sqlite_linkstate.py +743 -648
  221. flwr/server/superlink/linkstate/utils.py +11 -62
  222. flwr/server/superlink/serverappio/serverappio_grpc.py +1 -2
  223. flwr/server/superlink/serverappio/serverappio_servicer.py +28 -23
  224. flwr/server/superlink/simulation/simulationio_grpc.py +1 -2
  225. flwr/server/superlink/simulation/simulationio_servicer.py +19 -14
  226. flwr/server/superlink/utils.py +4 -6
  227. flwr/server/typing.py +1 -1
  228. flwr/server/utils/tensorboard.py +15 -8
  229. flwr/server/utils/validator.py +2 -3
  230. flwr/server/workflow/default_workflows.py +7 -6
  231. flwr/server/workflow/secure_aggregation/secagg_workflow.py +2 -4
  232. flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +13 -11
  233. flwr/serverapp/strategy/bulyan.py +16 -15
  234. flwr/serverapp/strategy/dp_adaptive_clipping.py +12 -11
  235. flwr/serverapp/strategy/dp_fixed_clipping.py +11 -14
  236. flwr/serverapp/strategy/fedadagrad.py +10 -11
  237. flwr/serverapp/strategy/fedadam.py +10 -11
  238. flwr/serverapp/strategy/fedavg.py +10 -11
  239. flwr/serverapp/strategy/fedavgm.py +17 -16
  240. flwr/serverapp/strategy/fedmedian.py +2 -2
  241. flwr/serverapp/strategy/fedopt.py +10 -11
  242. flwr/serverapp/strategy/fedprox.py +7 -8
  243. flwr/serverapp/strategy/fedtrimmedavg.py +9 -9
  244. flwr/serverapp/strategy/fedxgb_bagging.py +3 -3
  245. flwr/serverapp/strategy/fedxgb_cyclic.py +10 -10
  246. flwr/serverapp/strategy/fedyogi.py +9 -11
  247. flwr/serverapp/strategy/krum.py +7 -7
  248. flwr/serverapp/strategy/multikrum.py +9 -9
  249. flwr/serverapp/strategy/qfedavg.py +17 -16
  250. flwr/serverapp/strategy/strategy.py +6 -9
  251. flwr/serverapp/strategy/strategy_utils.py +7 -8
  252. flwr/simulation/app.py +46 -42
  253. flwr/simulation/legacy_app.py +12 -12
  254. flwr/simulation/ray_transport/ray_actor.py +11 -12
  255. flwr/simulation/ray_transport/ray_client_proxy.py +14 -19
  256. flwr/simulation/run_simulation.py +46 -44
  257. flwr/simulation/simulationio_connection.py +4 -4
  258. flwr/{common → supercore}/address.py +1 -37
  259. flwr/supercore/cli/flower_superexec.py +3 -4
  260. flwr/supercore/constant.py +69 -0
  261. flwr/supercore/corestate/corestate.py +24 -3
  262. flwr/supercore/corestate/in_memory_corestate.py +138 -0
  263. flwr/supercore/corestate/sql_corestate.py +153 -0
  264. flwr/supercore/corestate/sqlite_corestate.py +157 -0
  265. flwr/supercore/credential_store/__init__.py +33 -0
  266. flwr/supercore/credential_store/credential_store.py +34 -0
  267. flwr/supercore/credential_store/file_credential_store.py +76 -0
  268. flwr/{common → supercore}/date.py +0 -11
  269. flwr/supercore/ffs/disk_ffs.py +1 -2
  270. flwr/supercore/ffs/ffs.py +1 -2
  271. flwr/supercore/ffs/ffs_factory.py +1 -2
  272. flwr/{common → supercore}/heartbeat.py +20 -25
  273. flwr/supercore/object_store/in_memory_object_store.py +1 -6
  274. flwr/supercore/object_store/object_store.py +1 -2
  275. flwr/supercore/object_store/object_store_factory.py +27 -8
  276. flwr/supercore/object_store/sqlite_object_store.py +253 -0
  277. flwr/{cli/new/templates/app → supercore/primitives}/__init__.py +1 -1
  278. flwr/supercore/primitives/asymmetric.py +117 -0
  279. flwr/supercore/primitives/asymmetric_ed25519.py +175 -0
  280. flwr/supercore/sql_mixin.py +292 -0
  281. flwr/supercore/sqlite_mixin.py +156 -0
  282. flwr/{client/clientapp → supercore/state}/__init__.py +2 -2
  283. flwr/supercore/state/schema/README.md +125 -0
  284. flwr/{cli/new/templates → supercore/state/schema}/__init__.py +2 -2
  285. flwr/supercore/state/schema/corestate_tables.py +36 -0
  286. flwr/supercore/state/schema/linkstate_tables.py +152 -0
  287. flwr/supercore/state/schema/objectstore_tables.py +90 -0
  288. flwr/supercore/superexec/plugin/base_exec_plugin.py +1 -2
  289. flwr/supercore/superexec/plugin/exec_plugin.py +3 -3
  290. flwr/supercore/superexec/run_superexec.py +9 -13
  291. flwr/supercore/utils.py +224 -0
  292. flwr/superlink/artifact_provider/artifact_provider.py +1 -2
  293. flwr/superlink/auth_plugin/__init__.py +5 -2
  294. flwr/superlink/auth_plugin/auth_plugin.py +20 -19
  295. flwr/superlink/auth_plugin/noop_auth_plugin.py +84 -0
  296. flwr/superlink/federation/__init__.py +24 -0
  297. flwr/superlink/federation/federation_manager.py +64 -0
  298. flwr/superlink/federation/noop_federation_manager.py +71 -0
  299. flwr/superlink/servicer/control/{control_user_auth_interceptor.py → control_account_auth_interceptor.py} +41 -32
  300. flwr/superlink/servicer/control/control_event_log_interceptor.py +7 -7
  301. flwr/superlink/servicer/control/control_grpc.py +20 -17
  302. flwr/superlink/servicer/control/control_license_interceptor.py +3 -3
  303. flwr/superlink/servicer/control/control_servicer.py +328 -68
  304. flwr/supernode/cli/flower_supernode.py +74 -26
  305. flwr/supernode/nodestate/in_memory_nodestate.py +121 -49
  306. flwr/supernode/nodestate/nodestate.py +52 -8
  307. flwr/supernode/nodestate/nodestate_factory.py +7 -4
  308. flwr/supernode/runtime/run_clientapp.py +43 -24
  309. flwr/supernode/servicer/clientappio/clientappio_servicer.py +48 -10
  310. flwr/supernode/start_client_internal.py +185 -57
  311. {flwr_nightly-1.23.0.dev20250930.dist-info → flwr_nightly-1.26.0.dev20260121.dist-info}/METADATA +10 -11
  312. flwr_nightly-1.26.0.dev20260121.dist-info/RECORD +411 -0
  313. flwr/cli/new/templates/app/.gitignore.tpl +0 -163
  314. flwr/cli/new/templates/app/LICENSE.tpl +0 -202
  315. flwr/cli/new/templates/app/README.baseline.md.tpl +0 -127
  316. flwr/cli/new/templates/app/README.flowertune.md.tpl +0 -68
  317. flwr/cli/new/templates/app/README.md.tpl +0 -37
  318. flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +0 -1
  319. flwr/cli/new/templates/app/code/__init__.py.tpl +0 -1
  320. flwr/cli/new/templates/app/code/__init__.pytorch_legacy_api.py.tpl +0 -1
  321. flwr/cli/new/templates/app/code/client.baseline.py.tpl +0 -75
  322. flwr/cli/new/templates/app/code/client.huggingface.py.tpl +0 -93
  323. flwr/cli/new/templates/app/code/client.jax.py.tpl +0 -71
  324. flwr/cli/new/templates/app/code/client.mlx.py.tpl +0 -102
  325. flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -46
  326. flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -80
  327. flwr/cli/new/templates/app/code/client.pytorch_legacy_api.py.tpl +0 -55
  328. flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -108
  329. flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -82
  330. flwr/cli/new/templates/app/code/client.xgboost.py.tpl +0 -110
  331. flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +0 -36
  332. flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +0 -92
  333. flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +0 -87
  334. flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +0 -56
  335. flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +0 -73
  336. flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +0 -78
  337. flwr/cli/new/templates/app/code/model.baseline.py.tpl +0 -66
  338. flwr/cli/new/templates/app/code/server.baseline.py.tpl +0 -43
  339. flwr/cli/new/templates/app/code/server.huggingface.py.tpl +0 -42
  340. flwr/cli/new/templates/app/code/server.jax.py.tpl +0 -39
  341. flwr/cli/new/templates/app/code/server.mlx.py.tpl +0 -41
  342. flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -38
  343. flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -41
  344. flwr/cli/new/templates/app/code/server.pytorch_legacy_api.py.tpl +0 -31
  345. flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -44
  346. flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -38
  347. flwr/cli/new/templates/app/code/server.xgboost.py.tpl +0 -56
  348. flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +0 -1
  349. flwr/cli/new/templates/app/code/task.huggingface.py.tpl +0 -98
  350. flwr/cli/new/templates/app/code/task.jax.py.tpl +0 -57
  351. flwr/cli/new/templates/app/code/task.mlx.py.tpl +0 -102
  352. flwr/cli/new/templates/app/code/task.numpy.py.tpl +0 -7
  353. flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -98
  354. flwr/cli/new/templates/app/code/task.pytorch_legacy_api.py.tpl +0 -111
  355. flwr/cli/new/templates/app/code/task.sklearn.py.tpl +0 -67
  356. flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +0 -52
  357. flwr/cli/new/templates/app/code/task.xgboost.py.tpl +0 -67
  358. flwr/cli/new/templates/app/code/utils.baseline.py.tpl +0 -1
  359. flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +0 -146
  360. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +0 -80
  361. flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +0 -65
  362. flwr/cli/new/templates/app/pyproject.jax.toml.tpl +0 -52
  363. flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +0 -56
  364. flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +0 -49
  365. flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +0 -53
  366. flwr/cli/new/templates/app/pyproject.pytorch_legacy_api.toml.tpl +0 -53
  367. flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +0 -52
  368. flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +0 -53
  369. flwr/cli/new/templates/app/pyproject.xgboost.toml.tpl +0 -61
  370. flwr/common/pyproject.py +0 -42
  371. flwr/supercore/object_store/utils.py +0 -43
  372. flwr_nightly-1.23.0.dev20250930.dist-info/RECORD +0 -429
  373. /flwr/{common → supercore}/version.py +0 -0
  374. {flwr_nightly-1.23.0.dev20250930.dist-info → flwr_nightly-1.26.0.dev20260121.dist-info}/WHEEL +0 -0
  375. {flwr_nightly-1.23.0.dev20250930.dist-info → flwr_nightly-1.26.0.dev20260121.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,273 @@
1
+ # Copyright 2025 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
+ """Flower command line interface `supernode list` command."""
16
+
17
+
18
+ import io
19
+ import json
20
+ from datetime import datetime, timedelta
21
+ from pathlib import Path
22
+ from typing import Annotated, cast
23
+
24
+ import typer
25
+ from rich.console import Console
26
+ from rich.table import Table
27
+ from rich.text import Text
28
+
29
+ from flwr.cli.config_utils import (
30
+ exit_if_no_address,
31
+ load_and_validate,
32
+ process_loaded_project_config,
33
+ validate_federation_in_project_config,
34
+ )
35
+ from flwr.common.constant import FAB_CONFIG_FILE, NOOP_ACCOUNT_NAME, CliOutputFormat
36
+ from flwr.common.logger import print_json_error, redirect_output, restore_output
37
+ from flwr.proto.control_pb2 import ( # pylint: disable=E0611
38
+ ListNodesRequest,
39
+ ListNodesResponse,
40
+ )
41
+ from flwr.proto.control_pb2_grpc import ControlStub
42
+ from flwr.proto.node_pb2 import NodeInfo # pylint: disable=E0611
43
+ from flwr.supercore.date import isoformat8601_utc
44
+ from flwr.supercore.utils import humanize_duration
45
+
46
+ from ..utils import flwr_cli_grpc_exc_handler, init_channel, load_cli_auth_plugin
47
+
48
+ _NodeListType = tuple[int, str, str, str, str, str, str, str, float]
49
+
50
+
51
+ def ls( # pylint: disable=R0914, R0913, R0917
52
+ ctx: typer.Context,
53
+ app: Annotated[
54
+ Path,
55
+ typer.Argument(help="Path of the Flower project"),
56
+ ] = Path("."),
57
+ federation: Annotated[
58
+ str | None,
59
+ typer.Argument(help="Name of the federation"),
60
+ ] = None,
61
+ output_format: Annotated[
62
+ str,
63
+ typer.Option(
64
+ "--format",
65
+ case_sensitive=False,
66
+ help="Format output using 'default' view or 'json'",
67
+ ),
68
+ ] = CliOutputFormat.DEFAULT,
69
+ verbose: Annotated[
70
+ bool,
71
+ typer.Option(
72
+ "--verbose",
73
+ "-v",
74
+ help="Enable verbose output",
75
+ ),
76
+ ] = False,
77
+ ) -> None:
78
+ """List SuperNodes in the federation."""
79
+ # Resolve command used (list or ls)
80
+ command_name = cast(str, ctx.command.name) if ctx.command else "ls"
81
+
82
+ suppress_output = output_format == CliOutputFormat.JSON
83
+ captured_output = io.StringIO()
84
+ try:
85
+ if suppress_output:
86
+ redirect_output(captured_output)
87
+ typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
88
+
89
+ pyproject_path = app / FAB_CONFIG_FILE if app else None
90
+ config, errors, warnings = load_and_validate(pyproject_path, check_module=False)
91
+ config = process_loaded_project_config(config, errors, warnings)
92
+ federation, federation_config = validate_federation_in_project_config(
93
+ federation, config
94
+ )
95
+ exit_if_no_address(federation_config, f"supernode {command_name}")
96
+ channel = None
97
+ try:
98
+ auth_plugin = load_cli_auth_plugin(app, federation, federation_config)
99
+ channel = init_channel(app, federation_config, auth_plugin)
100
+ stub = ControlStub(channel)
101
+ typer.echo("📄 Listing all nodes...")
102
+ formatted_nodes = _list_nodes(stub)
103
+ restore_output()
104
+ if output_format == CliOutputFormat.JSON:
105
+ Console().print_json(_to_json(formatted_nodes, verbose=verbose))
106
+ else:
107
+ Console().print(_to_table(formatted_nodes, verbose=verbose))
108
+
109
+ finally:
110
+ if channel:
111
+ channel.close()
112
+ except (typer.Exit, Exception) as err: # pylint: disable=broad-except
113
+ if suppress_output:
114
+ restore_output()
115
+ e_message = captured_output.getvalue()
116
+ print_json_error(e_message, err)
117
+ else:
118
+ typer.secho(
119
+ f"{err}",
120
+ fg=typer.colors.RED,
121
+ bold=True,
122
+ )
123
+ finally:
124
+ if suppress_output:
125
+ restore_output()
126
+ captured_output.close()
127
+
128
+
129
+ def _list_nodes(stub: ControlStub) -> list[_NodeListType]:
130
+ """List all nodes."""
131
+ with flwr_cli_grpc_exc_handler():
132
+ res: ListNodesResponse = stub.ListNodes(ListNodesRequest())
133
+
134
+ return _format_nodes(list(res.nodes_info), res.now)
135
+
136
+
137
+ def _format_nodes(
138
+ nodes_info: list[NodeInfo], now_isoformat: str
139
+ ) -> list[_NodeListType]:
140
+ """Format node information for display."""
141
+
142
+ def _format_datetime(dt_str: str | None) -> str:
143
+ dt = datetime.fromisoformat(dt_str) if dt_str else None
144
+ return isoformat8601_utc(dt).replace("T", " ") if dt else "N/A"
145
+
146
+ formatted_nodes: list[_NodeListType] = []
147
+ # Add rows
148
+ for node in sorted(
149
+ nodes_info, key=lambda x: datetime.fromisoformat(x.registered_at)
150
+ ):
151
+
152
+ # Calculate elapsed times
153
+ elapsed_time_activated = timedelta()
154
+ if node.last_activated_at:
155
+ end_time = datetime.fromisoformat(now_isoformat)
156
+ elapsed_time_activated = end_time - datetime.fromisoformat(
157
+ node.last_activated_at
158
+ )
159
+
160
+ formatted_nodes.append(
161
+ (
162
+ node.node_id,
163
+ node.owner_aid,
164
+ node.owner_name,
165
+ node.status,
166
+ _format_datetime(node.registered_at),
167
+ _format_datetime(node.last_activated_at),
168
+ _format_datetime(node.last_deactivated_at),
169
+ _format_datetime(node.unregistered_at),
170
+ elapsed_time_activated.total_seconds(),
171
+ )
172
+ )
173
+
174
+ return formatted_nodes
175
+
176
+
177
+ def _to_table(nodes_info: list[_NodeListType], verbose: bool) -> Table:
178
+ """Format the provided node list to a rich Table."""
179
+ table = Table(header_style="bold cyan", show_lines=True)
180
+
181
+ # Add columns
182
+ table.add_column(
183
+ Text("Node ID", justify="center"), style="bright_black", no_wrap=True
184
+ )
185
+ table.add_column(Text("Owner", justify="center"))
186
+ table.add_column(Text("Status", justify="center"))
187
+ table.add_column(Text("Elapsed", justify="center"))
188
+ table.add_column(Text("Status Changed @", justify="center"), style="bright_black")
189
+
190
+ for row in nodes_info:
191
+ (
192
+ node_id,
193
+ _,
194
+ owner_name,
195
+ status,
196
+ _,
197
+ last_activated_at,
198
+ last_deactivated_at,
199
+ unregistered_at,
200
+ elapse_activated,
201
+ ) = row
202
+
203
+ if status == "online":
204
+ status_style = "green"
205
+ time_at = last_activated_at
206
+ elif status == "offline":
207
+ status_style = "bright_yellow"
208
+ time_at = last_deactivated_at
209
+ elif status == "unregistered":
210
+ if not verbose:
211
+ continue
212
+ status_style = "red"
213
+ time_at = unregistered_at
214
+ elif status == "registered":
215
+ status_style = "blue"
216
+ time_at = "N/A"
217
+ else:
218
+ raise ValueError(f"Unexpected node status '{status}'")
219
+
220
+ formatted_row = (
221
+ f"[bold]{node_id}[/bold]",
222
+ (
223
+ f"{owner_name}"
224
+ if owner_name != NOOP_ACCOUNT_NAME
225
+ else f"[dim]{owner_name}[/dim]"
226
+ ),
227
+ f"[{status_style}]{status}",
228
+ (
229
+ f"[cyan]{humanize_duration(elapse_activated)}[/cyan]"
230
+ if status == "online"
231
+ else ""
232
+ ),
233
+ time_at,
234
+ )
235
+ table.add_row(*formatted_row)
236
+
237
+ return table
238
+
239
+
240
+ def _to_json(nodes_info: list[_NodeListType], verbose: bool) -> str:
241
+ """Format node list to a JSON formatted string."""
242
+ nodes_list = []
243
+ for row in nodes_info:
244
+ (
245
+ node_id,
246
+ owner_aid,
247
+ owner_name,
248
+ status,
249
+ created_at,
250
+ activated_at,
251
+ deactivated_at,
252
+ deleted_at,
253
+ elapse_activated,
254
+ ) = row
255
+
256
+ if status == "deleted" and not verbose:
257
+ continue
258
+
259
+ nodes_list.append(
260
+ {
261
+ "node-id": f"{node_id}",
262
+ "owner-aid": owner_aid,
263
+ "owner-name": owner_name,
264
+ "status": status,
265
+ "created-at": created_at,
266
+ "online-at": activated_at,
267
+ "online-elapsed": elapse_activated,
268
+ "offline-at": deactivated_at,
269
+ "deleted-at": deleted_at,
270
+ }
271
+ )
272
+
273
+ return json.dumps({"success": True, "nodes": nodes_list})
@@ -0,0 +1,190 @@
1
+ # Copyright 2025 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
+ """Flower command line interface `supernode register` command."""
16
+
17
+
18
+ import io
19
+ import json
20
+ from pathlib import Path
21
+ from typing import Annotated
22
+
23
+ import typer
24
+ from cryptography.exceptions import UnsupportedAlgorithm
25
+ from cryptography.hazmat.primitives import serialization
26
+ from cryptography.hazmat.primitives.asymmetric import ec
27
+ from rich.console import Console
28
+
29
+ from flwr.cli.config_utils import (
30
+ exit_if_no_address,
31
+ load_and_validate,
32
+ process_loaded_project_config,
33
+ validate_federation_in_project_config,
34
+ )
35
+ from flwr.common.constant import FAB_CONFIG_FILE, CliOutputFormat
36
+ from flwr.common.exit import ExitCode, flwr_exit
37
+ from flwr.common.logger import print_json_error, redirect_output, restore_output
38
+ from flwr.proto.control_pb2 import ( # pylint: disable=E0611
39
+ RegisterNodeRequest,
40
+ RegisterNodeResponse,
41
+ )
42
+ from flwr.proto.control_pb2_grpc import ControlStub
43
+ from flwr.supercore.primitives.asymmetric import public_key_to_bytes, uses_nist_ec_curve
44
+
45
+ from ..utils import flwr_cli_grpc_exc_handler, init_channel, load_cli_auth_plugin
46
+
47
+
48
+ def register( # pylint: disable=R0914
49
+ public_key: Annotated[
50
+ Path,
51
+ typer.Argument(
52
+ help="Path to a P-384 (or any other NIST EC curve) public key file.",
53
+ ),
54
+ ],
55
+ app: Annotated[
56
+ Path,
57
+ typer.Argument(help="Path of the Flower project"),
58
+ ] = Path("."),
59
+ federation: Annotated[
60
+ str | None,
61
+ typer.Argument(help="Name of the federation"),
62
+ ] = None,
63
+ output_format: Annotated[
64
+ str,
65
+ typer.Option(
66
+ "--format",
67
+ case_sensitive=False,
68
+ help="Format output using 'default' view or 'json'",
69
+ ),
70
+ ] = CliOutputFormat.DEFAULT,
71
+ ) -> None:
72
+ """Add a SuperNode to the federation."""
73
+ suppress_output = output_format == CliOutputFormat.JSON
74
+ captured_output = io.StringIO()
75
+
76
+ # Load public key
77
+ public_key_path = Path(public_key)
78
+ public_key_bytes = try_load_public_key(public_key_path)
79
+
80
+ try:
81
+ if suppress_output:
82
+ redirect_output(captured_output)
83
+
84
+ # Load and validate federation config
85
+ typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
86
+
87
+ pyproject_path = app / FAB_CONFIG_FILE if app else None
88
+ config, errors, warnings = load_and_validate(pyproject_path, check_module=False)
89
+ config = process_loaded_project_config(config, errors, warnings)
90
+ federation, federation_config = validate_federation_in_project_config(
91
+ federation, config
92
+ )
93
+ exit_if_no_address(federation_config, "supernode register")
94
+
95
+ channel = None
96
+ try:
97
+ auth_plugin = load_cli_auth_plugin(app, federation, federation_config)
98
+ channel = init_channel(app, federation_config, auth_plugin)
99
+ stub = ControlStub(channel) # pylint: disable=unused-variable # noqa: F841
100
+
101
+ _register_node(
102
+ stub=stub, public_key=public_key_bytes, output_format=output_format
103
+ )
104
+
105
+ except ValueError as err:
106
+ typer.secho(
107
+ f"❌ {err}",
108
+ fg=typer.colors.RED,
109
+ bold=True,
110
+ err=True,
111
+ )
112
+ raise typer.Exit(code=1) from err
113
+ finally:
114
+ if channel:
115
+ channel.close()
116
+
117
+ except (typer.Exit, Exception) as err: # pylint: disable=broad-except
118
+ if suppress_output:
119
+ restore_output()
120
+ e_message = captured_output.getvalue()
121
+ print_json_error(e_message, err)
122
+ else:
123
+ typer.secho(
124
+ f"{err}",
125
+ fg=typer.colors.RED,
126
+ bold=True,
127
+ err=True,
128
+ )
129
+ finally:
130
+ if suppress_output:
131
+ restore_output()
132
+ captured_output.close()
133
+
134
+
135
+ def _register_node(stub: ControlStub, public_key: bytes, output_format: str) -> None:
136
+ """Register a node."""
137
+ with flwr_cli_grpc_exc_handler():
138
+ response: RegisterNodeResponse = stub.RegisterNode(
139
+ request=RegisterNodeRequest(public_key=public_key)
140
+ )
141
+ if response.node_id:
142
+ typer.secho(
143
+ f"✅ SuperNode {response.node_id} registered successfully.",
144
+ fg=typer.colors.GREEN,
145
+ )
146
+ if output_format == CliOutputFormat.JSON:
147
+ run_output = json.dumps(
148
+ {
149
+ "success": True,
150
+ "node-id": response.node_id,
151
+ }
152
+ )
153
+ restore_output()
154
+ Console().print_json(run_output)
155
+ else:
156
+ typer.secho(
157
+ "❌ SuperNode couldn't be registered.", fg=typer.colors.RED, err=True
158
+ )
159
+
160
+
161
+ def try_load_public_key(public_key_path: Path) -> bytes:
162
+ """Try to load a public key from a file."""
163
+ if not public_key_path.exists():
164
+ typer.secho(
165
+ f"❌ Public key file '{public_key_path}' does not exist.",
166
+ fg=typer.colors.RED,
167
+ bold=True,
168
+ err=True,
169
+ )
170
+ raise typer.Exit(code=1)
171
+
172
+ with open(public_key_path, "rb") as key_file:
173
+ try:
174
+ public_key = serialization.load_ssh_public_key(key_file.read())
175
+
176
+ if not isinstance(public_key, ec.EllipticCurvePublicKey):
177
+ raise ValueError(f"Not an EC public key, got {type(public_key)}")
178
+
179
+ # Verify it's one of the approved NIST curves
180
+ if not uses_nist_ec_curve(public_key):
181
+ raise ValueError(
182
+ f"EC curve {public_key.curve.name} is not an approved NIST curve"
183
+ )
184
+
185
+ except (ValueError, UnsupportedAlgorithm) as err:
186
+ flwr_exit(
187
+ ExitCode.FLWRCLI_NODE_AUTH_PUBLIC_KEY_INVALID,
188
+ str(err),
189
+ )
190
+ return public_key_to_bytes(public_key)
@@ -0,0 +1,140 @@
1
+ # Copyright 2025 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
+ """Flower command line interface `supernode unregister` command."""
16
+
17
+
18
+ import io
19
+ import json
20
+ from pathlib import Path
21
+ from typing import Annotated
22
+
23
+ import typer
24
+ from rich.console import Console
25
+
26
+ from flwr.cli.config_utils import (
27
+ exit_if_no_address,
28
+ load_and_validate,
29
+ process_loaded_project_config,
30
+ validate_federation_in_project_config,
31
+ )
32
+ from flwr.common.constant import FAB_CONFIG_FILE, CliOutputFormat
33
+ from flwr.common.logger import print_json_error, redirect_output, restore_output
34
+ from flwr.proto.control_pb2 import UnregisterNodeRequest # pylint: disable=E0611
35
+ from flwr.proto.control_pb2_grpc import ControlStub
36
+
37
+ from ..utils import flwr_cli_grpc_exc_handler, init_channel, load_cli_auth_plugin
38
+
39
+
40
+ def unregister( # pylint: disable=R0914
41
+ node_id: Annotated[
42
+ int,
43
+ typer.Argument(
44
+ help="ID of the SuperNode to remove.",
45
+ ),
46
+ ],
47
+ app: Annotated[
48
+ Path,
49
+ typer.Argument(help="Path of the Flower project"),
50
+ ] = Path("."),
51
+ federation: Annotated[
52
+ str | None,
53
+ typer.Argument(help="Name of the federation"),
54
+ ] = None,
55
+ output_format: Annotated[
56
+ str,
57
+ typer.Option(
58
+ "--format",
59
+ case_sensitive=False,
60
+ help="Format output using 'default' view or 'json'",
61
+ ),
62
+ ] = CliOutputFormat.DEFAULT,
63
+ ) -> None:
64
+ """Unregister a SuperNode from the federation."""
65
+ suppress_output = output_format == CliOutputFormat.JSON
66
+ captured_output = io.StringIO()
67
+
68
+ try:
69
+ if suppress_output:
70
+ redirect_output(captured_output)
71
+
72
+ # Load and validate federation config
73
+ typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
74
+
75
+ pyproject_path = app / FAB_CONFIG_FILE if app else None
76
+ config, errors, warnings = load_and_validate(pyproject_path, check_module=False)
77
+ config = process_loaded_project_config(config, errors, warnings)
78
+ federation, federation_config = validate_federation_in_project_config(
79
+ federation, config
80
+ )
81
+ exit_if_no_address(federation_config, "supernode unregister")
82
+
83
+ channel = None
84
+ try:
85
+ auth_plugin = load_cli_auth_plugin(app, federation, federation_config)
86
+ channel = init_channel(app, federation_config, auth_plugin)
87
+ stub = ControlStub(channel) # pylint: disable=unused-variable # noqa: F841
88
+
89
+ _unregister_node(stub=stub, node_id=node_id, output_format=output_format)
90
+
91
+ except ValueError as err:
92
+ typer.secho(
93
+ f"❌ {err}",
94
+ fg=typer.colors.RED,
95
+ bold=True,
96
+ err=True,
97
+ )
98
+ raise typer.Exit(code=1) from err
99
+ finally:
100
+ if channel:
101
+ channel.close()
102
+
103
+ except (typer.Exit, Exception) as err: # pylint: disable=broad-except
104
+ if suppress_output:
105
+ restore_output()
106
+ e_message = captured_output.getvalue()
107
+ print_json_error(e_message, err)
108
+ else:
109
+ typer.secho(
110
+ f"{err}",
111
+ fg=typer.colors.RED,
112
+ bold=True,
113
+ err=True,
114
+ )
115
+ finally:
116
+ if suppress_output:
117
+ restore_output()
118
+ captured_output.close()
119
+
120
+
121
+ def _unregister_node(
122
+ stub: ControlStub,
123
+ node_id: int,
124
+ output_format: str,
125
+ ) -> None:
126
+ """Unregister a SuperNode from the federation."""
127
+ with flwr_cli_grpc_exc_handler():
128
+ stub.UnregisterNode(request=UnregisterNodeRequest(node_id=node_id))
129
+ typer.secho(
130
+ f"✅ SuperNode {node_id} unregistered successfully.", fg=typer.colors.GREEN
131
+ )
132
+ if output_format == CliOutputFormat.JSON:
133
+ run_output = json.dumps(
134
+ {
135
+ "success": True,
136
+ "node-id": node_id,
137
+ }
138
+ )
139
+ restore_output()
140
+ Console().print_json(run_output)