flwr-nightly 1.19.0.dev20250605__tar.gz → 1.19.0.dev20250607__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 (364) hide show
  1. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/PKG-INFO +1 -1
  2. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/grpc_rere_client/connection.py +31 -23
  3. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/constant.py +11 -0
  4. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/inflatable.py +31 -15
  5. flwr_nightly-1.19.0.dev20250607/py/flwr/common/inflatable_grpc_utils.py +362 -0
  6. flwr_nightly-1.19.0.dev20250607/py/flwr/common/inflatable_utils.py +75 -0
  7. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/message.py +2 -2
  8. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/grid/grpc_grid.py +35 -21
  9. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/serverappio/serverappio_servicer.py +2 -2
  10. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/nodestate/in_memory_nodestate.py +41 -1
  11. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/nodestate/nodestate.py +55 -0
  12. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/pyproject.toml +1 -1
  13. flwr_nightly-1.19.0.dev20250605/py/flwr/common/inflatable_grpc_utils.py +0 -122
  14. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/README.md +0 -0
  15. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/__init__.py +0 -0
  16. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/app/__init__.py +0 -0
  17. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/app/error.py +0 -0
  18. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/app/metadata.py +0 -0
  19. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/__init__.py +0 -0
  20. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/app.py +0 -0
  21. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/auth_plugin/__init__.py +0 -0
  22. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/auth_plugin/oidc_cli_plugin.py +0 -0
  23. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/build.py +0 -0
  24. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/cli_user_auth_interceptor.py +0 -0
  25. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/config_utils.py +0 -0
  26. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/constant.py +0 -0
  27. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/example.py +0 -0
  28. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/install.py +0 -0
  29. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/log.py +0 -0
  30. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/login/__init__.py +0 -0
  31. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/login/login.py +0 -0
  32. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/ls.py +0 -0
  33. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/__init__.py +0 -0
  34. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/new.py +0 -0
  35. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/__init__.py +0 -0
  36. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/.gitignore.tpl +0 -0
  37. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/LICENSE.tpl +0 -0
  38. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/README.baseline.md.tpl +0 -0
  39. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/README.flowertune.md.tpl +0 -0
  40. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/README.md.tpl +0 -0
  41. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/__init__.py +0 -0
  42. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +0 -0
  43. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
  44. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
  45. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/client.baseline.py.tpl +0 -0
  46. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/client.huggingface.py.tpl +0 -0
  47. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/client.jax.py.tpl +0 -0
  48. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/client.mlx.py.tpl +0 -0
  49. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
  50. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
  51. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -0
  52. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
  53. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +0 -0
  54. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/flwr_tune/__init__.py +0 -0
  55. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +0 -0
  56. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +0 -0
  57. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +0 -0
  58. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +0 -0
  59. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +0 -0
  60. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/model.baseline.py.tpl +0 -0
  61. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/server.baseline.py.tpl +0 -0
  62. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/server.huggingface.py.tpl +0 -0
  63. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/server.jax.py.tpl +0 -0
  64. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/server.mlx.py.tpl +0 -0
  65. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
  66. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
  67. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -0
  68. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
  69. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +0 -0
  70. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/task.huggingface.py.tpl +0 -0
  71. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/task.jax.py.tpl +0 -0
  72. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/task.mlx.py.tpl +0 -0
  73. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/task.numpy.py.tpl +0 -0
  74. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
  75. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/task.sklearn.py.tpl +0 -0
  76. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +0 -0
  77. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/code/utils.baseline.py.tpl +0 -0
  78. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +0 -0
  79. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +0 -0
  80. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +0 -0
  81. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/pyproject.jax.toml.tpl +0 -0
  82. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +0 -0
  83. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +0 -0
  84. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +0 -0
  85. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +0 -0
  86. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +0 -0
  87. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/run/__init__.py +0 -0
  88. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/run/run.py +0 -0
  89. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/stop.py +0 -0
  90. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/cli/utils.py +0 -0
  91. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/__init__.py +0 -0
  92. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/client.py +0 -0
  93. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/client_app.py +0 -0
  94. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/clientapp/__init__.py +0 -0
  95. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/clientapp/utils.py +0 -0
  96. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/dpfedavg_numpy_client.py +0 -0
  97. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/grpc_adapter_client/__init__.py +0 -0
  98. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/grpc_adapter_client/connection.py +0 -0
  99. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/grpc_rere_client/__init__.py +0 -0
  100. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/grpc_rere_client/client_interceptor.py +0 -0
  101. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/grpc_rere_client/grpc_adapter.py +0 -0
  102. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/message_handler/__init__.py +0 -0
  103. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/message_handler/message_handler.py +0 -0
  104. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/mod/__init__.py +0 -0
  105. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/mod/centraldp_mods.py +0 -0
  106. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/mod/comms_mods.py +0 -0
  107. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/mod/localdp_mod.py +0 -0
  108. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
  109. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
  110. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
  111. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/mod/utils.py +0 -0
  112. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/numpy_client.py +0 -0
  113. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/rest_client/__init__.py +0 -0
  114. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/rest_client/connection.py +0 -0
  115. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/run_info_store.py +0 -0
  116. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/client/typing.py +0 -0
  117. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/clientapp/__init__.py +0 -0
  118. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/__init__.py +0 -0
  119. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/address.py +0 -0
  120. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/args.py +0 -0
  121. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/auth_plugin/__init__.py +0 -0
  122. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/auth_plugin/auth_plugin.py +0 -0
  123. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/config.py +0 -0
  124. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/context.py +0 -0
  125. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/date.py +0 -0
  126. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/differential_privacy.py +0 -0
  127. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/differential_privacy_constants.py +0 -0
  128. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/dp.py +0 -0
  129. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/event_log_plugin/__init__.py +0 -0
  130. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/event_log_plugin/event_log_plugin.py +0 -0
  131. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/exit/__init__.py +0 -0
  132. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/exit/exit.py +0 -0
  133. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/exit/exit_code.py +0 -0
  134. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/exit_handlers.py +0 -0
  135. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/grpc.py +0 -0
  136. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/heartbeat.py +0 -0
  137. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/logger.py +0 -0
  138. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/object_ref.py +0 -0
  139. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/parameter.py +0 -0
  140. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/pyproject.py +0 -0
  141. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/record/__init__.py +0 -0
  142. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/record/array.py +0 -0
  143. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/record/arrayrecord.py +0 -0
  144. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/record/configrecord.py +0 -0
  145. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/record/conversion_utils.py +0 -0
  146. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/record/metricrecord.py +0 -0
  147. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/record/recorddict.py +0 -0
  148. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/record/typeddict.py +0 -0
  149. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/recorddict_compat.py +0 -0
  150. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/retry_invoker.py +0 -0
  151. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/secure_aggregation/__init__.py +0 -0
  152. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
  153. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
  154. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +0 -0
  155. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
  156. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/secure_aggregation/quantization.py +0 -0
  157. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
  158. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
  159. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/serde.py +0 -0
  160. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/serde_utils.py +0 -0
  161. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/telemetry.py +0 -0
  162. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/typing.py +0 -0
  163. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/common/version.py +0 -0
  164. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/compat/__init__.py +0 -0
  165. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/compat/client/__init__.py +0 -0
  166. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/compat/client/app.py +0 -0
  167. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/compat/client/grpc_client/__init__.py +0 -0
  168. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/compat/client/grpc_client/connection.py +0 -0
  169. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/compat/common/__init__.py +0 -0
  170. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/compat/server/__init__.py +0 -0
  171. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/compat/server/app.py +0 -0
  172. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/compat/simulation/__init__.py +0 -0
  173. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/__init__.py +0 -0
  174. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/clientappio_pb2.py +0 -0
  175. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/clientappio_pb2.pyi +0 -0
  176. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/clientappio_pb2_grpc.py +0 -0
  177. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/clientappio_pb2_grpc.pyi +0 -0
  178. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/error_pb2.py +0 -0
  179. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/error_pb2.pyi +0 -0
  180. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/error_pb2_grpc.py +0 -0
  181. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/error_pb2_grpc.pyi +0 -0
  182. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/exec_pb2.py +0 -0
  183. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/exec_pb2.pyi +0 -0
  184. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/exec_pb2_grpc.py +0 -0
  185. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/exec_pb2_grpc.pyi +0 -0
  186. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/fab_pb2.py +0 -0
  187. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/fab_pb2.pyi +0 -0
  188. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/fab_pb2_grpc.py +0 -0
  189. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/fab_pb2_grpc.pyi +0 -0
  190. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/fleet_pb2.py +0 -0
  191. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/fleet_pb2.pyi +0 -0
  192. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/fleet_pb2_grpc.py +0 -0
  193. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/fleet_pb2_grpc.pyi +0 -0
  194. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/grpcadapter_pb2.py +0 -0
  195. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/grpcadapter_pb2.pyi +0 -0
  196. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/grpcadapter_pb2_grpc.py +0 -0
  197. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/grpcadapter_pb2_grpc.pyi +0 -0
  198. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/heartbeat_pb2.py +0 -0
  199. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/heartbeat_pb2.pyi +0 -0
  200. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/heartbeat_pb2_grpc.py +0 -0
  201. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/heartbeat_pb2_grpc.pyi +0 -0
  202. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/log_pb2.py +0 -0
  203. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/log_pb2.pyi +0 -0
  204. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/log_pb2_grpc.py +0 -0
  205. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/log_pb2_grpc.pyi +0 -0
  206. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/message_pb2.py +0 -0
  207. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/message_pb2.pyi +0 -0
  208. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/message_pb2_grpc.py +0 -0
  209. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/message_pb2_grpc.pyi +0 -0
  210. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/node_pb2.py +0 -0
  211. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/node_pb2.pyi +0 -0
  212. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/node_pb2_grpc.py +0 -0
  213. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/node_pb2_grpc.pyi +0 -0
  214. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/recorddict_pb2.py +0 -0
  215. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/recorddict_pb2.pyi +0 -0
  216. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/recorddict_pb2_grpc.py +0 -0
  217. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/recorddict_pb2_grpc.pyi +0 -0
  218. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/run_pb2.py +0 -0
  219. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/run_pb2.pyi +0 -0
  220. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/run_pb2_grpc.py +0 -0
  221. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/run_pb2_grpc.pyi +0 -0
  222. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/serverappio_pb2.py +0 -0
  223. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/serverappio_pb2.pyi +0 -0
  224. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/serverappio_pb2_grpc.py +0 -0
  225. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/serverappio_pb2_grpc.pyi +0 -0
  226. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/simulationio_pb2.py +0 -0
  227. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/simulationio_pb2.pyi +0 -0
  228. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/simulationio_pb2_grpc.py +0 -0
  229. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/simulationio_pb2_grpc.pyi +0 -0
  230. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/transport_pb2.py +0 -0
  231. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/transport_pb2.pyi +0 -0
  232. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/transport_pb2_grpc.py +0 -0
  233. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
  234. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/py.typed +0 -0
  235. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/__init__.py +0 -0
  236. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/app.py +0 -0
  237. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/client_manager.py +0 -0
  238. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/client_proxy.py +0 -0
  239. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/compat/__init__.py +0 -0
  240. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/compat/app.py +0 -0
  241. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/compat/app_utils.py +0 -0
  242. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/compat/grid_client_proxy.py +0 -0
  243. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/compat/legacy_context.py +0 -0
  244. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/criterion.py +0 -0
  245. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/fleet_event_log_interceptor.py +0 -0
  246. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/grid/__init__.py +0 -0
  247. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/grid/grid.py +0 -0
  248. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/grid/inmemory_grid.py +0 -0
  249. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/history.py +0 -0
  250. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/run_serverapp.py +0 -0
  251. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/server.py +0 -0
  252. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/server_app.py +0 -0
  253. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/server_config.py +0 -0
  254. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/serverapp/__init__.py +0 -0
  255. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/serverapp/app.py +0 -0
  256. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/serverapp_components.py +0 -0
  257. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/__init__.py +0 -0
  258. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/aggregate.py +0 -0
  259. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/bulyan.py +0 -0
  260. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
  261. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
  262. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
  263. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
  264. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
  265. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedadagrad.py +0 -0
  266. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedadam.py +0 -0
  267. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedavg.py +0 -0
  268. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedavg_android.py +0 -0
  269. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedavgm.py +0 -0
  270. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedmedian.py +0 -0
  271. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedopt.py +0 -0
  272. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedprox.py +0 -0
  273. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
  274. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
  275. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
  276. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
  277. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/fedyogi.py +0 -0
  278. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/krum.py +0 -0
  279. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/qfedavg.py +0 -0
  280. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/strategy/strategy.py +0 -0
  281. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/__init__.py +0 -0
  282. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/ffs/__init__.py +0 -0
  283. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/ffs/disk_ffs.py +0 -0
  284. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/ffs/ffs.py +0 -0
  285. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/ffs/ffs_factory.py +0 -0
  286. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/__init__.py +0 -0
  287. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/grpc_adapter/__init__.py +0 -0
  288. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +0 -0
  289. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
  290. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
  291. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
  292. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
  293. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +0 -0
  294. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
  295. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +0 -0
  296. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +0 -0
  297. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
  298. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/message_handler/message_handler.py +0 -0
  299. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
  300. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +0 -0
  301. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
  302. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
  303. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
  304. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +0 -0
  305. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/fleet/vce/vce_api.py +0 -0
  306. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/linkstate/__init__.py +0 -0
  307. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/linkstate/in_memory_linkstate.py +0 -0
  308. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/linkstate/linkstate.py +0 -0
  309. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/linkstate/linkstate_factory.py +0 -0
  310. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/linkstate/sqlite_linkstate.py +0 -0
  311. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/linkstate/utils.py +0 -0
  312. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/serverappio/__init__.py +0 -0
  313. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/serverappio/serverappio_grpc.py +0 -0
  314. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/simulation/__init__.py +0 -0
  315. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/simulation/simulationio_grpc.py +0 -0
  316. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/simulation/simulationio_servicer.py +0 -0
  317. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/superlink/utils.py +0 -0
  318. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/typing.py +0 -0
  319. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/utils/__init__.py +0 -0
  320. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/utils/tensorboard.py +0 -0
  321. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/utils/validator.py +0 -0
  322. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/workflow/__init__.py +0 -0
  323. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/workflow/constant.py +0 -0
  324. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/workflow/default_workflows.py +0 -0
  325. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
  326. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
  327. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +0 -0
  328. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/serverapp/__init__.py +0 -0
  329. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/simulation/__init__.py +0 -0
  330. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/simulation/app.py +0 -0
  331. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/simulation/legacy_app.py +0 -0
  332. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/simulation/ray_transport/__init__.py +0 -0
  333. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/simulation/ray_transport/ray_actor.py +0 -0
  334. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
  335. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/simulation/ray_transport/utils.py +0 -0
  336. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/simulation/run_simulation.py +0 -0
  337. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/simulation/simulationio_connection.py +0 -0
  338. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supercore/__init__.py +0 -0
  339. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supercore/object_store/__init__.py +0 -0
  340. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supercore/object_store/in_memory_object_store.py +0 -0
  341. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supercore/object_store/object_store.py +0 -0
  342. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supercore/object_store/object_store_factory.py +0 -0
  343. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/superexec/__init__.py +0 -0
  344. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/superexec/app.py +0 -0
  345. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/superexec/deployment.py +0 -0
  346. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/superexec/exec_event_log_interceptor.py +0 -0
  347. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/superexec/exec_grpc.py +0 -0
  348. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/superexec/exec_servicer.py +0 -0
  349. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/superexec/exec_user_auth_interceptor.py +0 -0
  350. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/superexec/executor.py +0 -0
  351. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/superexec/simulation.py +0 -0
  352. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/superlink/__init__.py +0 -0
  353. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/__init__.py +0 -0
  354. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/cli/__init__.py +0 -0
  355. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/cli/flower_supernode.py +0 -0
  356. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/cli/flwr_clientapp.py +0 -0
  357. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/nodestate/__init__.py +0 -0
  358. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/nodestate/nodestate_factory.py +0 -0
  359. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/runtime/__init__.py +0 -0
  360. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/runtime/run_clientapp.py +0 -0
  361. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/servicer/__init__.py +0 -0
  362. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/servicer/clientappio/__init__.py +0 -0
  363. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/servicer/clientappio/clientappio_servicer.py +0 -0
  364. {flwr_nightly-1.19.0.dev20250605 → flwr_nightly-1.19.0.dev20250607}/py/flwr/supernode/start_client_internal.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flwr-nightly
