flwr 1.13.1__tar.gz → 1.15.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 (350) hide show
  1. {flwr-1.13.1 → flwr-1.15.0}/PKG-INFO +14 -13
  2. {flwr-1.13.1 → flwr-1.15.0}/README.md +6 -6
  3. {flwr-1.13.1 → flwr-1.15.0}/pyproject.toml +26 -22
  4. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/app.py +5 -0
  5. flwr-1.15.0/src/py/flwr/cli/auth_plugin/__init__.py +31 -0
  6. flwr-1.15.0/src/py/flwr/cli/auth_plugin/oidc_cli_plugin.py +150 -0
  7. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/build.py +1 -0
  8. flwr-1.15.0/src/py/flwr/cli/cli_user_auth_interceptor.py +90 -0
  9. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/config_utils.py +43 -149
  10. flwr-1.15.0/src/py/flwr/cli/constant.py +27 -0
  11. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/example.py +1 -0
  12. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/install.py +2 -1
  13. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/log.py +34 -37
  14. flwr-1.15.0/src/py/flwr/cli/login/__init__.py +22 -0
  15. flwr-1.15.0/src/py/flwr/cli/login/login.py +116 -0
  16. flwr-1.15.0/src/py/flwr/cli/ls.py +336 -0
  17. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/__init__.py +1 -0
  18. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/new.py +2 -1
  19. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/.gitignore.tpl +3 -0
  20. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/README.md.tpl +3 -2
  21. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +4 -4
  22. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +4 -4
  23. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +4 -4
  24. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.jax.toml.tpl +2 -2
  25. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +3 -4
  26. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +2 -2
  27. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +4 -4
  28. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +3 -3
  29. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +2 -2
  30. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/run/__init__.py +1 -0
  31. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/run/run.py +103 -43
  32. flwr-1.15.0/src/py/flwr/cli/stop.py +139 -0
  33. flwr-1.15.0/src/py/flwr/cli/utils.py +316 -0
  34. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/app.py +49 -50
  35. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/client.py +1 -32
  36. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/clientapp/app.py +23 -26
  37. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/clientapp/utils.py +2 -1
  38. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_adapter_client/connection.py +1 -1
  39. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_client/connection.py +2 -13
  40. flwr-1.15.0/src/py/flwr/client/grpc_rere_client/client_interceptor.py +70 -0
  41. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_rere_client/connection.py +59 -43
  42. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_rere_client/grpc_adapter.py +12 -12
  43. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/message_handler/message_handler.py +1 -2
  44. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/message_handler/task_handler.py +0 -17
  45. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/comms_mods.py +1 -0
  46. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/localdp_mod.py +1 -1
  47. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/nodestate/__init__.py +1 -0
  48. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/nodestate/nodestate.py +1 -0
  49. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/nodestate/nodestate_factory.py +1 -0
  50. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/numpy_client.py +0 -44
  51. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/rest_client/connection.py +37 -29
  52. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/supernode/app.py +20 -74
  53. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/address.py +1 -0
  54. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/args.py +26 -47
  55. flwr-1.15.0/src/py/flwr/common/auth_plugin/__init__.py +24 -0
  56. flwr-1.15.0/src/py/flwr/common/auth_plugin/auth_plugin.py +122 -0
  57. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/config.py +169 -17
  58. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/constant.py +38 -9
  59. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/differential_privacy.py +2 -1
  60. flwr-1.15.0/src/py/flwr/common/exit/__init__.py +24 -0
  61. flwr-1.15.0/src/py/flwr/common/exit/exit.py +99 -0
  62. flwr-1.15.0/src/py/flwr/common/exit/exit_code.py +93 -0
  63. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/exit_handlers.py +24 -10
  64. flwr-1.13.1/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py → flwr-1.15.0/src/py/flwr/common/grpc.py +62 -120
  65. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/logger.py +66 -7
  66. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/message.py +1 -0
  67. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/object_ref.py +57 -54
  68. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/pyproject.py +1 -0
  69. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/__init__.py +1 -0
  70. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/parametersrecord.py +1 -0
  71. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/recordset.py +1 -1
  72. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/retry_invoker.py +77 -0
  73. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +45 -0
  74. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/secaggplus_utils.py +2 -2
  75. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/serde.py +6 -4
  76. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/telemetry.py +15 -4
  77. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/typing.py +32 -0
  78. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/version.py +1 -0
  79. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/clientappio_pb2.py +1 -1
  80. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/error_pb2.py +1 -1
  81. flwr-1.15.0/src/py/flwr/proto/exec_pb2.py +62 -0
  82. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/exec_pb2.pyi +80 -2
  83. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/exec_pb2_grpc.py +102 -0
  84. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/exec_pb2_grpc.pyi +39 -0
  85. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fab_pb2.py +5 -5
  86. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fab_pb2.pyi +4 -1
  87. flwr-1.15.0/src/py/flwr/proto/fleet_pb2.py +56 -0
  88. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fleet_pb2.pyi +23 -23
  89. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fleet_pb2_grpc.py +30 -30
  90. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fleet_pb2_grpc.pyi +20 -20
  91. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/grpcadapter_pb2.py +1 -1
  92. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/log_pb2.py +1 -1
  93. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/message_pb2.py +1 -1
  94. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/node_pb2.py +3 -3
  95. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/node_pb2.pyi +1 -4
  96. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/recordset_pb2.py +1 -1
  97. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/run_pb2.py +1 -1
  98. flwr-1.15.0/src/py/flwr/proto/serverappio_pb2.py +51 -0
  99. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/serverappio_pb2.pyi +32 -32
  100. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/serverappio_pb2_grpc.py +62 -28
  101. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/serverappio_pb2_grpc.pyi +29 -16
  102. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/simulationio_pb2.py +3 -3
  103. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/simulationio_pb2_grpc.py +34 -0
  104. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/simulationio_pb2_grpc.pyi +13 -0
  105. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/task_pb2.py +1 -1
  106. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/transport_pb2.py +1 -1
  107. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/app.py +152 -112
  108. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/compat/app_utils.py +7 -2
  109. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/compat/driver_client_proxy.py +1 -2
  110. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/driver/grpc_driver.py +38 -85
  111. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/driver/inmemory_driver.py +7 -2
  112. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/run_serverapp.py +8 -9
  113. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/serverapp/app.py +37 -13
  114. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/dpfedavg_fixed.py +1 -0
  115. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/driver/serverappio_grpc.py +2 -1
  116. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/driver/serverappio_servicer.py +148 -63
  117. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/ffs/disk_ffs.py +1 -0
  118. flwr-1.15.0/src/py/flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +94 -0
  119. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -0
  120. flwr-1.15.0/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +126 -0
  121. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +56 -35
  122. flwr-1.15.0/src/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +156 -0
  123. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/message_handler/message_handler.py +69 -29
  124. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +20 -19
  125. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/vce/__init__.py +1 -0
  126. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/vce/backend/__init__.py +1 -0
  127. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +1 -0
  128. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/vce/vce_api.py +2 -2
  129. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/in_memory_linkstate.py +60 -99
  130. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/linkstate.py +30 -36
  131. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/sqlite_linkstate.py +105 -188
  132. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/utils.py +18 -8
  133. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/simulation/simulationio_grpc.py +1 -1
  134. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/simulation/simulationio_servicer.py +33 -0
  135. flwr-1.15.0/src/py/flwr/server/superlink/utils.py +65 -0
  136. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/utils/validator.py +9 -34
  137. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/app.py +20 -10
  138. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/legacy_app.py +4 -2
  139. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/ray_transport/ray_actor.py +1 -0
  140. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/ray_transport/utils.py +1 -0
  141. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/run_simulation.py +36 -22
  142. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/simulationio_connection.py +5 -1
  143. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/app.py +1 -0
  144. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/deployment.py +1 -0
  145. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/exec_grpc.py +20 -2
  146. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/exec_servicer.py +97 -2
  147. flwr-1.15.0/src/py/flwr/superexec/exec_user_auth_interceptor.py +101 -0
  148. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/executor.py +1 -0
  149. flwr-1.13.1/src/py/flwr/cli/ls.py +0 -228
  150. flwr-1.13.1/src/py/flwr/cli/utils.py +0 -138
  151. flwr-1.13.1/src/py/flwr/client/grpc_rere_client/client_interceptor.py +0 -170
  152. flwr-1.13.1/src/py/flwr/common/grpc.py +0 -68
  153. flwr-1.13.1/src/py/flwr/proto/common_pb2.py +0 -36
  154. flwr-1.13.1/src/py/flwr/proto/common_pb2.pyi +0 -121
  155. flwr-1.13.1/src/py/flwr/proto/common_pb2_grpc.py +0 -4
  156. flwr-1.13.1/src/py/flwr/proto/common_pb2_grpc.pyi +0 -4
  157. flwr-1.13.1/src/py/flwr/proto/control_pb2.py +0 -27
  158. flwr-1.13.1/src/py/flwr/proto/control_pb2.pyi +0 -7
  159. flwr-1.13.1/src/py/flwr/proto/control_pb2_grpc.py +0 -135
  160. flwr-1.13.1/src/py/flwr/proto/control_pb2_grpc.pyi +0 -53
  161. flwr-1.13.1/src/py/flwr/proto/exec_pb2.py +0 -50
  162. flwr-1.13.1/src/py/flwr/proto/fleet_pb2.py +0 -56
  163. flwr-1.13.1/src/py/flwr/proto/serverappio_pb2.py +0 -52
  164. flwr-1.13.1/src/py/flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +0 -161
  165. flwr-1.13.1/src/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +0 -226
  166. {flwr-1.13.1 → flwr-1.15.0}/LICENSE +0 -0
  167. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/__init__.py +0 -0
  168. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/__init__.py +0 -0
  169. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/__init__.py +0 -0
  170. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/LICENSE.tpl +0 -0
  171. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/README.baseline.md.tpl +0 -0
  172. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/README.flowertune.md.tpl +0 -0
  173. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/__init__.py +0 -0
  174. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +0 -0
  175. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
  176. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
  177. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.baseline.py.tpl +0 -0
  178. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.huggingface.py.tpl +0 -0
  179. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.jax.py.tpl +0 -0
  180. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.mlx.py.tpl +0 -0
  181. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
  182. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
  183. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -0
  184. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
  185. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +0 -0
  186. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/__init__.py +0 -0
  187. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +0 -0
  188. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +0 -0
  189. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +0 -0
  190. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +0 -0
  191. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +0 -0
  192. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/model.baseline.py.tpl +0 -0
  193. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.baseline.py.tpl +0 -0
  194. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.huggingface.py.tpl +0 -0
  195. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.jax.py.tpl +0 -0
  196. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.mlx.py.tpl +0 -0
  197. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
  198. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
  199. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -0
  200. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
  201. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +0 -0
  202. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.huggingface.py.tpl +0 -0
  203. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.jax.py.tpl +0 -0
  204. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.mlx.py.tpl +0 -0
  205. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.numpy.py.tpl +0 -0
  206. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
  207. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.sklearn.py.tpl +0 -0
  208. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +0 -0
  209. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/utils.baseline.py.tpl +0 -0
  210. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/__init__.py +0 -0
  211. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/client_app.py +0 -0
  212. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/clientapp/__init__.py +0 -0
  213. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/clientapp/clientappio_servicer.py +0 -0
  214. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/dpfedavg_numpy_client.py +0 -0
  215. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_adapter_client/__init__.py +0 -0
  216. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_client/__init__.py +0 -0
  217. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_rere_client/__init__.py +0 -0
  218. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/heartbeat.py +0 -0
  219. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/message_handler/__init__.py +0 -0
  220. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/__init__.py +0 -0
  221. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/centraldp_mods.py +0 -0
  222. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
  223. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
  224. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
  225. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/utils.py +0 -0
  226. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/nodestate/in_memory_nodestate.py +0 -0
  227. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/rest_client/__init__.py +0 -0
  228. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/run_info_store.py +0 -0
  229. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/supernode/__init__.py +0 -0
  230. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/typing.py +0 -0
  231. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/__init__.py +0 -0
  232. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/context.py +0 -0
  233. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/date.py +0 -0
  234. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/differential_privacy_constants.py +0 -0
  235. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/dp.py +0 -0
  236. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/parameter.py +0 -0
  237. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/configsrecord.py +0 -0
  238. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/conversion_utils.py +0 -0
  239. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/metricsrecord.py +0 -0
  240. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/typeddict.py +0 -0
  241. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/recordset_compat.py +0 -0
  242. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/__init__.py +0 -0
  243. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
  244. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
  245. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
  246. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/quantization.py +0 -0
  247. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
  248. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/__init__.py +0 -0
  249. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/clientappio_pb2.pyi +0 -0
  250. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/clientappio_pb2_grpc.py +0 -0
  251. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/clientappio_pb2_grpc.pyi +0 -0
  252. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/error_pb2.pyi +0 -0
  253. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/error_pb2_grpc.py +0 -0
  254. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/error_pb2_grpc.pyi +0 -0
  255. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fab_pb2_grpc.py +0 -0
  256. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fab_pb2_grpc.pyi +0 -0
  257. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/grpcadapter_pb2.pyi +0 -0
  258. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/grpcadapter_pb2_grpc.py +0 -0
  259. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/grpcadapter_pb2_grpc.pyi +0 -0
  260. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/log_pb2.pyi +0 -0
  261. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/log_pb2_grpc.py +0 -0
  262. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/log_pb2_grpc.pyi +0 -0
  263. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/message_pb2.pyi +0 -0
  264. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/message_pb2_grpc.py +0 -0
  265. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/message_pb2_grpc.pyi +0 -0
  266. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/node_pb2_grpc.py +0 -0
  267. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/node_pb2_grpc.pyi +0 -0
  268. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/recordset_pb2.pyi +0 -0
  269. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/recordset_pb2_grpc.py +0 -0
  270. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/recordset_pb2_grpc.pyi +0 -0
  271. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/run_pb2.pyi +0 -0
  272. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/run_pb2_grpc.py +0 -0
  273. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/run_pb2_grpc.pyi +0 -0
  274. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/simulationio_pb2.pyi +0 -0
  275. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/task_pb2.pyi +0 -0
  276. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/task_pb2_grpc.py +0 -0
  277. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/task_pb2_grpc.pyi +0 -0
  278. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/transport_pb2.pyi +0 -0
  279. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/transport_pb2_grpc.py +0 -0
  280. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
  281. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/py.typed +0 -0
  282. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/__init__.py +0 -0
  283. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/client_manager.py +0 -0
  284. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/client_proxy.py +0 -0
  285. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/compat/__init__.py +0 -0
  286. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/compat/app.py +0 -0
  287. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/compat/legacy_context.py +0 -0
  288. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/criterion.py +0 -0
  289. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/driver/__init__.py +0 -0
  290. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/driver/driver.py +0 -0
  291. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/history.py +0 -0
  292. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/server.py +0 -0
  293. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/server_app.py +0 -0
  294. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/server_config.py +0 -0
  295. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/serverapp/__init__.py +0 -0
  296. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/serverapp_components.py +0 -0
  297. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/__init__.py +0 -0
  298. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/aggregate.py +0 -0
  299. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/bulyan.py +0 -0
  300. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
  301. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
  302. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
  303. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
  304. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedadagrad.py +0 -0
  305. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedadam.py +0 -0
  306. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedavg.py +0 -0
  307. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedavg_android.py +0 -0
  308. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedavgm.py +0 -0
  309. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedmedian.py +0 -0
  310. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedopt.py +0 -0
  311. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedprox.py +0 -0
  312. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
  313. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
  314. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
  315. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
  316. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedyogi.py +0 -0
  317. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/krum.py +0 -0
  318. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/qfedavg.py +0 -0
  319. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/strategy.py +0 -0
  320. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/__init__.py +0 -0
  321. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/driver/__init__.py +0 -0
  322. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/ffs/__init__.py +0 -0
  323. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/ffs/ffs.py +0 -0
  324. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/ffs/ffs_factory.py +0 -0
  325. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/__init__.py +0 -0
  326. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_adapter/__init__.py +0 -0
  327. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
  328. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
  329. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
  330. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
  331. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
  332. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
  333. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
  334. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/__init__.py +0 -0
  335. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/linkstate_factory.py +0 -0
  336. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/simulation/__init__.py +0 -0
  337. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/typing.py +0 -0
  338. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/utils/__init__.py +0 -0
  339. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/utils/tensorboard.py +0 -0
  340. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/__init__.py +0 -0
  341. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/constant.py +0 -0
  342. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/default_workflows.py +0 -0
  343. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
  344. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
  345. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +0 -0
  346. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/__init__.py +0 -0
  347. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/ray_transport/__init__.py +0 -0
  348. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
  349. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/__init__.py +0 -0
  350. {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/simulation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr
3
- Version: 1.13.1
3
+ Version: 1.15.0
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -32,21 +32,22 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
32
32
  Classifier: Typing :: Typed
33
33
  Provides-Extra: rest
34
34
  Provides-Extra: simulation
35
- Requires-Dist: cryptography (>=42.0.4,<43.0.0)
36
- Requires-Dist: grpcio (>=1.60.0,<2.0.0,!=1.64.2,<=1.64.3)
35
+ Requires-Dist: cryptography (>=43.0.1,<44.0.0)
36
+ Requires-Dist: grpcio (>=1.62.3,<2.0.0,!=1.65.0)
37
37
  Requires-Dist: iterators (>=0.0.2,<0.0.3)
38
38
  Requires-Dist: numpy (>=1.26.0,<3.0.0)
39
39
  Requires-Dist: pathspec (>=0.12.1,<0.13.0)
40
- Requires-Dist: protobuf (>=4.25.2,<5.0.0)
40
+ Requires-Dist: protobuf (>=4.21.6,<5.0.0)
41
41
  Requires-Dist: pycryptodome (>=3.18.0,<4.0.0)
42
+ Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
42
43
  Requires-Dist: ray (==2.10.0) ; (python_version >= "3.9" and python_version < "3.12") and (extra == "simulation")
43
- Requires-Dist: requests (>=2.31.0,<3.0.0) ; extra == "rest"
44
+ Requires-Dist: requests (>=2.31.0,<3.0.0)
44
45
  Requires-Dist: rich (>=13.5.0,<14.0.0)
45
- Requires-Dist: starlette (>=0.31.0,<0.32.0) ; extra == "rest"
46
+ Requires-Dist: starlette (>=0.45.2,<0.46.0) ; extra == "rest"
46
47
  Requires-Dist: tomli (>=2.0.1,<3.0.0)
47
48
  Requires-Dist: tomli-w (>=1.0.0,<2.0.0)
48
49
  Requires-Dist: typer (>=0.12.5,<0.13.0)
49
- Requires-Dist: uvicorn[standard] (>=0.23.0,<0.24.0) ; extra == "rest"
50
+ Requires-Dist: uvicorn[standard] (>=0.34.0,<0.35.0) ; extra == "rest"
50
51
  Project-URL: Documentation, https://flower.ai
51
52
  Project-URL: Repository, https://github.com/adap/flower
52
53
  Description-Content-Type: text/markdown
@@ -87,7 +88,7 @@ design of Flower is based on a few guiding principles:
87
88
 
88
89
  - **Framework-agnostic**: Different machine learning frameworks have different
89
90
  strengths. Flower can be used with any machine learning framework, for
90
- example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
91
+ example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [LeRobot](https://github.com/huggingface/lerobot) for federated robots, [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
91
92
  for users who enjoy computing gradients by hand.
92
93
 
93
94
  - **Understandable**: Flower is written with maintainability in mind. The
@@ -101,23 +102,23 @@ Flower's goal is to make federated learning accessible to everyone. This series
101
102
 
102
103
  0. **What is Federated Learning?**
103
104
 
104
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-what-is-federated-learning.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-what-is-federated-learning.ipynb))
105
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-what-is-federated-learning.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-what-is-federated-learning.ipynb))
105
106
 
