flwr 1.24.0__tar.gz → 1.25.0__tar.gz

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 (456) hide show
  1. {flwr-1.24.0 → flwr-1.25.0}/PKG-INFO +2 -4
  2. {flwr-1.24.0 → flwr-1.25.0}/README.md +1 -3
  3. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/app_cmd/review.py +13 -3
  4. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/federation/show.py +4 -3
  5. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/ls.py +44 -3
  6. flwr-1.25.0/py/flwr/cli/new/new.py +263 -0
  7. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/run/run.py +12 -17
  8. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/run_utils.py +23 -5
  9. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/stop.py +1 -1
  10. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/supernode/ls.py +10 -5
  11. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/utils.py +0 -137
  12. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/grpc_adapter_client/connection.py +2 -2
  13. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/grpc_rere_client/connection.py +6 -3
  14. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/rest_client/connection.py +6 -4
  15. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/serde.py +6 -0
  16. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/typing.py +6 -0
  17. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/fleet_pb2.py +10 -10
  18. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/fleet_pb2.pyi +5 -1
  19. flwr-1.25.0/py/flwr/proto/run_pb2.py +65 -0
  20. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/run_pb2.pyi +10 -1
  21. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/app.py +1 -0
  22. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/message_handler/message_handler.py +41 -2
  23. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/linkstate/in_memory_linkstate.py +34 -0
  24. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/linkstate/linkstate.py +32 -0
  25. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/linkstate/sqlite_linkstate.py +60 -3
  26. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/constant.py +3 -0
  27. flwr-1.25.0/py/flwr/supercore/utils.py +242 -0
  28. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/servicer/control/control_grpc.py +2 -0
  29. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/servicer/control/control_servicer.py +88 -5
  30. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/nodestate/in_memory_nodestate.py +62 -1
  31. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/nodestate/nodestate.py +45 -0
  32. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/servicer/clientappio/clientappio_servicer.py +7 -1
  33. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/start_client_internal.py +7 -4
  34. {flwr-1.24.0 → flwr-1.25.0}/pyproject.toml +1 -1
  35. flwr-1.24.0/py/flwr/cli/new/new.py +0 -454
  36. flwr-1.24.0/py/flwr/cli/new/templates/__init__.py +0 -15
  37. flwr-1.24.0/py/flwr/cli/new/templates/app/.gitignore.tpl +0 -163
  38. flwr-1.24.0/py/flwr/cli/new/templates/app/LICENSE.tpl +0 -202
  39. flwr-1.24.0/py/flwr/cli/new/templates/app/README.baseline.md.tpl +0 -127
  40. flwr-1.24.0/py/flwr/cli/new/templates/app/README.flowertune.md.tpl +0 -68
  41. flwr-1.24.0/py/flwr/cli/new/templates/app/README.md.tpl +0 -37
  42. flwr-1.24.0/py/flwr/cli/new/templates/app/__init__.py +0 -15
  43. flwr-1.24.0/py/flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +0 -1
  44. flwr-1.24.0/py/flwr/cli/new/templates/app/code/__init__.py +0 -15
  45. flwr-1.24.0/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -1
  46. flwr-1.24.0/py/flwr/cli/new/templates/app/code/__init__.pytorch_legacy_api.py.tpl +0 -1
  47. flwr-1.24.0/py/flwr/cli/new/templates/app/code/client.baseline.py.tpl +0 -75
  48. flwr-1.24.0/py/flwr/cli/new/templates/app/code/client.huggingface.py.tpl +0 -93
  49. flwr-1.24.0/py/flwr/cli/new/templates/app/code/client.jax.py.tpl +0 -71
  50. flwr-1.24.0/py/flwr/cli/new/templates/app/code/client.mlx.py.tpl +0 -102
  51. flwr-1.24.0/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -46
  52. flwr-1.24.0/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -80
  53. flwr-1.24.0/py/flwr/cli/new/templates/app/code/client.pytorch_legacy_api.py.tpl +0 -55
  54. flwr-1.24.0/py/flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -108
  55. flwr-1.24.0/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -82
  56. flwr-1.24.0/py/flwr/cli/new/templates/app/code/client.xgboost.py.tpl +0 -110
  57. flwr-1.24.0/py/flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +0 -36
  58. flwr-1.24.0/py/flwr/cli/new/templates/app/code/flwr_tune/__init__.py +0 -15
  59. flwr-1.24.0/py/flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +0 -92
  60. flwr-1.24.0/py/flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +0 -87
  61. flwr-1.24.0/py/flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +0 -56
  62. flwr-1.24.0/py/flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +0 -73
  63. flwr-1.24.0/py/flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +0 -78
  64. flwr-1.24.0/py/flwr/cli/new/templates/app/code/model.baseline.py.tpl +0 -66
  65. flwr-1.24.0/py/flwr/cli/new/templates/app/code/server.baseline.py.tpl +0 -43
  66. flwr-1.24.0/py/flwr/cli/new/templates/app/code/server.huggingface.py.tpl +0 -42
  67. flwr-1.24.0/py/flwr/cli/new/templates/app/code/server.jax.py.tpl +0 -39
  68. flwr-1.24.0/py/flwr/cli/new/templates/app/code/server.mlx.py.tpl +0 -41
  69. flwr-1.24.0/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -38
  70. flwr-1.24.0/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -41
  71. flwr-1.24.0/py/flwr/cli/new/templates/app/code/server.pytorch_legacy_api.py.tpl +0 -31
  72. flwr-1.24.0/py/flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -44
  73. flwr-1.24.0/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -38
  74. flwr-1.24.0/py/flwr/cli/new/templates/app/code/server.xgboost.py.tpl +0 -56
  75. flwr-1.24.0/py/flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +0 -1
  76. flwr-1.24.0/py/flwr/cli/new/templates/app/code/task.huggingface.py.tpl +0 -98
  77. flwr-1.24.0/py/flwr/cli/new/templates/app/code/task.jax.py.tpl +0 -57
  78. flwr-1.24.0/py/flwr/cli/new/templates/app/code/task.mlx.py.tpl +0 -102
  79. flwr-1.24.0/py/flwr/cli/new/templates/app/code/task.numpy.py.tpl +0 -7
  80. flwr-1.24.0/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -99
  81. flwr-1.24.0/py/flwr/cli/new/templates/app/code/task.pytorch_legacy_api.py.tpl +0 -111
  82. flwr-1.24.0/py/flwr/cli/new/templates/app/code/task.sklearn.py.tpl +0 -67
  83. flwr-1.24.0/py/flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +0 -52
  84. flwr-1.24.0/py/flwr/cli/new/templates/app/code/task.xgboost.py.tpl +0 -67
  85. flwr-1.24.0/py/flwr/cli/new/templates/app/code/utils.baseline.py.tpl +0 -1
  86. flwr-1.24.0/py/flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +0 -146
  87. flwr-1.24.0/py/flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +0 -80
  88. flwr-1.24.0/py/flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +0 -65
  89. flwr-1.24.0/py/flwr/cli/new/templates/app/pyproject.jax.toml.tpl +0 -52
  90. flwr-1.24.0/py/flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +0 -56
  91. flwr-1.24.0/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +0 -49
  92. flwr-1.24.0/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +0 -53
  93. flwr-1.24.0/py/flwr/cli/new/templates/app/pyproject.pytorch_legacy_api.toml.tpl +0 -53
  94. flwr-1.24.0/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +0 -52
  95. flwr-1.24.0/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +0 -53
  96. flwr-1.24.0/py/flwr/cli/new/templates/app/pyproject.xgboost.toml.tpl +0 -61
  97. flwr-1.24.0/py/flwr/proto/run_pb2.py +0 -65
  98. flwr-1.24.0/py/flwr/supercore/utils.py +0 -52
  99. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/__init__.py +0 -0
  100. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/app/__init__.py +0 -0
  101. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/app/error.py +0 -0
  102. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/app/exception.py +0 -0
  103. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/app/metadata.py +0 -0
  104. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/__init__.py +0 -0
  105. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/app.py +0 -0
  106. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/app_cmd/__init__.py +0 -0
  107. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/app_cmd/publish.py +0 -0
  108. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/auth_plugin/__init__.py +0 -0
  109. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/auth_plugin/auth_plugin.py +0 -0
  110. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/auth_plugin/noop_auth_plugin.py +0 -0
  111. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/auth_plugin/oidc_cli_plugin.py +0 -0
  112. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/build.py +0 -0
  113. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/cli_account_auth_interceptor.py +0 -0
  114. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/config_utils.py +0 -0
  115. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/constant.py +0 -0
  116. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/example.py +0 -0
  117. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/federation/__init__.py +0 -0
  118. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/federation/ls.py +0 -0
  119. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/install.py +0 -0
  120. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/log.py +0 -0
  121. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/login/__init__.py +0 -0
  122. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/login/login.py +0 -0
  123. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/new/__init__.py +0 -0
  124. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/pull.py +0 -0
  125. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/run/__init__.py +0 -0
  126. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/supernode/__init__.py +0 -0
  127. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/supernode/register.py +0 -0
  128. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/cli/supernode/unregister.py +0 -0
  129. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/__init__.py +0 -0
  130. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/client.py +0 -0
  131. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/dpfedavg_numpy_client.py +0 -0
  132. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/grpc_adapter_client/__init__.py +0 -0
  133. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/grpc_rere_client/__init__.py +0 -0
  134. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/grpc_rere_client/grpc_adapter.py +0 -0
  135. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/grpc_rere_client/node_auth_client_interceptor.py +0 -0
  136. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/message_handler/__init__.py +0 -0
  137. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/message_handler/message_handler.py +0 -0
  138. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/mod/__init__.py +0 -0
  139. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/mod/centraldp_mods.py +0 -0
  140. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/mod/comms_mods.py +0 -0
  141. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/mod/localdp_mod.py +0 -0
  142. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
  143. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
  144. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
  145. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/mod/utils.py +0 -0
  146. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/numpy_client.py +0 -0
  147. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/rest_client/__init__.py +0 -0
  148. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/run_info_store.py +0 -0
  149. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/client/typing.py +0 -0
  150. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/clientapp/__init__.py +0 -0
  151. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/clientapp/client_app.py +0 -0
  152. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/clientapp/mod/__init__.py +0 -0
  153. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/clientapp/mod/centraldp_mods.py +0 -0
  154. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/clientapp/mod/localdp_mod.py +0 -0
  155. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/clientapp/typing.py +0 -0
  156. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/clientapp/utils.py +0 -0
  157. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/__init__.py +0 -0
  158. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/address.py +0 -0
  159. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/args.py +0 -0
  160. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/config.py +0 -0
  161. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/constant.py +0 -0
  162. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/context.py +0 -0
  163. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/date.py +0 -0
  164. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/differential_privacy.py +0 -0
  165. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/differential_privacy_constants.py +0 -0
  166. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/dp.py +0 -0
  167. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/event_log_plugin/__init__.py +0 -0
  168. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/event_log_plugin/event_log_plugin.py +0 -0
  169. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/exit/__init__.py +0 -0
  170. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/exit/exit.py +0 -0
  171. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/exit/exit_code.py +0 -0
  172. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/exit/exit_handler.py +0 -0
  173. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/exit/signal_handler.py +0 -0
  174. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/grpc.py +0 -0
  175. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/inflatable.py +0 -0
  176. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/inflatable_protobuf_utils.py +0 -0
  177. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/inflatable_utils.py +0 -0
  178. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/logger.py +0 -0
  179. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/message.py +0 -0
  180. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/object_ref.py +0 -0
  181. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/parameter.py +0 -0
  182. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/pyproject.py +0 -0
  183. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/record/__init__.py +0 -0
  184. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/record/array.py +0 -0
  185. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/record/arraychunk.py +0 -0
  186. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/record/arrayrecord.py +0 -0
  187. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/record/configrecord.py +0 -0
  188. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/record/conversion_utils.py +0 -0
  189. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/record/metricrecord.py +0 -0
  190. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/record/recorddict.py +0 -0
  191. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/record/typeddict.py +0 -0
  192. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/recorddict_compat.py +0 -0
  193. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/retry_invoker.py +0 -0
  194. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/secure_aggregation/__init__.py +0 -0
  195. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
  196. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
  197. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +0 -0
  198. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
  199. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/secure_aggregation/quantization.py +0 -0
  200. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
  201. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
  202. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/serde_utils.py +0 -0
  203. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/telemetry.py +0 -0
  204. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/common/version.py +0 -0
  205. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/compat/__init__.py +0 -0
  206. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/compat/client/__init__.py +0 -0
  207. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/compat/client/app.py +0 -0
  208. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/compat/client/grpc_client/__init__.py +0 -0
  209. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/compat/client/grpc_client/connection.py +0 -0
  210. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/compat/common/__init__.py +0 -0
  211. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/compat/server/__init__.py +0 -0
  212. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/compat/server/app.py +0 -0
  213. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/compat/simulation/__init__.py +0 -0
  214. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/__init__.py +0 -0
  215. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/appio_pb2.py +0 -0
  216. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/appio_pb2.pyi +0 -0
  217. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/appio_pb2_grpc.py +0 -0
  218. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/appio_pb2_grpc.pyi +0 -0
  219. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/clientappio_pb2.py +0 -0
  220. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/clientappio_pb2.pyi +0 -0
  221. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/clientappio_pb2_grpc.py +0 -0
  222. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/clientappio_pb2_grpc.pyi +0 -0
  223. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/control_pb2.py +0 -0
  224. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/control_pb2.pyi +0 -0
  225. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/control_pb2_grpc.py +0 -0
  226. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/control_pb2_grpc.pyi +0 -0
  227. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/error_pb2.py +0 -0
  228. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/error_pb2.pyi +0 -0
  229. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/error_pb2_grpc.py +0 -0
  230. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/error_pb2_grpc.pyi +0 -0
  231. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/fab_pb2.py +0 -0
  232. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/fab_pb2.pyi +0 -0
  233. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/fab_pb2_grpc.py +0 -0
  234. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/fab_pb2_grpc.pyi +0 -0
  235. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/federation_pb2.py +0 -0
  236. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/federation_pb2.pyi +0 -0
  237. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/federation_pb2_grpc.py +0 -0
  238. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/federation_pb2_grpc.pyi +0 -0
  239. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/fleet_pb2_grpc.py +0 -0
  240. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/fleet_pb2_grpc.pyi +0 -0
  241. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/grpcadapter_pb2.py +0 -0
  242. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/grpcadapter_pb2.pyi +0 -0
  243. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/grpcadapter_pb2_grpc.py +0 -0
  244. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/grpcadapter_pb2_grpc.pyi +0 -0
  245. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/heartbeat_pb2.py +0 -0
  246. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/heartbeat_pb2.pyi +0 -0
  247. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/heartbeat_pb2_grpc.py +0 -0
  248. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/heartbeat_pb2_grpc.pyi +0 -0
  249. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/log_pb2.py +0 -0
  250. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/log_pb2.pyi +0 -0
  251. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/log_pb2_grpc.py +0 -0
  252. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/log_pb2_grpc.pyi +0 -0
  253. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/message_pb2.py +0 -0
  254. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/message_pb2.pyi +0 -0
  255. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/message_pb2_grpc.py +0 -0
  256. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/message_pb2_grpc.pyi +0 -0
  257. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/node_pb2.py +0 -0
  258. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/node_pb2.pyi +0 -0
  259. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/node_pb2_grpc.py +0 -0
  260. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/node_pb2_grpc.pyi +0 -0
  261. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/recorddict_pb2.py +0 -0
  262. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/recorddict_pb2.pyi +0 -0
  263. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/recorddict_pb2_grpc.py +0 -0
  264. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/recorddict_pb2_grpc.pyi +0 -0
  265. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/run_pb2_grpc.py +0 -0
  266. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/run_pb2_grpc.pyi +0 -0
  267. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/serverappio_pb2.py +0 -0
  268. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/serverappio_pb2.pyi +0 -0
  269. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/serverappio_pb2_grpc.py +0 -0
  270. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/serverappio_pb2_grpc.pyi +0 -0
  271. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/simulationio_pb2.py +0 -0
  272. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/simulationio_pb2.pyi +0 -0
  273. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/simulationio_pb2_grpc.py +0 -0
  274. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/simulationio_pb2_grpc.pyi +0 -0
  275. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/transport_pb2.py +0 -0
  276. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/transport_pb2.pyi +0 -0
  277. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/transport_pb2_grpc.py +0 -0
  278. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
  279. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/py.typed +0 -0
  280. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/__init__.py +0 -0
  281. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/client_manager.py +0 -0
  282. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/client_proxy.py +0 -0
  283. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/compat/__init__.py +0 -0
  284. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/compat/app.py +0 -0
  285. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/compat/app_utils.py +0 -0
  286. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/compat/grid_client_proxy.py +0 -0
  287. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/compat/legacy_context.py +0 -0
  288. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/criterion.py +0 -0
  289. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/fleet_event_log_interceptor.py +0 -0
  290. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/grid/__init__.py +0 -0
  291. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/grid/grid.py +0 -0
  292. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/grid/grpc_grid.py +0 -0
  293. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/grid/inmemory_grid.py +0 -0
  294. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/history.py +0 -0
  295. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/run_serverapp.py +0 -0
  296. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/server.py +0 -0
  297. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/server_app.py +0 -0
  298. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/server_config.py +0 -0
  299. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/serverapp/__init__.py +0 -0
  300. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/serverapp/app.py +0 -0
  301. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/serverapp_components.py +0 -0
  302. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/__init__.py +0 -0
  303. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/aggregate.py +0 -0
  304. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/bulyan.py +0 -0
  305. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
  306. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
  307. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
  308. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
  309. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
  310. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedadagrad.py +0 -0
  311. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedadam.py +0 -0
  312. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedavg.py +0 -0
  313. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedavg_android.py +0 -0
  314. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedavgm.py +0 -0
  315. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedmedian.py +0 -0
  316. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedopt.py +0 -0
  317. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedprox.py +0 -0
  318. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
  319. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
  320. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
  321. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
  322. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/fedyogi.py +0 -0
  323. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/krum.py +0 -0
  324. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/qfedavg.py +0 -0
  325. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/strategy/strategy.py +0 -0
  326. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/__init__.py +0 -0
  327. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/__init__.py +0 -0
  328. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/grpc_adapter/__init__.py +0 -0
  329. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +0 -0
  330. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
  331. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
  332. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
  333. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
  334. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +0 -0
  335. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
  336. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +0 -0
  337. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/grpc_rere/node_auth_server_interceptor.py +0 -0
  338. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
  339. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
  340. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +0 -0
  341. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
  342. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
  343. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
  344. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +0 -0
  345. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/fleet/vce/vce_api.py +0 -0
  346. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/linkstate/__init__.py +0 -0
  347. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/linkstate/linkstate_factory.py +0 -0
  348. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/linkstate/utils.py +0 -0
  349. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/serverappio/__init__.py +0 -0
  350. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/serverappio/serverappio_grpc.py +0 -0
  351. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/serverappio/serverappio_servicer.py +0 -0
  352. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/simulation/__init__.py +0 -0
  353. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/simulation/simulationio_grpc.py +0 -0
  354. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/simulation/simulationio_servicer.py +0 -0
  355. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/superlink/utils.py +0 -0
  356. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/typing.py +0 -0
  357. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/utils/__init__.py +0 -0
  358. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/utils/tensorboard.py +0 -0
  359. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/utils/validator.py +0 -0
  360. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/workflow/__init__.py +0 -0
  361. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/workflow/constant.py +0 -0
  362. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/workflow/default_workflows.py +0 -0
  363. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
  364. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
  365. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +0 -0
  366. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/__init__.py +0 -0
  367. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/exception.py +0 -0
  368. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/__init__.py +0 -0
  369. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/bulyan.py +0 -0
  370. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/dp_adaptive_clipping.py +0 -0
  371. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/dp_fixed_clipping.py +0 -0
  372. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/fedadagrad.py +0 -0
  373. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/fedadam.py +0 -0
  374. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/fedavg.py +0 -0
  375. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/fedavgm.py +0 -0
  376. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/fedmedian.py +0 -0
  377. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/fedopt.py +0 -0
  378. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/fedprox.py +0 -0
  379. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/fedtrimmedavg.py +0 -0
  380. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/fedxgb_bagging.py +0 -0
  381. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/fedxgb_cyclic.py +0 -0
  382. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/fedyogi.py +0 -0
  383. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/krum.py +0 -0
  384. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/multikrum.py +0 -0
  385. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/qfedavg.py +0 -0
  386. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/result.py +0 -0
  387. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/strategy.py +0 -0
  388. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/serverapp/strategy/strategy_utils.py +0 -0
  389. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/simulation/__init__.py +0 -0
  390. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/simulation/app.py +0 -0
  391. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/simulation/legacy_app.py +0 -0
  392. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/simulation/ray_transport/__init__.py +0 -0
  393. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/simulation/ray_transport/ray_actor.py +0 -0
  394. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
  395. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/simulation/ray_transport/utils.py +0 -0
  396. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/simulation/run_simulation.py +0 -0
  397. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/simulation/simulationio_connection.py +0 -0
  398. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/__init__.py +0 -0
  399. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/app_utils.py +0 -0
  400. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/cli/__init__.py +0 -0
  401. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/cli/flower_superexec.py +0 -0
  402. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/corestate/__init__.py +0 -0
  403. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/corestate/corestate.py +0 -0
  404. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/corestate/in_memory_corestate.py +0 -0
  405. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/corestate/sqlite_corestate.py +0 -0
  406. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/ffs/__init__.py +0 -0
  407. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/ffs/disk_ffs.py +0 -0
  408. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/ffs/ffs.py +0 -0
  409. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/ffs/ffs_factory.py +0 -0
  410. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/grpc_health/__init__.py +0 -0
  411. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/grpc_health/health_server.py +0 -0
  412. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/grpc_health/simple_health_servicer.py +0 -0
  413. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/heartbeat.py +0 -0
  414. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/license_plugin/__init__.py +0 -0
  415. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/license_plugin/license_plugin.py +0 -0
  416. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/object_store/__init__.py +0 -0
  417. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/object_store/in_memory_object_store.py +0 -0
  418. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/object_store/object_store.py +0 -0
  419. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/object_store/object_store_factory.py +0 -0
  420. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/object_store/sqlite_object_store.py +0 -0
  421. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/primitives/__init__.py +0 -0
  422. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/primitives/asymmetric.py +0 -0
  423. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/primitives/asymmetric_ed25519.py +0 -0
  424. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/sqlite_mixin.py +0 -0
  425. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/superexec/__init__.py +0 -0
  426. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/superexec/plugin/__init__.py +0 -0
  427. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/superexec/plugin/base_exec_plugin.py +0 -0
  428. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/superexec/plugin/clientapp_exec_plugin.py +0 -0
  429. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/superexec/plugin/exec_plugin.py +0 -0
  430. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/superexec/plugin/serverapp_exec_plugin.py +0 -0
  431. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/superexec/plugin/simulation_exec_plugin.py +0 -0
  432. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supercore/superexec/run_superexec.py +0 -0
  433. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/__init__.py +0 -0
  434. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/artifact_provider/__init__.py +0 -0
  435. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/artifact_provider/artifact_provider.py +0 -0
  436. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/auth_plugin/__init__.py +0 -0
  437. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/auth_plugin/auth_plugin.py +0 -0
  438. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/auth_plugin/noop_auth_plugin.py +0 -0
  439. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/federation/__init__.py +0 -0
  440. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/federation/federation_manager.py +0 -0
  441. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/federation/noop_federation_manager.py +0 -0
  442. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/servicer/__init__.py +0 -0
  443. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/servicer/control/__init__.py +0 -0
  444. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/servicer/control/control_account_auth_interceptor.py +0 -0
  445. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/servicer/control/control_event_log_interceptor.py +0 -0
  446. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/superlink/servicer/control/control_license_interceptor.py +0 -0
  447. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/__init__.py +0 -0
  448. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/cli/__init__.py +0 -0
  449. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/cli/flower_supernode.py +0 -0
  450. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/cli/flwr_clientapp.py +0 -0
  451. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/nodestate/__init__.py +0 -0
  452. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/nodestate/nodestate_factory.py +0 -0
  453. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/runtime/__init__.py +0 -0
  454. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/runtime/run_clientapp.py +0 -0
  455. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/servicer/__init__.py +0 -0
  456. {flwr-1.24.0 → flwr-1.25.0}/py/flwr/supernode/servicer/clientappio/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flwr
