flwr 1.15.1__tar.gz → 1.16.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flwr-1.15.1 → flwr-1.16.0}/PKG-INFO +5 -5
- {flwr-1.15.1 → flwr-1.16.0}/pyproject.toml +4 -8
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/build.py +2 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/log.py +20 -21
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/new.py +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/README.baseline.md.tpl +4 -4
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/README.md.tpl +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/pyproject.jax.toml.tpl +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/client_app.py +147 -36
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/clientapp/app.py +4 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/message_handler/message_handler.py +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/rest_client/connection.py +4 -6
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/supernode/__init__.py +0 -2
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/supernode/app.py +1 -11
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/address.py +35 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/args.py +8 -2
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/auth_plugin/auth_plugin.py +2 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/constant.py +16 -0
- flwr-1.16.0/src/py/flwr/common/event_log_plugin/__init__.py +22 -0
- flwr-1.16.0/src/py/flwr/common/event_log_plugin/event_log_plugin.py +60 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/grpc.py +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/message.py +18 -7
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/object_ref.py +0 -10
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/record/conversion_utils.py +8 -17
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/record/parametersrecord.py +151 -16
- flwr-1.16.0/src/py/flwr/common/record/recordset.py +209 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/secure_aggregation/quantization.py +5 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/serde.py +8 -126
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/telemetry.py +0 -10
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/typing.py +36 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/app.py +18 -2
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/compat/app.py +4 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/compat/app_utils.py +10 -2
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/compat/driver_client_proxy.py +2 -2
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/driver/driver.py +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/driver/grpc_driver.py +10 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/driver/inmemory_driver.py +17 -21
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/run_serverapp.py +2 -13
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/server_app.py +93 -20
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/driver/serverappio_servicer.py +27 -33
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +2 -2
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/message_handler/message_handler.py +8 -16
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/vce/backend/backend.py +1 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/vce/vce_api.py +32 -36
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/linkstate/in_memory_linkstate.py +140 -126
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/linkstate/linkstate.py +47 -60
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/linkstate/sqlite_linkstate.py +210 -282
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/linkstate/utils.py +91 -119
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/utils/__init__.py +2 -2
- flwr-1.16.0/src/py/flwr/server/utils/validator.py +93 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/workflow/default_workflows.py +4 -1
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +3 -3
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/superexec/app.py +0 -14
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/superexec/exec_servicer.py +4 -4
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/superexec/exec_user_auth_interceptor.py +5 -3
- flwr-1.15.1/src/py/flwr/client/message_handler/task_handler.py +0 -37
- flwr-1.15.1/src/py/flwr/common/record/recordset.py +0 -202
- flwr-1.15.1/src/py/flwr/proto/task_pb2.py +0 -33
- flwr-1.15.1/src/py/flwr/proto/task_pb2.pyi +0 -103
- flwr-1.15.1/src/py/flwr/proto/task_pb2_grpc.py +0 -4
- flwr-1.15.1/src/py/flwr/proto/task_pb2_grpc.pyi +0 -4
- flwr-1.15.1/src/py/flwr/server/utils/validator.py +0 -111
- {flwr-1.15.1 → flwr-1.16.0}/LICENSE +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/README.md +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/app.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/auth_plugin/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/auth_plugin/oidc_cli_plugin.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/cli_user_auth_interceptor.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/config_utils.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/constant.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/example.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/install.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/login/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/login/login.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/ls.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/.gitignore.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/LICENSE.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/README.flowertune.md.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/client.baseline.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/client.huggingface.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/client.jax.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/client.mlx.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/model.baseline.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/server.baseline.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/server.huggingface.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/server.jax.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/server.mlx.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/task.huggingface.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/task.jax.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/task.mlx.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/task.numpy.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/task.sklearn.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/new/templates/app/code/utils.baseline.py.tpl +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/run/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/run/run.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/stop.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/cli/utils.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/app.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/client.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/clientapp/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/clientapp/clientappio_servicer.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/clientapp/utils.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/dpfedavg_numpy_client.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/grpc_adapter_client/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/grpc_adapter_client/connection.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/grpc_client/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/grpc_client/connection.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/grpc_rere_client/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/grpc_rere_client/client_interceptor.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/grpc_rere_client/connection.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/grpc_rere_client/grpc_adapter.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/heartbeat.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/message_handler/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/mod/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/mod/centraldp_mods.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/mod/comms_mods.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/mod/localdp_mod.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/mod/utils.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/nodestate/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/nodestate/in_memory_nodestate.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/nodestate/nodestate.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/nodestate/nodestate_factory.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/numpy_client.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/rest_client/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/run_info_store.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/client/typing.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/auth_plugin/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/config.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/context.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/date.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/differential_privacy.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/differential_privacy_constants.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/dp.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/exit/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/exit/exit.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/exit/exit_code.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/exit_handlers.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/logger.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/parameter.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/pyproject.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/record/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/record/configsrecord.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/record/metricsrecord.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/record/typeddict.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/recordset_compat.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/retry_invoker.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/secure_aggregation/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/common/version.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/clientappio_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/clientappio_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/clientappio_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/clientappio_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/error_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/error_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/error_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/error_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/exec_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/exec_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/exec_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/exec_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/fab_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/fab_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/fab_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/fab_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/fleet_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/fleet_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/fleet_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/fleet_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/grpcadapter_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/grpcadapter_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/grpcadapter_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/grpcadapter_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/log_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/log_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/log_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/log_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/message_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/message_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/message_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/message_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/node_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/node_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/node_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/node_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/recordset_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/recordset_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/recordset_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/recordset_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/run_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/run_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/run_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/run_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/serverappio_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/serverappio_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/serverappio_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/serverappio_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/simulationio_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/simulationio_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/simulationio_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/simulationio_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/transport_pb2.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/transport_pb2.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/transport_pb2_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/py.typed +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/client_manager.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/client_proxy.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/compat/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/compat/legacy_context.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/criterion.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/driver/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/history.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/server.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/server_config.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/serverapp/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/serverapp/app.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/serverapp_components.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/aggregate.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/bulyan.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedadagrad.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedadam.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedavg.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedavg_android.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedavgm.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedmedian.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedopt.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedprox.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/fedyogi.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/krum.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/qfedavg.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/strategy/strategy.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/driver/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/driver/serverappio_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/ffs/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/ffs/disk_ffs.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/ffs/ffs.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/ffs/ffs_factory.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/grpc_adapter/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/linkstate/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/linkstate/linkstate_factory.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/simulation/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/simulation/simulationio_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/simulation/simulationio_servicer.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/superlink/utils.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/typing.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/utils/tensorboard.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/workflow/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/workflow/constant.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/simulation/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/simulation/app.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/simulation/legacy_app.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/simulation/ray_transport/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/simulation/ray_transport/ray_actor.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/simulation/ray_transport/utils.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/simulation/run_simulation.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/simulation/simulationio_connection.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/superexec/__init__.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/superexec/deployment.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/superexec/exec_grpc.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/superexec/executor.py +0 -0
- {flwr-1.15.1 → flwr-1.16.0}/src/py/flwr/superexec/simulation.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: flwr
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.16.0
|
|
4
4
|
Summary: Flower: A Friendly Federated AI Framework
|
|
5
5
|
Home-page: https://flower.ai
|
|
6
6
|
License: Apache-2.0
|
|
7
7
|
Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
|
|
8
8
|
Author: The Flower Authors
|
|
9
9
|
Author-email: hello@flower.ai
|
|
10
|
-
Requires-Python: >=3.9,<4.0
|
|
10
|
+
Requires-Python: >=3.9.2,<4.0.0
|
|
11
11
|
Classifier: Development Status :: 5 - Production/Stable
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
13
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -16,12 +16,12 @@ Classifier: Operating System :: MacOS :: MacOS X
|
|
|
16
16
|
Classifier: Operating System :: POSIX :: Linux
|
|
17
17
|
Classifier: Programming Language :: Python
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
22
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
24
23
|
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
25
25
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
26
26
|
Classifier: Topic :: Scientific/Engineering
|
|
27
27
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
@@ -32,7 +32,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
32
32
|
Classifier: Typing :: Typed
|
|
33
33
|
Provides-Extra: rest
|
|
34
34
|
Provides-Extra: simulation
|
|
35
|
-
Requires-Dist: cryptography (>=
|
|
35
|
+
Requires-Dist: cryptography (>=44.0.1,<45.0.0)
|
|
36
36
|
Requires-Dist: grpcio (>=1.62.3,<2.0.0,!=1.65.0)
|
|
37
37
|
Requires-Dist: iterators (>=0.0.2,<0.0.3)
|
|
38
38
|
Requires-Dist: numpy (>=1.26.0,<3.0.0)
|
|
@@ -40,7 +40,7 @@ Requires-Dist: pathspec (>=0.12.1,<0.13.0)
|
|
|
40
40
|
Requires-Dist: protobuf (>=4.21.6,<5.0.0)
|
|
41
41
|
Requires-Dist: pycryptodome (>=3.18.0,<4.0.0)
|
|
42
42
|
Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
|
|
43
|
-
Requires-Dist: ray (==2.
|
|
43
|
+
Requires-Dist: ray (==2.31.0) ; (python_version >= "3.9" and python_version < "3.13") and (extra == "simulation")
|
|
44
44
|
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
45
45
|
Requires-Dist: rich (>=13.5.0,<14.0.0)
|
|
46
46
|
Requires-Dist: starlette (>=0.45.2,<0.46.0) ; extra == "rest"
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "flwr"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.16.0"
|
|
8
8
|
description = "Flower: A Friendly Federated AI Framework"
|
|
9
9
|
license = "Apache-2.0"
|
|
10
10
|
authors = ["The Flower Authors <hello@flower.ai>"]
|
|
@@ -51,8 +51,6 @@ exclude = ["src/py/**/*_test.py"]
|
|
|
51
51
|
[tool.poetry.scripts]
|
|
52
52
|
# `flwr` CLI
|
|
53
53
|
flwr = "flwr.cli.app:app"
|
|
54
|
-
# SuperExec (can run with either Deployment Engine or Simulation Engine)
|
|
55
|
-
flower-superexec = "flwr.superexec.app:run_superexec" # Deprecated
|
|
56
54
|
# Simulation Engine
|
|
57
55
|
flwr-simulation = "flwr.simulation.app:flwr_simulation"
|
|
58
56
|
flower-simulation = "flwr.simulation.run_simulation:run_simulation_from_cli"
|
|
@@ -60,17 +58,15 @@ flower-simulation = "flwr.simulation.run_simulation:run_simulation_from_cli"
|
|
|
60
58
|
flower-superlink = "flwr.server.app:run_superlink"
|
|
61
59
|
flower-supernode = "flwr.client.supernode.app:run_supernode"
|
|
62
60
|
flwr-serverapp = "flwr.server.serverapp:flwr_serverapp"
|
|
63
|
-
flower-server-app = "flwr.server.run_serverapp:run_server_app" # Deprecated
|
|
64
61
|
flwr-clientapp = "flwr.client.clientapp:flwr_clientapp"
|
|
65
|
-
flower-client-app = "flwr.client.supernode:run_client_app" # Deprecated
|
|
66
62
|
|
|
67
63
|
[tool.poetry.dependencies]
|
|
68
|
-
python = "^3.9"
|
|
64
|
+
python = "^3.9.2"
|
|
69
65
|
# Mandatory dependencies
|
|
70
66
|
numpy = ">=1.26.0,<3.0.0"
|
|
71
67
|
grpcio = "^1.62.3,!=1.65.0"
|
|
72
68
|
protobuf = "^4.21.6"
|
|
73
|
-
cryptography = "^
|
|
69
|
+
cryptography = "^44.0.1"
|
|
74
70
|
pycryptodome = "^3.18.0"
|
|
75
71
|
iterators = "^0.0.2"
|
|
76
72
|
typer = "^0.12.5"
|
|
@@ -81,7 +77,7 @@ rich = "^13.5.0"
|
|
|
81
77
|
pyyaml = "^6.0.2"
|
|
82
78
|
requests = "^2.31.0"
|
|
83
79
|
# Optional dependencies (Simulation Engine)
|
|
84
|
-
ray = { version = "==2.
|
|
80
|
+
ray = { version = "==2.31.0", optional = true, python = ">=3.9,<3.13" }
|
|
85
81
|
# Optional dependencies (REST transport layer)
|
|
86
82
|
starlette = { version = "^0.45.2", optional = true }
|
|
87
83
|
uvicorn = { version = "^0.34.0", extras = ["standard"], optional = true }
|
|
@@ -38,6 +38,10 @@ from flwr.proto.exec_pb2_grpc import ExecStub
|
|
|
38
38
|
from .utils import init_channel, try_obtain_cli_auth_plugin, unauthenticated_exc_handler
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
class AllLogsRetrieved(BaseException):
|
|
42
|
+
"""Raised when all logs are retrieved."""
|
|
43
|
+
|
|
44
|
+
|
|
41
45
|
def start_stream(
|
|
42
46
|
run_id: int, channel: grpc.Channel, refresh_period: int = CONN_REFRESH_PERIOD
|
|
43
47
|
) -> None:
|
|
@@ -56,10 +60,10 @@ def start_stream(
|
|
|
56
60
|
# pylint: disable=E1101
|
|
57
61
|
if e.code() == grpc.StatusCode.NOT_FOUND:
|
|
58
62
|
logger(ERROR, "Invalid run_id `%s`, exiting", run_id)
|
|
59
|
-
if e.code() == grpc.StatusCode.CANCELLED:
|
|
60
|
-
pass
|
|
61
63
|
else:
|
|
62
64
|
raise e
|
|
65
|
+
except AllLogsRetrieved:
|
|
66
|
+
pass
|
|
63
67
|
finally:
|
|
64
68
|
channel.close()
|
|
65
69
|
|
|
@@ -94,6 +98,7 @@ def stream_logs(
|
|
|
94
98
|
with unauthenticated_exc_handler():
|
|
95
99
|
for res in stub.StreamLogs(req, timeout=duration):
|
|
96
100
|
print(res.log_output, end="")
|
|
101
|
+
raise AllLogsRetrieved()
|
|
97
102
|
except grpc.RpcError as e:
|
|
98
103
|
# pylint: disable=E1101
|
|
99
104
|
if e.code() != grpc.StatusCode.DEADLINE_EXCEEDED:
|
|
@@ -108,27 +113,21 @@ def stream_logs(
|
|
|
108
113
|
def print_logs(run_id: int, channel: grpc.Channel, timeout: int) -> None:
|
|
109
114
|
"""Print logs from the beginning of a run."""
|
|
110
115
|
stub = ExecStub(channel)
|
|
111
|
-
req = StreamLogsRequest(run_id=run_id)
|
|
116
|
+
req = StreamLogsRequest(run_id=run_id, after_timestamp=0.0)
|
|
112
117
|
|
|
113
118
|
try:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
break
|
|
127
|
-
if e.code() == grpc.StatusCode.CANCELLED:
|
|
128
|
-
break
|
|
129
|
-
raise e
|
|
130
|
-
except KeyboardInterrupt:
|
|
131
|
-
logger(DEBUG, "Stream interrupted by user")
|
|
119
|
+
with unauthenticated_exc_handler():
|
|
120
|
+
# Enforce timeout for graceful exit
|
|
121
|
+
for res in stub.StreamLogs(req, timeout=timeout):
|
|
122
|
+
print(res.log_output)
|
|
123
|
+
break
|
|
124
|
+
except grpc.RpcError as e:
|
|
125
|
+
if e.code() == grpc.StatusCode.NOT_FOUND: # pylint: disable=E1101
|
|
126
|
+
logger(ERROR, "Invalid run_id `%s`, exiting", run_id)
|
|
127
|
+
elif e.code() == grpc.StatusCode.DEADLINE_EXCEEDED: # pylint: disable=E1101
|
|
128
|
+
pass
|
|
129
|
+
else:
|
|
130
|
+
raise e
|
|
132
131
|
finally:
|
|
133
132
|
channel.close()
|
|
134
133
|
logger(DEBUG, "Channel closed")
|
|
@@ -213,7 +213,7 @@ def new(
|
|
|
213
213
|
else:
|
|
214
214
|
challenge_name = "Code"
|
|
215
215
|
num_clients = "10"
|
|
216
|
-
dataset_name = "
|
|
216
|
+
dataset_name = "flwrlabs/code-alpaca-20k"
|
|
217
217
|
|
|
218
218
|
context["llm_challenge_str"] = llm_challenge_str
|
|
219
219
|
context["fraction_fit"] = fraction_fit
|
|
@@ -13,7 +13,7 @@ dataset: [dataset1, dataset2] # TODO: list of datasets you include in your basel
|
|
|
13
13
|
|
|
14
14
|
> [!IMPORTANT]
|
|
15
15
|
> To help having all baselines similarly formatted and structured, we have included two scripts in `baselines/dev` that when run will format your code and run some tests checking if it's formatted.
|
|
16
|
-
> These checks use standard packages such as `isort`, `black`, `pylint` and others. You as a baseline creator will need to install additional
|
|
16
|
+
> These checks use standard packages such as `isort`, `black`, `pylint` and others. You as a baseline creator will need to install additional packages. These are already specified in the `pyproject.toml` of
|
|
17
17
|
> your baseline. Follow these steps:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
@@ -66,9 +66,9 @@ cd .. # so you are in the `flower/baselines` directory
|
|
|
66
66
|
|
|
67
67
|
## About this baseline
|
|
68
68
|
|
|
69
|
-
**What’s implemented:** :warning: *_Concisely describe what experiment(s) (e.g. Figure 1, Table 2, etc) in the publication can be replicated by running the code. Please only use a few sentences. ”_*
|
|
69
|
+
**What’s implemented:** :warning: *_Concisely describe what experiment(s) (e.g. Figure 1, Table 2, etc.) in the publication can be replicated by running the code. Please only use a few sentences. ”_*
|
|
70
70
|
|
|
71
|
-
**Datasets:** :warning: *_List the datasets you used (if you used a medium to large dataset, >10GB please also include the sizes of the dataset). We highly recommend using [FlowerDatasets](https://flower.ai/docs/datasets/index.html) to download and partition your dataset. If you have other ways to download the data, you can also use `FlowerDatasets` to
|
|
71
|
+
**Datasets:** :warning: *_List the datasets you used (if you used a medium to large dataset, >10GB please also include the sizes of the dataset). We highly recommend using [FlowerDatasets](https://flower.ai/docs/datasets/index.html) to download and partition your dataset. If you have other ways to download the data, you can also use `FlowerDatasets` to partition it._*
|
|
72
72
|
|
|
73
73
|
**Hardware Setup:** :warning: *_Give some details about the hardware (e.g. a server with 8x V100 32GB and 256GB of RAM) you used to run the experiments for this baseline. Indicate how long it took to run the experiments. Someone out there might not have access to the same resources you have so, could you list the absolute minimum hardware needed to run the experiment in a reasonable amount of time ? (e.g. minimum is 1x 16GB GPU otherwise a client model can’t be trained with a sufficiently large batch size). Could you test this works too?_*
|
|
74
74
|
|
|
@@ -122,6 +122,6 @@ flwr run . --run-config learning-rate=0.1,coefficient=0.123
|
|
|
122
122
|
flwr run . --run-config <my-big-experiment-config>.toml
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
:warning: _It is preferable to show a single
|
|
125
|
+
:warning: _It is preferable to show a single command (or multiple commands if they belong to the same experiment) and then a table/plot with the expected results, instead of showing all the commands first and then all the results/plots._
|
|
126
126
|
:warning: _If you present plots or other figures, please include either a Jupyter notebook showing how to create them or include a utility function that can be called after the experiments finish running._
|
|
127
127
|
:warning: If you include plots or figures, save them in `.png` format and place them in a new directory named `_static` at the same level as your `README.md`.
|
|
@@ -18,7 +18,7 @@ Refer to the [How to Run Simulations](https://flower.ai/docs/framework/how-to-ru
|
|
|
18
18
|
|
|
19
19
|
## Run with the Deployment Engine
|
|
20
20
|
|
|
21
|
-
Follow this [how-to guide](https://flower.ai/docs/framework/how-to-run-flower-with-deployment-engine.html) to run the same app in this example but with Flower's Deployment Engine. After that, you might be
|
|
21
|
+
Follow this [how-to guide](https://flower.ai/docs/framework/how-to-run-flower-with-deployment-engine.html) to run the same app in this example but with Flower's Deployment Engine. After that, you might be interested in setting up [secure TLS-enabled communications](https://flower.ai/docs/framework/how-to-enable-tls-connections.html) and [SuperNode authentication](https://flower.ai/docs/framework/how-to-authenticate-supernodes.html) in your federation.
|
|
22
22
|
|
|
23
23
|
You can run Flower on Docker too! Check out the [Flower with Docker](https://flower.ai/docs/framework/docker/index.html) documentation.
|
|
24
24
|
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
import inspect
|
|
19
|
+
from collections.abc import Iterator
|
|
20
|
+
from contextlib import contextmanager
|
|
19
21
|
from typing import Callable, Optional
|
|
20
22
|
|
|
21
23
|
from flwr.client.client import Client
|
|
@@ -71,6 +73,11 @@ def _inspect_maybe_adapt_client_fn_signature(client_fn: ClientFnExt) -> ClientFn
|
|
|
71
73
|
return client_fn
|
|
72
74
|
|
|
73
75
|
|
|
76
|
+
@contextmanager
|
|
77
|
+
def _empty_lifespan(_: Context) -> Iterator[None]:
|
|
78
|
+
yield
|
|
79
|
+
|
|
80
|
+
|
|
74
81
|
class ClientAppException(Exception):
|
|
75
82
|
"""Exception raised when an exception is raised while executing a ClientApp."""
|
|
76
83
|
|
|
@@ -95,15 +102,6 @@ class ClientApp:
|
|
|
95
102
|
>>> return FlowerClient().to_client()
|
|
96
103
|
>>>
|
|
97
104
|
>>> app = ClientApp(client_fn)
|
|
98
|
-
|
|
99
|
-
If the above code is in a Python module called `client`, it can be started as
|
|
100
|
-
follows:
|
|
101
|
-
|
|
102
|
-
>>> flower-client-app client:app --insecure
|
|
103
|
-
|
|
104
|
-
In this `client:app` example, `client` refers to the Python module `client.py` in
|
|
105
|
-
which the previous code lives in and `app` refers to the global attribute `app` that
|
|
106
|
-
points to an object of type `ClientApp`.
|
|
107
105
|
"""
|
|
108
106
|
|
|
109
107
|
def __init__(
|
|
@@ -135,35 +133,41 @@ class ClientApp:
|
|
|
135
133
|
self._train: Optional[ClientAppCallable] = None
|
|
136
134
|
self._evaluate: Optional[ClientAppCallable] = None
|
|
137
135
|
self._query: Optional[ClientAppCallable] = None
|
|
136
|
+
self._lifespan = _empty_lifespan
|
|
138
137
|
|
|
139
138
|
def __call__(self, message: Message, context: Context) -> Message:
|
|
140
139
|
"""Execute `ClientApp`."""
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
140
|
+
with self._lifespan(context):
|
|
141
|
+
# Execute message using `client_fn`
|
|
142
|
+
if self._call:
|
|
143
|
+
return self._call(message, context)
|
|
144
|
+
|
|
145
|
+
# Execute message using a new
|
|
146
|
+
if message.metadata.message_type == MessageType.TRAIN:
|
|
147
|
+
if self._train:
|
|
148
|
+
return self._train(message, context)
|
|
149
|
+
raise ValueError("No `train` function registered")
|
|
150
|
+
if message.metadata.message_type == MessageType.EVALUATE:
|
|
151
|
+
if self._evaluate:
|
|
152
|
+
return self._evaluate(message, context)
|
|
153
|
+
raise ValueError("No `evaluate` function registered")
|
|
154
|
+
if message.metadata.message_type == MessageType.QUERY:
|
|
155
|
+
if self._query:
|
|
156
|
+
return self._query(message, context)
|
|
157
|
+
raise ValueError("No `query` function registered")
|
|
158
|
+
|
|
159
|
+
# Message type did not match one of the known message types abvoe
|
|
160
|
+
raise ValueError(f"Unknown message_type: {message.metadata.message_type}")
|
|
161
|
+
|
|
162
|
+
def train(
|
|
163
|
+
self, mods: Optional[list[Mod]] = None
|
|
164
|
+
) -> Callable[[ClientAppCallable], ClientAppCallable]:
|
|
163
165
|
"""Return a decorator that registers the train fn with the client app.
|
|
164
166
|
|
|
165
167
|
Examples
|
|
166
168
|
--------
|
|
169
|
+
Registering a train function:
|
|
170
|
+
|
|
167
171
|
>>> app = ClientApp()
|
|
168
172
|
>>>
|
|
169
173
|
>>> @app.train()
|
|
@@ -171,6 +175,17 @@ class ClientApp:
|
|
|
171
175
|
>>> print("ClientApp training running")
|
|
172
176
|
>>> # Create and return an echo reply message
|
|
173
177
|
>>> return message.create_reply(content=message.content())
|
|
178
|
+
|
|
179
|
+
Registering a train function with a function-specific modifier:
|
|
180
|
+
|
|
181
|
+
>>> from flwr.client.mod import message_size_mod
|
|
182
|
+
>>>
|
|
183
|
+
>>> app = ClientApp()
|
|
184
|
+
>>>
|
|
185
|
+
>>> @app.train(mods=[message_size_mod])
|
|
186
|
+
>>> def train(message: Message, context: Context) -> Message:
|
|
187
|
+
>>> print("ClientApp training running with message size mod")
|
|
188
|
+
>>> return message.create_reply(content=message.content())
|
|
174
189
|
"""
|
|
175
190
|
|
|
176
191
|
def train_decorator(train_fn: ClientAppCallable) -> ClientAppCallable:
|
|
@@ -182,18 +197,22 @@ class ClientApp:
|
|
|
182
197
|
|
|
183
198
|
# Register provided function with the ClientApp object
|
|
184
199
|
# Wrap mods around the wrapped step function
|
|
185
|
-
self._train = make_ffn(train_fn, self._mods)
|
|
200
|
+
self._train = make_ffn(train_fn, self._mods + (mods or []))
|
|
186
201
|
|
|
187
202
|
# Return provided function unmodified
|
|
188
203
|
return train_fn
|
|
189
204
|
|
|
190
205
|
return train_decorator
|
|
191
206
|
|
|
192
|
-
def evaluate(
|
|
207
|
+
def evaluate(
|
|
208
|
+
self, mods: Optional[list[Mod]] = None
|
|
209
|
+
) -> Callable[[ClientAppCallable], ClientAppCallable]:
|
|
193
210
|
"""Return a decorator that registers the evaluate fn with the client app.
|
|
194
211
|
|
|
195
212
|
Examples
|
|
196
213
|
--------
|
|
214
|
+
Registering an evaluate function:
|
|
215
|
+
|
|
197
216
|
>>> app = ClientApp()
|
|
198
217
|
>>>
|
|
199
218
|
>>> @app.evaluate()
|
|
@@ -201,6 +220,18 @@ class ClientApp:
|
|
|
201
220
|
>>> print("ClientApp evaluation running")
|
|
202
221
|
>>> # Create and return an echo reply message
|
|
203
222
|
>>> return message.create_reply(content=message.content())
|
|
223
|
+
|
|
224
|
+
Registering an evaluate function with a function-specific modifier:
|
|
225
|
+
|
|
226
|
+
>>> from flwr.client.mod import message_size_mod
|
|
227
|
+
>>>
|
|
228
|
+
>>> app = ClientApp()
|
|
229
|
+
>>>
|
|
230
|
+
>>> @app.evaluate(mods=[message_size_mod])
|
|
231
|
+
>>> def evaluate(message: Message, context: Context) -> Message:
|
|
232
|
+
>>> print("ClientApp evaluation running with message size mod")
|
|
233
|
+
>>> # Create and return an echo reply message
|
|
234
|
+
>>> return message.create_reply(content=message.content())
|
|
204
235
|
"""
|
|
205
236
|
|
|
206
237
|
def evaluate_decorator(evaluate_fn: ClientAppCallable) -> ClientAppCallable:
|
|
@@ -212,18 +243,22 @@ class ClientApp:
|
|
|
212
243
|
|
|
213
244
|
# Register provided function with the ClientApp object
|
|
214
245
|
# Wrap mods around the wrapped step function
|
|
215
|
-
self._evaluate = make_ffn(evaluate_fn, self._mods)
|
|
246
|
+
self._evaluate = make_ffn(evaluate_fn, self._mods + (mods or []))
|
|
216
247
|
|
|
217
248
|
# Return provided function unmodified
|
|
218
249
|
return evaluate_fn
|
|
219
250
|
|
|
220
251
|
return evaluate_decorator
|
|
221
252
|
|
|
222
|
-
def query(
|
|
253
|
+
def query(
|
|
254
|
+
self, mods: Optional[list[Mod]] = None
|
|
255
|
+
) -> Callable[[ClientAppCallable], ClientAppCallable]:
|
|
223
256
|
"""Return a decorator that registers the query fn with the client app.
|
|
224
257
|
|
|
225
258
|
Examples
|
|
226
259
|
--------
|
|
260
|
+
Registering a query function:
|
|
261
|
+
|
|
227
262
|
>>> app = ClientApp()
|
|
228
263
|
>>>
|
|
229
264
|
>>> @app.query()
|
|
@@ -231,6 +266,18 @@ class ClientApp:
|
|
|
231
266
|
>>> print("ClientApp query running")
|
|
232
267
|
>>> # Create and return an echo reply message
|
|
233
268
|
>>> return message.create_reply(content=message.content())
|
|
269
|
+
|
|
270
|
+
Registering a query function with a function-specific modifier:
|
|
271
|
+
|
|
272
|
+
>>> from flwr.client.mod import message_size_mod
|
|
273
|
+
>>>
|
|
274
|
+
>>> app = ClientApp()
|
|
275
|
+
>>>
|
|
276
|
+
>>> @app.query(mods=[message_size_mod])
|
|
277
|
+
>>> def query(message: Message, context: Context) -> Message:
|
|
278
|
+
>>> print("ClientApp query running with message size mod")
|
|
279
|
+
>>> # Create and return an echo reply message
|
|
280
|
+
>>> return message.create_reply(content=message.content())
|
|
234
281
|
"""
|
|
235
282
|
|
|
236
283
|
def query_decorator(query_fn: ClientAppCallable) -> ClientAppCallable:
|
|
@@ -242,13 +289,77 @@ class ClientApp:
|
|
|
242
289
|
|
|
243
290
|
# Register provided function with the ClientApp object
|
|
244
291
|
# Wrap mods around the wrapped step function
|
|
245
|
-
self._query = make_ffn(query_fn, self._mods)
|
|
292
|
+
self._query = make_ffn(query_fn, self._mods + (mods or []))
|
|
246
293
|
|
|
247
294
|
# Return provided function unmodified
|
|
248
295
|
return query_fn
|
|
249
296
|
|
|
250
297
|
return query_decorator
|
|
251
298
|
|
|
299
|
+
def lifespan(
|
|
300
|
+
self,
|
|
301
|
+
) -> Callable[
|
|
302
|
+
[Callable[[Context], Iterator[None]]], Callable[[Context], Iterator[None]]
|
|
303
|
+
]:
|
|
304
|
+
"""Return a decorator that registers the lifespan fn with the client app.
|
|
305
|
+
|
|
306
|
+
The decorated function should accept a `Context` object and use `yield`
|
|
307
|
+
to define enter and exit behavior.
|
|
308
|
+
|
|
309
|
+
Examples
|
|
310
|
+
--------
|
|
311
|
+
>>> app = ClientApp()
|
|
312
|
+
>>>
|
|
313
|
+
>>> @app.lifespan()
|
|
314
|
+
>>> def lifespan(context: Context) -> None:
|
|
315
|
+
>>> # Perform initialization tasks before the app starts
|
|
316
|
+
>>> print("Initializing ClientApp")
|
|
317
|
+
>>>
|
|
318
|
+
>>> yield # ClientApp is running
|
|
319
|
+
>>>
|
|
320
|
+
>>> # Perform cleanup tasks after the app stops
|
|
321
|
+
>>> print("Cleaning up ClientApp")
|
|
322
|
+
"""
|
|
323
|
+
|
|
324
|
+
def lifespan_decorator(
|
|
325
|
+
lifespan_fn: Callable[[Context], Iterator[None]]
|
|
326
|
+
) -> Callable[[Context], Iterator[None]]:
|
|
327
|
+
"""Register the lifespan fn with the ServerApp object."""
|
|
328
|
+
warn_preview_feature("ClientApp-register-lifespan-function")
|
|
329
|
+
|
|
330
|
+
@contextmanager
|
|
331
|
+
def decorated_lifespan(context: Context) -> Iterator[None]:
|
|
332
|
+
# Execute the code before `yield` in lifespan_fn
|
|
333
|
+
try:
|
|
334
|
+
if not isinstance(it := lifespan_fn(context), Iterator):
|
|
335
|
+
raise StopIteration
|
|
336
|
+
next(it)
|
|
337
|
+
except StopIteration:
|
|
338
|
+
raise RuntimeError(
|
|
339
|
+
"lifespan function should yield at least once."
|
|
340
|
+
) from None
|
|
341
|
+
|
|
342
|
+
try:
|
|
343
|
+
# Enter the context
|
|
344
|
+
yield
|
|
345
|
+
finally:
|
|
346
|
+
try:
|
|
347
|
+
# Execute the code after `yield` in lifespan_fn
|
|
348
|
+
next(it)
|
|
349
|
+
except StopIteration:
|
|
350
|
+
pass
|
|
351
|
+
else:
|
|
352
|
+
raise RuntimeError("lifespan function should only yield once.")
|
|
353
|
+
|
|
354
|
+
# Register provided function with the ClientApp object
|
|
355
|
+
# Ignore mypy error because of different argument names (`_` vs `context`)
|
|
356
|
+
self._lifespan = decorated_lifespan # type: ignore
|
|
357
|
+
|
|
358
|
+
# Return provided function unmodified
|
|
359
|
+
return lifespan_fn
|
|
360
|
+
|
|
361
|
+
return lifespan_decorator
|
|
362
|
+
|
|
252
363
|
|
|
253
364
|
class LoadClientAppError(Exception):
|
|
254
365
|
"""Error when trying to load `ClientApp`."""
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
import argparse
|
|
19
|
+
import gc
|
|
19
20
|
import time
|
|
20
21
|
from logging import DEBUG, ERROR, INFO
|
|
21
22
|
from typing import Optional
|
|
@@ -160,6 +161,9 @@ def run_clientapp( # pylint: disable=R0914
|
|
|
160
161
|
stub=stub, token=token, message=reply_message, context=context
|
|
161
162
|
)
|
|
162
163
|
|
|
164
|
+
del client_app, message, context, run, fab, reply_message
|
|
165
|
+
gc.collect()
|
|
166
|
+
|
|
163
167
|
# Reset token to `None` to prevent flwr-clientapp from trying to pull the
|
|
164
168
|
# same inputs again
|
|
165
169
|
token = None
|
|
@@ -82,7 +82,7 @@ def handle_control_message(message: Message) -> tuple[Optional[Message], int]:
|
|
|
82
82
|
recordset = RecordSet()
|
|
83
83
|
recordset.configs_records["config"] = ConfigsRecord({"reason": reason})
|
|
84
84
|
out_message = message.create_reply(recordset)
|
|
85
|
-
# Return
|
|
85
|
+
# Return Message and sleep duration
|
|
86
86
|
return out_message, sleep_duration
|
|
87
87
|
|
|
88
88
|
# Any other message
|