flwr 1.18.0__tar.gz → 1.20.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 (398) hide show
  1. {flwr-1.18.0 → flwr-1.20.0}/PKG-INFO +6 -4
  2. flwr-1.20.0/py/flwr/app/__init__.py +15 -0
  3. flwr-1.20.0/py/flwr/app/error.py +68 -0
  4. flwr-1.20.0/py/flwr/app/metadata.py +223 -0
  5. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/build.py +94 -59
  6. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/log.py +3 -3
  7. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/login/login.py +3 -7
  8. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/ls.py +15 -36
  9. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/new.py +12 -4
  10. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/README.flowertune.md.tpl +2 -0
  11. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/README.md.tpl +5 -0
  12. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/model.baseline.py.tpl +1 -1
  13. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/server.baseline.py.tpl +2 -3
  14. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +25 -17
  15. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +13 -1
  16. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +21 -2
  17. flwr-1.20.0/py/flwr/cli/new/templates/app/pyproject.jax.toml.tpl +52 -0
  18. flwr-1.20.0/py/flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +56 -0
  19. flwr-1.20.0/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +49 -0
  20. flwr-1.20.0/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +53 -0
  21. flwr-1.20.0/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +52 -0
  22. flwr-1.20.0/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +53 -0
  23. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/run/run.py +48 -49
  24. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/stop.py +2 -2
  25. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/utils.py +38 -5
  26. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/__init__.py +2 -2
  27. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/client_app.py +1 -1
  28. flwr-1.20.0/py/flwr/client/clientapp/__init__.py +15 -0
  29. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/grpc_adapter_client/connection.py +15 -8
  30. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/grpc_rere_client/connection.py +142 -97
  31. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/grpc_rere_client/grpc_adapter.py +34 -6
  32. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/message_handler/message_handler.py +1 -1
  33. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/mod/comms_mods.py +36 -17
  34. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/rest_client/connection.py +176 -103
  35. flwr-1.20.0/py/flwr/clientapp/__init__.py +15 -0
  36. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/__init__.py +2 -2
  37. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/auth_plugin/__init__.py +2 -0
  38. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/auth_plugin/auth_plugin.py +29 -3
  39. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/constant.py +39 -8
  40. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/event_log_plugin/event_log_plugin.py +3 -3
  41. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/exit/exit_code.py +16 -1
  42. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/exit_handlers.py +30 -0
  43. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/grpc.py +12 -1
  44. flwr-1.20.0/py/flwr/common/heartbeat.py +165 -0
  45. flwr-1.20.0/py/flwr/common/inflatable.py +290 -0
  46. flwr-1.20.0/py/flwr/common/inflatable_protobuf_utils.py +141 -0
  47. flwr-1.20.0/py/flwr/common/inflatable_utils.py +508 -0
  48. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/message.py +110 -242
  49. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/record/__init__.py +2 -1
  50. flwr-1.20.0/py/flwr/common/record/array.py +402 -0
  51. flwr-1.20.0/py/flwr/common/record/arraychunk.py +59 -0
  52. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/record/arrayrecord.py +103 -225
  53. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/record/configrecord.py +59 -4
  54. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/record/conversion_utils.py +1 -1
  55. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/record/metricrecord.py +55 -4
  56. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/record/recorddict.py +69 -1
  57. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/recorddict_compat.py +2 -2
  58. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/retry_invoker.py +5 -1
  59. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/serde.py +59 -211
  60. flwr-1.20.0/py/flwr/common/serde_utils.py +175 -0
  61. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/typing.py +5 -3
  62. flwr-1.20.0/py/flwr/compat/__init__.py +15 -0
  63. flwr-1.20.0/py/flwr/compat/client/__init__.py +15 -0
  64. {flwr-1.18.0/py/flwr → flwr-1.20.0/py/flwr/compat}/client/app.py +28 -185
  65. flwr-1.20.0/py/flwr/compat/common/__init__.py +15 -0
  66. flwr-1.20.0/py/flwr/compat/server/__init__.py +15 -0
  67. flwr-1.20.0/py/flwr/compat/server/app.py +174 -0
  68. flwr-1.20.0/py/flwr/compat/simulation/__init__.py +15 -0
  69. flwr-1.20.0/py/flwr/proto/appio_pb2.py +43 -0
  70. flwr-1.18.0/py/flwr/proto/serverappio_pb2.pyi → flwr-1.20.0/py/flwr/proto/appio_pb2.pyi +53 -49
  71. flwr-1.20.0/py/flwr/proto/clientappio_pb2.py +38 -0
  72. flwr-1.20.0/py/flwr/proto/clientappio_pb2.pyi +54 -0
  73. flwr-1.20.0/py/flwr/proto/clientappio_pb2_grpc.py +376 -0
  74. flwr-1.20.0/py/flwr/proto/clientappio_pb2_grpc.pyi +147 -0
  75. flwr-1.20.0/py/flwr/proto/fleet_pb2.py +53 -0
  76. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/fleet_pb2.pyi +19 -35
  77. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/fleet_pb2_grpc.py +117 -13
  78. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/fleet_pb2_grpc.pyi +47 -6
  79. flwr-1.20.0/py/flwr/proto/heartbeat_pb2.py +33 -0
  80. flwr-1.20.0/py/flwr/proto/heartbeat_pb2.pyi +66 -0
  81. flwr-1.20.0/py/flwr/proto/message_pb2.py +58 -0
  82. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/message_pb2.pyi +125 -0
  83. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/recorddict_pb2.py +16 -28
  84. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/recorddict_pb2.pyi +46 -64
  85. flwr-1.20.0/py/flwr/proto/recorddict_pb2_grpc.py +4 -0
  86. flwr-1.20.0/py/flwr/proto/recorddict_pb2_grpc.pyi +4 -0
  87. flwr-1.20.0/py/flwr/proto/run_pb2.py +56 -0
  88. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/run_pb2.pyi +4 -52
  89. flwr-1.20.0/py/flwr/proto/run_pb2_grpc.py +4 -0
  90. flwr-1.20.0/py/flwr/proto/run_pb2_grpc.pyi +4 -0
  91. flwr-1.20.0/py/flwr/proto/serverappio_pb2.py +37 -0
  92. flwr-1.20.0/py/flwr/proto/serverappio_pb2.pyi +37 -0
  93. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/serverappio_pb2_grpc.py +177 -72
  94. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/serverappio_pb2_grpc.pyi +75 -33
  95. flwr-1.20.0/py/flwr/proto/simulationio_pb2.py +39 -0
  96. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/simulationio_pb2_grpc.py +35 -0
  97. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/simulationio_pb2_grpc.pyi +14 -0
  98. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/__init__.py +1 -1
  99. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/app.py +69 -187
  100. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/compat/app_utils.py +50 -28
  101. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/fleet_event_log_interceptor.py +6 -2
  102. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/grid/grpc_grid.py +148 -41
  103. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/grid/inmemory_grid.py +5 -4
  104. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/serverapp/app.py +45 -17
  105. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +21 -3
  106. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +102 -8
  107. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +2 -5
  108. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/message_handler/message_handler.py +130 -19
  109. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +73 -13
  110. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/vce/vce_api.py +6 -3
  111. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/linkstate/in_memory_linkstate.py +138 -43
  112. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/linkstate/linkstate.py +53 -20
  113. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/linkstate/sqlite_linkstate.py +149 -55
  114. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/linkstate/utils.py +33 -29
  115. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/serverappio/serverappio_grpc.py +4 -1
  116. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/serverappio/serverappio_servicer.py +230 -84
  117. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/simulation/simulationio_grpc.py +1 -1
  118. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/simulation/simulationio_servicer.py +26 -2
  119. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/utils.py +9 -2
  120. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/utils/validator.py +2 -2
  121. flwr-1.20.0/py/flwr/serverapp/__init__.py +15 -0
  122. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/simulation/app.py +25 -0
  123. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/simulation/run_simulation.py +17 -0
  124. flwr-1.20.0/py/flwr/supercore/__init__.py +15 -0
  125. {flwr-1.18.0/py/flwr/server/superlink → flwr-1.20.0/py/flwr/supercore}/ffs/__init__.py +2 -0
  126. {flwr-1.18.0/py/flwr/server/superlink → flwr-1.20.0/py/flwr/supercore}/ffs/disk_ffs.py +1 -1
  127. flwr-1.20.0/py/flwr/supercore/grpc_health/__init__.py +22 -0
  128. flwr-1.20.0/py/flwr/supercore/grpc_health/simple_health_servicer.py +38 -0
  129. flwr-1.20.0/py/flwr/supercore/license_plugin/__init__.py +22 -0
  130. flwr-1.20.0/py/flwr/supercore/license_plugin/license_plugin.py +26 -0
  131. flwr-1.20.0/py/flwr/supercore/object_store/__init__.py +24 -0
  132. flwr-1.20.0/py/flwr/supercore/object_store/in_memory_object_store.py +229 -0
  133. flwr-1.20.0/py/flwr/supercore/object_store/object_store.py +170 -0
  134. flwr-1.20.0/py/flwr/supercore/object_store/object_store_factory.py +44 -0
  135. flwr-1.20.0/py/flwr/supercore/object_store/utils.py +43 -0
  136. {flwr-1.18.0/py/flwr/client/supernode → flwr-1.20.0/py/flwr/supercore/scheduler}/__init__.py +3 -3
  137. flwr-1.20.0/py/flwr/supercore/scheduler/plugin.py +71 -0
  138. flwr-1.20.0/py/flwr/supercore/utils.py +32 -0
  139. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/superexec/deployment.py +7 -4
  140. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/superexec/exec_event_log_interceptor.py +8 -4
  141. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/superexec/exec_grpc.py +25 -5
  142. flwr-1.20.0/py/flwr/superexec/exec_license_interceptor.py +82 -0
  143. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/superexec/exec_servicer.py +135 -24
  144. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/superexec/exec_user_auth_interceptor.py +45 -8
  145. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/superexec/executor.py +5 -1
  146. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/superexec/simulation.py +8 -3
  147. flwr-1.20.0/py/flwr/superlink/__init__.py +15 -0
  148. flwr-1.20.0/py/flwr/supernode/__init__.py +15 -0
  149. flwr-1.20.0/py/flwr/supernode/cli/__init__.py +24 -0
  150. flwr-1.18.0/py/flwr/client/supernode/app.py → flwr-1.20.0/py/flwr/supernode/cli/flower_supernode.py +3 -19
  151. flwr-1.20.0/py/flwr/supernode/cli/flwr_clientapp.py +88 -0
  152. flwr-1.20.0/py/flwr/supernode/nodestate/in_memory_nodestate.py +199 -0
  153. flwr-1.20.0/py/flwr/supernode/nodestate/nodestate.py +227 -0
  154. flwr-1.20.0/py/flwr/supernode/runtime/__init__.py +15 -0
  155. flwr-1.18.0/py/flwr/client/clientapp/app.py → flwr-1.20.0/py/flwr/supernode/runtime/run_clientapp.py +135 -89
  156. flwr-1.20.0/py/flwr/supernode/scheduler/__init__.py +22 -0
  157. flwr-1.20.0/py/flwr/supernode/scheduler/simple_clientapp_scheduler_plugin.py +49 -0
  158. flwr-1.20.0/py/flwr/supernode/servicer/__init__.py +15 -0
  159. {flwr-1.18.0/py/flwr/client/clientapp → flwr-1.20.0/py/flwr/supernode/servicer/clientappio}/__init__.py +3 -3
  160. flwr-1.20.0/py/flwr/supernode/servicer/clientappio/clientappio_servicer.py +303 -0
  161. flwr-1.20.0/py/flwr/supernode/start_client_internal.py +589 -0
  162. {flwr-1.18.0 → flwr-1.20.0}/pyproject.toml +6 -4
  163. flwr-1.18.0/py/flwr/cli/new/templates/app/pyproject.jax.toml.tpl +0 -35
  164. flwr-1.18.0/py/flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +0 -39
  165. flwr-1.18.0/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +0 -32
  166. flwr-1.18.0/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +0 -36
  167. flwr-1.18.0/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +0 -35
  168. flwr-1.18.0/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +0 -36
  169. flwr-1.18.0/py/flwr/client/clientapp/clientappio_servicer.py +0 -244
  170. flwr-1.18.0/py/flwr/client/heartbeat.py +0 -74
  171. flwr-1.18.0/py/flwr/client/nodestate/in_memory_nodestate.py +0 -38
  172. flwr-1.18.0/py/flwr/client/nodestate/nodestate.py +0 -31
  173. flwr-1.18.0/py/flwr/proto/clientappio_pb2.py +0 -45
  174. flwr-1.18.0/py/flwr/proto/clientappio_pb2.pyi +0 -132
  175. flwr-1.18.0/py/flwr/proto/clientappio_pb2_grpc.py +0 -135
  176. flwr-1.18.0/py/flwr/proto/clientappio_pb2_grpc.pyi +0 -53
  177. flwr-1.18.0/py/flwr/proto/fleet_pb2.py +0 -56
  178. flwr-1.18.0/py/flwr/proto/message_pb2.py +0 -41
  179. flwr-1.18.0/py/flwr/proto/run_pb2.py +0 -64
  180. flwr-1.18.0/py/flwr/proto/serverappio_pb2.py +0 -51
  181. flwr-1.18.0/py/flwr/proto/simulationio_pb2.py +0 -38
  182. {flwr-1.18.0 → flwr-1.20.0}/README.md +0 -0
  183. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/__init__.py +0 -0
  184. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/__init__.py +0 -0
  185. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/app.py +0 -0
  186. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/auth_plugin/__init__.py +0 -0
  187. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/auth_plugin/oidc_cli_plugin.py +0 -0
  188. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/cli_user_auth_interceptor.py +0 -0
  189. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/config_utils.py +0 -0
  190. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/constant.py +0 -0
  191. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/example.py +0 -0
  192. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/install.py +0 -0
  193. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/login/__init__.py +0 -0
  194. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/__init__.py +0 -0
  195. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/__init__.py +0 -0
  196. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/.gitignore.tpl +0 -0
  197. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/LICENSE.tpl +0 -0
  198. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/README.baseline.md.tpl +0 -0
  199. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/__init__.py +0 -0
  200. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +0 -0
  201. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
  202. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
  203. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/client.baseline.py.tpl +1 -1
  204. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/client.huggingface.py.tpl +0 -0
  205. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/client.jax.py.tpl +0 -0
  206. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/client.mlx.py.tpl +0 -0
  207. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
  208. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
  209. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -0
  210. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
  211. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +0 -0
  212. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/flwr_tune/__init__.py +0 -0
  213. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +0 -0
  214. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +0 -0
  215. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +0 -0
  216. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +0 -0
  217. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +0 -0
  218. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/server.huggingface.py.tpl +0 -0
  219. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/server.jax.py.tpl +0 -0
  220. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/server.mlx.py.tpl +0 -0
  221. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
  222. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
  223. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -0
  224. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
  225. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +0 -0
  226. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/task.huggingface.py.tpl +0 -0
  227. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/task.jax.py.tpl +0 -0
  228. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/task.mlx.py.tpl +0 -0
  229. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/task.numpy.py.tpl +0 -0
  230. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
  231. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/task.sklearn.py.tpl +0 -0
  232. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +0 -0
  233. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/new/templates/app/code/utils.baseline.py.tpl +0 -0
  234. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/cli/run/__init__.py +0 -0
  235. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/client.py +0 -0
  236. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/clientapp/utils.py +0 -0
  237. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/dpfedavg_numpy_client.py +0 -0
  238. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/grpc_adapter_client/__init__.py +0 -0
  239. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/grpc_rere_client/__init__.py +0 -0
  240. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/grpc_rere_client/client_interceptor.py +0 -0
  241. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/message_handler/__init__.py +0 -0
  242. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/mod/__init__.py +0 -0
  243. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/mod/centraldp_mods.py +0 -0
  244. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/mod/localdp_mod.py +0 -0
  245. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
  246. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
  247. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
  248. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/mod/utils.py +0 -0
  249. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/numpy_client.py +0 -0
  250. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/rest_client/__init__.py +0 -0
  251. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/run_info_store.py +0 -0
  252. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/client/typing.py +0 -0
  253. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/address.py +0 -0
  254. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/args.py +0 -0
  255. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/config.py +0 -0
  256. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/context.py +0 -0
  257. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/date.py +0 -0
  258. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/differential_privacy.py +0 -0
  259. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/differential_privacy_constants.py +0 -0
  260. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/dp.py +0 -0
  261. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/event_log_plugin/__init__.py +0 -0
  262. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/exit/__init__.py +0 -0
  263. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/exit/exit.py +0 -0
  264. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/logger.py +0 -0
  265. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/object_ref.py +0 -0
  266. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/parameter.py +0 -0
  267. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/pyproject.py +0 -0
  268. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/record/typeddict.py +0 -0
  269. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/secure_aggregation/__init__.py +0 -0
  270. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
  271. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
  272. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +0 -0
  273. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
  274. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/secure_aggregation/quantization.py +0 -0
  275. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
  276. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
  277. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/telemetry.py +0 -0
  278. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/common/version.py +0 -0
  279. {flwr-1.18.0/py/flwr → flwr-1.20.0/py/flwr/compat}/client/grpc_client/__init__.py +0 -0
  280. {flwr-1.18.0/py/flwr → flwr-1.20.0/py/flwr/compat}/client/grpc_client/connection.py +0 -0
  281. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/__init__.py +0 -0
  282. /flwr-1.18.0/py/flwr/proto/error_pb2_grpc.py → /flwr-1.20.0/py/flwr/proto/appio_pb2_grpc.py +0 -0
  283. /flwr-1.18.0/py/flwr/proto/error_pb2_grpc.pyi → /flwr-1.20.0/py/flwr/proto/appio_pb2_grpc.pyi +0 -0
  284. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/error_pb2.py +0 -0
  285. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/error_pb2.pyi +0 -0
  286. /flwr-1.18.0/py/flwr/proto/fab_pb2_grpc.py → /flwr-1.20.0/py/flwr/proto/error_pb2_grpc.py +0 -0
  287. /flwr-1.18.0/py/flwr/proto/fab_pb2_grpc.pyi → /flwr-1.20.0/py/flwr/proto/error_pb2_grpc.pyi +0 -0
  288. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/exec_pb2.py +0 -0
  289. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/exec_pb2.pyi +0 -0
  290. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/exec_pb2_grpc.py +0 -0
  291. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/exec_pb2_grpc.pyi +0 -0
  292. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/fab_pb2.py +0 -0
  293. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/fab_pb2.pyi +0 -0
  294. /flwr-1.18.0/py/flwr/proto/log_pb2_grpc.py → /flwr-1.20.0/py/flwr/proto/fab_pb2_grpc.py +0 -0
  295. /flwr-1.18.0/py/flwr/proto/log_pb2_grpc.pyi → /flwr-1.20.0/py/flwr/proto/fab_pb2_grpc.pyi +0 -0
  296. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/grpcadapter_pb2.py +0 -0
  297. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/grpcadapter_pb2.pyi +0 -0
  298. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/grpcadapter_pb2_grpc.py +0 -0
  299. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/grpcadapter_pb2_grpc.pyi +0 -0
  300. /flwr-1.18.0/py/flwr/proto/message_pb2_grpc.py → /flwr-1.20.0/py/flwr/proto/heartbeat_pb2_grpc.py +0 -0
  301. /flwr-1.18.0/py/flwr/proto/message_pb2_grpc.pyi → /flwr-1.20.0/py/flwr/proto/heartbeat_pb2_grpc.pyi +0 -0
  302. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/log_pb2.py +0 -0
  303. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/log_pb2.pyi +0 -0
  304. /flwr-1.18.0/py/flwr/proto/node_pb2_grpc.py → /flwr-1.20.0/py/flwr/proto/log_pb2_grpc.py +0 -0
  305. /flwr-1.18.0/py/flwr/proto/node_pb2_grpc.pyi → /flwr-1.20.0/py/flwr/proto/log_pb2_grpc.pyi +0 -0
  306. /flwr-1.18.0/py/flwr/proto/recorddict_pb2_grpc.py → /flwr-1.20.0/py/flwr/proto/message_pb2_grpc.py +0 -0
  307. /flwr-1.18.0/py/flwr/proto/recorddict_pb2_grpc.pyi → /flwr-1.20.0/py/flwr/proto/message_pb2_grpc.pyi +0 -0
  308. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/node_pb2.py +0 -0
  309. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/node_pb2.pyi +0 -0
  310. /flwr-1.18.0/py/flwr/proto/run_pb2_grpc.py → /flwr-1.20.0/py/flwr/proto/node_pb2_grpc.py +0 -0
  311. /flwr-1.18.0/py/flwr/proto/run_pb2_grpc.pyi → /flwr-1.20.0/py/flwr/proto/node_pb2_grpc.pyi +0 -0
  312. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/simulationio_pb2.pyi +0 -0
  313. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/transport_pb2.py +0 -0
  314. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/transport_pb2.pyi +0 -0
  315. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/transport_pb2_grpc.py +0 -0
  316. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
  317. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/py.typed +0 -0
  318. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/client_manager.py +0 -0
  319. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/client_proxy.py +0 -0
  320. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/compat/__init__.py +0 -0
  321. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/compat/app.py +0 -0
  322. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/compat/grid_client_proxy.py +0 -0
  323. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/compat/legacy_context.py +0 -0
  324. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/criterion.py +0 -0
  325. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/grid/__init__.py +0 -0
  326. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/grid/grid.py +0 -0
  327. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/history.py +0 -0
  328. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/run_serverapp.py +0 -0
  329. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/server.py +0 -0
  330. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/server_app.py +0 -0
  331. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/server_config.py +0 -0
  332. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/serverapp/__init__.py +0 -0
  333. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/serverapp_components.py +0 -0
  334. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/__init__.py +0 -0
  335. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/aggregate.py +0 -0
  336. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/bulyan.py +0 -0
  337. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
  338. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
  339. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
  340. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
  341. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
  342. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedadagrad.py +0 -0
  343. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedadam.py +0 -0
  344. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedavg.py +0 -0
  345. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedavg_android.py +0 -0
  346. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedavgm.py +0 -0
  347. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedmedian.py +0 -0
  348. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedopt.py +0 -0
  349. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedprox.py +0 -0
  350. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
  351. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
  352. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
  353. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
  354. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/fedyogi.py +0 -0
  355. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/krum.py +0 -0
  356. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/qfedavg.py +0 -0
  357. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/strategy/strategy.py +0 -0
  358. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/__init__.py +0 -0
  359. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/__init__.py +0 -0
  360. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/grpc_adapter/__init__.py +0 -0
  361. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
  362. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
  363. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
  364. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
  365. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +0 -0
  366. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
  367. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
  368. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
  369. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
  370. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
  371. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
  372. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +0 -0
  373. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/linkstate/__init__.py +0 -0
  374. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/linkstate/linkstate_factory.py +0 -0
  375. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/serverappio/__init__.py +0 -0
  376. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/superlink/simulation/__init__.py +0 -0
  377. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/typing.py +0 -0
  378. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/utils/__init__.py +0 -0
  379. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/utils/tensorboard.py +0 -0
  380. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/workflow/__init__.py +0 -0
  381. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/workflow/constant.py +0 -0
  382. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/workflow/default_workflows.py +0 -0
  383. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
  384. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
  385. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +0 -0
  386. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/simulation/__init__.py +0 -0
  387. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/simulation/legacy_app.py +0 -0
  388. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/simulation/ray_transport/__init__.py +0 -0
  389. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/simulation/ray_transport/ray_actor.py +0 -0
  390. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
  391. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/simulation/ray_transport/utils.py +0 -0
  392. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/simulation/simulationio_connection.py +0 -0
  393. {flwr-1.18.0/py/flwr/server/superlink → flwr-1.20.0/py/flwr/supercore}/ffs/ffs.py +0 -0
  394. {flwr-1.18.0/py/flwr/server/superlink → flwr-1.20.0/py/flwr/supercore}/ffs/ffs_factory.py +0 -0
  395. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/superexec/__init__.py +0 -0
  396. {flwr-1.18.0 → flwr-1.20.0}/py/flwr/superexec/app.py +0 -0
  397. {flwr-1.18.0/py/flwr/client → flwr-1.20.0/py/flwr/supernode}/nodestate/__init__.py +0 -0
  398. {flwr-1.18.0/py/flwr/client → flwr-1.20.0/py/flwr/supernode}/nodestate/nodestate_factory.py +0 -0
@@ -1,8 +1,7 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: flwr
3
- Version: 1.18.0
3
+ Version: 1.20.0
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
- Home-page: https://flower.ai
6
5
  License: Apache-2.0
7
6
  Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
8
7
  Author: The Flower Authors
@@ -19,8 +18,8 @@ Classifier: Programming Language :: Python :: 3
19
18
  Classifier: Programming Language :: Python :: 3.10
20
19
  Classifier: Programming Language :: Python :: 3.11
21
20
  Classifier: Programming Language :: Python :: 3.12
22
- Classifier: Programming Language :: Python :: 3 :: Only
23
21
  Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3 :: Only
24
23
  Classifier: Programming Language :: Python :: 3.9
25
24
  Classifier: Programming Language :: Python :: Implementation :: CPython
26
25
  Classifier: Topic :: Scientific/Engineering
@@ -32,8 +31,10 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
32
31
  Classifier: Typing :: Typed
33
32
  Provides-Extra: rest
34
33
  Provides-Extra: simulation
34
+ Requires-Dist: click (<8.2.0)
35
35
  Requires-Dist: cryptography (>=44.0.1,<45.0.0)
36
36
  Requires-Dist: grpcio (>=1.62.3,<2.0.0,!=1.65.0)
37
+ Requires-Dist: grpcio-health-checking (>=1.62.3,<2.0.0)
37
38
  Requires-Dist: iterators (>=0.0.2,<0.0.3)