106
107
  1. **An Introduction to Federated Learning**
107
108
 
108
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-get-started-with-flower-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-get-started-with-flower-pytorch.ipynb))
109
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-get-started-with-flower-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-get-started-with-flower-pytorch.ipynb))
109
110
 
110
111
  2. **Using Strategies in Federated Learning**
111
112
 
112
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb))
113
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb))
113
114
 
114
115
  3. **Building Strategies for Federated Learning**
115
116
 
116
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb))
117
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb))
117
118
 
118
119
  4. **Custom Clients for Federated Learning**
119
120
 
120
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-customize-the-client-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-customize-the-client-pytorch.ipynb))
121
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-customize-the-client-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-customize-the-client-pytorch.ipynb))
121
122
 
122
123
  Stay tuned, more tutorials are coming soon. Topics include **Privacy and Security in Federated Learning**, and **Scaling Federated Learning**.
123
124
 
@@ -34,7 +34,7 @@ design of Flower is based on a few guiding principles:
34
34
 
35
35
  - **Framework-agnostic**: Different machine learning frameworks have different
36
36
  strengths. Flower can be used with any machine learning framework, for
37
- example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
37
+ example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [LeRobot](https://github.com/huggingface/lerobot) for federated robots, [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
38
38
  for users who enjoy computing gradients by hand.
39
39
 
40
40
  - **Understandable**: Flower is written with maintainability in mind. The
@@ -48,23 +48,23 @@ Flower's goal is to make federated learning accessible to everyone. This series
48
48
 
49
49
  0. **What is Federated Learning?**
50
50
 
51
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-what-is-federated-learning.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-what-is-federated-learning.ipynb))
51
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-what-is-federated-learning.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-what-is-federated-learning.ipynb))
52
52
 
