flwr 1.22.0__tar.gz → 1.23.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 (444) hide show
  1. {flwr-1.22.0 → flwr-1.23.0}/PKG-INFO +1 -1
  2. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/app.py +15 -1
  3. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/auth_plugin/__init__.py +15 -6
  4. flwr-1.23.0/py/flwr/cli/auth_plugin/auth_plugin.py +95 -0
  5. flwr-1.23.0/py/flwr/cli/auth_plugin/noop_auth_plugin.py +58 -0
  6. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/auth_plugin/oidc_cli_plugin.py +16 -25
  7. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/build.py +118 -47
  8. flwr-1.22.0/py/flwr/cli/cli_user_auth_interceptor.py → flwr-1.23.0/py/flwr/cli/cli_account_auth_interceptor.py +6 -5
  9. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/log.py +2 -2
  10. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/login/login.py +34 -23
  11. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/ls.py +13 -9
  12. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/new.py +187 -35
  13. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +1 -1
  14. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +1 -1
  15. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +1 -1
  16. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/pyproject.jax.toml.tpl +1 -1
  17. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -1
  18. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +1 -1
  19. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +1 -1
  20. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/pyproject.pytorch_legacy_api.toml.tpl +1 -1
  21. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
  22. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +1 -1
  23. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/pyproject.xgboost.toml.tpl +1 -1
  24. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/pull.py +2 -2
  25. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/run/run.py +11 -7
  26. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/stop.py +2 -2
  27. flwr-1.23.0/py/flwr/cli/supernode/__init__.py +25 -0
  28. flwr-1.23.0/py/flwr/cli/supernode/ls.py +260 -0
  29. flwr-1.23.0/py/flwr/cli/supernode/register.py +185 -0
  30. flwr-1.23.0/py/flwr/cli/supernode/unregister.py +138 -0
  31. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/utils.py +92 -69
  32. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/__init__.py +2 -1
  33. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/grpc_adapter_client/connection.py +6 -8
  34. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/grpc_rere_client/connection.py +59 -31
  35. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/grpc_rere_client/grpc_adapter.py +28 -12
  36. flwr-1.22.0/py/flwr/client/grpc_rere_client/client_interceptor.py → flwr-1.23.0/py/flwr/client/grpc_rere_client/node_auth_client_interceptor.py +3 -6
  37. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +7 -5
  38. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/rest_client/connection.py +82 -37
  39. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/clientapp/__init__.py +1 -2
  40. {flwr-1.22.0/py/flwr/client → flwr-1.23.0/py/flwr}/clientapp/utils.py +1 -1
  41. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/constant.py +53 -13
  42. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/exit/exit_code.py +20 -10
  43. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/inflatable_utils.py +10 -10
  44. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/record/array.py +3 -3
  45. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/record/arrayrecord.py +10 -1
  46. flwr-1.23.0/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +76 -0
  47. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/serde.py +4 -2
  48. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/typing.py +7 -6
  49. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/compat/client/app.py +1 -1
  50. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/compat/client/grpc_client/connection.py +2 -2
  51. flwr-1.23.0/py/flwr/proto/control_pb2.py +79 -0
  52. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/control_pb2.pyi +71 -5
  53. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/control_pb2_grpc.py +102 -0
  54. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/control_pb2_grpc.pyi +39 -0
  55. flwr-1.23.0/py/flwr/proto/fab_pb2.py +35 -0
  56. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/fab_pb2.pyi +21 -1
  57. flwr-1.23.0/py/flwr/proto/fleet_pb2.py +61 -0
  58. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/fleet_pb2.pyi +63 -23
  59. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/fleet_pb2_grpc.py +98 -28
  60. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/fleet_pb2_grpc.pyi +45 -13
  61. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/node_pb2.py +3 -1
  62. flwr-1.23.0/py/flwr/proto/node_pb2.pyi +69 -0
  63. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/app.py +139 -114
  64. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +17 -7
  65. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +132 -38
  66. flwr-1.22.0/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py → flwr-1.23.0/py/flwr/server/superlink/fleet/grpc_rere/node_auth_server_interceptor.py +27 -51
  67. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/message_handler/message_handler.py +67 -22
  68. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +52 -31
  69. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/vce/backend/backend.py +1 -1
  70. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +1 -1
  71. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/vce/vce_api.py +18 -5
  72. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/linkstate/in_memory_linkstate.py +167 -73
  73. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/linkstate/linkstate.py +107 -24
  74. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/linkstate/linkstate_factory.py +2 -1
  75. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/linkstate/sqlite_linkstate.py +306 -255
  76. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/linkstate/utils.py +3 -54
  77. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/serverappio/serverappio_servicer.py +2 -2
  78. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/simulation/simulationio_servicer.py +1 -1
  79. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/utils/validator.py +2 -3
  80. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +4 -2
  81. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/simulation/ray_transport/ray_actor.py +1 -1
  82. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/simulation/ray_transport/ray_client_proxy.py +1 -1
  83. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/simulation/run_simulation.py +3 -2
  84. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/constant.py +22 -0
  85. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/object_store/in_memory_object_store.py +0 -4
  86. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/object_store/object_store_factory.py +26 -6
  87. flwr-1.23.0/py/flwr/supercore/object_store/sqlite_object_store.py +252 -0
  88. flwr-1.23.0/py/flwr/supercore/primitives/__init__.py +15 -0
  89. flwr-1.22.0/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py → flwr-1.23.0/py/flwr/supercore/primitives/asymmetric.py +10 -57
  90. flwr-1.23.0/py/flwr/supercore/primitives/asymmetric_ed25519.py +165 -0
  91. flwr-1.23.0/py/flwr/supercore/sqlite_mixin.py +156 -0
  92. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/utils.py +20 -0
  93. {flwr-1.22.0/py/flwr/common → flwr-1.23.0/py/flwr/superlink}/auth_plugin/__init__.py +6 -6
  94. flwr-1.23.0/py/flwr/superlink/auth_plugin/auth_plugin.py +91 -0
  95. flwr-1.23.0/py/flwr/superlink/auth_plugin/noop_auth_plugin.py +87 -0
  96. flwr-1.22.0/py/flwr/superlink/servicer/control/control_user_auth_interceptor.py → flwr-1.23.0/py/flwr/superlink/servicer/control/control_account_auth_interceptor.py +19 -19
  97. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/superlink/servicer/control/control_event_log_interceptor.py +1 -1
  98. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/superlink/servicer/control/control_grpc.py +13 -11
  99. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/superlink/servicer/control/control_servicer.py +152 -60
  100. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/cli/flower_supernode.py +19 -26
  101. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/runtime/run_clientapp.py +2 -2
  102. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/servicer/clientappio/clientappio_servicer.py +1 -1
  103. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/start_client_internal.py +17 -9
  104. {flwr-1.22.0 → flwr-1.23.0}/pyproject.toml +3 -2
  105. flwr-1.22.0/py/flwr/client/clientapp/__init__.py +0 -15
  106. flwr-1.22.0/py/flwr/common/auth_plugin/auth_plugin.py +0 -149
  107. flwr-1.22.0/py/flwr/proto/control_pb2.py +0 -66
  108. flwr-1.22.0/py/flwr/proto/fab_pb2.py +0 -31
  109. flwr-1.22.0/py/flwr/proto/fleet_pb2.py +0 -53
  110. flwr-1.22.0/py/flwr/proto/node_pb2.pyi +0 -21
  111. {flwr-1.22.0 → flwr-1.23.0}/README.md +0 -0
  112. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/__init__.py +0 -0
  113. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/app/__init__.py +0 -0
  114. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/app/error.py +0 -0
  115. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/app/exception.py +0 -0
  116. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/app/metadata.py +0 -0
  117. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/__init__.py +0 -0
  118. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/config_utils.py +0 -0
  119. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/constant.py +0 -0
  120. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/example.py +0 -0
  121. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/install.py +0 -0
  122. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/login/__init__.py +0 -0
  123. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/__init__.py +0 -0
  124. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/__init__.py +0 -0
  125. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/.gitignore.tpl +0 -0
  126. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/LICENSE.tpl +0 -0
  127. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/README.baseline.md.tpl +0 -0
  128. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/README.flowertune.md.tpl +0 -0
  129. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/README.md.tpl +0 -0
  130. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/__init__.py +0 -0
  131. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +0 -0
  132. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
  133. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
  134. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/__init__.pytorch_legacy_api.py.tpl +0 -0
  135. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/client.baseline.py.tpl +0 -0
  136. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/client.huggingface.py.tpl +0 -0
  137. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/client.jax.py.tpl +0 -0
  138. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/client.mlx.py.tpl +0 -0
  139. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
  140. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
  141. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/client.pytorch_legacy_api.py.tpl +0 -0
  142. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -0
  143. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
  144. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/client.xgboost.py.tpl +0 -0
  145. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +0 -0
  146. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/flwr_tune/__init__.py +0 -0
  147. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +0 -0
  148. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +0 -0
  149. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +0 -0
  150. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +0 -0
  151. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +0 -0
  152. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/model.baseline.py.tpl +0 -0
  153. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/server.baseline.py.tpl +0 -0
  154. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/server.huggingface.py.tpl +0 -0
  155. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/server.jax.py.tpl +0 -0
  156. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/server.mlx.py.tpl +0 -0
  157. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
  158. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
  159. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/server.pytorch_legacy_api.py.tpl +0 -0
  160. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -0
  161. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
  162. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/server.xgboost.py.tpl +0 -0
  163. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +0 -0
  164. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/task.huggingface.py.tpl +0 -0
  165. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/task.jax.py.tpl +0 -0
  166. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/task.mlx.py.tpl +0 -0
  167. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/task.numpy.py.tpl +0 -0
  168. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
  169. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/task.pytorch_legacy_api.py.tpl +0 -0
  170. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/task.sklearn.py.tpl +0 -0
  171. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +0 -0
  172. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/task.xgboost.py.tpl +0 -0
  173. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/new/templates/app/code/utils.baseline.py.tpl +0 -0
  174. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/cli/run/__init__.py +0 -0
  175. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/client.py +0 -0
  176. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/dpfedavg_numpy_client.py +0 -0
  177. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/grpc_adapter_client/__init__.py +0 -0
  178. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/grpc_rere_client/__init__.py +0 -0
  179. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/message_handler/__init__.py +0 -0
  180. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/message_handler/message_handler.py +0 -0
  181. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/mod/__init__.py +0 -0
  182. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/mod/centraldp_mods.py +0 -0
  183. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/mod/comms_mods.py +0 -0
  184. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/mod/localdp_mod.py +0 -0
  185. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
  186. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
  187. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/mod/utils.py +0 -0
  188. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/numpy_client.py +0 -0
  189. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/rest_client/__init__.py +0 -0
  190. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/run_info_store.py +0 -0
  191. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/client/typing.py +0 -0
  192. {flwr-1.22.0/py/flwr/client → flwr-1.23.0/py/flwr/clientapp}/client_app.py +0 -0
  193. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/clientapp/mod/__init__.py +0 -0
  194. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/clientapp/mod/centraldp_mods.py +0 -0
  195. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/clientapp/mod/localdp_mod.py +0 -0
  196. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/clientapp/typing.py +0 -0
  197. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/__init__.py +0 -0
  198. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/address.py +0 -0
  199. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/args.py +0 -0
  200. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/config.py +0 -0
  201. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/context.py +0 -0
  202. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/date.py +0 -0
  203. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/differential_privacy.py +0 -0
  204. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/differential_privacy_constants.py +0 -0
  205. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/dp.py +0 -0
  206. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/event_log_plugin/__init__.py +0 -0
  207. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/event_log_plugin/event_log_plugin.py +0 -0
  208. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/exit/__init__.py +0 -0
  209. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/exit/exit.py +0 -0
  210. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/exit/exit_handler.py +0 -0
  211. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/exit/signal_handler.py +0 -0
  212. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/grpc.py +0 -0
  213. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/heartbeat.py +0 -0
  214. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/inflatable.py +0 -0
  215. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/inflatable_protobuf_utils.py +0 -0
  216. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/logger.py +0 -0
  217. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/message.py +0 -0
  218. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/object_ref.py +0 -0
  219. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/parameter.py +0 -0
  220. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/pyproject.py +0 -0
  221. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/record/__init__.py +0 -0
  222. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/record/arraychunk.py +0 -0
  223. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/record/configrecord.py +0 -0
  224. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/record/conversion_utils.py +0 -0
  225. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/record/metricrecord.py +0 -0
  226. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/record/recorddict.py +0 -0
  227. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/record/typeddict.py +0 -0
  228. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/recorddict_compat.py +0 -0
  229. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/retry_invoker.py +0 -0
  230. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/secure_aggregation/__init__.py +0 -0
  231. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
  232. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
  233. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
  234. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/secure_aggregation/quantization.py +0 -0
  235. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
  236. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
  237. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/serde_utils.py +0 -0
  238. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/telemetry.py +0 -0
  239. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/common/version.py +0 -0
  240. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/compat/__init__.py +0 -0
  241. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/compat/client/__init__.py +0 -0
  242. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/compat/client/grpc_client/__init__.py +0 -0
  243. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/compat/common/__init__.py +0 -0
  244. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/compat/server/__init__.py +0 -0
  245. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/compat/server/app.py +0 -0
  246. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/compat/simulation/__init__.py +0 -0
  247. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/__init__.py +0 -0
  248. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/appio_pb2.py +0 -0
  249. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/appio_pb2.pyi +0 -0
  250. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/appio_pb2_grpc.py +0 -0
  251. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/appio_pb2_grpc.pyi +0 -0
  252. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/clientappio_pb2.py +0 -0
  253. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/clientappio_pb2.pyi +0 -0
  254. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/clientappio_pb2_grpc.py +0 -0
  255. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/clientappio_pb2_grpc.pyi +0 -0
  256. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/error_pb2.py +0 -0
  257. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/error_pb2.pyi +0 -0
  258. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/error_pb2_grpc.py +0 -0
  259. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/error_pb2_grpc.pyi +0 -0
  260. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/fab_pb2_grpc.py +0 -0
  261. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/fab_pb2_grpc.pyi +0 -0
  262. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/grpcadapter_pb2.py +0 -0
  263. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/grpcadapter_pb2.pyi +0 -0
  264. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/grpcadapter_pb2_grpc.py +0 -0
  265. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/grpcadapter_pb2_grpc.pyi +0 -0
  266. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/heartbeat_pb2.py +0 -0
  267. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/heartbeat_pb2.pyi +0 -0
  268. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/heartbeat_pb2_grpc.py +0 -0
  269. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/heartbeat_pb2_grpc.pyi +0 -0
  270. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/log_pb2.py +0 -0
  271. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/log_pb2.pyi +0 -0
  272. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/log_pb2_grpc.py +0 -0
  273. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/log_pb2_grpc.pyi +0 -0
  274. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/message_pb2.py +0 -0
  275. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/message_pb2.pyi +0 -0
  276. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/message_pb2_grpc.py +0 -0
  277. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/message_pb2_grpc.pyi +0 -0
  278. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/node_pb2_grpc.py +0 -0
  279. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/node_pb2_grpc.pyi +0 -0
  280. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/recorddict_pb2.py +0 -0
  281. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/recorddict_pb2.pyi +0 -0
  282. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/recorddict_pb2_grpc.py +0 -0
  283. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/recorddict_pb2_grpc.pyi +0 -0
  284. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/run_pb2.py +0 -0
  285. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/run_pb2.pyi +0 -0
  286. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/run_pb2_grpc.py +0 -0
  287. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/run_pb2_grpc.pyi +0 -0
  288. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/serverappio_pb2.py +0 -0
  289. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/serverappio_pb2.pyi +0 -0
  290. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/serverappio_pb2_grpc.py +0 -0
  291. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/serverappio_pb2_grpc.pyi +0 -0
  292. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/simulationio_pb2.py +0 -0
  293. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/simulationio_pb2.pyi +0 -0
  294. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/simulationio_pb2_grpc.py +0 -0
  295. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/simulationio_pb2_grpc.pyi +0 -0
  296. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/transport_pb2.py +0 -0
  297. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/transport_pb2.pyi +0 -0
  298. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/transport_pb2_grpc.py +0 -0
  299. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
  300. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/py.typed +0 -0
  301. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/__init__.py +0 -0
  302. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/client_manager.py +0 -0
  303. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/client_proxy.py +0 -0
  304. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/compat/__init__.py +0 -0
  305. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/compat/app.py +0 -0
  306. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/compat/app_utils.py +0 -0
  307. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/compat/grid_client_proxy.py +0 -0
  308. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/compat/legacy_context.py +0 -0
  309. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/criterion.py +0 -0
  310. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/fleet_event_log_interceptor.py +0 -0
  311. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/grid/__init__.py +0 -0
  312. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/grid/grid.py +0 -0
  313. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/grid/grpc_grid.py +0 -0
  314. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/grid/inmemory_grid.py +0 -0
  315. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/history.py +0 -0
  316. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/run_serverapp.py +0 -0
  317. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/server.py +0 -0
  318. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/server_app.py +0 -0
  319. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/server_config.py +0 -0
  320. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/serverapp/__init__.py +0 -0
  321. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/serverapp/app.py +0 -0
  322. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/serverapp_components.py +0 -0
  323. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/__init__.py +0 -0
  324. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/aggregate.py +0 -0
  325. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/bulyan.py +0 -0
  326. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
  327. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
  328. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
  329. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
  330. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
  331. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedadagrad.py +0 -0
  332. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedadam.py +0 -0
  333. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedavg.py +0 -0
  334. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedavg_android.py +0 -0
  335. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedavgm.py +0 -0
  336. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedmedian.py +0 -0
  337. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedopt.py +0 -0
  338. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedprox.py +0 -0
  339. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
  340. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
  341. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
  342. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
  343. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/fedyogi.py +0 -0
  344. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/krum.py +0 -0
  345. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/qfedavg.py +0 -0
  346. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/strategy/strategy.py +0 -0
  347. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/__init__.py +0 -0
  348. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/__init__.py +0 -0
  349. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/grpc_adapter/__init__.py +0 -0
  350. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
  351. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
  352. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
  353. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
  354. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +0 -0
  355. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
  356. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
  357. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
  358. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
  359. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
  360. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/linkstate/__init__.py +0 -0
  361. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/serverappio/__init__.py +0 -0
  362. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/serverappio/serverappio_grpc.py +0 -0
  363. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/simulation/__init__.py +0 -0
  364. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/simulation/simulationio_grpc.py +0 -0
  365. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/superlink/utils.py +0 -0
  366. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/typing.py +0 -0
  367. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/utils/__init__.py +0 -0
  368. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/utils/tensorboard.py +0 -0
  369. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/workflow/__init__.py +0 -0
  370. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/workflow/constant.py +0 -0
  371. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/workflow/default_workflows.py +0 -0
  372. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
  373. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
  374. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/__init__.py +0 -0
  375. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/exception.py +0 -0
  376. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/__init__.py +0 -0
  377. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/bulyan.py +0 -0
  378. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/dp_adaptive_clipping.py +0 -0
  379. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/dp_fixed_clipping.py +0 -0
  380. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/fedadagrad.py +0 -0
  381. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/fedadam.py +0 -0
  382. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/fedavg.py +0 -0
  383. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/fedavgm.py +0 -0
  384. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/fedmedian.py +0 -0
  385. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/fedopt.py +0 -0
  386. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/fedprox.py +0 -0
  387. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/fedtrimmedavg.py +0 -0
  388. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/fedxgb_bagging.py +0 -0
  389. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/fedxgb_cyclic.py +0 -0
  390. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/fedyogi.py +0 -0
  391. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/krum.py +0 -0
  392. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/multikrum.py +0 -0
  393. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/qfedavg.py +0 -0
  394. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/result.py +0 -0
  395. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/strategy.py +0 -0
  396. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/serverapp/strategy/strategy_utils.py +0 -0
  397. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/simulation/__init__.py +0 -0
  398. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/simulation/app.py +0 -0
  399. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/simulation/legacy_app.py +0 -0
  400. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/simulation/ray_transport/__init__.py +0 -0
  401. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/simulation/ray_transport/utils.py +0 -0
  402. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/simulation/simulationio_connection.py +0 -0
  403. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/__init__.py +0 -0
  404. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/app_utils.py +0 -0
  405. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/cli/__init__.py +0 -0
  406. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/cli/flower_superexec.py +0 -0
  407. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/corestate/__init__.py +0 -0
  408. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/corestate/corestate.py +0 -0
  409. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/ffs/__init__.py +0 -0
  410. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/ffs/disk_ffs.py +0 -0
  411. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/ffs/ffs.py +0 -0
  412. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/ffs/ffs_factory.py +0 -0
  413. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/grpc_health/__init__.py +0 -0
  414. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/grpc_health/health_server.py +0 -0
  415. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/grpc_health/simple_health_servicer.py +0 -0
  416. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/license_plugin/__init__.py +0 -0
  417. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/license_plugin/license_plugin.py +0 -0
  418. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/object_store/__init__.py +0 -0
  419. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/object_store/object_store.py +0 -0
  420. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/object_store/utils.py +0 -0
  421. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/superexec/__init__.py +0 -0
  422. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/superexec/plugin/__init__.py +0 -0
  423. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/superexec/plugin/base_exec_plugin.py +0 -0
  424. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/superexec/plugin/clientapp_exec_plugin.py +0 -0
  425. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/superexec/plugin/exec_plugin.py +0 -0
  426. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/superexec/plugin/serverapp_exec_plugin.py +0 -0
  427. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/superexec/plugin/simulation_exec_plugin.py +0 -0
  428. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supercore/superexec/run_superexec.py +0 -0
  429. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/superlink/__init__.py +0 -0
  430. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/superlink/artifact_provider/__init__.py +0 -0
  431. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/superlink/artifact_provider/artifact_provider.py +0 -0
  432. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/superlink/servicer/__init__.py +0 -0
  433. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/superlink/servicer/control/__init__.py +0 -0
  434. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/superlink/servicer/control/control_license_interceptor.py +0 -0
  435. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/__init__.py +0 -0
  436. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/cli/__init__.py +0 -0
  437. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/cli/flwr_clientapp.py +0 -0
  438. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/nodestate/__init__.py +0 -0
  439. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/nodestate/in_memory_nodestate.py +0 -0
  440. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/nodestate/nodestate.py +0 -0
  441. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/nodestate/nodestate_factory.py +0 -0
  442. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/runtime/__init__.py +0 -0
  443. {flwr-1.22.0 → flwr-1.23.0}/py/flwr/supernode/servicer/__init__.py +0 -0
  444. {flwr-1.22.0 → flwr-1.23.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.22.0
3
+ Version: 1.23.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
@@ -28,6 +28,9 @@ from .new import new
28
28
  from .pull import pull
29
29
  from .run import run
30
30
  from .stop import stop
31
+ from .supernode import ls as supernode_list
32
+ from .supernode import register as supernode_register
33
+ from .supernode import unregister as supernode_unregister
31
34
 
32
35
  app = typer.Typer(
33
36
  help=typer.style(
@@ -44,11 +47,22 @@ app.command()(run)
44
47
  app.command()(build)
45
48
  app.command()(install)
46
49
  app.command()(log)
47
- app.command()(ls)
50
+ app.command("list")(ls)
51
+ app.command(hidden=True)(ls)
48
52
  app.command()(stop)
49
53
  app.command()(login)
50
54
  app.command()(pull)
51
55
 
56
+ # Create supernode command group
57
+ supernode_app = typer.Typer(help="Manage SuperNodes")
58
+ supernode_app.command()(supernode_register)
59
+ supernode_app.command()(supernode_unregister)
60
+ # Make it appear as "list"
61
+ supernode_app.command("list")(supernode_list)
62
+ # Hide "ls" command (left as alias)
63
+ supernode_app.command(hidden=True)(supernode_list)
64
+ app.add_typer(supernode_app, name="supernode")
65
+
52
66
  typer_click_object = get_command(app)
53
67
 
54
68
 
@@ -12,20 +12,29 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  # ==============================================================================
15
- """Flower user auth plugins."""
15
+ """Flower account auth plugins."""
16
16
 
17
17
 
18
- from flwr.common.auth_plugin import CliAuthPlugin
19
- from flwr.common.constant import AuthType
18
+ from flwr.common.constant import AuthnType
20
19
 
20
+ from .auth_plugin import CliAuthPlugin, LoginError
21
+ from .noop_auth_plugin import NoOpCliAuthPlugin
21
22
  from .oidc_cli_plugin import OidcCliPlugin
22
23
 
23
24
 
24
- def get_cli_auth_plugins() -> dict[str, type[CliAuthPlugin]]:
25
+ def get_cli_plugin_class(authn_type: str) -> type[CliAuthPlugin]:
25
26
  """Return all CLI authentication plugins."""
26
- return {AuthType.OIDC: OidcCliPlugin}
27
+ if authn_type == AuthnType.NOOP:
28
+ return NoOpCliAuthPlugin
29
+ if authn_type == AuthnType.OIDC:
30
+ return OidcCliPlugin
31
+ raise ValueError(f"Unsupported authentication type: {authn_type}")
27
32
 
28
33
 
29
34
  __all__ = [
30
- "get_cli_auth_plugins",
35
+ "CliAuthPlugin",
36
+ "LoginError",
37
+ "NoOpCliAuthPlugin",
38
+ "OidcCliPlugin",
39
+ "get_cli_plugin_class",
31
40
  ]
@@ -0,0 +1,95 @@
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
+ """Abstract classes for Flower account auth plugin."""
16
+
17
+
18
+ from abc import ABC, abstractmethod
19
+ from collections.abc import Sequence
20
+ from pathlib import Path
21
+ from typing import Optional, Union
22
+
23
+ from flwr.common.typing import AccountAuthCredentials, AccountAuthLoginDetails
24
+ from flwr.proto.control_pb2_grpc import ControlStub
25
+
26
+
27
+ class LoginError(Exception):
28
+ """Login error exception."""
29
+
30
+ def __init__(self, message: str):
31
+ self.message = message
32
+
33
+
34
+ class CliAuthPlugin(ABC):
35
+ """Abstract Flower Auth Plugin class for CLI.
36
+
37
+ Parameters
38
+ ----------
39
+ credentials_path : Path
40
+ Path to the Flower account's authentication credentials file.
41
+ """
42
+
43
+ @staticmethod
44
+ @abstractmethod
45
+ def login(
46
+ login_details: AccountAuthLoginDetails,
47
+ control_stub: ControlStub,
48
+ ) -> AccountAuthCredentials:
49
+ """Authenticate the account and retrieve authentication credentials.
50
+
51
+ Parameters
52
+ ----------
53
+ login_details : AccountAuthLoginDetails
54
+ An object containing the account's login details.
55
+ control_stub : ControlStub
56
+ A stub for executing RPC calls to the server.
57
+
58
+ Returns
59
+ -------
60
+ AccountAuthCredentials
61
+ The authentication credentials obtained after login.
62
+
63
+ Raises
64
+ ------
65
+ LoginError
66
+ If the login process fails.
67
+ """
68
+
69
+ @abstractmethod
70
+ def __init__(self, credentials_path: Path):
71
+ """Abstract constructor."""
72
+
73
+ @abstractmethod
74
+ def store_tokens(self, credentials: AccountAuthCredentials) -> None:
75
+ """Store authentication tokens to the `credentials_path`.
76
+
77
+ The credentials, including tokens, will be saved as a JSON file
78
+ at `credentials_path`.
79
+ """
80
+
81
+ @abstractmethod
82
+ def load_tokens(self) -> None:
83
+ """Load authentication tokens from the `credentials_path`."""
84
+
85
+ @abstractmethod
86
+ def write_tokens_to_metadata(
87
+ self, metadata: Sequence[tuple[str, Union[str, bytes]]]
88
+ ) -> Sequence[tuple[str, Union[str, bytes]]]:
89
+ """Write authentication tokens to the provided metadata."""
90
+
91
+ @abstractmethod
92
+ def read_tokens_from_metadata(
93
+ self, metadata: Sequence[tuple[str, Union[str, bytes]]]
94
+ ) -> Optional[AccountAuthCredentials]:
95
+ """Read authentication tokens from the provided metadata."""
@@ -0,0 +1,58 @@
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
+ """Concrete NoOp implementation for CLI-side account authentication plugin."""
16
+
17
+
18
+ from collections.abc import Sequence
19
+ from pathlib import Path
20
+ from typing import Optional, Union
21
+
22
+ from flwr.common.typing import AccountAuthCredentials, AccountAuthLoginDetails
23
+ from flwr.proto.control_pb2_grpc import ControlStub
24
+
25
+ from .auth_plugin import CliAuthPlugin, LoginError
26
+
27
+
28
+ class NoOpCliAuthPlugin(CliAuthPlugin):
29
+ """No-operation implementation of the CliAuthPlugin."""
30
+
31
+ @staticmethod
32
+ def login(
33
+ login_details: AccountAuthLoginDetails,
34
+ control_stub: ControlStub,
35
+ ) -> AccountAuthCredentials:
36
+ """Raise LoginError as no-op plugin does not support login."""
37
+ raise LoginError("Account authentication is not enabled on this SuperLink.")
38
+
39
+ def __init__(self, credentials_path: Path) -> None:
40
+ pass
41
+
42
+ def store_tokens(self, credentials: AccountAuthCredentials) -> None:
43
+ """Do nothing."""
44
+
45
+ def load_tokens(self) -> None:
46
+ """Do nothing."""
47
+
48
+ def write_tokens_to_metadata(
49
+ self, metadata: Sequence[tuple[str, Union[str, bytes]]]
50
+ ) -> Sequence[tuple[str, Union[str, bytes]]]:
51
+ """Return the metadata unchanged."""
52
+ return metadata
53
+
54
+ def read_tokens_from_metadata(
55
+ self, metadata: Sequence[tuple[str, Union[str, bytes]]]
56
+ ) -> Optional[AccountAuthCredentials]:
57
+ """Return None."""
58
+ return None
@@ -12,7 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  # ==============================================================================
15
- """Flower CLI user auth plugin for OIDC."""
15
+ """Flower CLI account auth plugin for OIDC."""
16
16
 
17
17
 
18
18
  import json
@@ -23,20 +23,21 @@ from typing import Any, Optional, Union
23
23
 
24
24
  import typer
25
25
 
26
- from flwr.common.auth_plugin import CliAuthPlugin
27
26
  from flwr.common.constant import (
28
27
  ACCESS_TOKEN_KEY,
29
- AUTH_TYPE_JSON_KEY,
28
+ AUTHN_TYPE_JSON_KEY,
30
29
  REFRESH_TOKEN_KEY,
31
- AuthType,
30
+ AuthnType,
32
31
  )
33
- from flwr.common.typing import UserAuthCredentials, UserAuthLoginDetails
32
+ from flwr.common.typing import AccountAuthCredentials, AccountAuthLoginDetails
34
33
  from flwr.proto.control_pb2 import ( # pylint: disable=E0611
35
34
  GetAuthTokensRequest,
36
35
  GetAuthTokensResponse,
37
36
  )
38
37
  from flwr.proto.control_pb2_grpc import ControlStub
39
38
 
39
+ from .auth_plugin import CliAuthPlugin, LoginError
40
+
40
41
 
41
42
  class OidcCliPlugin(CliAuthPlugin):
42
43
  """Flower OIDC auth plugin for CLI."""
@@ -48,12 +49,12 @@ class OidcCliPlugin(CliAuthPlugin):
48
49
 
49
50
  @staticmethod
50
51
  def login(
51
- login_details: UserAuthLoginDetails,
52
+ login_details: AccountAuthLoginDetails,
52
53
  control_stub: ControlStub,
53
- ) -> UserAuthCredentials:
54
- """Authenticate the user and retrieve authentication credentials."""
54
+ ) -> AccountAuthCredentials:
55
+ """Authenticate the account and retrieve authentication credentials."""
55
56
  typer.secho(
56
- "Please login with your user credentials here: "
57
+ "Please log into your Flower account here: "
57
58
  f"{login_details.verification_uri_complete}",
58
59
  fg=typer.colors.BLUE,
59
60
  )
@@ -69,26 +70,16 @@ class OidcCliPlugin(CliAuthPlugin):
69
70
  refresh_token = res.refresh_token
70
71
 
71
72
  if access_token and refresh_token:
72
- typer.secho(
73
- "✅ Login successful.",
74
- fg=typer.colors.GREEN,
75
- bold=False,
76
- )
77
- return UserAuthCredentials(
73
+ return AccountAuthCredentials(
78
74
  access_token=access_token,
79
75
  refresh_token=refresh_token,
80
76
  )
81
77
 
82
78
  time.sleep(login_details.interval)
83
79
 
84
- typer.secho(
85
- "❌ Timeout, failed to sign in.",
86
- fg=typer.colors.RED,
87
- bold=True,
88
- )
89
- raise typer.Exit(code=1)
80
+ raise LoginError("Process timed out.")
90
81
 
91
- def store_tokens(self, credentials: UserAuthCredentials) -> None:
82
+ def store_tokens(self, credentials: AccountAuthCredentials) -> None:
92
83
  """Store authentication tokens to the `credentials_path`.
93
84
 
94
85
  The credentials, including tokens, will be saved as a JSON file
@@ -97,7 +88,7 @@ class OidcCliPlugin(CliAuthPlugin):
97
88
  self.access_token = credentials.access_token
98
89
  self.refresh_token = credentials.refresh_token
99
90
  json_dict = {
100
- AUTH_TYPE_JSON_KEY: AuthType.OIDC,
91
+ AUTHN_TYPE_JSON_KEY: AuthnType.OIDC,
101
92
  ACCESS_TOKEN_KEY: credentials.access_token,
102
93
  REFRESH_TOKEN_KEY: credentials.refresh_token,
103
94
  }
@@ -135,14 +126,14 @@ class OidcCliPlugin(CliAuthPlugin):
135
126
 
136
127
  def read_tokens_from_metadata(
137
128
  self, metadata: Sequence[tuple[str, Union[str, bytes]]]
138
- ) -> Optional[UserAuthCredentials]:
129
+ ) -> Optional[AccountAuthCredentials]:
139
130
  """Read authentication tokens from the provided metadata."""
140
131
  metadata_dict = dict(metadata)
141
132
  access_token = metadata_dict.get(ACCESS_TOKEN_KEY)
142
133
  refresh_token = metadata_dict.get(REFRESH_TOKEN_KEY)
143
134
 
144
135
  if isinstance(access_token, str) and isinstance(refresh_token, str):
145
- return UserAuthCredentials(
136
+ return AccountAuthCredentials(
146
137
  access_token=access_token,
147
138
  refresh_token=refresh_token,
148
139
  )
@@ -17,22 +17,25 @@
17
17
 
18
18
  import hashlib
19
19
  import zipfile
20
+ from collections.abc import Iterable
20
21
  from io import BytesIO
21
22
  from pathlib import Path
22
23
  from typing import Annotated, Any, Optional, Union
23
24
 
24
25
  import pathspec
26
+ import tomli
25
27
  import tomli_w
26
28
  import typer
27
29
 
28
30
  from flwr.common.constant import (
29
- FAB_ALLOWED_EXTENSIONS,
31
+ FAB_CONFIG_FILE,
30
32
  FAB_DATE,
33
+ FAB_EXCLUDE_PATTERNS,
31
34
  FAB_HASH_TRUNCATION,
35
+ FAB_INCLUDE_PATTERNS,
32
36
  FAB_MAX_SIZE,
33
37
  )
34
38
 
35
- from .config_utils import load as load_toml
36
39
  from .config_utils import load_and_validate
37
40
  from .utils import is_valid_project_name
38
41
 
@@ -112,7 +115,10 @@ def build(
112
115
  )
113
116
 
114
117
  # Build FAB
115
- fab_bytes, fab_hash, _ = build_fab(app)
118
+ fab_bytes = build_fab_from_disk(app)
119
+
120
+ # Calculate hash for filename
121
+ fab_hash = hashlib.sha256(fab_bytes).hexdigest()
116
122
 
117
123
  # Get the name of the zip file
118
124
  fab_filename = get_fab_filename(config, fab_hash)
@@ -125,11 +131,10 @@ def build(
125
131
  )
126
132
 
127
133
 
128
- def build_fab(app: Path) -> tuple[bytes, str, dict[str, Any]]:
129
- """Build a FAB in memory and return the bytes, hash, and config.
134
+ def build_fab_from_disk(app: Path) -> bytes:
135
+ """Build a FAB from files on disk and return the FAB as bytes.
130
136
 
131
- This function assumes that the provided path points to a valid Flower app and
132
- bundles it into a FAB without performing additional validation.
137
+ This function reads files from disk and bundles them into a FAB.
133
138
 
134
139
  Parameters
135
140
  ----------
@@ -138,18 +143,67 @@ def build_fab(app: Path) -> tuple[bytes, str, dict[str, Any]]:
138
143
 
139
144
  Returns
140
145
  -------
141
- tuple[bytes, str, dict[str, Any]]
142
- A tuple containing:
143
- - the FAB as bytes
144
- - the SHA256 hash of the FAB
145
- - the project configuration (with the 'federations' field removed)
146
+ bytes
147
+ The FAB as bytes.
146
148
  """
147
149
  app = app.resolve()
148
150
 
149
- # Load the pyproject.toml file
150
- config = load_toml(app / "pyproject.toml")
151
- if config is None:
152
- raise ValueError("Project configuration could not be loaded.")
151
+ # Collect all files recursively (including pyproject.toml and .gitignore)
152
+ all_files = [f for f in app.rglob("*") if f.is_file()]
153
+
154
+ # Create dict mapping relative paths to Path objects
155
+ files_dict: dict[str, Union[bytes, Path]] = {
156
+ # Ensure consistent path separators across platforms
157
+ str(file_path.relative_to(app)).replace("\\", "/"): file_path
158
+ for file_path in all_files
159
+ }
160
+
161
+ # Build FAB from the files dict
162
+ return build_fab_from_files(files_dict)
163
+
164
+
165
+ def build_fab_from_files(files: dict[str, Union[bytes, Path]]) -> bytes:
166
+ r"""Build a FAB from in-memory files and return the FAB as bytes.
167
+
168
+ This is the core FAB building function that works with in-memory data.
169
+ It accepts either bytes or Path objects as file contents, applies filtering
170
+ rules (include/exclude patterns), and builds the FAB.
171
+
172
+ Parameters
173
+ ----------
174
+ files : dict[str, Union[bytes, Path]]
175
+ Dictionary mapping relative file paths to their contents.
176
+ - Keys: Relative paths (strings)
177
+ - Values: Either bytes (file contents) or Path (will be read)
178
+ Must include "pyproject.toml" and optionally ".gitignore".
179
+
180
+ Returns
181
+ -------
182
+ bytes
183
+ The FAB as bytes.
184
+
185
+ Examples
186
+ --------
187
+ Build a FAB from in-memory files::
188
+
189
+ files = {
190
+ "pyproject.toml": b"[project]\nname = 'myapp'\n...",
191
+ ".gitignore": b"*.pyc\n__pycache__/\n",
192
+ "src/client.py": Path("/path/to/client.py"),
193
+ "src/server.py": b"print('hello')",
194
+ "README.md": b"# My App\n",
195
+ }
196
+ fab_bytes = build_fab_from_files(files)
197
+ """
198
+
199
+ def to_bytes(content: Union[bytes, Path]) -> bytes:
200
+ return content.read_bytes() if isinstance(content, Path) else content
201
+
202
+ # Extract, load, and parse pyproject.toml
203
+ if FAB_CONFIG_FILE not in files:
204
+ raise ValueError(f"{FAB_CONFIG_FILE} not found in files")
205
+ pyproject_content = to_bytes(files[FAB_CONFIG_FILE])
206
+ config = tomli.loads(pyproject_content.decode("utf-8"))
153
207
 
154
208
  # Remove the 'federations' field if it exists
155
209
  if (
@@ -159,18 +213,22 @@ def build_fab(app: Path) -> tuple[bytes, str, dict[str, Any]]:
159
213
  ):
160
214
  del config["tool"]["flwr"]["federations"]
161
215
 
162
- # Load .gitignore rules if present
163
- ignore_spec = _load_gitignore(app)
216
+ # Extract and load .gitignore if present
217
+ gitignore_content = None
218
+ if ".gitignore" in files:
219
+ gitignore_content = to_bytes(files[".gitignore"])
220
+
221
+ # Get exclude and include specs
222
+ exclude_spec = get_fab_exclude_pathspec(gitignore_content)
223
+ include_spec = get_fab_include_pathspec()
164
224
 
165
- # Search for all files in the app directory
166
- all_files = [
167
- f
168
- for f in app.rglob("*")
169
- if not ignore_spec.match_file(f)
170
- and f.suffix in FAB_ALLOWED_EXTENSIONS
171
- and f.name != "pyproject.toml" # Exclude the original pyproject.toml
225
+ # Filter files based on include/exclude specs
226
+ filtered_paths = [
227
+ path.replace("\\", "/") # Ensure consistent path separators across platforms
228
+ for path in files.keys()
229
+ if include_spec.match_file(path) and not exclude_spec.match_file(path)
172
230
  ]
173
- all_files.sort()
231
+ filtered_paths.sort() # Sort for deterministic output
174
232
 
175
233
  # Create a zip file in memory
176
234
  list_file_content = ""
@@ -178,41 +236,54 @@ def build_fab(app: Path) -> tuple[bytes, str, dict[str, Any]]:
178
236
  fab_buffer = BytesIO()
179
237
  with zipfile.ZipFile(fab_buffer, "w", zipfile.ZIP_DEFLATED) as fab_file:
180
238
  # Add pyproject.toml
181
- write_to_zip(fab_file, "pyproject.toml", tomli_w.dumps(config))
239
+ write_to_zip(fab_file, FAB_CONFIG_FILE, tomli_w.dumps(config))
182
240
 
183
- for file_path in all_files:
184
- # Read the file content manually
185
- file_contents = file_path.read_bytes()
241
+ for file_path in filtered_paths:
186
242
 
187
- archive_path = str(file_path.relative_to(app)).replace("\\", "/")
188
- write_to_zip(fab_file, archive_path, file_contents)
243
+ # Get file contents as bytes
244
+ file_content = to_bytes(files[file_path])
189
245
 
190
- # Calculate file info
191
- sha256_hash = hashlib.sha256(file_contents).hexdigest()
192
- file_size_bits = len(file_contents) * 8 # size in bits
193
- list_file_content += f"{archive_path},{sha256_hash},{file_size_bits}\n"
246
+ # Write file to FAB
247
+ write_to_zip(fab_file, file_path, file_content)
194
248
 
195
- # Add CONTENT and CONTENT.jwt to the zip file
249
+ # Calculate file info for CONTENT manifest
250
+ sha256_hash = hashlib.sha256(file_content).hexdigest()
251
+ file_size_bits = len(file_content) * 8 # size in bits
252
+ list_file_content += f"{file_path},{sha256_hash},{file_size_bits}\n"
253
+
254
+ # Add CONTENT manifest to the zip file
196
255
  write_to_zip(fab_file, ".info/CONTENT", list_file_content)
197
256
 
198
257
  fab_bytes = fab_buffer.getvalue()
258
+
259
+ # Validate FAB size
199
260
  if len(fab_bytes) > FAB_MAX_SIZE:
200
261
  raise ValueError(
201
- f"FAB size exceeds maximum allowed size of {FAB_MAX_SIZE:,} bytes."
262
+ f"FAB size exceeds maximum allowed size of {FAB_MAX_SIZE:,} bytes. "
202
263
  "To reduce the package size, consider ignoring unnecessary files "
203
264
  "via your `.gitignore` file or excluding them from the build."
204
265
  )
205
266
 
206
- fab_hash = hashlib.sha256(fab_bytes).hexdigest()
267
+ return fab_bytes
207
268
 
208
- return fab_bytes, fab_hash, config
209
269
 
270
+ def build_pathspec(patterns: Iterable[str]) -> pathspec.PathSpec:
271
+ """Build a PathSpec from a list of patterns."""
272
+ return pathspec.PathSpec.from_lines("gitwildmatch", patterns)
273
+
274
+
275
+ def get_fab_include_pathspec() -> pathspec.PathSpec:
276
+ """Get the PathSpec for files to include in a FAB."""
277
+ return build_pathspec(FAB_INCLUDE_PATTERNS)
210
278
 
211
- def _load_gitignore(app: Path) -> pathspec.PathSpec:
212
- """Load and parse .gitignore file, returning a pathspec."""
213
- gitignore_path = app / ".gitignore"
214
- patterns = ["__pycache__/"] # Default pattern
215
- if gitignore_path.exists():
216
- with open(gitignore_path, encoding="UTF-8") as file:
217
- patterns.extend(file.readlines())
279
+
280
+ def get_fab_exclude_pathspec(gitignore_content: Optional[bytes]) -> pathspec.PathSpec:
281
+ """Get the PathSpec for files to exclude from a FAB.
282
+
283
+ If gitignore_content is provided, its patterns will be combined with the default
284
+ exclude patterns.
285
+ """
286
+ patterns = list(FAB_EXCLUDE_PATTERNS)
287
+ if gitignore_content:
288
+ patterns += gitignore_content.decode("UTF-8").splitlines()
218
289
  return pathspec.PathSpec.from_lines("gitwildmatch", patterns)
@@ -19,22 +19,23 @@ from typing import Any, Callable, Union
19
19
 
20
20
  import grpc
21
21
 
22
- from flwr.common.auth_plugin import CliAuthPlugin
23
22
  from flwr.proto.control_pb2 import ( # pylint: disable=E0611
24
23
  StartRunRequest,
25
24
  StreamLogsRequest,
26
25
  )
27
26
 
27
+ from .auth_plugin import CliAuthPlugin
28
+
28
29
  Request = Union[
29
30
  StartRunRequest,
30
31
  StreamLogsRequest,
31
32
  ]
32
33
 
33
34
 
34
- class CliUserAuthInterceptor(
35
+ class CliAccountAuthInterceptor(
35
36
  grpc.UnaryUnaryClientInterceptor, grpc.UnaryStreamClientInterceptor # type: ignore
36
37
  ):
37
- """CLI interceptor for user authentication."""
38
+ """CLI interceptor for account authentication."""
38
39
 
39
40
  def __init__(self, auth_plugin: CliAuthPlugin):
40
41
  self.auth_plugin = auth_plugin
@@ -69,7 +70,7 @@ class CliUserAuthInterceptor(
69
70
  client_call_details: grpc.ClientCallDetails,
70
71
  request: Request,
71
72
  ) -> grpc.Call:
72
- """Intercept a unary-unary call for user authentication.
73
+ """Intercept a unary-unary call for account authentication.
73
74
 
74
75
  This method intercepts a unary-unary RPC call initiated from the CLI and adds
75
76
  the required authentication tokens to the RPC metadata.
@@ -82,7 +83,7 @@ class CliUserAuthInterceptor(
82
83
  client_call_details: grpc.ClientCallDetails,
83
84
  request: Request,
84
85
  ) -> grpc.Call:
85
- """Intercept a unary-stream call for user authentication.
86
+ """Intercept a unary-stream call for account authentication.
86
87
 
87
88
  This method intercepts a unary-stream RPC call initiated from the CLI and adds
88
89
  the required authentication tokens to the RPC metadata.
@@ -35,7 +35,7 @@ from flwr.common.logger import log as logger
35
35
  from flwr.proto.control_pb2 import StreamLogsRequest # pylint: disable=E0611
36
36
  from flwr.proto.control_pb2_grpc import ControlStub
37
37
 
38
- from .utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
38
+ from .utils import flwr_cli_grpc_exc_handler, init_channel, load_cli_auth_plugin
39
39
 
40
40
 
41
41
  class AllLogsRetrieved(BaseException):
@@ -186,7 +186,7 @@ def _log_with_control_api(
186
186
  run_id: int,
187
187
  stream: bool,
188
188
  ) -> None:
189
- auth_plugin = try_obtain_cli_auth_plugin(app, federation, federation_config)
189
+ auth_plugin = load_cli_auth_plugin(app, federation, federation_config)
190
190
  channel = init_channel(app, federation_config, auth_plugin)
191
191
 
192
192
  if stream: