flwr-nightly 1.8.0.dev20240328__tar.gz → 1.8.0.dev20240401__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.
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/PKG-INFO +1 -1
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/pyproject.toml +1 -1
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/app.py +2 -4
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/client_app.py +7 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/grpc_rere_client/connection.py +70 -28
- flwr_nightly-1.8.0.dev20240401/src/py/flwr/client/heartbeat.py +72 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/rest_client/connection.py +101 -27
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/constant.py +6 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/logger.py +4 -4
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/retry_invoker.py +24 -13
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/server_app.py +3 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/message_handler/message_handler.py +2 -1
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +28 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/vce/vce_api.py +8 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/LICENSE +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/README.md +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/app.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/example.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/flower_toml.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/new.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/README.md.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/flower.toml.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/requirements.numpy.txt.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/requirements.pytorch.txt.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/run/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/run/run.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/cli/utils.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/client.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/dpfedavg_numpy_client.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/grpc_client/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/grpc_client/connection.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/grpc_rere_client/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/message_handler/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/message_handler/message_handler.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/message_handler/task_handler.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/mod/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/mod/centraldp_mods.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/mod/comms_mods.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/mod/localdp_mod.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/mod/utils.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/node_state.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/node_state_tests.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/numpy_client.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/rest_client/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/typing.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/address.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/context.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/date.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/differential_privacy.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/differential_privacy_constants.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/dp.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/exit_handlers.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/message.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/object_ref.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/parameter.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/pyproject.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/record/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/record/configsrecord.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/record/conversion_utils.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/record/metricsrecord.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/record/parametersrecord.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/record/recordset.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/record/typeddict.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/recordset_compat.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/secure_aggregation/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/secure_aggregation/quantization.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/serde.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/telemetry.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/typing.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/version.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/driver_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/driver_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/driver_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/driver_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/error_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/error_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/error_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/error_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/fleet_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/fleet_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/fleet_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/fleet_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/node_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/node_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/node_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/node_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/recordset_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/recordset_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/recordset_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/recordset_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/task_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/task_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/task_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/task_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/transport_pb2.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/transport_pb2.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/transport_pb2_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/py.typed +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/app.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/client_manager.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/client_proxy.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/compat/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/compat/app.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/compat/app_utils.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/compat/driver_client_proxy.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/compat/legacy_context.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/criterion.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/driver/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/driver/driver.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/driver/grpc_driver.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/history.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/run_serverapp.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/server.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/server_config.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/aggregate.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/bulyan.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedadagrad.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedadam.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedavg.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedavg_android.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedavgm.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedmedian.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedopt.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedprox.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/fedyogi.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/krum.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/qfedavg.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/strategy/strategy.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/driver/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/driver/driver_grpc.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/driver/driver_servicer.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/state/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/state/in_memory_state.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/state/sqlite_state.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/state/state.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/superlink/state/state_factory.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/typing.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/utils/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/utils/tensorboard.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/utils/validator.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/workflow/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/workflow/constant.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/workflow/default_workflows.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/simulation/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/simulation/app.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/simulation/ray_transport/__init__.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/simulation/ray_transport/ray_actor.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/simulation/ray_transport/utils.py +0 -0
- {flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/simulation/run_simulation.py +0 -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-
|
|
7
|
+
version = "1.8.0-dev20240401"
|
|
8
8
|
description = "Flower: A Friendly Federated Learning Framework"
|
|
9
9
|
license = "Apache-2.0"
|
|
10
10
|
authors = ["The Flower Authors <hello@flower.ai>"]
|
|
@@ -36,7 +36,7 @@ from flwr.common.constant import (
|
|
|
36
36
|
TRANSPORT_TYPES,
|
|
37
37
|
)
|
|
38
38
|
from flwr.common.exit_handlers import register_exit_handlers
|
|
39
|
-
from flwr.common.logger import log, warn_deprecated_feature
|
|
39
|
+
from flwr.common.logger import log, warn_deprecated_feature
|
|
40
40
|
from flwr.common.message import Error
|
|
41
41
|
from flwr.common.object_ref import load_app, validate
|
|
42
42
|
from flwr.common.retry_invoker import RetryInvoker, exponential
|
|
@@ -385,8 +385,6 @@ def _start_client_internal(
|
|
|
385
385
|
return ClientApp(client_fn=client_fn)
|
|
386
386
|
|
|
387
387
|
load_client_app_fn = _load_client_app
|
|
388
|
-
else:
|
|
389
|
-
warn_experimental_feature("`load_client_app_fn`")
|
|
390
388
|
|
|
391
389
|
# At this point, only `load_client_app_fn` should be used
|
|
392
390
|
# Both `client` and `client_fn` must not be used directly
|
|
@@ -397,7 +395,7 @@ def _start_client_internal(
|
|
|
397
395
|
)
|
|
398
396
|
|
|
399
397
|
retry_invoker = RetryInvoker(
|
|
400
|
-
|
|
398
|
+
wait_gen_factory=exponential,
|
|
401
399
|
recoverable_exceptions=connection_error_type,
|
|
402
400
|
max_tries=max_retries,
|
|
403
401
|
max_time=max_wait_time,
|
{flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/client/client_app.py
RENAMED
|
@@ -23,6 +23,7 @@ from flwr.client.message_handler.message_handler import (
|
|
|
23
23
|
from flwr.client.mod.utils import make_ffn
|
|
24
24
|
from flwr.client.typing import ClientFn, Mod
|
|
25
25
|
from flwr.common import Context, Message, MessageType
|
|
26
|
+
from flwr.common.logger import warn_preview_feature
|
|
26
27
|
|
|
27
28
|
from .typing import ClientAppCallable
|
|
28
29
|
|
|
@@ -123,6 +124,8 @@ class ClientApp:
|
|
|
123
124
|
if self._call:
|
|
124
125
|
raise _registration_error(MessageType.TRAIN)
|
|
125
126
|
|
|
127
|
+
warn_preview_feature("ClientApp-register-train-function")
|
|
128
|
+
|
|
126
129
|
# Register provided function with the ClientApp object
|
|
127
130
|
# Wrap mods around the wrapped step function
|
|
128
131
|
self._train = make_ffn(train_fn, self._mods)
|
|
@@ -151,6 +154,8 @@ class ClientApp:
|
|
|
151
154
|
if self._call:
|
|
152
155
|
raise _registration_error(MessageType.EVALUATE)
|
|
153
156
|
|
|
157
|
+
warn_preview_feature("ClientApp-register-evaluate-function")
|
|
158
|
+
|
|
154
159
|
# Register provided function with the ClientApp object
|
|
155
160
|
# Wrap mods around the wrapped step function
|
|
156
161
|
self._evaluate = make_ffn(evaluate_fn, self._mods)
|
|
@@ -179,6 +184,8 @@ class ClientApp:
|
|
|
179
184
|
if self._call:
|
|
180
185
|
raise _registration_error(MessageType.QUERY)
|
|
181
186
|
|
|
187
|
+
warn_preview_feature("ClientApp-register-query-function")
|
|
188
|
+
|
|
182
189
|
# Register provided function with the ClientApp object
|
|
183
190
|
# Wrap mods around the wrapped step function
|
|
184
191
|
self._query = make_ffn(query_fn, self._mods)
|
|
@@ -15,23 +15,34 @@
|
|
|
15
15
|
"""Contextmanager for a gRPC request-response channel to the Flower server."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
import random
|
|
19
|
+
import threading
|
|
18
20
|
from contextlib import contextmanager
|
|
19
21
|
from copy import copy
|
|
20
22
|
from logging import DEBUG, ERROR
|
|
21
23
|
from pathlib import Path
|
|
22
|
-
from typing import Callable,
|
|
24
|
+
from typing import Callable, Iterator, Optional, Tuple, Union, cast
|
|
23
25
|
|
|
26
|
+
from flwr.client.heartbeat import start_ping_loop
|
|
24
27
|
from flwr.client.message_handler.message_handler import validate_out_message
|
|
25
28
|
from flwr.client.message_handler.task_handler import get_task_ins, validate_task_ins
|
|
26
29
|
from flwr.common import GRPC_MAX_MESSAGE_LENGTH
|
|
30
|
+
from flwr.common.constant import (
|
|
31
|
+
PING_BASE_MULTIPLIER,
|
|
32
|
+
PING_CALL_TIMEOUT,
|
|
33
|
+
PING_DEFAULT_INTERVAL,
|
|
34
|
+
PING_RANDOM_RANGE,
|
|
35
|
+
)
|
|
27
36
|
from flwr.common.grpc import create_channel
|
|
28
|
-
from flwr.common.logger import log
|
|
37
|
+
from flwr.common.logger import log
|
|
29
38
|
from flwr.common.message import Message, Metadata
|
|
30
39
|
from flwr.common.retry_invoker import RetryInvoker
|
|
31
40
|
from flwr.common.serde import message_from_taskins, message_to_taskres
|
|
32
41
|
from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
33
42
|
CreateNodeRequest,
|
|
34
43
|
DeleteNodeRequest,
|
|
44
|
+
PingRequest,
|
|
45
|
+
PingResponse,
|
|
35
46
|
PullTaskInsRequest,
|
|
36
47
|
PushTaskResRequest,
|
|
37
48
|
)
|
|
@@ -39,9 +50,6 @@ from flwr.proto.fleet_pb2_grpc import FleetStub # pylint: disable=E0611
|
|
|
39
50
|
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
|
40
51
|
from flwr.proto.task_pb2 import TaskIns # pylint: disable=E0611
|
|
41
52
|
|
|
42
|
-
KEY_NODE = "node"
|
|
43
|
-
KEY_METADATA = "in_message_metadata"
|
|
44
|
-
|
|
45
53
|
|
|
46
54
|
def on_channel_state_change(channel_connectivity: str) -> None:
|
|
47
55
|
"""Log channel connectivity."""
|
|
@@ -49,7 +57,7 @@ def on_channel_state_change(channel_connectivity: str) -> None:
|
|
|
49
57
|
|
|
50
58
|
|
|
51
59
|
@contextmanager
|
|
52
|
-
def grpc_request_response(
|
|
60
|
+
def grpc_request_response( # pylint: disable=R0914, R0915
|
|
53
61
|
server_address: str,
|
|
54
62
|
insecure: bool,
|
|
55
63
|
retry_invoker: RetryInvoker,
|
|
@@ -95,8 +103,6 @@ def grpc_request_response(
|
|
|
95
103
|
create_node : Optional[Callable]
|
|
96
104
|
delete_node : Optional[Callable]
|
|
97
105
|
"""
|
|
98
|
-
warn_experimental_feature("`grpc-rere`")
|
|
99
|
-
|
|
100
106
|
if isinstance(root_certificates, str):
|
|
101
107
|
root_certificates = Path(root_certificates).read_bytes()
|
|
102
108
|
|
|
@@ -107,47 +113,81 @@ def grpc_request_response(
|
|
|
107
113
|
max_message_length=max_message_length,
|
|
108
114
|
)
|
|
109
115
|
channel.subscribe(on_channel_state_change)
|
|
110
|
-
stub = FleetStub(channel)
|
|
111
116
|
|
|
112
|
-
#
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
+
# Shared variables for inner functions
|
|
118
|
+
stub = FleetStub(channel)
|
|
119
|
+
metadata: Optional[Metadata] = None
|
|
120
|
+
node: Optional[Node] = None
|
|
121
|
+
ping_thread: Optional[threading.Thread] = None
|
|
122
|
+
ping_stop_event = threading.Event()
|
|
117
123
|
|
|
118
124
|
###########################################################################
|
|
119
|
-
# receive/send functions
|
|
125
|
+
# ping/create_node/delete_node/receive/send functions
|
|
120
126
|
###########################################################################
|
|
121
127
|
|
|
128
|
+
def ping() -> None:
|
|
129
|
+
# Get Node
|
|
130
|
+
if node is None:
|
|
131
|
+
log(ERROR, "Node instance missing")
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
# Construct the ping request
|
|
135
|
+
req = PingRequest(node=node, ping_interval=PING_DEFAULT_INTERVAL)
|
|
136
|
+
|
|
137
|
+
# Call FleetAPI
|
|
138
|
+
res: PingResponse = stub.Ping(req, timeout=PING_CALL_TIMEOUT)
|
|
139
|
+
|
|
140
|
+
# Check if success
|
|
141
|
+
if not res.success:
|
|
142
|
+
raise RuntimeError("Ping failed unexpectedly.")
|
|
143
|
+
|
|
144
|
+
# Wait
|
|
145
|
+
rd = random.uniform(*PING_RANDOM_RANGE)
|
|
146
|
+
next_interval: float = PING_DEFAULT_INTERVAL - PING_CALL_TIMEOUT
|
|
147
|
+
next_interval *= PING_BASE_MULTIPLIER + rd
|
|
148
|
+
if not ping_stop_event.is_set():
|
|
149
|
+
ping_stop_event.wait(next_interval)
|
|
150
|
+
|
|
122
151
|
def create_node() -> None:
|
|
123
152
|
"""Set create_node."""
|
|
153
|
+
# Call FleetAPI
|
|
124
154
|
create_node_request = CreateNodeRequest()
|
|
125
155
|
create_node_response = retry_invoker.invoke(
|
|
126
156
|
stub.CreateNode,
|
|
127
157
|
request=create_node_request,
|
|
128
158
|
)
|
|
129
|
-
|
|
159
|
+
|
|
160
|
+
# Remember the node and the ping-loop thread
|
|
161
|
+
nonlocal node, ping_thread
|
|
162
|
+
node = cast(Node, create_node_response.node)
|
|
163
|
+
ping_thread = start_ping_loop(ping, ping_stop_event)
|
|
130
164
|
|
|
131
165
|
def delete_node() -> None:
|
|
132
166
|
"""Set delete_node."""
|
|
133
167
|
# Get Node
|
|
134
|
-
|
|
168
|
+
nonlocal node
|
|
169
|
+
if node is None:
|
|
135
170
|
log(ERROR, "Node instance missing")
|
|
136
171
|
return
|
|
137
|
-
node: Node = cast(Node, node_store[KEY_NODE])
|
|
138
172
|
|
|
173
|
+
# Stop the ping-loop thread
|
|
174
|
+
ping_stop_event.set()
|
|
175
|
+
if ping_thread is not None:
|
|
176
|
+
ping_thread.join()
|
|
177
|
+
|
|
178
|
+
# Call FleetAPI
|
|
139
179
|
delete_node_request = DeleteNodeRequest(node=node)
|
|
140
180
|
retry_invoker.invoke(stub.DeleteNode, request=delete_node_request)
|
|
141
181
|
|
|
142
|
-
|
|
182
|
+
# Cleanup
|
|
183
|
+
node = None
|
|
143
184
|
|
|
144
185
|
def receive() -> Optional[Message]:
|
|
145
186
|
"""Receive next task from server."""
|
|
146
187
|
# Get Node
|
|
147
|
-
if
|
|
188
|
+
if node is None:
|
|
148
189
|
log(ERROR, "Node instance missing")
|
|
149
190
|
return None
|
|
150
|
-
node: Node = cast(Node, node_store[KEY_NODE])
|
|
151
191
|
|
|
152
192
|
# Request instructions (task) from server
|
|
153
193
|
request = PullTaskInsRequest(node=node)
|
|
@@ -167,7 +207,8 @@ def grpc_request_response(
|
|
|
167
207
|
in_message = message_from_taskins(task_ins) if task_ins else None
|
|
168
208
|
|
|
169
209
|
# Remember `metadata` of the in message
|
|
170
|
-
|
|
210
|
+
nonlocal metadata
|
|
211
|
+
metadata = copy(in_message.metadata) if in_message else None
|
|
171
212
|
|
|
172
213
|
# Return the message if available
|
|
173
214
|
return in_message
|
|
@@ -175,18 +216,18 @@ def grpc_request_response(
|
|
|
175
216
|
def send(message: Message) -> None:
|
|
176
217
|
"""Send task result back to server."""
|
|
177
218
|
# Get Node
|
|
178
|
-
if
|
|
219
|
+
if node is None:
|
|
179
220
|
log(ERROR, "Node instance missing")
|
|
180
221
|
return
|
|
181
222
|
|
|
182
|
-
# Get incoming message
|
|
183
|
-
|
|
184
|
-
if
|
|
223
|
+
# Get the metadata of the incoming message
|
|
224
|
+
nonlocal metadata
|
|
225
|
+
if metadata is None:
|
|
185
226
|
log(ERROR, "No current message")
|
|
186
227
|
return
|
|
187
228
|
|
|
188
229
|
# Validate out message
|
|
189
|
-
if not validate_out_message(message,
|
|
230
|
+
if not validate_out_message(message, metadata):
|
|
190
231
|
log(ERROR, "Invalid out message")
|
|
191
232
|
return
|
|
192
233
|
|
|
@@ -197,7 +238,8 @@ def grpc_request_response(
|
|
|
197
238
|
request = PushTaskResRequest(task_res_list=[task_res])
|
|
198
239
|
_ = retry_invoker.invoke(stub.PushTaskRes, request)
|
|
199
240
|
|
|
200
|
-
|
|
241
|
+
# Cleanup
|
|
242
|
+
metadata = None
|
|
201
243
|
|
|
202
244
|
try:
|
|
203
245
|
# Yield methods
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
"""Heartbeat utility functions."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
import threading
|
|
19
|
+
from typing import Callable
|
|
20
|
+
|
|
21
|
+
import grpc
|
|
22
|
+
|
|
23
|
+
from flwr.common.constant import PING_CALL_TIMEOUT
|
|
24
|
+
from flwr.common.retry_invoker import RetryInvoker, RetryState, exponential
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _ping_loop(ping_fn: Callable[[], None], stop_event: threading.Event) -> None:
|
|
28
|
+
def wait_fn(wait_time: float) -> None:
|
|
29
|
+
if not stop_event.is_set():
|
|
30
|
+
stop_event.wait(wait_time)
|
|
31
|
+
|
|
32
|
+
def on_backoff(state: RetryState) -> None:
|
|
33
|
+
err = state.exception
|
|
34
|
+
if not isinstance(err, grpc.RpcError):
|
|
35
|
+
return
|
|
36
|
+
status_code = err.code()
|
|
37
|
+
# If ping call timeout is triggered
|
|
38
|
+
if status_code == grpc.StatusCode.DEADLINE_EXCEEDED:
|
|
39
|
+
# Avoid long wait time.
|
|
40
|
+
if state.actual_wait is None:
|
|
41
|
+
return
|
|
42
|
+
state.actual_wait = max(state.actual_wait - PING_CALL_TIMEOUT, 0.0)
|
|
43
|
+
|
|
44
|
+
def wrapped_ping() -> None:
|
|
45
|
+
if not stop_event.is_set():
|
|
46
|
+
ping_fn()
|
|
47
|
+
|
|
48
|
+
retrier = RetryInvoker(
|
|
49
|
+
exponential,
|
|
50
|
+
grpc.RpcError,
|
|
51
|
+
max_tries=None,
|
|
52
|
+
max_time=None,
|
|
53
|
+
on_backoff=on_backoff,
|
|
54
|
+
wait_function=wait_fn,
|
|
55
|
+
)
|
|
56
|
+
while not stop_event.is_set():
|
|
57
|
+
retrier.invoke(wrapped_ping)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def start_ping_loop(
|
|
61
|
+
ping_fn: Callable[[], None], stop_event: threading.Event
|
|
62
|
+
) -> threading.Thread:
|
|
63
|
+
"""Start a ping loop in a separate thread.
|
|
64
|
+
|
|
65
|
+
This function initializes a new thread that runs a ping loop, allowing for
|
|
66
|
+
asynchronous ping operations. The loop can be terminated through the provided stop
|
|
67
|
+
event.
|
|
68
|
+
"""
|
|
69
|
+
thread = threading.Thread(target=_ping_loop, args=(ping_fn, stop_event))
|
|
70
|
+
thread.start()
|
|
71
|
+
|
|
72
|
+
return thread
|
|
@@ -15,16 +15,25 @@
|
|
|
15
15
|
"""Contextmanager for a REST request-response channel to the Flower server."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
import random
|
|
18
19
|
import sys
|
|
20
|
+
import threading
|
|
19
21
|
from contextlib import contextmanager
|
|
20
22
|
from copy import copy
|
|
21
23
|
from logging import ERROR, INFO, WARN
|
|
22
|
-
from typing import Callable,
|
|
24
|
+
from typing import Callable, Iterator, Optional, Tuple, Union
|
|
23
25
|
|
|
26
|
+
from flwr.client.heartbeat import start_ping_loop
|
|
24
27
|
from flwr.client.message_handler.message_handler import validate_out_message
|
|
25
28
|
from flwr.client.message_handler.task_handler import get_task_ins, validate_task_ins
|
|
26
29
|
from flwr.common import GRPC_MAX_MESSAGE_LENGTH
|
|
27
|
-
from flwr.common.constant import
|
|
30
|
+
from flwr.common.constant import (
|
|
31
|
+
MISSING_EXTRA_REST,
|
|
32
|
+
PING_BASE_MULTIPLIER,
|
|
33
|
+
PING_CALL_TIMEOUT,
|
|
34
|
+
PING_DEFAULT_INTERVAL,
|
|
35
|
+
PING_RANDOM_RANGE,
|
|
36
|
+
)
|
|
28
37
|
from flwr.common.logger import log
|
|
29
38
|
from flwr.common.message import Message, Metadata
|
|
30
39
|
from flwr.common.retry_invoker import RetryInvoker
|
|
@@ -33,6 +42,8 @@ from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
|
|
|
33
42
|
CreateNodeRequest,
|
|
34
43
|
CreateNodeResponse,
|
|
35
44
|
DeleteNodeRequest,
|
|
45
|
+
PingRequest,
|
|
46
|
+
PingResponse,
|
|
36
47
|
PullTaskInsRequest,
|
|
37
48
|
PullTaskInsResponse,
|
|
38
49
|
PushTaskResRequest,
|
|
@@ -47,19 +58,15 @@ except ModuleNotFoundError:
|
|
|
47
58
|
sys.exit(MISSING_EXTRA_REST)
|
|
48
59
|
|
|
49
60
|
|
|
50
|
-
KEY_NODE = "node"
|
|
51
|
-
KEY_METADATA = "in_message_metadata"
|
|
52
|
-
|
|
53
|
-
|
|
54
61
|
PATH_CREATE_NODE: str = "api/v0/fleet/create-node"
|
|
55
62
|
PATH_DELETE_NODE: str = "api/v0/fleet/delete-node"
|
|
56
63
|
PATH_PULL_TASK_INS: str = "api/v0/fleet/pull-task-ins"
|
|
57
64
|
PATH_PUSH_TASK_RES: str = "api/v0/fleet/push-task-res"
|
|
65
|
+
PATH_PING: str = "api/v0/fleet/ping"
|
|
58
66
|
|
|
59
67
|
|
|
60
68
|
@contextmanager
|
|
61
|
-
# pylint: disable
|
|
62
|
-
def http_request_response(
|
|
69
|
+
def http_request_response( # pylint: disable=R0914, R0915
|
|
63
70
|
server_address: str,
|
|
64
71
|
insecure: bool, # pylint: disable=unused-argument
|
|
65
72
|
retry_invoker: RetryInvoker,
|
|
@@ -127,16 +134,71 @@ def http_request_response(
|
|
|
127
134
|
"must be provided as a string path to the client.",
|
|
128
135
|
)
|
|
129
136
|
|
|
130
|
-
#
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
# Shared variables for inner functions
|
|
138
|
+
metadata: Optional[Metadata] = None
|
|
139
|
+
node: Optional[Node] = None
|
|
140
|
+
ping_thread: Optional[threading.Thread] = None
|
|
141
|
+
ping_stop_event = threading.Event()
|
|
135
142
|
|
|
136
143
|
###########################################################################
|
|
137
|
-
# receive/send functions
|
|
144
|
+
# ping/create_node/delete_node/receive/send functions
|
|
138
145
|
###########################################################################
|
|
139
146
|
|
|
147
|
+
def ping() -> None:
|
|
148
|
+
# Get Node
|
|
149
|
+
if node is None:
|
|
150
|
+
log(ERROR, "Node instance missing")
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
# Construct the ping request
|
|
154
|
+
req = PingRequest(node=node, ping_interval=PING_DEFAULT_INTERVAL)
|
|
155
|
+
req_bytes: bytes = req.SerializeToString()
|
|
156
|
+
|
|
157
|
+
# Send the request
|
|
158
|
+
res = requests.post(
|
|
159
|
+
url=f"{base_url}/{PATH_PING}",
|
|
160
|
+
headers={
|
|
161
|
+
"Accept": "application/protobuf",
|
|
162
|
+
"Content-Type": "application/protobuf",
|
|
163
|
+
},
|
|
164
|
+
data=req_bytes,
|
|
165
|
+
verify=verify,
|
|
166
|
+
timeout=PING_CALL_TIMEOUT,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# Check status code and headers
|
|
170
|
+
if res.status_code != 200:
|
|
171
|
+
return
|
|
172
|
+
if "content-type" not in res.headers:
|
|
173
|
+
log(
|
|
174
|
+
WARN,
|
|
175
|
+
"[Node] POST /%s: missing header `Content-Type`",
|
|
176
|
+
PATH_PULL_TASK_INS,
|
|
177
|
+
)
|
|
178
|
+
return
|
|
179
|
+
if res.headers["content-type"] != "application/protobuf":
|
|
180
|
+
log(
|
|
181
|
+
WARN,
|
|
182
|
+
"[Node] POST /%s: header `Content-Type` has wrong value",
|
|
183
|
+
PATH_PULL_TASK_INS,
|
|
184
|
+
)
|
|
185
|
+
return
|
|
186
|
+
|
|
187
|
+
# Deserialize ProtoBuf from bytes
|
|
188
|
+
ping_res = PingResponse()
|
|
189
|
+
ping_res.ParseFromString(res.content)
|
|
190
|
+
|
|
191
|
+
# Check if success
|
|
192
|
+
if not ping_res.success:
|
|
193
|
+
raise RuntimeError("Ping failed unexpectedly.")
|
|
194
|
+
|
|
195
|
+
# Wait
|
|
196
|
+
rd = random.uniform(*PING_RANDOM_RANGE)
|
|
197
|
+
next_interval: float = PING_DEFAULT_INTERVAL - PING_CALL_TIMEOUT
|
|
198
|
+
next_interval *= PING_BASE_MULTIPLIER + rd
|
|
199
|
+
if not ping_stop_event.is_set():
|
|
200
|
+
ping_stop_event.wait(next_interval)
|
|
201
|
+
|
|
140
202
|
def create_node() -> None:
|
|
141
203
|
"""Set create_node."""
|
|
142
204
|
create_node_req_proto = CreateNodeRequest()
|
|
@@ -175,15 +237,25 @@ def http_request_response(
|
|
|
175
237
|
# Deserialize ProtoBuf from bytes
|
|
176
238
|
create_node_response_proto = CreateNodeResponse()
|
|
177
239
|
create_node_response_proto.ParseFromString(res.content)
|
|
178
|
-
|
|
179
|
-
|
|
240
|
+
|
|
241
|
+
# Remember the node and the ping-loop thread
|
|
242
|
+
nonlocal node, ping_thread
|
|
243
|
+
node = create_node_response_proto.node
|
|
244
|
+
ping_thread = start_ping_loop(ping, ping_stop_event)
|
|
180
245
|
|
|
181
246
|
def delete_node() -> None:
|
|
182
247
|
"""Set delete_node."""
|
|
183
|
-
|
|
248
|
+
nonlocal node
|
|
249
|
+
if node is None:
|
|
184
250
|
log(ERROR, "Node instance missing")
|
|
185
251
|
return
|
|
186
|
-
|
|
252
|
+
|
|
253
|
+
# Stop the ping-loop thread
|
|
254
|
+
ping_stop_event.set()
|
|
255
|
+
if ping_thread is not None:
|
|
256
|
+
ping_thread.join()
|
|
257
|
+
|
|
258
|
+
# Send DeleteNode request
|
|
187
259
|
delete_node_req_proto = DeleteNodeRequest(node=node)
|
|
188
260
|
delete_node_req_req_bytes: bytes = delete_node_req_proto.SerializeToString()
|
|
189
261
|
res = retry_invoker.invoke(
|
|
@@ -215,13 +287,15 @@ def http_request_response(
|
|
|
215
287
|
PATH_PULL_TASK_INS,
|
|
216
288
|
)
|
|
217
289
|
|
|
290
|
+
# Cleanup
|
|
291
|
+
node = None
|
|
292
|
+
|
|
218
293
|
def receive() -> Optional[Message]:
|
|
219
294
|
"""Receive next task from server."""
|
|
220
295
|
# Get Node
|
|
221
|
-
if
|
|
296
|
+
if node is None:
|
|
222
297
|
log(ERROR, "Node instance missing")
|
|
223
298
|
return None
|
|
224
|
-
node: Node = cast(Node, node_store[KEY_NODE])
|
|
225
299
|
|
|
226
300
|
# Request instructions (task) from server
|
|
227
301
|
pull_task_ins_req_proto = PullTaskInsRequest(node=node)
|
|
@@ -273,29 +347,29 @@ def http_request_response(
|
|
|
273
347
|
task_ins = None
|
|
274
348
|
|
|
275
349
|
# Return the Message if available
|
|
350
|
+
nonlocal metadata
|
|
276
351
|
message = None
|
|
277
|
-
state[KEY_METADATA] = None
|
|
278
352
|
if task_ins is not None:
|
|
279
353
|
message = message_from_taskins(task_ins)
|
|
280
|
-
|
|
354
|
+
metadata = copy(message.metadata)
|
|
281
355
|
log(INFO, "[Node] POST /%s: success", PATH_PULL_TASK_INS)
|
|
282
356
|
return message
|
|
283
357
|
|
|
284
358
|
def send(message: Message) -> None:
|
|
285
359
|
"""Send task result back to server."""
|
|
286
360
|
# Get Node
|
|
287
|
-
if
|
|
361
|
+
if node is None:
|
|
288
362
|
log(ERROR, "Node instance missing")
|
|
289
363
|
return
|
|
290
364
|
|
|
291
365
|
# Get incoming message
|
|
292
|
-
|
|
293
|
-
if
|
|
366
|
+
nonlocal metadata
|
|
367
|
+
if metadata is None:
|
|
294
368
|
log(ERROR, "No current message")
|
|
295
369
|
return
|
|
296
370
|
|
|
297
371
|
# Validate out message
|
|
298
|
-
if not validate_out_message(message,
|
|
372
|
+
if not validate_out_message(message, metadata):
|
|
299
373
|
log(ERROR, "Invalid out message")
|
|
300
374
|
return
|
|
301
375
|
|
|
@@ -321,7 +395,7 @@ def http_request_response(
|
|
|
321
395
|
timeout=None,
|
|
322
396
|
)
|
|
323
397
|
|
|
324
|
-
|
|
398
|
+
metadata = None
|
|
325
399
|
|
|
326
400
|
# Check status code and headers
|
|
327
401
|
if res.status_code != 200:
|
{flwr_nightly-1.8.0.dev20240328 → flwr_nightly-1.8.0.dev20240401}/src/py/flwr/common/logger.py
RENAMED
|
@@ -164,13 +164,13 @@ logger = logging.getLogger(LOGGER_NAME) # pylint: disable=invalid-name
|
|
|
164
164
|
log = logger.log # pylint: disable=invalid-name
|
|
165
165
|
|
|
166
166
|
|
|
167
|
-
def
|
|
168
|
-
"""Warn the user when they use
|
|
167
|
+
def warn_preview_feature(name: str) -> None:
|
|
168
|
+
"""Warn the user when they use a preview feature."""
|
|
169
169
|
log(
|
|
170
170
|
WARN,
|
|
171
|
-
"""
|
|
171
|
+
"""PREVIEW FEATURE: %s
|
|
172
172
|
|
|
173
|
-
This is
|
|
173
|
+
This is a preview feature. It could change significantly or be removed
|
|
174
174
|
entirely in future versions of Flower.
|
|
175
175
|
""",
|
|
176
176
|
name,
|