53
53
  1. **An Introduction to Federated Learning**
54
54
 
55
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-get-started-with-flower-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-get-started-with-flower-pytorch.ipynb))
55
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-get-started-with-flower-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-get-started-with-flower-pytorch.ipynb))
56
56
 
57
57
  2. **Using Strategies in Federated Learning**
58
58
 
59
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb))
59
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb))
60
60
 
61
61
  3. **Building Strategies for Federated Learning**
62
62
 
63
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb))
63
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb))
64
64
 
65
65
  4. **Custom Clients for Federated Learning**
66
66
 
67
- [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/doc/source/tutorial-series-customize-the-client-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/doc/source/tutorial-series-customize-the-client-pytorch.ipynb))
67
+ [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-customize-the-client-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-customize-the-client-pytorch.ipynb))
68
68
 
69
69
  Stay tuned, more tutorials are coming soon. Topics include **Privacy and Security in Federated Learning**, and **Scaling Federated Learning**.
70
70
 
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "flwr"
7
- version = "1.13.1"
7
+ version = "1.15.0"
8
8
  description = "Flower: A Friendly Federated AI Framework"
9
9
  license = "Apache-2.0"
10
10
  authors = ["The Flower Authors <hello@flower.ai>"]
@@ -68,9 +68,9 @@ flower-client-app = "flwr.client.supernode:run_client_app" # Deprecated
68
68
  python = "^3.9"
69
69
  # Mandatory dependencies
70
70
  numpy = ">=1.26.0,<3.0.0"
71
- grpcio = "^1.60.0,!=1.64.2,<=1.64.3"
72
- protobuf = "^4.25.2"
73
- cryptography = "^42.0.4"
71
+ grpcio = "^1.62.3,!=1.65.0"
72
+ protobuf = "^4.21.6"
73
+ cryptography = "^43.0.1"
74
74
  pycryptodome = "^3.18.0"
75
75
  iterators = "^0.0.2"
76
76
  typer = "^0.12.5"
@@ -78,20 +78,21 @@ tomli = "^2.0.1"
78
78
  tomli-w = "^1.0.0"
79
79
  pathspec = "^0.12.1"
80
80
  rich = "^13.5.0"
81
+ pyyaml = "^6.0.2"
82
+ requests = "^2.31.0"
81
83
  # Optional dependencies (Simulation Engine)
82
84
  ray = { version = "==2.10.0", optional = true, python = ">=3.9,<3.12" }
83
85
  # Optional dependencies (REST transport layer)
84
- requests = { version = "^2.31.0", optional = true }
85
- starlette = { version = "^0.31.0", optional = true }
86
- uvicorn = { version = "^0.23.0", extras = ["standard"], optional = true }
86
+ starlette = { version = "^0.45.2", optional = true }
87
+ uvicorn = { version = "^0.34.0", extras = ["standard"], optional = true }
87
88
 
88
89
  [tool.poetry.extras]
89
90
  simulation = ["ray"]
90
- rest = ["requests", "starlette", "uvicorn"]
91
+ rest = ["starlette", "uvicorn"]
91
92
 
92
93
  [tool.poetry.group.dev.dependencies]
93
94
  types-dataclasses = "==0.6.6"
94
- types-protobuf = "==3.19.18"
95
+ types-protobuf = "==4.21.0.7"
95
96
  types-requests = "==2.31.0.20240125"
96
97
  types-setuptools = "==69.0.0.20240125"
97
98
  clang-format = "==17.0.6"
@@ -105,11 +106,11 @@ flake8 = "==5.0.4"
105
106
  parameterized = "==0.9.0"
106
107
  pytest = "==7.4.4"
107
108
  pytest-cov = "==4.1.0"
108
- pytest-watcher = "==0.4.1"
109
- grpcio-tools = "==1.60.0"
109
+ pytest-watcher = "==0.4.3"
110
+ grpcio-tools = "==1.62.3"
110
111
  mypy-protobuf = "==3.2.0"
111
112
  jupyterlab = "==4.0.12"
112
- rope = "==1.11.0"
113
+ rope = "==1.13.0"
113
114
  semver = "==3.0.2"
114
115
  sphinx = "==7.4.7"
115
116
  sphinx-intl = "==2.2.0"
@@ -123,7 +124,7 @@ furo = "==2024.8.6"
123
124
  sphinx-reredirects = "==0.1.5"
124
125
  nbsphinx = "==0.9.5"
125
126
  nbstripout = "==0.6.1"
126
- ruff = "==0.1.9"
127
+ ruff = "==0.4.5"
127
128
  sphinx-argparse = "==0.4.0"
128
129
  pipreqs = "==0.4.13"
129
130
  mdformat = "==0.7.18"
@@ -131,6 +132,7 @@ mdformat-gfm = "==0.3.6"
131
132
  mdformat-frontmatter = "==2.0.1"
132
133
  mdformat-beautysh = "==0.1.1"
133
134
  twine = "==5.1.1"
135
+ types-PyYAML = "^6.0.2"
134
136
  pyroma = "==4.2"
135
137
  check-wheel-contents = "==0.4.0"
136
138
  GitPython = "==3.1.32"
@@ -144,10 +146,10 @@ docsig = "==0.64.0"
144
146
 
145
147
  [tool.docstrfmt]
146
148
  extend_exclude = [
147
- "doc/source/conf.py",
148
- "doc/source/tutorial-quickstart-huggingface.rst",
149
- "doc/source/_templates/autosummary/*",
150
- "doc/source/ref-api/*",
149
+ "framework/docs/source/conf.py",
150
+ "framework/docs/source/tutorial-quickstart-huggingface.rst",
151
+ "framework/docs/source/_templates/autosummary/*",
152
+ "framework/docs/source/ref-api/*",
151
153
  ]
152
154
 
153
155
  [tool.isort]
@@ -199,9 +201,6 @@ wrap-descriptions = 88
199
201
  [tool.ruff]
200
202
  target-version = "py39"
201
203
  line-length = 88