3
- Version: 1.19.0.dev20250605
3
+ Version: 1.19.0.dev20250607
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  License: Apache-2.0
6
6
  Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
@@ -30,16 +30,16 @@ from flwr.common import GRPC_MAX_MESSAGE_LENGTH
30
30
  from flwr.common.constant import HEARTBEAT_CALL_TIMEOUT, HEARTBEAT_DEFAULT_INTERVAL
31
31
  from flwr.common.grpc import create_channel, on_channel_state_change
32
32
  from flwr.common.heartbeat import HeartbeatSender
33
+ from flwr.common.inflatable import get_all_nested_objects
33
34
  from flwr.common.inflatable_grpc_utils import (
34
- pull_object_from_servicer,
35
- push_object_to_servicer,
35
+ inflate_object_from_contents,
36
+ make_pull_object_fn_grpc,
37
+ make_push_object_fn_grpc,
38
+ pull_objects,
39
+ push_objects,
36
40
  )
37
41
  from flwr.common.logger import log
38
- from flwr.common.message import (
39
- Message,
40
- get_message_to_descendant_id_mapping,
41
- remove_content_from_message,
42
- )
42
+ from flwr.common.message import Message, remove_content_from_message
43
43
  from flwr.common.retry_invoker import RetryInvoker, _wrap_stub