38
39
  Requires-Dist: numpy (>=1.26.0,<3.0.0)
39
40
  Requires-Dist: pathspec (>=0.12.1,<0.13.0)
@@ -49,6 +50,7 @@ Requires-Dist: tomli-w (>=1.0.0,<2.0.0)
49
50
  Requires-Dist: typer (>=0.12.5,<0.13.0)
50
51
  Requires-Dist: uvicorn[standard] (>=0.34.0,<0.35.0) ; extra == "rest"
51
52
  Project-URL: Documentation, https://flower.ai
53
+ Project-URL: Homepage, https://flower.ai
52
54
  Project-URL: Repository, https://github.com/adap/flower
53
55
  Description-Content-Type: text/markdown
54
56
 
@@ -0,0 +1,15 @@
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
+ """Public Flower App APIs."""
@@ -0,0 +1,68 @@
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
+ """Error."""
16
+
17
+
18
+ from __future__ import annotations
19
+
20
+ from typing import Optional, cast
21
+
22
+ DEFAULT_TTL = 43200 # This is 12 hours
23
+ MESSAGE_INIT_ERROR_MESSAGE = (
24
+ "Invalid arguments for Message. Expected one of the documented "
25
+ "signatures: Message(content: RecordDict, dst_node_id: int, message_type: str,"
26
+ " *, [ttl: float, group_id: str]) or Message(content: RecordDict | error: Error,"
27
+ " *, reply_to: Message, [ttl: float])."
28
+ )
29
+
30
+
31
+ class Error:
32
+ """The class storing information about an error that occurred.
33
+
34
+ Parameters
35
+ ----------
36
+ code : int
37
+ An identifier for the error.
38
+ reason : Optional[str]
39
+ A reason for why the error arose (e.g. an exception stack-trace)
40
+ """
41
+
42
+ def __init__(self, code: int, reason: str | None = None) -> None:
43
+ var_dict = {
44
+ "_code": code,
45
+ "_reason": reason,
46
+ }
47
+ self.__dict__.update(var_dict)
48
+
49
+ @property
50
+ def code(self) -> int:
51
+ """Error code."""
52
+ return cast(int, self.__dict__["_code"])
53
+
54
+ @property
55
+ def reason(self) -> str | None:
56
+ """Reason reported about the error."""
57
+ return cast(Optional[str], self.__dict__["_reason"])
58
+
59
+ def __repr__(self) -> str:
60
+ """Return a string representation of this instance."""
61
+ view = ", ".join([f"{k.lstrip('_')}={v!r}" for k, v in self.__dict__.items()])
62
+ return f"{self.__class__.__qualname__}({view})"
63
+
64
+ def __eq__(self, other: object) -> bool:
65
+ """Compare two instances of the class."""
66
+ if not isinstance(other, self.__class__):
67
+ raise NotImplementedError
68
+ return self.__dict__ == other.__dict__
@@ -0,0 +1,223 @@
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
+ """Metadata."""
16
+
17
+
18
+ from __future__ import annotations
19
+
20
+ from typing import cast
21
+
22
+ from ..common.constant import MessageType, MessageTypeLegacy
23
+
24
+
25
+ class Metadata: # pylint: disable=too-many-instance-attributes
26
+ """The class representing metadata associated with the current message.
27
+
28
+ Parameters
29
+ ----------
30
+ run_id : int
31
+ An identifier for the current run.
32
+ message_id : str
33
+ An identifier for the current message.
34
+ src_node_id : int
35
+ An identifier for the node sending this message.
36
+ dst_node_id : int
37
+ An identifier for the node receiving this message.
38
+ reply_to_message_id : str
39
+ An identifier for the message to which this message is a reply.
40
+ group_id : str
41
+ An identifier for grouping messages. In some settings,
42
+ this is used as the FL round.
43
+ created_at : float
44
+ Unix timestamp when the message was created.
45
+ ttl : float
46
+ Time-to-live for this message in seconds.
47
+ message_type : str
48
+ A string that encodes the action to be executed on
49
+ the receiving end.
50
+ """
51
+
52
+ def __init__( # pylint: disable=too-many-arguments,too-many-positional-arguments
53
+ self,
54
+ run_id: int,
55
+ message_id: str,
56
+ src_node_id: int,
57
+ dst_node_id: int,
58
+ reply_to_message_id: str,
59
+ group_id: str,
60
+ created_at: float,
61
+ ttl: float,
62
+ message_type: str,
63
+ ) -> None:
64
+ var_dict = {
65
+ "_run_id": run_id,
66
+ "_message_id": message_id,
67
+ "_src_node_id": src_node_id,
68
+ "_dst_node_id": dst_node_id,
69
+ "_reply_to_message_id": reply_to_message_id,
70
+ "_group_id": group_id,
71
+ "_created_at": created_at,
72
+ "_ttl": ttl,
73
+ "_message_type": message_type,
74
+ }
75
+ self.__dict__.update(var_dict)
76
+ self.message_type = message_type # Trigger validation
77
+
78
+ @property
79
+ def run_id(self) -> int:
80
+ """An identifier for the current run."""
81
+ return cast(int, self.__dict__["_run_id"])
82
+
83
+ @property
84
+ def message_id(self) -> str:
85
+ """An identifier for the current message."""
86
+ return cast(str, self.__dict__["_message_id"])
87
+
88
+ @property
89
+ def src_node_id(self) -> int:
90
+ """An identifier for the node sending this message."""
91
+ return cast(int, self.__dict__["_src_node_id"])
92
+
93
+ @property
94
+ def reply_to_message_id(self) -> str:
95
+ """An identifier for the message to which this message is a reply."""
96
+ return cast(str, self.__dict__["_reply_to_message_id"])
97
+
98
+ @property
99
+ def dst_node_id(self) -> int:
100
+ """An identifier for the node receiving this message."""
101
+ return cast(int, self.__dict__["_dst_node_id"])
102
+
103
+ @dst_node_id.setter
104
+ def dst_node_id(self, value: int) -> None:
105
+ """Set dst_node_id."""
106
+ self.__dict__["_dst_node_id"] = value
107
+
108
+ @property
109
+ def group_id(self) -> str:
110
+ """An identifier for grouping messages."""
111
+ return cast(str, self.__dict__["_group_id"])
112
+
113
+ @group_id.setter
114
+ def group_id(self, value: str) -> None:
115
+ """Set group_id."""
116
+ self.__dict__["_group_id"] = value
117
+
118
+ @property
119
+ def created_at(self) -> float:
120
+ """Unix timestamp when the message was created."""
121
+ return cast(float, self.__dict__["_created_at"])
122
+
123
+ @created_at.setter
124
+ def created_at(self, value: float) -> None:
125
+ """Set creation timestamp of this message."""
126
+ self.__dict__["_created_at"] = value
127
+
128
+ @property
129
+ def delivered_at(self) -> str:
130
+ """Unix timestamp when the message was delivered."""
131
+ return cast(str, self.__dict__["_delivered_at"])
132
+
133
+ @delivered_at.setter
134
+ def delivered_at(self, value: str) -> None:
135
+ """Set delivery timestamp of this message."""
136
+ self.__dict__["_delivered_at"] = value
137
+
138
+ @property
139
+ def ttl(self) -> float:
140
+ """Time-to-live for this message."""
141
+ return cast(float, self.__dict__["_ttl"])
142
+
143
+ @ttl.setter
144
+ def ttl(self, value: float) -> None:
145
+ """Set ttl."""
146
+ self.__dict__["_ttl"] = value
147
+
148
+ @property
149
+ def message_type(self) -> str:
150
+ """A string that encodes the action to be executed on the receiving end."""
151
+ return cast(str, self.__dict__["_message_type"])
152
+
153
+ @message_type.setter
154
+ def message_type(self, value: str) -> None:
155
+ """Set message_type."""
156
+ # Validate message type
157
+ if validate_legacy_message_type(value):
158
+ pass # Backward compatibility for legacy message types
159
+ elif not validate_message_type(value):
160
+ raise ValueError(
161
+ f"Invalid message type: '{value}'. "
162
+ "Expected format: '<category>' or '<category>.<action>', "
163
+ "where <category> must be 'train', 'evaluate', or 'query', "
164
+ "and <action> must be a valid Python identifier."
165
+ )
166
+
167
+ self.__dict__["_message_type"] = value
168
+
169
+ def __repr__(self) -> str:
170
+ """Return a string representation of this instance."""
171
+ view = ", ".join([f"{k.lstrip('_')}={v!r}" for k, v in self.__dict__.items()])
172
+ return f"{self.__class__.__qualname__}({view})"
173
+
174
+ def __eq__(self, other: object) -> bool:
175
+ """Compare two instances of the class."""
176
+ if not isinstance(other, self.__class__):
177
+ raise NotImplementedError
178
+ return self.__dict__ == other.__dict__
179
+
180
+
181
+ def validate_message_type(message_type: str) -> bool:
182
+ """Validate if the message type is valid.
183
+
184
+ A valid message type format must be one of the following:
185
+
186
+ - "<category>"
187
+ - "<category>.<action>"
188
+
189
+ where `category` must be one of "train", "evaluate", or "query",
190
+ and `action` must be a valid Python identifier.
191
+ """
192
+ # Check if conforming to the format "<category>"
193
+ valid_types = {
194
+ MessageType.TRAIN,
195
+ MessageType.EVALUATE,
196
+ MessageType.QUERY,
197
+ MessageType.SYSTEM,
198
+ }
199
+ if message_type in valid_types:
200
+ return True
201
+
202
+ # Check if conforming to the format "<category>.<action>"
203
+ if message_type.count(".") != 1:
204
+ return False
205
+
206
+ category, action = message_type.split(".")
207
+ if category in valid_types and action.isidentifier():
208
+ return True
209
+
210
+ return False
211
+
212
+
213
+ def validate_legacy_message_type(message_type: str) -> bool:
214
+ """Validate if the legacy message type is valid."""
215
+ # Backward compatibility for legacy message types
216
+ if message_type in (
217
+ MessageTypeLegacy.GET_PARAMETERS,
218
+ MessageTypeLegacy.GET_PROPERTIES,
219
+ "reconnect",
220
+ ):
221
+ return True
222
+
223
+ return False
@@ -16,10 +16,8 @@
16
16
 
17
17
 
18
18
  import hashlib
19
- import os
20
- import shutil
21
- import tempfile
22
19
  import zipfile
20
+ from io import BytesIO
23
21
  from pathlib import Path
24
22
  from typing import Annotated, Any, Optional, Union
25
23
 
@@ -27,8 +25,14 @@ import pathspec
27
25
  import tomli_w
28
26
  import typer
29
27
 
30
- from flwr.common.constant import FAB_ALLOWED_EXTENSIONS, FAB_DATE, FAB_HASH_TRUNCATION
28
+ from flwr.common.constant import (
29
+ FAB_ALLOWED_EXTENSIONS,
30
+ FAB_DATE,
31
+ FAB_HASH_TRUNCATION,
32
+ FAB_MAX_SIZE,
33
+ )
31
34
 
35
+ from .config_utils import load as load_toml
32
36
  from .config_utils import load_and_validate
33
37
  from .utils import is_valid_project_name
34
38
 
@@ -43,11 +47,11 @@ def write_to_zip(
43
47
  return zipfile_obj
44
48
 
45
49
 
46
- def get_fab_filename(conf: dict[str, Any], fab_hash: str) -> str:
50
+ def get_fab_filename(config: dict[str, Any], fab_hash: str) -> str:
47
51
  """Get the FAB filename based on the given config and FAB hash."""
48
- publisher = conf["tool"]["flwr"]["app"]["publisher"]
49
- name = conf["project"]["name"]
50
- version = conf["project"]["version"].replace(".", "-")
52
+ publisher = config["tool"]["flwr"]["app"]["publisher"]
53
+ name = config["project"]["name"]
54
+ version = config["project"]["version"].replace(".", "-")
51
55
  fab_hash_truncated = fab_hash[:FAB_HASH_TRUNCATION]
52
56
  return f"{publisher}.{name}.{version}.{fab_hash_truncated}.fab"
53
57
 
@@ -58,7 +62,7 @@ def build(
58
62
  Optional[Path],
59
63
  typer.Option(help="Path of the Flower App to bundle into a FAB"),
60
64
  ] = None,
61
- ) -> tuple[str, str]:
65
+ ) -> None:
62
66
  """Build a Flower App into a Flower App Bundle (FAB).
63
67
 
64
68
  You can run ``flwr build`` without any arguments to bundle the app located in the
@@ -89,8 +93,8 @@ def build(
89
93
  )
90
94
  raise typer.Exit(code=1)
91
95
 
92
- conf, errors, warnings = load_and_validate(app / "pyproject.toml")
93
- if conf is None:
96
+ config, errors, warnings = load_and_validate(app / "pyproject.toml")
97
+ if config is None:
94
98
  typer.secho(
95
99
  "Project configuration could not be loaded.\npyproject.toml is invalid:\n"
96
100
  + "\n".join([f"- {line}" for line in errors]),
@@ -107,70 +111,101 @@ def build(
107
111
  bold=True,
108
112
  )
109
113
 
110
- # Load .gitignore rules if present
111
- ignore_spec = _load_gitignore(app)
114
+ # Build FAB
115
+ fab_bytes, fab_hash, _ = build_fab(app)
112
116
 
113
- list_file_content = ""
117
+ # Get the name of the zip file
118
+ fab_filename = get_fab_filename(config, fab_hash)
114
119
 
115
- # Remove the 'federations' field from 'tool.flwr' if it exists
116
- if (
117
- "tool" in conf
118
- and "flwr" in conf["tool"]
119
- and "federations" in conf["tool"]["flwr"]
120
- ):
121
- del conf["tool"]["flwr"]["federations"]
120
+ # Write the FAB
121
+ Path(fab_filename).write_bytes(fab_bytes)
122
122
 
123
- toml_contents = tomli_w.dumps(conf)
123
+ typer.secho(
124
+ f"🎊 Successfully built {fab_filename}", fg=typer.colors.GREEN, bold=True
125
+ )
124
126
 
125
- with tempfile.NamedTemporaryFile(suffix=".zip", delete=False) as temp_file:
126
- temp_filename = temp_file.name
127
127
 
128
- with zipfile.ZipFile(temp_filename, "w", zipfile.ZIP_DEFLATED) as fab_file:
129
- write_to_zip(fab_file, "pyproject.toml", toml_contents)
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.
130
130
 
131
- # Continue with adding other files
132
- all_files = [
133
- f
134
- for f in app.rglob("*")
135
- if not ignore_spec.match_file(f)
136
- and f.name != temp_filename
137
- and f.suffix in FAB_ALLOWED_EXTENSIONS
138
- and f.name != "pyproject.toml" # Exclude the original pyproject.toml
139
- ]
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.
140
133
 
141
- all_files.sort()
134
+ Parameters
135
+ ----------
136
+ app : Path
137
+ Path to the Flower app to bundle into a FAB.
142
138
 
143
- for file_path in all_files:
144
- # Read the file content manually
145
- with open(file_path, "rb") as f:
146
- file_contents = f.read()
139
+ Returns
140
+ -------
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
+ """
147
+ app = app.resolve()
147
148
 
148
- archive_path = file_path.relative_to(app)
149
- write_to_zip(fab_file, str(archive_path), file_contents)
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.")
150
153
 
151
- # Calculate file info
152
- sha256_hash = hashlib.sha256(file_contents).hexdigest()
153
- file_size_bits = os.path.getsize(file_path) * 8 # size in bits
154
- list_file_content += f"{archive_path},{sha256_hash},{file_size_bits}\n"
154
+ # Remove the 'federations' field if it exists
155
+ if (
156
+ "tool" in config
157
+ and "flwr" in config["tool"]
158
+ and "federations" in config["tool"]["flwr"]
159
+ ):
160
+ del config["tool"]["flwr"]["federations"]
155
161
 
156
- # Add CONTENT and CONTENT.jwt to the zip file
157
- write_to_zip(fab_file, ".info/CONTENT", list_file_content)
162
+ # Load .gitignore rules if present
163
+ ignore_spec = _load_gitignore(app)
158
164
 
159
- # Get hash of FAB file
160
- content = Path(temp_filename).read_bytes()
161
- fab_hash = hashlib.sha256(content).hexdigest()
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
172
+ ]
173
+ all_files.sort()
174
+
175
+ # Create a zip file in memory
176
+ list_file_content = ""
162
177
 
163
- # Set the name of the zip file
164
- fab_filename = get_fab_filename(conf, fab_hash)
178
+ fab_buffer = BytesIO()
179
+ with zipfile.ZipFile(fab_buffer, "w", zipfile.ZIP_DEFLATED) as fab_file:
180
+ # Add pyproject.toml
181
+ write_to_zip(fab_file, "pyproject.toml", tomli_w.dumps(config))
165
182
 
166
- # Once the temporary zip file is created, rename it to the final filename
167
- shutil.move(temp_filename, fab_filename)
183
+ for file_path in all_files:
184
+ # Read the file content manually
185
+ file_contents = file_path.read_bytes()
168
186
 
169
- typer.secho(
170
- f"🎊 Successfully built {fab_filename}", fg=typer.colors.GREEN, bold=True
171
- )
187
+ archive_path = str(file_path.relative_to(app)).replace("\\", "/")
188
+ write_to_zip(fab_file, archive_path, file_contents)
189
+
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"
194
+
195
+ # Add CONTENT and CONTENT.jwt to the zip file
196
+ write_to_zip(fab_file, ".info/CONTENT", list_file_content)
197
+
198
+ fab_bytes = fab_buffer.getvalue()
199
+ if len(fab_bytes) > FAB_MAX_SIZE:
200
+ raise ValueError(
201
+ f"FAB size exceeds maximum allowed size of {FAB_MAX_SIZE:,} bytes."
202
+ "To reduce the package size, consider ignoring unnecessary files "
203
+ "via your `.gitignore` file or excluding them from the build."
204
+ )
205
+
206
+ fab_hash = hashlib.sha256(fab_bytes).hexdigest()
172
207
 
173
- return fab_filename, fab_hash
208
+ return fab_bytes, fab_hash, config
174
209
 
175
210
 
176
211
  def _load_gitignore(app: Path) -> pathspec.PathSpec:
@@ -35,7 +35,7 @@ from flwr.common.logger import log as logger
35
35
  from flwr.proto.exec_pb2 import StreamLogsRequest # pylint: disable=E0611
36
36
  from flwr.proto.exec_pb2_grpc import ExecStub
37
37
 
38
- from .utils import init_channel, try_obtain_cli_auth_plugin, unauthenticated_exc_handler
38
+ from .utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
39
39
 
40
40
 
41
41
  class AllLogsRetrieved(BaseException):
@@ -95,7 +95,7 @@ def stream_logs(
95
95
  latest_timestamp = 0.0
96
96
  res = None
97
97
  try:
98
- with unauthenticated_exc_handler():
98
+ with flwr_cli_grpc_exc_handler():
99
99
  for res in stub.StreamLogs(req, timeout=duration):
100
100
  print(res.log_output, end="")
101
101
  raise AllLogsRetrieved()
@@ -116,7 +116,7 @@ def print_logs(run_id: int, channel: grpc.Channel, timeout: int) -> None:
116
116
  req = StreamLogsRequest(run_id=run_id, after_timestamp=0.0)
117
117
 
118
118
  try:
119
- with unauthenticated_exc_handler():
119
+ with flwr_cli_grpc_exc_handler():
120
120
  # Enforce timeout for graceful exit
121
121
  for res in stub.StreamLogs(req, timeout=timeout):
122
122
  print(res.log_output)
@@ -35,11 +35,7 @@ from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
35
35
  )
36
36
  from flwr.proto.exec_pb2_grpc import ExecStub
37
37
 
38
- from ..utils import (
39
- init_channel,
40
- try_obtain_cli_auth_plugin,
41
- unauthenticated_exc_handler,
42
- )
38
+ from ..utils import flwr_cli_grpc_exc_handler, init_channel, try_obtain_cli_auth_plugin
43
39
 
44
40
 
45
41
  def login( # pylint: disable=R0914
@@ -96,7 +92,7 @@ def login( # pylint: disable=R0914
96
92
  stub = ExecStub(channel)
97
93
 
98
94
  login_request = GetLoginDetailsRequest()
99
- with unauthenticated_exc_handler():
95
+ with flwr_cli_grpc_exc_handler():
100
96
  login_response: GetLoginDetailsResponse = stub.GetLoginDetails(login_request)
101
97
 
102
98
  # Get the auth plugin
@@ -120,7 +116,7 @@ def login( # pylint: disable=R0914
120
116
  expires_in=login_response.expires_in,
121
117
  interval=login_response.interval,
122
118
  )
123
- with unauthenticated_exc_handler():
119
+ with flwr_cli_grpc_exc_handler():
124
120
  credentials = auth_plugin.login(details, stub)
125
121
 
126
122
  # Store the tokens