flwr-nightly 1.8.0.dev20240401__tar.gz → 1.9.0.dev20240403__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.

Potentially problematic release.


This version of flwr-nightly might be problematic. Click here for more details.

Files changed (213) hide show
  1. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/PKG-INFO +1 -1
  2. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/pyproject.toml +1 -1
  3. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +1 -1
  4. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/requirements.pytorch.txt.tpl +1 -1
  5. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/app.py +24 -9
  6. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/client_app.py +9 -0
  7. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/grpc_rere_client/connection.py +1 -1
  8. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/rest_client/connection.py +1 -1
  9. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/constant.py +14 -0
  10. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/message.py +15 -0
  11. flwr_nightly-1.9.0.dev20240403/src/py/flwr/proto/fleet_pb2.py +54 -0
  12. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/fleet_pb2.pyi +5 -0
  13. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/driver/driver.py +15 -5
  14. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/message_handler/message_handler.py +1 -1
  15. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/vce/vce_api.py +14 -4
  16. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/state/in_memory_state.py +25 -8
  17. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/state/sqlite_state.py +53 -5
  18. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/state/state.py +1 -1
  19. flwr_nightly-1.9.0.dev20240403/src/py/flwr/server/superlink/state/utils.py +56 -0
  20. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/workflow/default_workflows.py +1 -4
  21. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +0 -5
  22. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/simulation/ray_transport/ray_actor.py +2 -22
  23. flwr_nightly-1.8.0.dev20240401/src/py/flwr/proto/fleet_pb2.py +0 -54
  24. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/LICENSE +0 -0
  25. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/README.md +0 -0
  26. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/__init__.py +0 -0
  27. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/__init__.py +0 -0
  28. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/app.py +0 -0
  29. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/example.py +0 -0
  30. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/flower_toml.py +0 -0
  31. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/__init__.py +0 -0
  32. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/new.py +0 -0
  33. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/__init__.py +0 -0
  34. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/README.md.tpl +0 -0
  35. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/__init__.py +0 -0
  36. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
  37. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
  38. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
  39. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
  40. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
  41. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
  42. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
  43. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
  44. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
  45. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/flower.toml.tpl +0 -0
  46. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +0 -0
  47. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +0 -0
  48. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/requirements.numpy.txt.tpl +0 -0
  49. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl +0 -0
  50. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/run/__init__.py +0 -0
  51. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/run/run.py +0 -0
  52. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/cli/utils.py +0 -0
  53. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/__init__.py +0 -0
  54. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/client.py +0 -0
  55. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/dpfedavg_numpy_client.py +0 -0
  56. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/grpc_client/__init__.py +0 -0
  57. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/grpc_client/connection.py +0 -0
  58. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/grpc_rere_client/__init__.py +0 -0
  59. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/heartbeat.py +0 -0
  60. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/message_handler/__init__.py +0 -0
  61. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/message_handler/message_handler.py +0 -0
  62. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/message_handler/task_handler.py +0 -0
  63. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/mod/__init__.py +0 -0
  64. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/mod/centraldp_mods.py +0 -0
  65. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/mod/comms_mods.py +0 -0
  66. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/mod/localdp_mod.py +0 -0
  67. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
  68. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
  69. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
  70. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/mod/utils.py +0 -0
  71. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/node_state.py +0 -0
  72. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/node_state_tests.py +0 -0
  73. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/numpy_client.py +0 -0
  74. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/rest_client/__init__.py +0 -0
  75. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/client/typing.py +0 -0
  76. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/__init__.py +0 -0
  77. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/address.py +0 -0
  78. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/context.py +0 -0
  79. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/date.py +0 -0
  80. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/differential_privacy.py +0 -0
  81. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/differential_privacy_constants.py +0 -0
  82. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/dp.py +0 -0
  83. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/exit_handlers.py +0 -0
  84. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/grpc.py +0 -0
  85. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/logger.py +0 -0
  86. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/object_ref.py +0 -0
  87. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/parameter.py +0 -0
  88. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/pyproject.py +0 -0
  89. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/record/__init__.py +0 -0
  90. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/record/configsrecord.py +0 -0
  91. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/record/conversion_utils.py +0 -0
  92. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/record/metricsrecord.py +0 -0
  93. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/record/parametersrecord.py +0 -0
  94. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/record/recordset.py +0 -0
  95. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/record/typeddict.py +0 -0
  96. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/recordset_compat.py +0 -0
  97. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/retry_invoker.py +0 -0
  98. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/secure_aggregation/__init__.py +0 -0
  99. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
  100. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
  101. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +0 -0
  102. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
  103. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/secure_aggregation/quantization.py +0 -0
  104. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
  105. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
  106. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/serde.py +0 -0
  107. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/telemetry.py +0 -0
  108. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/typing.py +0 -0
  109. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/common/version.py +0 -0
  110. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/__init__.py +0 -0
  111. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/driver_pb2.py +0 -0
  112. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/driver_pb2.pyi +0 -0
  113. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/driver_pb2_grpc.py +0 -0
  114. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/driver_pb2_grpc.pyi +0 -0
  115. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/error_pb2.py +0 -0
  116. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/error_pb2.pyi +0 -0
  117. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/error_pb2_grpc.py +0 -0
  118. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/error_pb2_grpc.pyi +0 -0
  119. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/fleet_pb2_grpc.py +0 -0
  120. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/fleet_pb2_grpc.pyi +0 -0
  121. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/node_pb2.py +0 -0
  122. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/node_pb2.pyi +0 -0
  123. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/node_pb2_grpc.py +0 -0
  124. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/node_pb2_grpc.pyi +0 -0
  125. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/recordset_pb2.py +0 -0
  126. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/recordset_pb2.pyi +0 -0
  127. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/recordset_pb2_grpc.py +0 -0
  128. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/recordset_pb2_grpc.pyi +0 -0
  129. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/task_pb2.py +0 -0
  130. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/task_pb2.pyi +0 -0
  131. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/task_pb2_grpc.py +0 -0
  132. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/task_pb2_grpc.pyi +0 -0
  133. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/transport_pb2.py +0 -0
  134. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/transport_pb2.pyi +0 -0
  135. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/transport_pb2_grpc.py +0 -0
  136. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
  137. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/py.typed +0 -0
  138. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/__init__.py +0 -0
  139. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/app.py +0 -0
  140. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/client_manager.py +0 -0
  141. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/client_proxy.py +0 -0
  142. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/compat/__init__.py +0 -0
  143. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/compat/app.py +0 -0
  144. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/compat/app_utils.py +0 -0
  145. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/compat/driver_client_proxy.py +0 -0
  146. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/compat/legacy_context.py +0 -0
  147. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/criterion.py +0 -0
  148. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/driver/__init__.py +0 -0
  149. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/driver/grpc_driver.py +0 -0
  150. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/history.py +0 -0
  151. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/run_serverapp.py +0 -0
  152. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/server.py +0 -0
  153. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/server_app.py +0 -0
  154. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/server_config.py +0 -0
  155. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/__init__.py +0 -0
  156. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/aggregate.py +0 -0
  157. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/bulyan.py +0 -0
  158. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
  159. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
  160. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
  161. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
  162. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
  163. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedadagrad.py +0 -0
  164. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedadam.py +0 -0
  165. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedavg.py +0 -0
  166. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedavg_android.py +0 -0
  167. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedavgm.py +0 -0
  168. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedmedian.py +0 -0
  169. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedopt.py +0 -0
  170. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedprox.py +0 -0
  171. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
  172. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
  173. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
  174. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
  175. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/fedyogi.py +0 -0
  176. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/krum.py +0 -0
  177. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/qfedavg.py +0 -0
  178. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/strategy/strategy.py +0 -0
  179. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/__init__.py +0 -0
  180. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/driver/__init__.py +0 -0
  181. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/driver/driver_grpc.py +0 -0
  182. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/driver/driver_servicer.py +0 -0
  183. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/__init__.py +0 -0
  184. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
  185. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
  186. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
  187. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
  188. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +0 -0
  189. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
  190. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +0 -0
  191. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
  192. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
  193. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +0 -0
  194. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
  195. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
  196. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
  197. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +0 -0
  198. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/state/__init__.py +0 -0
  199. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/superlink/state/state_factory.py +0 -0
  200. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/typing.py +0 -0
  201. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/utils/__init__.py +0 -0
  202. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/utils/tensorboard.py +0 -0
  203. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/utils/validator.py +0 -0
  204. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/workflow/__init__.py +0 -0
  205. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/workflow/constant.py +0 -0
  206. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
  207. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
  208. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/simulation/__init__.py +0 -0
  209. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/simulation/app.py +0 -0
  210. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/simulation/ray_transport/__init__.py +0 -0
  211. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
  212. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/simulation/ray_transport/utils.py +0 -0
  213. {flwr_nightly-1.8.0.dev20240401 → flwr_nightly-1.9.0.dev20240403}/src/py/flwr/simulation/run_simulation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.8.0.dev20240401