3
- Version: 1.24.0
3
+ Version: 1.25.0
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  License: Apache-2.0
6
6
  Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
@@ -180,7 +180,7 @@ Quickstart examples:
180
180
  - [Quickstart (Pandas)](https://github.com/adap/flower/tree/main/examples/quickstart-pandas)
181
181
  - [Quickstart (JAX)](https://github.com/adap/flower/tree/main/examples/quickstart-jax)
182
182
  - [Quickstart (MONAI)](https://github.com/adap/flower/tree/main/examples/quickstart-monai)
183
- - [Quickstart (scikit-learn)](https://github.com/adap/flower/tree/main/examples/sklearn-logreg-mnist)
183
+ - [Quickstart (scikit-learn)](https://github.com/adap/flower/tree/main/examples/quickstart-sklearn)
184
184
  - [Quickstart (Android [TFLite])](https://github.com/adap/flower/tree/main/examples/android)
185
185
  - [Quickstart (iOS [CoreML])](https://github.com/adap/flower/tree/main/examples/ios)
186
186
  - [Quickstart (MLX)](https://github.com/adap/flower/tree/main/examples/quickstart-mlx)
@@ -197,10 +197,8 @@ Other [examples](https://github.com/adap/flower/tree/main/examples):
197
197
  - [Advanced Flower with TensorFlow/Keras](https://github.com/adap/flower/tree/main/examples/advanced-tensorflow)
198
198
  - [Advanced Flower with PyTorch](https://github.com/adap/flower/tree/main/examples/advanced-pytorch)
199
199
  - [Comprehensive Flower+XGBoost](https://github.com/adap/flower/tree/main/examples/xgboost-comprehensive)
200
- - [Flower through Docker Compose and with Grafana dashboard](https://github.com/adap/flower/tree/main/examples/flower-via-docker-compose)
201
200
  - [Flower with KaplanMeierFitter from the lifelines library](https://github.com/adap/flower/tree/main/examples/federated-kaplan-meier-fitter)
202
201
  - [Sample Level Privacy with Opacus](https://github.com/adap/flower/tree/main/examples/opacus)
203
- - [Sample Level Privacy with TensorFlow-Privacy](https://github.com/adap/flower/tree/main/examples/tensorflow-privacy)
204
202
  - [Flower with a Tabular Dataset](https://github.com/adap/flower/tree/main/examples/fl-tabular)
205
203
 
206
204
  ## Community
@@ -124,7 +124,7 @@ Quickstart examples:
124
124
  - [Quickstart (Pandas)](https://github.com/adap/flower/tree/main/examples/quickstart-pandas)
125
125
  - [Quickstart (JAX)](https://github.com/adap/flower/tree/main/examples/quickstart-jax)
126
126
  - [Quickstart (MONAI)](https://github.com/adap/flower/tree/main/examples/quickstart-monai)
127
- - [Quickstart (scikit-learn)](https://github.com/adap/flower/tree/main/examples/sklearn-logreg-mnist)
127
+ - [Quickstart (scikit-learn)](https://github.com/adap/flower/tree/main/examples/quickstart-sklearn)
128
128
  - [Quickstart (Android [TFLite])](https://github.com/adap/flower/tree/main/examples/android)
129
129
  - [Quickstart (iOS [CoreML])](https://github.com/adap/flower/tree/main/examples/ios)
130
130
  - [Quickstart (MLX)](https://github.com/adap/flower/tree/main/examples/quickstart-mlx)
@@ -141,10 +141,8 @@ Other [examples](https://github.com/adap/flower/tree/main/examples):
141
141
  - [Advanced Flower with TensorFlow/Keras](https://github.com/adap/flower/tree/main/examples/advanced-tensorflow)
142
142
  - [Advanced Flower with PyTorch](https://github.com/adap/flower/tree/main/examples/advanced-pytorch)
143
143
  - [Comprehensive Flower+XGBoost](https://github.com/adap/flower/tree/main/examples/xgboost-comprehensive)
144
- - [Flower through Docker Compose and with Grafana dashboard](https://github.com/adap/flower/tree/main/examples/flower-via-docker-compose)
145
144
  - [Flower with KaplanMeierFitter from the lifelines library](https://github.com/adap/flower/tree/main/examples/federated-kaplan-meier-fitter)
146
145
  - [Sample Level Privacy with Opacus](https://github.com/adap/flower/tree/main/examples/opacus)
147
- - [Sample Level Privacy with TensorFlow-Privacy](https://github.com/adap/flower/tree/main/examples/tensorflow-privacy)
148
146
  - [Flower with a Tabular Dataset](https://github.com/adap/flower/tree/main/examples/fl-tabular)
149
147
 
150
148
  ## Community
@@ -36,6 +36,7 @@ from flwr.supercore.primitives.asymmetric_ed25519 import (
36
36
  load_private_key,
37
37
  sign_message,
38
38
  )
39
+ from flwr.supercore.utils import parse_app_spec, request_download_link
39
40
 
40
41
  from ..auth_plugin.oidc_cli_plugin import OidcCliPlugin
41
42
  from ..config_utils import (
@@ -45,7 +46,7 @@ from ..config_utils import (
45
46
  )
46
47
  from ..constant import FEDERATION_CONFIG_HELP_MESSAGE
47
48
  from ..install import install_from_fab
48
- from ..utils import load_cli_auth_plugin, parse_app_spec, request_download_link
49
+ from ..utils import load_cli_auth_plugin
49
50
 
50
51
  TRY_AGAIN_MESSAGE = "Please try again or press CTRL+C to abort.\n"
51
52
 
@@ -104,12 +105,21 @@ def review(
104
105
  token = auth_plugin.access_token
105
106
 
106
107
  # Validate app version and ID format
107
- app_id, app_version = parse_app_spec(app_spec)
108
+ try:
109
+ app_id, app_version = parse_app_spec(app_spec)
110
+ except ValueError as e:
111
+ typer.secho(f"❌ {e}", fg=typer.colors.RED, err=True)
112
+ raise typer.Exit(code=1) from e
108
113
 
109
114
  # Download FAB
110
115
  typer.secho("Downloading FAB... ", fg=typer.colors.BLUE)
111
116
  url = f"{PLATFORM_API_URL}/hub/fetch-fab"
112
- presigned_url = request_download_link(app_id, app_version, url, "fab_url")
117
+ try:
118
+ presigned_url, _ = request_download_link(app_id, app_version, url, "fab_url")
119
+ except ValueError as e:
120
+ typer.secho(f"❌ {e}", fg=typer.colors.RED, err=True)
121
+ raise typer.Exit(code=1) from e
122
+
113
123
  fab_bytes = _download_fab(presigned_url)
114
124
 
115
125
  # Unpack FAB
@@ -41,6 +41,7 @@ from flwr.proto.control_pb2 import ( # pylint: disable=E0611
41
41
  from flwr.proto.control_pb2_grpc import ControlStub
42
42
  from flwr.proto.node_pb2 import NodeInfo # pylint: disable=E0611
43
43
  from flwr.supercore.constant import NOOP_FEDERATION
44
+ from flwr.supercore.utils import humanize_duration
44
45
 
45
46
  from ..run_utils import RunRow, format_runs
46
47
  from ..utils import flwr_cli_grpc_exc_handler, init_channel, load_cli_auth_plugin
@@ -262,7 +263,7 @@ def _to_runs_table(run_list: list[RunRow]) -> Table:
262
263
  f"[bold]{row.run_id}[/bold]",
263
264
  f"@{row.fab_id}=={row.fab_version}",
264
265
  f"[{status_style}]{row.status_text}[/{status_style}]",
265
- row.elapsed,
266
+ f"{humanize_duration(row.elapsed)}",
266
267
  )
267
268
  table.add_row(*formatted_row)
268
269
 
@@ -298,7 +299,7 @@ def _to_json(
298
299
  for node in nodes:
299
300
  nodes_list.append(
300
301
  {
301
- "node_id": node.node_id,
302
+ "node_id": f"{node.node_id}",
302
303
  "owner": node.owner_name,
303
304
  "status": node.status,
304
305
  }
@@ -307,7 +308,7 @@ def _to_json(
307
308
  for run in runs:
308
309
  runs_list.append(
309
310
  {
310
- "run_id": run.run_id,
311
+ "run_id": f"{run.run_id}",
311
312
  "app": f"@{run.fab_id}=={run.fab_version}",
312
313
  "status": run.status_text,
313
314
  "elapsed": run.elapsed,
@@ -40,6 +40,7 @@ from flwr.proto.control_pb2 import ( # pylint: disable=E0611
40
40
  ListRunsResponse,
41
41
  )
42
42
  from flwr.proto.control_pb2_grpc import ControlStub
43
+ from flwr.supercore.utils import humanize_bytes, humanize_duration
43
44
 
44
45
  from .run_utils import RunRow, format_runs
45
46
  from .utils import flwr_cli_grpc_exc_handler, init_channel, load_cli_auth_plugin
@@ -231,7 +232,7 @@ def _to_table(run_list: list[RunRow]) -> Table:
231
232
  row.federation,
232
233
  f"@{row.fab_id}=={row.fab_version}",
233
234
  f"[{status_style}]{row.status_text}[/{status_style}]",
234
- row.elapsed,
235
+ humanize_duration(row.elapsed),
235
236
  status_changed_at,
236
237
  )
237
238
  table.add_row(*formatted_row)
@@ -265,11 +266,39 @@ def _to_detail_table(run: RunRow) -> Table:
265
266
  table.add_row("App", f"@{run.fab_id}=={run.fab_version}")
266
267
  table.add_row("FAB Hash", f"{run.fab_hash[:8]}...{run.fab_hash[-8:]}")
267
268
  table.add_row("Status", f"[{status_style}]{run.status_text}[/{status_style}]")
268
- table.add_row("Elapsed", f"[blue]{run.elapsed}[/blue]")
269
+ table.add_row("Elapsed", f"[blue]{humanize_duration(run.elapsed)}[/blue]")
269
270
  table.add_row("Pending At", run.pending_at)
270
271
  table.add_row("Starting At", run.starting_at)
271
272
  table.add_row("Running At", run.running_at)
272
273
  table.add_row("Finished At", run.finished_at)
274
+ table.add_row(
275
+ "Network traffic (inbound)",
276
+ f"[blue]{humanize_bytes(run.network_traffic_inbound)}[/blue]",
277
+ )
278
+ table.add_row(
279
+ "Network traffic (outbound)",
280
+ f"[blue]{humanize_bytes(run.network_traffic_outbound)}[/blue]",
281
+ )
282
+ table.add_row(
283
+ "Network Traffic (total)",
284
+ "[blue]"
285
+ f"{humanize_bytes(run.network_traffic_inbound + run.network_traffic_outbound)}"
286
+ "[/blue]",
287
+ )
288
+ table.add_row(
289
+ "Compute Time (ServerApp)",
290
+ f"[blue]{humanize_duration(run.compute_time_serverapp)}[/blue]",
291
+ )
292
+ table.add_row(
293
+ "Compute Time (ClientApp)",
294
+ f"[blue]{humanize_duration(run.compute_time_clientapp)}[/blue]",
295
+ )
296
+ table.add_row(
297
+ "Compute Time (total)",
298
+ "[blue]"
299
+ f"{humanize_duration(run.compute_time_serverapp + run.compute_time_clientapp)}"
300
+ "[/blue]",
301
+ )
273
302
 
274
303
  return table
275
304
 
@@ -291,7 +320,7 @@ def _to_json(run_list: list[RunRow]) -> str:
291
320
  for row in run_list:
292
321
  runs_list.append(
293
322
  {
294
- "run-id": row.run_id,
323
+ "run-id": f"{row.run_id}",
295
324
  "federation": row.federation,
296
325
  "fab-id": row.fab_id,
297
326
  "fab-name": row.fab_id.split("/")[-1],
@@ -303,6 +332,18 @@ def _to_json(run_list: list[RunRow]) -> str:
303
332
  "starting-at": row.starting_at,
304
333
  "running-at": row.running_at,
305
334
  "finished-at": row.finished_at,
335
+ "network-traffic": {
336
+ "inbound-bytes": row.network_traffic_inbound,
337
+ "outbound-bytes": row.network_traffic_outbound,
338
+ "total-bytes": row.network_traffic_inbound
339
+ + row.network_traffic_outbound,
340
+ },
341
+ "compute-time": {
342
+ "serverapp-seconds": row.compute_time_serverapp,
343
+ "clientapp-seconds": row.compute_time_clientapp,
344
+ "total-seconds": row.compute_time_serverapp
345
+ + row.compute_time_clientapp,
346
+ },
306
347
  }
307
348
  )
308
349
 
@@ -0,0 +1,263 @@
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 `new` command."""
16
+
17
+
18
+ import io
19
+ import zipfile
20
+ from pathlib import Path
21
+ from typing import Annotated, cast
22
+
23
+ import requests
24
+ import typer
25
+
26
+ from flwr.supercore.constant import PLATFORM_API_URL
27
+ from flwr.supercore.utils import parse_app_spec, request_download_link
28
+
29
+ from ..utils import prompt_options, prompt_text
30
+
31
+
32
+ # pylint: disable=too-many-locals,too-many-branches,too-many-statements
33
+ def new(
34
+ app_spec: Annotated[
35
+ str | None,
36
+ typer.Argument(
37
+ help="Flower app specifier. Use the format "
38
+ "'@account_name/app_name' or '@account_name/app_name==x.y.z'. "
39
+ "Version is optional (defaults to latest)."
40
+ ),
41
+ ] = None,
42
+ framework: Annotated[
43
+ str | None,
44
+ typer.Option(case_sensitive=False, help="Deprecated. The ML framework to use"),
45
+ ] = None,
46
+ username: Annotated[
47
+ str | None,
48
+ typer.Option(
49
+ case_sensitive=False, help="Deprecated. The Flower username of the author"
50
+ ),
51
+ ] = None,
52
+ ) -> None:
53
+ """Create new Flower App."""
54
+ if framework is not None or username is not None:
55
+ typer.secho(
56
+ "❌ The --framework and --username options are deprecated and will be "
57
+ "removed in future versions of Flower. Please provide an app specifier "
58
+ "after `flwr new` instead, e.g., '@account_name/app_name' or "
59
+ "'@account_name/app_name==x.y.z'.",
60
+ fg=typer.colors.RED,
61
+ bold=True,
62
+ err=True,
63
+ )
64
+ raise typer.Exit(code=1)
65
+
66
+ if app_spec is None:
67
+ # Fetch recommended apps
68
+ print(
69
+ typer.style(
70
+ "\n🌸 Fetching recommended apps...",
71
+ fg=typer.colors.GREEN,
72
+ bold=True,
73
+ )
74
+ )
75
+ apps = fetch_recommended_apps()
76
+
77
+ if not apps:
78
+ typer.secho(
79
+ "No recommended apps found. Please provide an app specifier manually.",
80
+ fg=typer.colors.YELLOW,
81
+ )
82
+ app_spec = prompt_text("Please provide the app specifier")
83
+ else:
84
+ # Extract app_ids and show selection menu
85
+ app_ids = [app["app_id"] for app in apps]
86
+ app_spec = prompt_options(
87
+ "Select a Flower App to create by entering "
88
+ "the number from the list below:",
89
+ app_ids,
90
+ )
91
+
92
+ # Download remote app
93
+ download_remote_app_via_api(app_spec)
94
+
95
+
96
+ def print_success_prompt(package_name: str) -> None:
97
+ """Print styled setup instructions for running a new Flower App after creation."""
98
+ prompt = typer.style(
99
+ "🎊 Flower App creation successful.\n\n"
100
+ "To run your Flower App, first install its dependencies:\n\n",
101
+ fg=typer.colors.GREEN,
102
+ bold=True,
103
+ )
104
+
105
+ prompt += typer.style(
106
+ f" cd {package_name} && pip install -e .\n\n",
107
+ fg=typer.colors.BRIGHT_CYAN,
108
+ bold=True,
109
+ )
110
+
111
+ prompt += typer.style(
112
+ "then, run the app:\n\n ",
113
+ fg=typer.colors.GREEN,
114
+ bold=True,
115
+ )
116
+
117
+ prompt += typer.style(
118
+ "\tflwr run .\n\n",
119
+ fg=typer.colors.BRIGHT_CYAN,
120
+ bold=True,
121
+ )
122
+
123
+ prompt += typer.style(
124
+ "💡 Check the README in your app directory to learn how to\n"
125
+ "customize it and how to run it using the Deployment Runtime.\n",
126
+ fg=typer.colors.GREEN,
127
+ bold=True,
128
+ )
129
+
130
+ print(prompt)
131
+
132
+
133
+ def fetch_recommended_apps() -> list[dict[str, str]]:
134
+ """Fetch recommended apps from Platform API."""
135
+ url = f"{PLATFORM_API_URL}/hub/apps?tag=recommended"
136
+ try:
137
+ response = requests.get(url, headers={"accept": "application/json"}, timeout=10)
138
+ response.raise_for_status()
139
+ data = response.json()
140
+ apps = data.get("apps", [])
141
+ return cast(list[dict[str, str]], apps)
142
+
143
+ except requests.RequestException as e:
144
+ typer.secho(
145
+ f"❌ Failed to fetch recommended apps: {e}",
146
+ fg=typer.colors.RED,
147
+ err=True,
148
+ )
149
+ raise typer.Exit(code=1) from e
150
+
151
+
152
+ # Security: prevent zip-slip
153
+ def _safe_extract_zip(zf: zipfile.ZipFile, dest_dir: Path) -> None:
154
+ """Extract ZIP file into destination directory."""
155
+ dest_dir = dest_dir.resolve()
156
+
157
+ def _is_within_directory(base: Path, target: Path) -> bool:
158
+ try:
159
+ target.relative_to(base)
160
+ return True
161
+ except ValueError:
162
+ return False
163
+
164
+ for member in zf.infolist():
165
+ # Skip directory placeholders;
166
+ # ZipInfo can represent them as names ending with '/'.
167
+ if member.is_dir():
168
+ target_path = (dest_dir / member.filename).resolve()
169
+ if not _is_within_directory(dest_dir, target_path):
170
+ raise ValueError(f"Unsafe path in zip: {member.filename}")
171
+ target_path.mkdir(parents=True, exist_ok=True)
172
+ continue
173
+
174
+ # Files
175
+ target_path = (dest_dir / member.filename).resolve()
176
+ if not _is_within_directory(dest_dir, target_path):
177
+ raise ValueError(f"Unsafe path in zip: {member.filename}")
178
+
179
+ # Ensure parent exists
180
+ target_path.parent.mkdir(parents=True, exist_ok=True)
181
+
182
+ # Extract
183
+ with zf.open(member, "r") as src, open(target_path, "wb") as dst:
184
+ dst.write(src.read())
185
+
186
+
187
+ def _download_zip_to_memory(presigned_url: str) -> io.BytesIO:
188
+ """Download ZIP file from Platform API to memory."""
189
+ try:
190
+ r = requests.get(presigned_url, timeout=60)
191
+ r.raise_for_status()
192
+ except requests.RequestException as e:
193
+ typer.secho(
194
+ f"ZIP download failed: {e}",
195
+ fg=typer.colors.RED,
196
+ err=True,
197
+ )
198
+ raise typer.Exit(code=1) from e
199
+
200
+ buf = io.BytesIO(r.content)
201
+ # Validate it's a zip
202
+ if not zipfile.is_zipfile(buf):
203
+ typer.secho(
204
+ "Downloaded file is not a valid ZIP",
205
+ fg=typer.colors.RED,
206
+ err=True,
207
+ )
208
+ raise typer.Exit(code=1)
209
+ buf.seek(0)
210
+ return buf
211
+
212
+
213
+ def download_remote_app_via_api(app_spec: str) -> None:
214
+ """Download App from Platform API."""
215
+ # Validate app version and ID format
216
+ try:
217
+ app_id, app_version = parse_app_spec(app_spec)
218
+ except ValueError as e:
219
+ typer.secho(f"❌ {e}", fg=typer.colors.RED, err=True)
220
+ raise typer.Exit(code=1) from e
221
+
222
+ app_name = app_id.split("/")[1]
223
+
224
+ project_dir = Path.cwd() / app_name
225
+ if project_dir.exists():
226
+ if not typer.confirm(
227
+ typer.style(
228
+ f"\n💬 {app_name} already exists, do you want to override it?",
229
+ fg=typer.colors.MAGENTA,
230
+ bold=True,
231
+ )
232
+ ):
233
+ return
234
+
235
+ typer.secho(
236
+ f"\n🔗 Requesting download link for {app_id}...",
237
+ fg=typer.colors.GREEN,
238
+ bold=True,
239
+ )
240
+ # Fetch ZIP downloading URL
241
+ url = f"{PLATFORM_API_URL}/hub/fetch-zip"
242
+ try:
243
+ presigned_url, _ = request_download_link(app_id, app_version, url, "zip_url")
244
+ except ValueError as e:
245
+ typer.secho(f"❌ {e}", fg=typer.colors.RED, err=True)
246
+ raise typer.Exit(code=1) from e
247
+
248
+ typer.secho(
249
+ "🔽 Downloading ZIP into memory...",
250
+ fg=typer.colors.GREEN,
251
+ bold=True,
252
+ )
253
+ zip_buf = _download_zip_to_memory(presigned_url)
254
+
255
+ typer.secho(
256
+ f"📦 Unpacking into {project_dir}...",
257
+ fg=typer.colors.GREEN,
258
+ bold=True,
259
+ )
260
+ with zipfile.ZipFile(zip_buf) as zf:
261
+ _safe_extract_zip(zf, Path.cwd())
262
+
263
+ print_success_prompt(app_name)
@@ -46,14 +46,10 @@ from flwr.common.typing import Fab
46
46
  from flwr.proto.control_pb2 import StartRunRequest # pylint: disable=E0611
47
47
  from flwr.proto.control_pb2_grpc import ControlStub
48
48
  from flwr.supercore.constant import NOOP_FEDERATION
49
+ from flwr.supercore.utils import parse_app_spec
49
50
 
50
51
  from ..log import start_stream
51
- from ..utils import (
52
- flwr_cli_grpc_exc_handler,
53
- init_channel,
54
- load_cli_auth_plugin,
55
- parse_app_spec,
56
- )
52
+ from ..utils import flwr_cli_grpc_exc_handler, init_channel, load_cli_auth_plugin
57
53
 
58
54
  CONN_REFRESH_PERIOD = 60 # Connection refresh period for log streaming (seconds)
59
55
 
@@ -111,8 +107,15 @@ def run(
111
107
  app_spec = None
112
108
  if (app_str := str(app)).startswith("@"):
113
109
  # Validate app version and ID format
114
- _ = parse_app_spec(app_str)
110
+ try:
111
+ _ = parse_app_spec(app_str)
112
+ except ValueError as e:
113
+ typer.secho(f"❌ {e}", fg=typer.colors.RED, err=True)
114
+ raise typer.Exit(code=1) from e
115
+
115
116
  app_spec = app_str
117
+ # Set `app` to current directory for credential storage
118
+ app = Path(".")
116
119
  is_remote_app = app_spec is not None
117
120
 
118
121
  typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
@@ -212,22 +215,14 @@ def _run_with_control_api(
212
215
  f"🎊 Successfully started run {res.run_id}", fg=typer.colors.GREEN
213
216
  )
214
217
  else:
215
- if is_remote_app:
216
- typer.secho(
217
- "❌ Failed to start run. Please check that the provided "
218
- "app identifier (@account_name/app_name) is correct.",
219
- fg=typer.colors.RED,
220
- err=True,
221
- )
222
- else:
223
- typer.secho("❌ Failed to start run", fg=typer.colors.RED, err=True)
218
+ typer.secho("❌ Failed to start run", fg=typer.colors.RED, err=True)
224
219
  raise typer.Exit(code=1)
225
220
 
226
221
  if output_format == CliOutputFormat.JSON:
227
222
  # Only include FAB metadata if we actually built a local FAB
228
223
  payload: dict[str, Any] = {
229
224
  "success": res.HasField("run_id"),
230
- "run-id": res.run_id if res.HasField("run_id") else None,
225
+ "run-id": f"{res.run_id}" if res.HasField("run_id") else None,
231
226
  }
232
227
  if not is_remote_app:
233
228
  payload.update(
@@ -18,7 +18,7 @@
18
18
  from dataclasses import dataclass
19
19
  from datetime import datetime, timedelta
20
20
 
21
- from flwr.common.date import format_timedelta, isoformat8601_utc
21
+ from flwr.common.date import isoformat8601_utc
22
22
  from flwr.common.typing import Run
23
23
 
24
24
 
@@ -40,8 +40,8 @@ class RunRow: # pylint: disable=too-many-instance-attributes
40
40
  The SHA-256 hash of the FAB.
41
41
  status_text : str
42
42
  The formatted status text.
43
- elapsed : str
44
- The formatted elapsed time.
43
+ elapsed : float
44
+ The elapsed time in seconds.
45
45
  pending_at : str
46
46
  Timestamp when run entered pending state.
47
47
  starting_at : str
@@ -50,6 +50,16 @@ class RunRow: # pylint: disable=too-many-instance-attributes
50
50
  Timestamp when run entered running state.
51
51
  finished_at : str
52
52
  Timestamp when run finished.
53
+ network_traffic_inbound : int
54
+ The total inbound network traffic (in bytes) used during the run.
55
+ It includes the traffic from SuperNodes to SuperLink.
56
+ network_traffic_outbound : int
57
+ The total outbound network traffic (in bytes) used during the run.
58
+ It includes the traffic from SuperLink to SuperNodes.
59
+ compute_time_serverapp : float
60
+ The total compute time (in seconds) of the ServerApp during the run.
61
+ compute_time_clientapp : float
62
+ The total compute time (in seconds) of all ClientApps during the run.
53
63
  """
54
64
 
55
65
  run_id: int
@@ -58,11 +68,15 @@ class RunRow: # pylint: disable=too-many-instance-attributes
58
68
  fab_version: str
59
69
  fab_hash: str
60
70
  status_text: str
61
- elapsed: str
71
+ elapsed: float
62
72
  pending_at: str
63
73
  starting_at: str
64
74
  running_at: str
65
75
  finished_at: str
76
+ network_traffic_inbound: int
77
+ network_traffic_outbound: int
78
+ compute_time_serverapp: float
79
+ compute_time_clientapp: float
66
80
 
67
81
 
68
82
  def format_runs(runs: list[Run], now_isoformat: str) -> list[RunRow]:
@@ -120,11 +134,15 @@ def format_runs(runs: list[Run], now_isoformat: str) -> list[RunRow]:
120
134
  fab_version=run.fab_version,
121
135
  fab_hash=run.fab_hash,
122
136
  status_text=status_text,
123
- elapsed=format_timedelta(elapsed_time),
137
+ elapsed=elapsed_time.total_seconds(),
124
138
  pending_at=_format_datetime(pending_at),
125
139
  starting_at=_format_datetime(starting_at),
126
140
  running_at=_format_datetime(running_at),
127
141
  finished_at=_format_datetime(finished_at),
142
+ network_traffic_inbound=run.bytes_recv,
143
+ network_traffic_outbound=run.bytes_sent,
144
+ compute_time_serverapp=elapsed_time.total_seconds(),
145
+ compute_time_clientapp=run.clientapp_runtime,
128
146
  )
129
147
  run_list.append(row)
130
148
  return run_list
@@ -149,7 +149,7 @@ def _stop_run(stub: ControlStub, run_id: int, output_format: str) -> None:
149
149
  run_output = json.dumps(
150
150
  {
151
151
  "success": True,
152
- "run-id": run_id,
152
+ "run-id": f"{run_id}",
153
153
  }
154
154
  )
155
155
  restore_output()
@@ -33,7 +33,7 @@ from flwr.cli.config_utils import (
33
33
  validate_federation_in_project_config,
34
34
  )
35
35
  from flwr.common.constant import FAB_CONFIG_FILE, NOOP_ACCOUNT_NAME, CliOutputFormat
36
- from flwr.common.date import format_timedelta, isoformat8601_utc
36
+ from flwr.common.date import isoformat8601_utc
37
37
  from flwr.common.logger import print_json_error, redirect_output, restore_output
38
38
  from flwr.proto.control_pb2 import ( # pylint: disable=E0611
39
39
  ListNodesRequest,
@@ -41,10 +41,11 @@ from flwr.proto.control_pb2 import ( # pylint: disable=E0611
41
41
  )
42
42
  from flwr.proto.control_pb2_grpc import ControlStub
43
43
  from flwr.proto.node_pb2 import NodeInfo # pylint: disable=E0611
44
+ from flwr.supercore.utils import humanize_duration
44
45
 
45
46
  from ..utils import flwr_cli_grpc_exc_handler, init_channel, load_cli_auth_plugin
46
47
 
47
- _NodeListType = tuple[int, str, str, str, str, str, str, str, str]
48
+ _NodeListType = tuple[int, str, str, str, str, str, str, str, float]
48
49
 
49
50
 
50
51
  def ls( # pylint: disable=R0914, R0913, R0917
@@ -166,7 +167,7 @@ def _format_nodes(
166
167
  _format_datetime(node.last_activated_at),
167
168
  _format_datetime(node.last_deactivated_at),
168
169
  _format_datetime(node.unregistered_at),
169
- format_timedelta(elapsed_time_activated),
170
+ elapsed_time_activated.total_seconds(),
170
171
  )
171
172
  )
172
173
 
@@ -224,7 +225,11 @@ def _to_table(nodes_info: list[_NodeListType], verbose: bool) -> Table:
224
225
  else f"[dim]{owner_name}[/dim]"
225
226
  ),
226
227
  f"[{status_style}]{status}",
227
- f"[cyan]{elapse_activated}[/cyan]" if status == "online" else "",
228
+ (
229
+ f"[cyan]{humanize_duration(elapse_activated)}[/cyan]"
230
+ if status == "online"
231
+ else ""
232
+ ),
228
233
  time_at,
229
234
  )
230
235
  table.add_row(*formatted_row)
@@ -253,7 +258,7 @@ def _to_json(nodes_info: list[_NodeListType], verbose: bool) -> str:
253
258
 
254
259
  nodes_list.append(
255
260
  {
256
- "node-id": node_id,
261
+ "node-id": f"{node_id}",
257
262
  "owner-aid": owner_aid,
258
263
  "owner-name": owner_name,
259
264
  "status": status,