44
44
  from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
45
45
  generate_key_pairs,
@@ -60,6 +60,7 @@ from flwr.proto.heartbeat_pb2 import ( # pylint: disable=E0611
60
60
  SendNodeHeartbeatRequest,
61
61
  SendNodeHeartbeatResponse,
62
62
  )
63
+ from flwr.proto.message_pb2 import ObjectIDs # pylint: disable=E0611
63
64
  from flwr.proto.node_pb2 import Node # pylint: disable=E0611
64
65
  from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
65
66
 
@@ -265,21 +266,21 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
265
266
  in_message: Optional[Message] = None
266
267
 
267
268
  if message_proto:
268
- in_message = cast(
269
- Message,
270
- pull_object_from_servicer(
271
- object_id=message_proto.metadata.message_id,
272
- stub=stub,
269
+ msg_id = message_proto.metadata.message_id
270
+ all_object_contents = pull_objects(
271
+ list(response.objects_to_pull[msg_id].object_ids) + [msg_id],
272
+ pull_object_fn=make_pull_object_fn_grpc(
273
+ pull_object_grpc=stub.PullObject,
273
274
  node=node,
274
275
  run_id=message_proto.metadata.run_id,
275
276
  ),
276
277
  )
277
-
278
- if in_message:
278
+ in_message = cast(
279
+ Message, inflate_object_from_contents(msg_id, all_object_contents)
280
+ )
279
281
  # The deflated message doesn't contain the message_id (its own object_id)
280
282
  # Inject
281
- # pylint: disable-next=W0212
282
- in_message.metadata._message_id = message_proto.metadata.message_id # type: ignore
283
+ in_message.metadata.__dict__["_message_id"] = msg_id
283
284
 
284
285
  # Remember `metadata` of the in message
285
286
  nonlocal metadata
@@ -308,23 +309,30 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
308
309
  log(ERROR, "Invalid out message")
309
310
  return
310
311
 
312
+ # Get all nested objects
313
+ all_objects = get_all_nested_objects(message)
314
+ all_object_ids = list(all_objects.keys())
315
+ msg_id = all_object_ids[-1] # Last object is the message itself
316
+ descendant_ids = all_object_ids[:-1] # All but the last object are descendants
317
+
311
318
  # Serialize Message
312
319
  message_proto = message_to_proto(message=remove_content_from_message(message))
313
- descendants_mapping = get_message_to_descendant_id_mapping(message)
314
320
  request = PushMessagesRequest(
315
321
  node=node,
316
322
  messages_list=[message_proto],
317
- msg_to_descendant_mapping=descendants_mapping,
323
+ msg_to_descendant_mapping={msg_id: ObjectIDs(object_ids=descendant_ids)},
318
324
  )
319
325
  response: PushMessagesResponse = stub.PushMessages(request=request)
320
326
 
321
327
  if response.objects_to_push:
322
328
  objs_to_push = set(response.objects_to_push[message.object_id].object_ids)
323
- push_object_to_servicer(
324
- message,
325
- stub,
326
- node,
327
- run_id=message.metadata.run_id,
329
+ push_objects(
330
+ all_objects,
331
+ push_object_fn=make_push_object_fn_grpc(
332
+ push_object_grpc=stub.PushObject,
333
+ node=node,
334
+ run_id=message.metadata.run_id,
335
+ ),
328
336
  object_ids_to_push=objs_to_push,
329
337
  )
330
338
  log(DEBUG, "Pushed %s objects to servicer.", len(objs_to_push))
@@ -138,6 +138,17 @@ HEAD_VALUE_DIVIDER = " "
138
138
  # Constants for serialization
139
139
  INT64_MAX_VALUE = 9223372036854775807 # (1 << 63) - 1
140
140
 
141
+ # Constants for `flwr-serverapp` and `flwr-clientapp` CLI commands
142
+ FLWR_APP_TOKEN_LENGTH = 128 # Length of the token used
143
+
144
+ # Constants for object pushing and pulling
145
+ MAX_CONCURRENT_PUSHES = 8 # Default maximum number of concurrent pushes
146
+ MAX_CONCURRENT_PULLS = 8 # Default maximum number of concurrent pulls
147
+ PULL_MAX_TIME = 7200 # Default maximum time to wait for pulling objects
148
+ PULL_MAX_TRIES_PER_OBJECT = 500 # Default maximum number of tries to pull an object
149
+ PULL_INITIAL_BACKOFF = 1 # Initial backoff time for pulling objects
150
+ PULL_BACKOFF_CAP = 10 # Maximum backoff time for pulling objects
151
+
141
152
 
142
153
  class MessageType:
143
154
  """Message type."""
@@ -25,6 +25,16 @@ from .constant import HEAD_BODY_DIVIDER, HEAD_VALUE_DIVIDER
25
25
  from .logger import log
26
26
 
27
27
 
28
+ class UnexpectedObjectContentError(Exception):
29
+ """Exception raised when the content of an object does not conform to the expected
30
+ structure for an InflatableObject (i.e., head, body, and values within the head)."""
31
+
32
+ def __init__(self, object_id: str, reason: str):
33
+ super().__init__(
34
+ f"Object with ID '{object_id}' has an unexpected structure. {reason}"
35
+ )
36
+
37
+
28
38
  class InflatableObject:
29
39
  """Base class for inflatable objects."""
30
40
 
@@ -117,12 +127,14 @@ def add_header_to_object_body(object_body: bytes, obj: InflatableObject) -> byte
117
127
 
118
128
  def _get_object_head(object_content: bytes) -> bytes:
119
129
  """Return object head from object content."""
120
- return object_content.split(HEAD_BODY_DIVIDER, 1)[0]
130
+ index = object_content.find(HEAD_BODY_DIVIDER)
131
+ return object_content[:index]
121
132
 
122
133
 
123
134
  def _get_object_body(object_content: bytes) -> bytes:
124
135
  """Return object body from object content."""
125
- return object_content.split(HEAD_BODY_DIVIDER, 1)[1]
136
+ index = object_content.find(HEAD_BODY_DIVIDER)
137
+ return object_content[index + len(HEAD_BODY_DIVIDER) :]
126
138
 
127
139
 
128
140
  def is_valid_sha256_hash(object_id: str) -> bool:
@@ -197,21 +209,25 @@ def get_object_head_values_from_object_content(
197
209
  return obj_type, children_ids, int(body_len)
198
210
 
199
211
 
200
- def _get_descendants_object_ids_recursively(obj: InflatableObject) -> set[str]:
212
+ def get_descendant_object_ids(obj: InflatableObject) -> set[str]:
213
+ """Get a set of object IDs of all descendants."""
214
+ descendants = set(get_all_nested_objects(obj).keys())
215
+ # Exclude Object ID of parent object
216
+ descendants.discard(obj.object_id)
217
+ return descendants
201
218
 
202
- descendants: set[str] = set()
203
- if children := obj.children:
204
- for child in children.values():
205
- descendants |= _get_descendants_object_ids_recursively(child)
206
219
 
207
- descendants.add(obj.object_id)
220
+ def get_all_nested_objects(obj: InflatableObject) -> dict[str, InflatableObject]:
221
+ """Get a dictionary of all nested objects, including the object itself.
208
222
 
209
- return descendants
223
+ Each key in the dictionary is an object ID, and the entries are ordered by post-
224
+ order traversal, i.e., child objects appear before their respective parents.
225
+ """
226
+ ret: dict[str, InflatableObject] = {}
227
+ if children := obj.children:
228
+ for child in children.values():
229
+ ret.update(get_all_nested_objects(child))
210
230
 
231
+ ret[obj.object_id] = obj
211
232
 
212
- def get_desdendant_object_ids(obj: InflatableObject) -> set[str]:
213
- """Get a set of object IDs of all descendants."""
214
- descendants = _get_descendants_object_ids_recursively(obj)
215
- # Exclude Object ID of parent object
216
- descendants.discard(obj.object_id)
217
- return descendants
233
+ return ret
@@ -0,0 +1,362 @@
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
+ """InflatableObject utils."""
16
+
17
+
18
+ import concurrent.futures
19
+ import random
20
+ import threading
21
+ import time
22
+ from typing import Callable, Optional
23
+
24
+ from flwr.proto.message_pb2 import ( # pylint: disable=E0611
25
+ PullObjectRequest,
26
+ PullObjectResponse,
27
+ PushObjectRequest,
28
+ PushObjectResponse,
29
+ )
30
+ from flwr.proto.node_pb2 import Node # pylint: disable=E0611
31
+
32
+ from .constant import (
33
+ MAX_CONCURRENT_PULLS,
34
+ MAX_CONCURRENT_PUSHES,
35
+ PULL_BACKOFF_CAP,
36
+ PULL_INITIAL_BACKOFF,
37
+ PULL_MAX_TIME,
38
+ PULL_MAX_TRIES_PER_OBJECT,
39
+ )
40
+ from .inflatable import InflatableObject, get_object_head_values_from_object_content
41
+ from .message import Message
42
+ from .record import Array, ArrayRecord, ConfigRecord, MetricRecord, RecordDict
43
+
44
+ # Helper registry that maps names of classes to their type
45
+ inflatable_class_registry: dict[str, type[InflatableObject]] = {
46
+ Array.__qualname__: Array,
47
+ ArrayRecord.__qualname__: ArrayRecord,
48
+ ConfigRecord.__qualname__: ConfigRecord,
49
+ Message.__qualname__: Message,
50
+ MetricRecord.__qualname__: MetricRecord,
51
+ RecordDict.__qualname__: RecordDict,
52
+ }
53
+
54
+
55
+ class ObjectUnavailableError(Exception):
56
+ """Exception raised when an object has been pre-registered but is not yet
57
+ available."""
58
+
59
+ def __init__(self, object_id: str):
60
+ super().__init__(f"Object with ID '{object_id}' is not yet available.")
61
+
62
+
63
+ class ObjectIdNotPreregisteredError(Exception):
64
+ """Exception raised when an object ID is not pre-registered."""
65
+
66
+ def __init__(self, object_id: str):
67
+ super().__init__(f"Object with ID '{object_id}' could not be found.")
68
+
69
+
70
+ def make_pull_object_fn_grpc(
71
+ pull_object_grpc: Callable[[PullObjectRequest], PullObjectResponse],
72
+ node: Node,
73
+ run_id: int,
74
+ ) -> Callable[[str], bytes]:
75
+ """Create a pull object function that uses gRPC to pull objects.
76
+
77
+ Parameters
78
+ ----------
79
+ pull_object_grpc : Callable[[PullObjectRequest], PullObjectResponse]
80
+ The gRPC function to pull objects, e.g., `FleetStub.PullObject`.
81
+ node : Node
82
+ The node making the request.
83
+ run_id : int
84
+ The run ID for the current operation.
85
+
86
+ Returns
87
+ -------
88
+ Callable[[str], bytes]
89
+ A function that takes an object ID and returns the object content as bytes.
90
+ The function raises `ObjectIdNotPreregisteredError` if the object ID is not
91
+ pre-registered, or `ObjectUnavailableError` if the object is not yet available.
92
+ """
93
+
94
+ def pull_object_fn(object_id: str) -> bytes:
95
+ request = PullObjectRequest(node=node, run_id=run_id, object_id=object_id)
96
+ response: PullObjectResponse = pull_object_grpc(request)
97
+ if not response.object_found:
98
+ raise ObjectIdNotPreregisteredError(object_id)
99
+ if not response.object_available:
100
+ raise ObjectUnavailableError(object_id)
101
+ return response.object_content
102
+
103
+ return pull_object_fn
104
+
105
+
106
+ def make_push_object_fn_grpc(
107
+ push_object_grpc: Callable[[PushObjectRequest], PushObjectResponse],
108
+ node: Node,
109
+ run_id: int,
110
+ ) -> Callable[[str, bytes], None]:
111
+ """Create a push object function that uses gRPC to push objects.
112
+
113
+ Parameters
114
+ ----------
115
+ push_object_grpc : Callable[[PushObjectRequest], PushObjectResponse]
116
+ The gRPC function to push objects, e.g., `FleetStub.PushObject`.
117
+ node : Node
118
+ The node making the request.
119
+ run_id : int
120
+ The run ID for the current operation.
121
+
122
+ Returns
123
+ -------
124
+ Callable[[str, bytes], None]
125
+ A function that takes an object ID and its content as bytes, and pushes it
126
+ to the servicer. The function raises `ObjectIdNotPreregisteredError` if
127
+ the object ID is not pre-registered.
128
+ """
129
+
130
+ def push_object_fn(object_id: str, object_content: bytes) -> None:
131
+ request = PushObjectRequest(
132
+ node=node, run_id=run_id, object_id=object_id, object_content=object_content
133
+ )
134
+ response: PushObjectResponse = push_object_grpc(request)
135
+ if not response.stored:
136
+ raise ObjectIdNotPreregisteredError(object_id)
137
+
138
+ return push_object_fn
139
+
140
+
141
+ def push_objects(
142
+ objects: dict[str, InflatableObject],
143
+ push_object_fn: Callable[[str, bytes], None],
144
+ *,
145
+ object_ids_to_push: Optional[set[str]] = None,
146
+ keep_objects: bool = False,
147
+ max_concurrent_pushes: int = MAX_CONCURRENT_PUSHES,
148
+ ) -> None:
149
+ """Push multiple objects to the servicer.
150
+
151
+ Parameters
152
+ ----------
153
+ objects : dict[str, InflatableObject]
154
+ A dictionary of objects to push, where keys are object IDs and values are
155
+ `InflatableObject` instances.
156
+ push_object_fn : Callable[[str, bytes], None]
157
+ A function that takes an object ID and its content as bytes, and pushes
158
+ it to the servicer. This function should raise `ObjectIdNotPreregisteredError`
159
+ if the object ID is not pre-registered.
160
+ object_ids_to_push : Optional[set[str]] (default: None)
161
+ A set of object IDs to push. If not provided, all objects will be pushed.
162
+ keep_objects : bool (default: False)
163
+ If `True`, the original objects will be kept in the `objects` dictionary
164
+ after pushing. If `False`, they will be removed from the dictionary to avoid
165
+ high memory usage.
166
+ max_concurrent_pushes : int (default: MAX_CONCURRENT_PUSHES)
167
+ The maximum number of concurrent pushes to perform.
168
+ """
169
+ if object_ids_to_push is not None:
170
+ # Filter objects to push only those with IDs in the set
171
+ objects = {k: v for k, v in objects.items() if k in object_ids_to_push}
172
+
173
+ lock = threading.Lock()
174
+
175
+ def push(obj_id: str) -> None:
176
+ """Push a single object."""
177
+ object_content = objects[obj_id].deflate()
178
+ if not keep_objects:
179
+ with lock:
180
+ del objects[obj_id]
181
+ push_object_fn(obj_id, object_content)
182
+
183
+ with concurrent.futures.ThreadPoolExecutor(
184
+ max_workers=max_concurrent_pushes
185
+ ) as executor:
186
+ list(executor.map(push, list(objects.keys())))
187
+
188
+
189
+ def pull_objects( # pylint: disable=too-many-arguments
190
+ object_ids: list[str],
191
+ pull_object_fn: Callable[[str], bytes],
192
+ *,
193
+ max_concurrent_pulls: int = MAX_CONCURRENT_PULLS,
194
+ max_time: Optional[float] = PULL_MAX_TIME,
195
+ max_tries_per_object: Optional[int] = PULL_MAX_TRIES_PER_OBJECT,
196
+ initial_backoff: float = PULL_INITIAL_BACKOFF,
197
+ backoff_cap: float = PULL_BACKOFF_CAP,
198
+ ) -> dict[str, bytes]:
199
+ """Pull multiple objects from the servicer.
200
+
201
+ Parameters
202
+ ----------
203
+ object_ids : list[str]
204
+ A list of object IDs to pull.
205
+ pull_object_fn : Callable[[str], bytes]
206
+ A function that takes an object ID and returns the object content as bytes.
207
+ The function should raise `ObjectUnavailableError` if the object is not yet
208
+ available, or `ObjectIdNotPreregisteredError` if the object ID is not
209
+ pre-registered.
210
+ max_concurrent_pulls : int (default: MAX_CONCURRENT_PULLS)
211
+ The maximum number of concurrent pulls to perform.
212
+ max_time : Optional[float] (default: PULL_MAX_TIME)
213
+ The maximum time to wait for all pulls to complete. If `None`, waits
214
+ indefinitely.
215
+ max_tries_per_object : Optional[int] (default: PULL_MAX_TRIES_PER_OBJECT)
216
+ The maximum number of attempts to pull each object. If `None`, pulls
217
+ indefinitely until the object is available.
218
+ initial_backoff : float (default: PULL_INITIAL_BACKOFF)
219
+ The initial backoff time in seconds for retrying pulls after an
220
+ `ObjectUnavailableError`.
221
+ backoff_cap : float (default: PULL_BACKOFF_CAP)
222
+ The maximum backoff time in seconds. Backoff times will not exceed this value.
223
+
224
+ Returns
225
+ -------
226
+ dict[str, bytes]
227
+ A dictionary where keys are object IDs and values are the pulled
228
+ object contents.
229
+ """
230
+ if max_tries_per_object is None:
231
+ max_tries_per_object = int(1e9)
232
+ if max_time is None:
233
+ max_time = float("inf")
234
+
235
+ results: dict[str, bytes] = {}
236
+ results_lock = threading.Lock()
237
+ err_to_raise: Optional[Exception] = None
238
+ early_stop = threading.Event()
239
+ start = time.monotonic()
240
+
241
+ def pull_with_retries(object_id: str) -> None:
242
+ """Attempt to pull a single object with retry and backoff."""
243
+ nonlocal err_to_raise
244
+ tries = 0
245
+ delay = initial_backoff
246
+
247
+ while not early_stop.is_set():
248
+ try:
249
+ object_content = pull_object_fn(object_id)
250
+ with results_lock:
251
+ results[object_id] = object_content
252
+ return
253
+
254
+ except ObjectUnavailableError as err:
255
+ tries += 1
256
+ if (
257
+ tries >= max_tries_per_object
258
+ or time.monotonic() - start >= max_time
259
+ ):
260
+ # Stop all work if one object exhausts retries
261
+ early_stop.set()
262
+ with results_lock:
263
+ if err_to_raise is None:
264
+ err_to_raise = err
265
+ return
266
+
267
+ # Apply exponential backoff with ±20% jitter
268
+ sleep_time = delay * (1 + random.uniform(-0.2, 0.2))
269
+ early_stop.wait(sleep_time)
270
+ delay = min(delay * 2, backoff_cap)
271
+
272
+ except ObjectIdNotPreregisteredError as err:
273
+ # Permanent failure: object ID is invalid
274
+ early_stop.set()
275
+ with results_lock:
276
+ if err_to_raise is None:
277
+ err_to_raise = err
278
+ return
279
+
280
+ # Submit all pull tasks concurrently
281
+ with concurrent.futures.ThreadPoolExecutor(
282
+ max_workers=max_concurrent_pulls
283
+ ) as executor:
284
+ futures = {
285
+ executor.submit(pull_with_retries, obj_id): obj_id for obj_id in object_ids
286
+ }
287
+
288
+ # Wait for completion
289
+ concurrent.futures.wait(futures)
290
+
291
+ if err_to_raise is not None:
292
+ raise err_to_raise
293
+
294
+ return results
295
+
296
+
297
+ def inflate_object_from_contents(
298
+ object_id: str,
299
+ object_contents: dict[str, bytes],
300
+ *,
301
+ keep_object_contents: bool = False,
302
+ objects: Optional[dict[str, InflatableObject]] = None,
303
+ ) -> InflatableObject:
304
+ """Inflate an object from object contents.
305
+
306
+ Parameters
307
+ ----------
308
+ object_id : str
309
+ The ID of the object to inflate.
310
+ object_contents : dict[str, bytes]
311
+ A dictionary mapping object IDs to their contents as bytes.
312
+ All descendant objects must be present in this dictionary.
313
+ keep_object_contents : bool (default: False)
314
+ If `True`, the object content will be kept in the `object_contents`
315
+ dictionary after inflation. If `False`, the object content will be
316
+ removed from the dictionary to save memory.
317
+ objects : Optional[dict[str, InflatableObject]] (default: None)
318
+ No need to provide this parameter. A dictionary to store already
319
+ inflated objects, mapping object IDs to their corresponding
320
+ `InflatableObject` instances.
321
+
322
+ Returns
323
+ -------
324
+ InflatableObject
325
+ The inflated object.
326
+ """
327
+ if objects is None:
328
+ # Initialize objects dictionary
329
+ objects = {}
330
+
331
+ if object_id in objects:
332
+ # If the object is already in the objects dictionary, return it
333
+ return objects[object_id]
334
+
335
+ # Extract object class and object_ids of children
336
+ object_content = object_contents[object_id]
337
+ obj_type, children_obj_ids, _ = get_object_head_values_from_object_content(
338
+ object_content=object_contents[object_id]
339
+ )
340
+
341
+ # Remove the object content from the dictionary to save memory
342
+ if not keep_object_contents:
343
+ del object_contents[object_id]
344
+
345
+ # Resolve object class
346
+ cls_type = inflatable_class_registry[obj_type]
347
+
348
+ # Inflate all children objects
349
+ children: dict[str, InflatableObject] = {}
350
+ for child_obj_id in children_obj_ids:
351
+ children[child_obj_id] = inflate_object_from_contents(
352
+ child_obj_id,
353
+ object_contents,
354
+ keep_object_contents=keep_object_contents,
355
+ objects=objects,
356
+ )
357
+
358
+ # Inflate object passing its children
359
+ obj = cls_type.inflate(object_content, children=children)
360
+ del object_content # Free memory after inflation
361
+ objects[object_id] = obj
362
+ return obj
@@ -0,0 +1,75 @@
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
+ """InflatableObject utilities."""
16
+
17
+
18
+ from .constant import HEAD_BODY_DIVIDER, HEAD_VALUE_DIVIDER
19
+ from .inflatable import (
20
+ UnexpectedObjectContentError,
21
+ _get_object_head,
22
+ get_object_id,
23
+ is_valid_sha256_hash,
24
+ )
25
+ from .inflatable_grpc_utils import inflatable_class_registry
26
+
27
+
28
+ def validate_object_content(content: bytes) -> None:
29
+ """Validate the deflated content of an InflatableObject."""
30
+ try:
31
+ # Check if there is a head-body divider
32
+ index = content.find(HEAD_BODY_DIVIDER)
33
+ if index == -1:
34
+ raise ValueError(
35
+ "Unexpected format for object content. Head and body "
36
+ "could not be split."
37
+ )
38
+
39
+ head = _get_object_head(content)
40
+
41
+ # check if the head has three parts:
42
+ # <object_type> <children_ids> <object_body_len>
43
+ head_decoded = head.decode(encoding="utf-8")
44
+ head_parts = head_decoded.split(HEAD_VALUE_DIVIDER)
45
+
46
+ if len(head_parts) != 3:
47
+ raise ValueError("Unexpected format for object head.")
48
+
49
+ obj_type, children_str, body_len = head_parts
50
+
51
+ # Check that children IDs are valid IDs
52
+ children = children_str.split(",")
53
+ for children_id in children:
54
+ if children_id and not is_valid_sha256_hash(children_id):
55
+ raise ValueError(
56
+ f"Detected invalid object ID ({children_id}) in children."
57
+ )
58
+
59
+ # Check that object type is recognized
60
+ if obj_type not in inflatable_class_registry:
61
+ if obj_type != "CustomDataClass": # to allow for the class in tests
62
+ raise ValueError(f"Object of type {obj_type} is not supported.")
63
+
64
+ # Check if the body length in the head matches that of the body
65
+ actual_body_len = len(content) - len(head) - len(HEAD_BODY_DIVIDER)
66
+ if actual_body_len != int(body_len):
67
+ raise ValueError(
68
+ f"Object content length expected {body_len} bytes but got "
69
+ f"{actual_body_len} bytes."
70
+ )
71
+
72
+ except ValueError as err:
73
+ raise UnexpectedObjectContentError(
74
+ object_id=get_object_id(content), reason=str(err)
75
+ ) from err
@@ -32,7 +32,7 @@ from .constant import MESSAGE_TTL_TOLERANCE
32
32
  from .inflatable import (
33
33
  InflatableObject,
34
34
  add_header_to_object_body,
35
- get_desdendant_object_ids,
35
+ get_descendant_object_ids,
36
36
  get_object_body,
37
37
  get_object_children_ids_from_object_content,
38
38
  )
@@ -524,6 +524,6 @@ def get_message_to_descendant_id_mapping(message: Message) -> dict[str, ObjectID
524
524
  """Construct a mapping between message object_id and that of its descendants."""
525
525
  return {
526
526
  message.object_id: ObjectIDs(
527
- object_ids=list(get_desdendant_object_ids(message))
527
+ object_ids=list(get_descendant_object_ids(message))
528
528
  )
529
529
  }