3
+ Version: 1.9.0.dev20240403
4
4
  Summary: Flower: A Friendly Federated Learning Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "flwr-nightly"
7
- version = "1.8.0-dev20240401"
7
+ version = "1.9.0-dev20240403"
8
8
  description = "Flower: A Friendly Federated Learning Framework"
9
9
  license = "Apache-2.0"
10
10
  authors = ["The Flower Authors <hello@flower.ai>"]
@@ -15,7 +15,7 @@ readme = "README.md"
15
15
  [tool.poetry.dependencies]
16
16
  python = "^3.9"
17
17
  # Mandatory dependencies
18
- flwr-nightly = { version = "1.8.0.dev20240313", extras = ["simulation"] }
18
+ flwr = { version = "^1.8.0", extras = ["simulation"] }
19
19
  flwr-datasets = { version = "0.0.2", extras = ["vision"] }
20
20
  torch = "2.2.1"
21
21
  torchvision = "0.17.1"
@@ -1,4 +1,4 @@
1
- flwr-nightly[simulation]==1.8.0.dev20240313
1
+ flwr[simulation]>=1.8.0
2
2
  flwr-datasets[vision]==0.0.2
3
3
  torch==2.2.1
4
4
  torchvision==0.17.1
@@ -34,6 +34,7 @@ from flwr.common.constant import (
34
34
  TRANSPORT_TYPE_GRPC_RERE,
35
35
  TRANSPORT_TYPE_REST,
36
36
  TRANSPORT_TYPES,
37
+ ErrorCode,
37
38
  )
38
39
  from flwr.common.exit_handlers import register_exit_handlers
39
40
  from flwr.common.logger import log, warn_deprecated_feature
@@ -483,7 +484,7 @@ def _start_client_internal(
483
484
  # Create an error reply message that will never be used to prevent
484
485
  # the used-before-assignment linting error
485
486
  reply_message = message.create_error_reply(
486
- error=Error(code=0, reason="Unknown")
487
+ error=Error(code=ErrorCode.UNKNOWN, reason="Unknown")
487
488
  )
488
489
 
489
490
  # Handle app loading and task message
@@ -491,27 +492,41 @@ def _start_client_internal(
491
492
  # Load ClientApp instance
492
493
  client_app: ClientApp = load_client_app_fn()
493
494
 
495
+ # Execute ClientApp
494
496
  reply_message = client_app(message=message, context=context)
495
- # Update node state
496
- node_state.update_context(
497
- run_id=message.metadata.run_id,
498
- context=context,
499
- )
500
497
  except Exception as ex: # pylint: disable=broad-exception-caught
501
- log(ERROR, "ClientApp raised an exception", exc_info=ex)
502
498
 
503
499
  # Legacy grpc-bidi
504
500
  if transport in ["grpc-bidi", None]:
501
+ log(ERROR, "Client raised an exception.", exc_info=ex)
505
502
  # Raise exception, crash process
506
503
  raise ex
507
504
 
508
505
  # Don't update/change NodeState
509
506
 
510
- # Create error message
507
+ e_code = ErrorCode.CLIENT_APP_RAISED_EXCEPTION
511
508
  # Reason example: "<class 'ZeroDivisionError'>:<'division by zero'>"
512
509
  reason = str(type(ex)) + ":<'" + str(ex) + "'>"
510
+ exc_entity = "ClientApp"
511
+ if isinstance(ex, LoadClientAppError):
512
+ reason = (
513
+ "An exception was raised when attempting to load "
514
+ "`ClientApp`"
515
+ )
516
+ e_code = ErrorCode.LOAD_CLIENT_APP_EXCEPTION
517
+ exc_entity = "SuperNode"
518
+
519
+ log(ERROR, "%s raised an exception", exc_entity, exc_info=ex)
520
+
521
+ # Create error message
513
522
  reply_message = message.create_error_reply(
514
- error=Error(code=0, reason=reason)
523
+ error=Error(code=e_code, reason=reason)
524
+ )
525
+ else:
526
+ # No exception, update node state
527
+ node_state.update_context(
528
+ run_id=message.metadata.run_id,
529
+ context=context,
515
530
  )
516
531
 
517
532
  # Send
@@ -28,6 +28,15 @@ from flwr.common.logger import warn_preview_feature
28
28
  from .typing import ClientAppCallable
29
29
 
30
30
 
31
+ class ClientAppException(Exception):
32
+ """Exception raised when an exception is raised while executing a ClientApp."""
33
+
34
+ def __init__(self, message: str):
35
+ ex_name = self.__class__.__name__
36
+ self.message = f"\nException {ex_name} occurred. Message: " + message
37
+ super().__init__(self.message)
38
+
39
+
31
40
  class ClientApp:
32
41
  """Flower ClientApp.
33
42
 
@@ -151,7 +151,7 @@ def grpc_request_response( # pylint: disable=R0914, R0915
151
151
  def create_node() -> None:
152
152
  """Set create_node."""
153
153
  # Call FleetAPI
154
- create_node_request = CreateNodeRequest()
154
+ create_node_request = CreateNodeRequest(ping_interval=PING_DEFAULT_INTERVAL)
155
155
  create_node_response = retry_invoker.invoke(
156
156
  stub.CreateNode,
157
157
  request=create_node_request,
@@ -201,7 +201,7 @@ def http_request_response( # pylint: disable=R0914, R0915
201
201
 
202
202
  def create_node() -> None:
203
203
  """Set create_node."""
204
- create_node_req_proto = CreateNodeRequest()
204
+ create_node_req_proto = CreateNodeRequest(ping_interval=PING_DEFAULT_INTERVAL)
205
205
  create_node_req_bytes: bytes = create_node_req_proto.SerializeToString()
206
206
 
207
207
  res = retry_invoker.invoke(
@@ -41,6 +41,7 @@ PING_DEFAULT_INTERVAL = 30
41
41
  PING_CALL_TIMEOUT = 5
42
42
  PING_BASE_MULTIPLIER = 0.8
43
43
  PING_RANDOM_RANGE = (-0.1, 0.1)
44
+ PING_MAX_INTERVAL = 1e300
44
45
 
45
46
 
46
47
  class MessageType:
@@ -74,3 +75,16 @@ class SType:
74
75
  def __new__(cls) -> SType:
75
76
  """Prevent instantiation."""
76
77
  raise TypeError(f"{cls.__name__} cannot be instantiated.")
78
+
79
+
80
+ class ErrorCode:
81
+ """Error codes for Message's Error."""
82
+
83
+ UNKNOWN = 0
84
+ LOAD_CLIENT_APP_EXCEPTION = 1
85
+ CLIENT_APP_RAISED_EXCEPTION = 2
86
+ NODE_UNAVAILABLE = 3
87
+
88
+ def __new__(cls) -> ErrorCode:
89
+ """Prevent instantiation."""
90
+ raise TypeError(f"{cls.__name__} cannot be instantiated.")
@@ -17,6 +17,7 @@
17
17
  from __future__ import annotations
18
18
 
19
19
  import time
20
+ import warnings
20
21
  from dataclasses import dataclass
21
22
 
22
23
  from .record import RecordSet
@@ -311,6 +312,13 @@ class Message:
311
312
 
312
313
  ttl = msg.meta.ttl - (reply.meta.created_at - msg.meta.created_at)
313
314
  """
315
+ if ttl:
316
+ warnings.warn(
317
+ "A custom TTL was set, but note that the SuperLink does not enforce "
318
+ "the TTL yet. The SuperLink will start enforcing the TTL in a future "
319
+ "version of Flower.",
320
+ stacklevel=2,
321
+ )
314
322
  # If no TTL passed, use default for message creation (will update after
315
323
  # message creation)
316
324
  ttl_ = DEFAULT_TTL if ttl is None else ttl
@@ -349,6 +357,13 @@ class Message:
349
357
  Message
350
358
  A new `Message` instance representing the reply.
351
359
  """
360
+ if ttl:
361
+ warnings.warn(
362
+ "A custom TTL was set, but note that the SuperLink does not enforce "
363
+ "the TTL yet. The SuperLink will start enforcing the TTL in a future "
364
+ "version of Flower.",
365
+ stacklevel=2,
366
+ )
352
367
  # If no TTL passed, use default for message creation (will update after
353
368
  # message creation)
354
369
  ttl_ = DEFAULT_TTL if ttl is None else ttl
@@ -0,0 +1,54 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: flwr/proto/fleet.proto
4
+ # Protobuf Python Version: 4.25.0
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+ from flwr.proto import node_pb2 as flwr_dot_proto_dot_node__pb2
16
+ from flwr.proto import task_pb2 as flwr_dot_proto_dot_task__pb2
17
+
18
+
19
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x15\x66lwr/proto/task.proto\"*\n\x11\x43reateNodeRequest\x12\x15\n\rping_interval\x18\x01 \x01(\x01\"4\n\x12\x43reateNodeResponse\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"3\n\x11\x44\x65leteNodeRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"\x14\n\x12\x44\x65leteNodeResponse\"D\n\x0bPingRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x15\n\rping_interval\x18\x02 \x01(\x01\"\x1f\n\x0cPingResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"F\n\x12PullTaskInsRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x10\n\x08task_ids\x18\x02 \x03(\t\"k\n\x13PullTaskInsResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rtask_ins_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.TaskIns\"@\n\x12PushTaskResRequest\x12*\n\rtask_res_list\x18\x01 \x03(\x0b\x32\x13.flwr.proto.TaskRes\"\xae\x01\n\x13PushTaskResResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12=\n\x07results\x18\x02 \x03(\x0b\x32,.flwr.proto.PushTaskResResponse.ResultsEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\"\x1e\n\tReconnect\x12\x11\n\treconnect\x18\x01 \x01(\x04\x32\x86\x03\n\x05\x46leet\x12M\n\nCreateNode\x12\x1d.flwr.proto.CreateNodeRequest\x1a\x1e.flwr.proto.CreateNodeResponse\"\x00\x12M\n\nDeleteNode\x12\x1d.flwr.proto.DeleteNodeRequest\x1a\x1e.flwr.proto.DeleteNodeResponse\"\x00\x12;\n\x04Ping\x12\x17.flwr.proto.PingRequest\x1a\x18.flwr.proto.PingResponse\"\x00\x12P\n\x0bPullTaskIns\x12\x1e.flwr.proto.PullTaskInsRequest\x1a\x1f.flwr.proto.PullTaskInsResponse\"\x00\x12P\n\x0bPushTaskRes\x12\x1e.flwr.proto.PushTaskResRequest\x1a\x1f.flwr.proto.PushTaskResResponse\"\x00\x62\x06proto3')
20
+
21
+ _globals = globals()
22
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
23
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.fleet_pb2', _globals)
24
+ if _descriptor._USE_C_DESCRIPTORS == False:
25
+ DESCRIPTOR._options = None
26
+ _globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._options = None
27
+ _globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._serialized_options = b'8\001'
28
+ _globals['_CREATENODEREQUEST']._serialized_start=84
29
+ _globals['_CREATENODEREQUEST']._serialized_end=126
30
+ _globals['_CREATENODERESPONSE']._serialized_start=128
31
+ _globals['_CREATENODERESPONSE']._serialized_end=180
32
+ _globals['_DELETENODEREQUEST']._serialized_start=182
33
+ _globals['_DELETENODEREQUEST']._serialized_end=233
34
+ _globals['_DELETENODERESPONSE']._serialized_start=235
35
+ _globals['_DELETENODERESPONSE']._serialized_end=255
36
+ _globals['_PINGREQUEST']._serialized_start=257
37
+ _globals['_PINGREQUEST']._serialized_end=325
38
+ _globals['_PINGRESPONSE']._serialized_start=327
39
+ _globals['_PINGRESPONSE']._serialized_end=358
40
+ _globals['_PULLTASKINSREQUEST']._serialized_start=360
41
+ _globals['_PULLTASKINSREQUEST']._serialized_end=430
42
+ _globals['_PULLTASKINSRESPONSE']._serialized_start=432
43
+ _globals['_PULLTASKINSRESPONSE']._serialized_end=539
44
+ _globals['_PUSHTASKRESREQUEST']._serialized_start=541
45
+ _globals['_PUSHTASKRESREQUEST']._serialized_end=605
46
+ _globals['_PUSHTASKRESRESPONSE']._serialized_start=608
47
+ _globals['_PUSHTASKRESRESPONSE']._serialized_end=782
48
+ _globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._serialized_start=736
49
+ _globals['_PUSHTASKRESRESPONSE_RESULTSENTRY']._serialized_end=782
50
+ _globals['_RECONNECT']._serialized_start=784
51
+ _globals['_RECONNECT']._serialized_end=814
52
+ _globals['_FLEET']._serialized_start=817
53
+ _globals['_FLEET']._serialized_end=1207
54
+ # @@protoc_insertion_point(module_scope)
@@ -16,8 +16,13 @@ DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
16
16
  class CreateNodeRequest(google.protobuf.message.Message):
17
17
  """CreateNode messages"""
18
18
  DESCRIPTOR: google.protobuf.descriptor.Descriptor
19
+ PING_INTERVAL_FIELD_NUMBER: builtins.int
20
+ ping_interval: builtins.float
19
21
  def __init__(self,
22
+ *,
23
+ ping_interval: builtins.float = ...,
20
24
  ) -> None: ...
25
+ def ClearField(self, field_name: typing_extensions.Literal["ping_interval",b"ping_interval"]) -> None: ...
21
26
  global___CreateNodeRequest = CreateNodeRequest
22
27
 
23
28
  class CreateNodeResponse(google.protobuf.message.Message):
@@ -14,8 +14,8 @@
14
14
  # ==============================================================================
15
15
  """Flower driver service client."""
16
16
 
17
-
18
17
  import time
18
+ import warnings
19
19
  from typing import Iterable, List, Optional, Tuple
20
20
 
21
21
  from flwr.common import DEFAULT_TTL, Message, Metadata, RecordSet
@@ -91,7 +91,7 @@ class Driver:
91
91
  message_type: str,
92
92
  dst_node_id: int,
93
93
  group_id: str,
94
- ttl: float = DEFAULT_TTL,
94
+ ttl: Optional[float] = None,
95
95
  ) -> Message:
96
96
  """Create a new message with specified parameters.
97
97
 
@@ -111,10 +111,11 @@ class Driver:
111
111
  group_id : str
112
112
  The ID of the group to which this message is associated. In some settings,
113
113
  this is used as the FL round.
114
- ttl : float (default: common.DEFAULT_TTL)
114
+ ttl : Optional[float] (default: None)
115
115
  Time-to-live for the round trip of this message, i.e., the time from sending
116
116
  this message to receiving a reply. It specifies in seconds the duration for
117
- which the message and its potential reply are considered valid.
117
+ which the message and its potential reply are considered valid. If unset,
118
+ the default TTL (i.e., `common.DEFAULT_TTL`) will be used.
118
119
 
119
120
  Returns
120
121
  -------
@@ -122,6 +123,15 @@ class Driver:
122
123
  A new `Message` instance with the specified content and metadata.
123
124
  """
124
125
  _, run_id = self._get_grpc_driver_and_run_id()
126
+ if ttl:
127
+ warnings.warn(
128
+ "A custom TTL was set, but note that the SuperLink does not enforce "
129
+ "the TTL yet. The SuperLink will start enforcing the TTL in a future "
130
+ "version of Flower.",
131
+ stacklevel=2,
132
+ )
133
+
134
+ ttl_ = DEFAULT_TTL if ttl is None else ttl
125
135
  metadata = Metadata(
126
136
  run_id=run_id,
127
137
  message_id="", # Will be set by the server
@@ -129,7 +139,7 @@ class Driver:
129
139
  dst_node_id=dst_node_id,
130
140
  reply_to_message="",
131
141
  group_id=group_id,
132
- ttl=ttl,
142
+ ttl=ttl_,
133
143
  message_type=message_type,
134
144
  )
135
145
  return Message(metadata=metadata, content=content)
@@ -43,7 +43,7 @@ def create_node(
43
43
  ) -> CreateNodeResponse:
44
44
  """."""
45
45
  # Create node
46
- node_id = state.create_node()
46
+ node_id = state.create_node(ping_interval=request.ping_interval)
47
47
  return CreateNodeResponse(node=Node(node_id=node_id, anonymous=False))
48
48
 
49
49
 
@@ -22,8 +22,9 @@ import traceback
22
22
  from logging import DEBUG, ERROR, INFO, WARN
23
23
  from typing import Callable, Dict, List, Optional
24
24
 
25
- from flwr.client.client_app import ClientApp, LoadClientAppError
25
+ from flwr.client.client_app import ClientApp, ClientAppException, LoadClientAppError
26
26
  from flwr.client.node_state import NodeState
27
+ from flwr.common.constant import PING_MAX_INTERVAL, ErrorCode
27
28
  from flwr.common.logger import log
28
29
  from flwr.common.message import Error
29
30
  from flwr.common.object_ref import load_app
@@ -43,7 +44,7 @@ def _register_nodes(
43
44
  nodes_mapping: NodeToPartitionMapping = {}
44
45
  state = state_factory.state()
45
46
  for i in range(num_nodes):
46
- node_id = state.create_node()
47
+ node_id = state.create_node(ping_interval=PING_MAX_INTERVAL)
47
48
  nodes_mapping[node_id] = i
48
49
  log(INFO, "Registered %i nodes", len(nodes_mapping))
49
50
  return nodes_mapping
@@ -93,9 +94,18 @@ async def worker(
93
94
  except Exception as ex: # pylint: disable=broad-exception-caught
94
95
  log(ERROR, ex)
95
96
  log(ERROR, traceback.format_exc())
97
+
98
+ if isinstance(ex, ClientAppException):
99
+ e_code = ErrorCode.CLIENT_APP_RAISED_EXCEPTION
100
+ elif isinstance(ex, LoadClientAppError):
101
+ e_code = ErrorCode.LOAD_CLIENT_APP_EXCEPTION
102
+ else:
103
+ e_code = ErrorCode.UNKNOWN
104
+
96
105
  reason = str(type(ex)) + ":<'" + str(ex) + "'>"
97
- error = Error(code=0, reason=reason)
98
- out_mssg = message.create_error_reply(error=error)
106
+ out_mssg = message.create_error_reply(
107
+ error=Error(code=e_code, reason=reason)
108
+ )
99
109
 
100
110
  finally:
101
111
  if out_mssg:
@@ -27,6 +27,8 @@ from flwr.proto.task_pb2 import TaskIns, TaskRes # pylint: disable=E0611
27
27
  from flwr.server.superlink.state.state import State
28
28
  from flwr.server.utils import validate_task_ins_or_res
29
29
 
30
+ from .utils import make_node_unavailable_taskres
31
+
30
32
 
31
33
  class InMemoryState(State):
32
34
  """In-memory State implementation."""
@@ -129,15 +131,32 @@ class InMemoryState(State):
129
131
  with self.lock:
130
132
  # Find TaskRes that were not delivered yet
131
133
  task_res_list: List[TaskRes] = []
134
+ replied_task_ids: Set[UUID] = set()
132
135
  for _, task_res in self.task_res_store.items():
133
- if (
134
- UUID(task_res.task.ancestry[0]) in task_ids
135
- and task_res.task.delivered_at == ""
136
- ):
136
+ reply_to = UUID(task_res.task.ancestry[0])
137
+ if reply_to in task_ids and task_res.task.delivered_at == "":
137
138
  task_res_list.append(task_res)
139
+ replied_task_ids.add(reply_to)
138
140
  if limit and len(task_res_list) == limit:
139
141
  break
140
142
 
143
+ # Check if the node is offline
144
+ for task_id in task_ids - replied_task_ids:
145
+ if limit and len(task_res_list) == limit:
146
+ break
147
+ task_ins = self.task_ins_store.get(task_id)
148
+ if task_ins is None:
149
+ continue
150
+ node_id = task_ins.task.consumer.node_id
151
+ online_until, _ = self.node_ids[node_id]
152
+ # Generate a TaskRes containing an error reply if the node is offline.
153
+ if online_until < time.time():
154
+ err_taskres = make_node_unavailable_taskres(
155
+ ref_taskins=task_ins,
156
+ )
157
+ self.task_res_store[UUID(err_taskres.task_id)] = err_taskres
158
+ task_res_list.append(err_taskres)
159
+
141
160
  # Mark all of them as delivered
142
161
  delivered_at = now().isoformat()
143
162
  for task_res in task_res_list:
@@ -182,16 +201,14 @@ class InMemoryState(State):
182
201
  """
183
202
  return len(self.task_res_store)
184
203
 
185
- def create_node(self) -> int:
204
+ def create_node(self, ping_interval: float) -> int:
186
205
  """Create, store in state, and return `node_id`."""
187
206
  # Sample a random int64 as node_id
188
207
  node_id: int = int.from_bytes(os.urandom(8), "little", signed=True)
189
208
 
190
209
  with self.lock:
191
210
  if node_id not in self.node_ids:
192
- # Default ping interval is 30s
193
- # TODO: change 1e9 to 30s # pylint: disable=W0511
194
- self.node_ids[node_id] = (time.time() + 1e9, 1e9)
211
+ self.node_ids[node_id] = (time.time() + ping_interval, ping_interval)
195
212
  return node_id
196
213
  log(ERROR, "Unexpected node registration failure.")
197
214
  return 0
@@ -30,6 +30,7 @@ from flwr.proto.task_pb2 import Task, TaskIns, TaskRes # pylint: disable=E0611
30
30
  from flwr.server.utils.validator import validate_task_ins_or_res
31
31
 
32
32
  from .state import State
33
+ from .utils import make_node_unavailable_taskres
33
34
 
34
35
  SQL_CREATE_TABLE_NODE = """
35
36
  CREATE TABLE IF NOT EXISTS node(
@@ -344,6 +345,7 @@ class SqliteState(State):
344
345
 
345
346
  return task_id
346
347
 
348
+ # pylint: disable-next=R0914
347
349
  def get_task_res(self, task_ids: Set[UUID], limit: Optional[int]) -> List[TaskRes]:
348
350
  """Get TaskRes for task_ids.
349
351
 
@@ -374,7 +376,7 @@ class SqliteState(State):
374
376
  AND delivered_at = ""
375
377
  """
376
378
 
377
- data: Dict[str, Union[str, int]] = {}
379
+ data: Dict[str, Union[str, float, int]] = {}
378
380
 
379
381
  if limit is not None:
380
382
  query += " LIMIT :limit"
@@ -408,6 +410,54 @@ class SqliteState(State):
408
410
  rows = self.query(query, data)
409
411
 
410
412
  result = [dict_to_task_res(row) for row in rows]
413
+
414
+ # 1. Query: Fetch consumer_node_id of remaining task_ids
415
+ # Assume the ancestry field only contains one element
416
+ data.clear()
417
+ replied_task_ids: Set[UUID] = {UUID(str(row["ancestry"])) for row in rows}
418
+ remaining_task_ids = task_ids - replied_task_ids
419
+ placeholders = ",".join([f":id_{i}" for i in range(len(remaining_task_ids))])
420
+ query = f"""
421
+ SELECT consumer_node_id
422
+ FROM task_ins
423
+ WHERE task_id IN ({placeholders});
424
+ """
425
+ for index, task_id in enumerate(remaining_task_ids):
426
+ data[f"id_{index}"] = str(task_id)
427
+ node_ids = [int(row["consumer_node_id"]) for row in self.query(query, data)]
428
+
429
+ # 2. Query: Select offline nodes
430
+ placeholders = ",".join([f":id_{i}" for i in range(len(node_ids))])
431
+ query = f"""
432
+ SELECT node_id
433
+ FROM node
434
+ WHERE node_id IN ({placeholders})
435
+ AND online_until < :time;
436
+ """
437
+ data = {f"id_{i}": str(node_id) for i, node_id in enumerate(node_ids)}
438
+ data["time"] = time.time()
439
+ offline_node_ids = [int(row["node_id"]) for row in self.query(query, data)]
440
+
441
+ # 3. Query: Select TaskIns for offline nodes
442
+ placeholders = ",".join([f":id_{i}" for i in range(len(offline_node_ids))])
443
+ query = f"""
444
+ SELECT *
445
+ FROM task_ins
446
+ WHERE consumer_node_id IN ({placeholders});
447
+ """
448
+ data = {f"id_{i}": str(node_id) for i, node_id in enumerate(offline_node_ids)}
449
+ task_ins_rows = self.query(query, data)
450
+
451
+ # Make TaskRes containing node unavailabe error
452
+ for row in task_ins_rows:
453
+ if limit and len(result) == limit:
454
+ break
455
+ task_ins = dict_to_task_ins(row)
456
+ err_taskres = make_node_unavailable_taskres(
457
+ ref_taskins=task_ins,
458
+ )
459
+ result.append(err_taskres)
460
+
411
461
  return result
412
462
 
413
463
  def num_task_ins(self) -> int:
@@ -468,7 +518,7 @@ class SqliteState(State):
468
518
 
469
519
  return None
470
520
 
471
- def create_node(self) -> int:
521
+ def create_node(self, ping_interval: float) -> int:
472
522
  """Create, store in state, and return `node_id`."""
473
523
  # Sample a random int64 as node_id
474
524
  node_id: int = int.from_bytes(os.urandom(8), "little", signed=True)
@@ -478,9 +528,7 @@ class SqliteState(State):
478
528
  )
479
529
 
480
530
  try:
481
- # Default ping interval is 30s
482
- # TODO: change 1e9 to 30s # pylint: disable=W0511
483
- self.query(query, (node_id, time.time() + 1e9, 1e9))
531
+ self.query(query, (node_id, time.time() + ping_interval, ping_interval))
484
532
  except sqlite3.IntegrityError:
485
533
  log(ERROR, "Unexpected node registration failure.")
486
534
  return 0
@@ -132,7 +132,7 @@ class State(abc.ABC):
132
132
  """Delete all delivered TaskIns/TaskRes pairs."""
133
133
 
134
134
  @abc.abstractmethod
135
- def create_node(self) -> int:
135
+ def create_node(self, ping_interval: float) -> int:
136
136
  """Create, store in state, and return `node_id`."""
137
137
 
138
138
  @abc.abstractmethod
@@ -0,0 +1,56 @@
1
+ # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """Utility functions for State."""
16
+
17
+
18
+ import time
19
+ from logging import ERROR
20
+ from uuid import uuid4
21
+
22
+ from flwr.common import log
23
+ from flwr.common.constant import ErrorCode
24
+ from flwr.proto.error_pb2 import Error # pylint: disable=E0611
25
+ from flwr.proto.node_pb2 import Node # pylint: disable=E0611
26
+ from flwr.proto.task_pb2 import Task, TaskIns, TaskRes # pylint: disable=E0611
27
+
28
+ NODE_UNAVAILABLE_ERROR_REASON = (
29
+ "Error: Node Unavailable - The destination node is currently unavailable. "
30
+ "It exceeds the time limit specified in its last ping."
31
+ )
32
+
33
+
34
+ def make_node_unavailable_taskres(ref_taskins: TaskIns) -> TaskRes:
35
+ """Generate a TaskRes with a node unavailable error from a TaskIns."""
36
+ current_time = time.time()
37
+ ttl = ref_taskins.task.ttl - (current_time - ref_taskins.task.created_at)
38
+ if ttl < 0:
39
+ log(ERROR, "Creating TaskRes for TaskIns that exceeds its TTL.")
40
+ ttl = 0
41
+ return TaskRes(
42
+ task_id=str(uuid4()),
43
+ group_id=ref_taskins.group_id,
44
+ run_id=ref_taskins.run_id,
45
+ task=Task(
46
+ producer=Node(node_id=ref_taskins.task.consumer.node_id, anonymous=False),
47
+ consumer=Node(node_id=ref_taskins.task.producer.node_id, anonymous=False),
48
+ created_at=current_time,
49
+ ttl=ttl,
50
+ ancestry=[ref_taskins.task_id],
51
+ task_type=ref_taskins.task.task_type,
52
+ error=Error(
53
+ code=ErrorCode.NODE_UNAVAILABLE, reason=NODE_UNAVAILABLE_ERROR_REASON
54
+ ),
55
+ ),
56
+ )
@@ -21,7 +21,7 @@ from logging import INFO
21
21
  from typing import Optional, cast
22
22
 
23
23
  import flwr.common.recordset_compat as compat
24
- from flwr.common import DEFAULT_TTL, ConfigsRecord, Context, GetParametersIns, log
24
+ from flwr.common import ConfigsRecord, Context, GetParametersIns, log
25
25
  from flwr.common.constant import MessageType, MessageTypeLegacy
26
26
 
27
27
  from ..compat.app_utils import start_update_client_manager_thread
@@ -127,7 +127,6 @@ def default_init_params_workflow(driver: Driver, context: Context) -> None:
127
127
  message_type=MessageTypeLegacy.GET_PARAMETERS,
128
128
  dst_node_id=random_client.node_id,
129
129
  group_id="0",
130
- ttl=DEFAULT_TTL,
131
130
  )
132
131
  ]
133
132
  )
@@ -226,7 +225,6 @@ def default_fit_workflow( # pylint: disable=R0914
226
225
  message_type=MessageType.TRAIN,
227
226
  dst_node_id=proxy.node_id,
228
227
  group_id=str(current_round),
229
- ttl=DEFAULT_TTL,
230
228
  )
231
229
  for proxy, fitins in client_instructions
232
230
  ]
@@ -306,7 +304,6 @@ def default_evaluate_workflow(driver: Driver, context: Context) -> None:
306
304
  message_type=MessageType.EVALUATE,
307
305
  dst_node_id=proxy.node_id,
308
306
  group_id=str(current_round),
309
- ttl=DEFAULT_TTL,
310
307
  )
311
308
  for proxy, evalins in client_instructions
312
309
  ]