202
- select = ["D", "E", "F", "W", "B", "ISC", "C4", "UP"]
203
- fixable = ["D", "E", "F", "W", "B", "ISC", "C4", "UP"]
204
- ignore = ["B024", "B027", "D205", "D209"]
205
204
  exclude = [
206
205
  ".bzr",
207
206
  ".direnv",
@@ -226,10 +225,15 @@ exclude = [
226
225
  "proto",
227
226
  ]
228
227
 
229
- [tool.ruff.pydocstyle]
228
+ [tool.ruff.lint]
229
+ select = ["D", "E", "F", "W", "B", "ISC", "C4", "UP"]
230
+ fixable = ["D", "E", "F", "W", "B", "ISC", "C4", "UP"]
231
+ ignore = ["B024", "B027", "D205", "D209"]
232
+
233
+ [tool.ruff.lint.pydocstyle]
230
234
  convention = "numpy"
231
235
 
232
- [tool.ruff.per-file-ignores]
236
+ [tool.ruff.lint.per-file-ignores]
233
237
  "src/py/flwr/server/strategy/*.py" = ["E501"]
234
238
 
235
239
  [tool.docsig]
@@ -14,15 +14,18 @@
14
14
  # ==============================================================================
15
15
  """Flower command line interface."""
16
16
 
17
+
17
18
  import typer
18
19
  from typer.main import get_command
19
20
 
20
21
  from .build import build
21
22
  from .install import install
22
23
  from .log import log
24
+ from .login import login
23
25
  from .ls import ls
24
26
  from .new import new
25
27
  from .run import run
28
+ from .stop import stop
26
29
 
27
30
  app = typer.Typer(
28
31
  help=typer.style(
@@ -39,6 +42,8 @@ app.command()(build)
39
42
  app.command()(install)
40
43
  app.command()(log)
41
44
  app.command()(ls)
45
+ app.command()(stop)
46
+ app.command()(login)
42
47
 
43
48
  typer_click_object = get_command(app)
44
49
 
@@ -0,0 +1,31 @@
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 user auth plugins."""
16
+
17
+
18
+ from flwr.common.auth_plugin import CliAuthPlugin
19
+ from flwr.common.constant import AuthType
20
+
21
+ from .oidc_cli_plugin import OidcCliPlugin
22
+
23
+
24
+ def get_cli_auth_plugins() -> dict[str, type[CliAuthPlugin]]:
25
+ """Return all CLI authentication plugins."""
26
+ return {AuthType.OIDC: OidcCliPlugin}
27
+
28
+
29
+ __all__ = [
30
+ "get_cli_auth_plugins",
31
+ ]
@@ -0,0 +1,150 @@
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 CLI user auth plugin for OIDC."""
16
+
17
+
18
+ import json
19
+ import time
20
+ from collections.abc import Sequence
21
+ from pathlib import Path
22
+ from typing import Any, Optional, Union
23
+
24
+ import typer
25
+
26
+ from flwr.common.auth_plugin import CliAuthPlugin
27
+ from flwr.common.constant import (
28
+ ACCESS_TOKEN_KEY,
29
+ AUTH_TYPE_KEY,
30
+ REFRESH_TOKEN_KEY,
31
+ AuthType,
32
+ )
33
+ from flwr.common.typing import UserAuthCredentials, UserAuthLoginDetails
34
+ from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
35
+ GetAuthTokensRequest,
36
+ GetAuthTokensResponse,
37
+ )
38
+ from flwr.proto.exec_pb2_grpc import ExecStub
39
+
40
+
41
+ class OidcCliPlugin(CliAuthPlugin):
42
+ """Flower OIDC auth plugin for CLI."""
43
+
44
+ def __init__(self, credentials_path: Path):
45
+ self.access_token: Optional[str] = None
46
+ self.refresh_token: Optional[str] = None
47
+ self.credentials_path = credentials_path
48
+
49
+ @staticmethod
50
+ def login(
51
+ login_details: UserAuthLoginDetails,
52
+ exec_stub: ExecStub,
53
+ ) -> UserAuthCredentials:
54
+ """Authenticate the user and retrieve authentication credentials."""
55
+ typer.secho(
56
+ "Please login with your user credentials here: "
57
+ f"{login_details.verification_uri_complete}",
58
+ fg=typer.colors.BLUE,
59
+ )
60
+ start_time = time.time()
61
+ time.sleep(login_details.interval)
62
+
63
+ while (time.time() - start_time) < login_details.expires_in:
64
+ res: GetAuthTokensResponse = exec_stub.GetAuthTokens(
65
+ GetAuthTokensRequest(device_code=login_details.device_code)
66
+ )
67
+
68
+ access_token = res.access_token
69
+ refresh_token = res.refresh_token
70
+
71
+ if access_token and refresh_token:
72
+ typer.secho(
73
+ "✅ Login successful.",
74
+ fg=typer.colors.GREEN,
75
+ bold=False,
76
+ )
77
+ return UserAuthCredentials(
78
+ access_token=access_token,
79
+ refresh_token=refresh_token,
80
+ )
81
+
82
+ time.sleep(login_details.interval)
83
+
84
+ typer.secho(
85
+ "❌ Timeout, failed to sign in.",
86
+ fg=typer.colors.RED,
87
+ bold=True,
88
+ )
89
+ raise typer.Exit(code=1)
90
+
91
+ def store_tokens(self, credentials: UserAuthCredentials) -> None:
92
+ """Store authentication tokens to the `credentials_path`.
93
+
94
+ The credentials, including tokens, will be saved as a JSON file
95
+ at `credentials_path`.
96
+ """
97
+ self.access_token = credentials.access_token
98
+ self.refresh_token = credentials.refresh_token
99
+ json_dict = {
100
+ AUTH_TYPE_KEY: AuthType.OIDC,
101
+ ACCESS_TOKEN_KEY: credentials.access_token,
102
+ REFRESH_TOKEN_KEY: credentials.refresh_token,
103
+ }
104
+
105
+ with open(self.credentials_path, "w", encoding="utf-8") as file:
106
+ json.dump(json_dict, file, indent=4)
107
+
108
+ def load_tokens(self) -> None:
109
+ """Load authentication tokens from the `credentials_path`."""
110
+ with open(self.credentials_path, encoding="utf-8") as file:
111
+ json_dict: dict[str, Any] = json.load(file)
112
+ access_token = json_dict.get(ACCESS_TOKEN_KEY)
113
+ refresh_token = json_dict.get(REFRESH_TOKEN_KEY)
114
+
115
+ if isinstance(access_token, str) and isinstance(refresh_token, str):
116
+ self.access_token = access_token
117
+ self.refresh_token = refresh_token
118
+
119
+ def write_tokens_to_metadata(
120
+ self, metadata: Sequence[tuple[str, Union[str, bytes]]]
121
+ ) -> Sequence[tuple[str, Union[str, bytes]]]:
122
+ """Write authentication tokens to the provided metadata."""
123
+ if self.access_token is None or self.refresh_token is None:
124
+ typer.secho(
125
+ "❌ Missing authentication tokens. Please login first.",
126
+ fg=typer.colors.RED,
127
+ bold=True,
128
+ )
129
+ raise typer.Exit(code=1)
130
+
131
+ return list(metadata) + [
132
+ (ACCESS_TOKEN_KEY, self.access_token),
133
+ (REFRESH_TOKEN_KEY, self.refresh_token),
134
+ ]
135
+
136
+ def read_tokens_from_metadata(
137
+ self, metadata: Sequence[tuple[str, Union[str, bytes]]]
138
+ ) -> Optional[UserAuthCredentials]:
139
+ """Read authentication tokens from the provided metadata."""
140
+ metadata_dict = dict(metadata)
141
+ access_token = metadata_dict.get(ACCESS_TOKEN_KEY)
142
+ refresh_token = metadata_dict.get(REFRESH_TOKEN_KEY)
143
+
144
+ if isinstance(access_token, str) and isinstance(refresh_token, str):
145
+ return UserAuthCredentials(
146
+ access_token=access_token,
147
+ refresh_token=refresh_token,
148
+ )
149
+
150
+ return None
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """Flower command line interface `build` command."""
16
16
 
17
+
17
18
  import hashlib
18
19
  import os
19
20
  import shutil
@@ -0,0 +1,90 @@
1
+ # Copyright 2024 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 run interceptor."""
16
+
17
+
18
+ from typing import Any, Callable, Union
19
+
20
+ import grpc
21
+
22
+ from flwr.common.auth_plugin import CliAuthPlugin
23
+ from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
24
+ StartRunRequest,
25
+ StreamLogsRequest,
26
+ )
27
+
28
+ Request = Union[
29
+ StartRunRequest,
30
+ StreamLogsRequest,
31
+ ]
32
+
33
+
34
+ class CliUserAuthInterceptor(
35
+ grpc.UnaryUnaryClientInterceptor, grpc.UnaryStreamClientInterceptor # type: ignore
36
+ ):
37
+ """CLI interceptor for user authentication."""
38
+
39
+ def __init__(self, auth_plugin: CliAuthPlugin):
40
+ self.auth_plugin = auth_plugin
41
+
42
+ def _authenticated_call(
43
+ self,
44
+ continuation: Callable[[Any, Any], Any],
45
+ client_call_details: grpc.ClientCallDetails,
46
+ request: Request,
47
+ ) -> grpc.Call:
48
+ """Send and receive tokens via metadata."""
49
+ new_metadata = self.auth_plugin.write_tokens_to_metadata(
50
+ client_call_details.metadata or []
51
+ )
52
+
53
+ details = client_call_details._replace(metadata=new_metadata)
54
+
55
+ response = continuation(details, request)
56
+ if response.initial_metadata():
57
+ credentials = self.auth_plugin.read_tokens_from_metadata(
58
+ response.initial_metadata()
59
+ )
60
+ # The metadata contains tokens only if they have been refreshed
61
+ if credentials is not None:
62
+ self.auth_plugin.store_tokens(credentials)
63
+
64
+ return response
65
+
66
+ def intercept_unary_unary(
67
+ self,
68
+ continuation: Callable[[Any, Any], Any],
69
+ client_call_details: grpc.ClientCallDetails,
70
+ request: Request,
71
+ ) -> grpc.Call:
72
+ """Intercept a unary-unary call for user authentication.
73
+
74
+ This method intercepts a unary-unary RPC call initiated from the CLI and adds
75
+ the required authentication tokens to the RPC metadata.
76
+ """
77
+ return self._authenticated_call(continuation, client_call_details, request)
78
+
79
+ def intercept_unary_stream(
80
+ self,
81
+ continuation: Callable[[Any, Any], Any],
82
+ client_call_details: grpc.ClientCallDetails,
83
+ request: Request,
84
+ ) -> grpc.Call:
85
+ """Intercept a unary-stream call for user authentication.
86
+
87
+ This method intercepts a unary-stream RPC call initiated from the CLI and adds
88
+ the required authentication tokens to the RPC metadata.
89
+ """
90
+ return self._authenticated_call(continuation, client_call_details, request)