flwr 1.13.1__tar.gz → 1.15.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.13.1 → flwr-1.15.0}/PKG-INFO +14 -13
- {flwr-1.13.1 → flwr-1.15.0}/README.md +6 -6
- {flwr-1.13.1 → flwr-1.15.0}/pyproject.toml +26 -22
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/app.py +5 -0
- flwr-1.15.0/src/py/flwr/cli/auth_plugin/__init__.py +31 -0
- flwr-1.15.0/src/py/flwr/cli/auth_plugin/oidc_cli_plugin.py +150 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/build.py +1 -0
- flwr-1.15.0/src/py/flwr/cli/cli_user_auth_interceptor.py +90 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/config_utils.py +43 -149
- flwr-1.15.0/src/py/flwr/cli/constant.py +27 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/example.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/install.py +2 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/log.py +34 -37
- flwr-1.15.0/src/py/flwr/cli/login/__init__.py +22 -0
- flwr-1.15.0/src/py/flwr/cli/login/login.py +116 -0
- flwr-1.15.0/src/py/flwr/cli/ls.py +336 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/__init__.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/new.py +2 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/.gitignore.tpl +3 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/README.md.tpl +3 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +4 -4
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +4 -4
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +4 -4
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.jax.toml.tpl +2 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +3 -4
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +2 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +4 -4
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +3 -3
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +2 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/run/__init__.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/run/run.py +103 -43
- flwr-1.15.0/src/py/flwr/cli/stop.py +139 -0
- flwr-1.15.0/src/py/flwr/cli/utils.py +316 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/app.py +49 -50
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/client.py +1 -32
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/clientapp/app.py +23 -26
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/clientapp/utils.py +2 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_adapter_client/connection.py +1 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_client/connection.py +2 -13
- flwr-1.15.0/src/py/flwr/client/grpc_rere_client/client_interceptor.py +70 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_rere_client/connection.py +59 -43
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_rere_client/grpc_adapter.py +12 -12
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/message_handler/message_handler.py +1 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/message_handler/task_handler.py +0 -17
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/comms_mods.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/localdp_mod.py +1 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/nodestate/__init__.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/nodestate/nodestate.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/nodestate/nodestate_factory.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/numpy_client.py +0 -44
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/rest_client/connection.py +37 -29
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/supernode/app.py +20 -74
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/address.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/args.py +26 -47
- flwr-1.15.0/src/py/flwr/common/auth_plugin/__init__.py +24 -0
- flwr-1.15.0/src/py/flwr/common/auth_plugin/auth_plugin.py +122 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/config.py +169 -17
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/constant.py +38 -9
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/differential_privacy.py +2 -1
- flwr-1.15.0/src/py/flwr/common/exit/__init__.py +24 -0
- flwr-1.15.0/src/py/flwr/common/exit/exit.py +99 -0
- flwr-1.15.0/src/py/flwr/common/exit/exit_code.py +93 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/exit_handlers.py +24 -10
- flwr-1.13.1/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py → flwr-1.15.0/src/py/flwr/common/grpc.py +62 -120
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/logger.py +66 -7
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/message.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/object_ref.py +57 -54
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/pyproject.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/__init__.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/parametersrecord.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/recordset.py +1 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/retry_invoker.py +77 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +45 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/secaggplus_utils.py +2 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/serde.py +6 -4
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/telemetry.py +15 -4
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/typing.py +32 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/version.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/clientappio_pb2.py +1 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/error_pb2.py +1 -1
- flwr-1.15.0/src/py/flwr/proto/exec_pb2.py +62 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/exec_pb2.pyi +80 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/exec_pb2_grpc.py +102 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/exec_pb2_grpc.pyi +39 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fab_pb2.py +5 -5
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fab_pb2.pyi +4 -1
- flwr-1.15.0/src/py/flwr/proto/fleet_pb2.py +56 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fleet_pb2.pyi +23 -23
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fleet_pb2_grpc.py +30 -30
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fleet_pb2_grpc.pyi +20 -20
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/grpcadapter_pb2.py +1 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/log_pb2.py +1 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/message_pb2.py +1 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/node_pb2.py +3 -3
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/node_pb2.pyi +1 -4
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/recordset_pb2.py +1 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/run_pb2.py +1 -1
- flwr-1.15.0/src/py/flwr/proto/serverappio_pb2.py +51 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/serverappio_pb2.pyi +32 -32
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/serverappio_pb2_grpc.py +62 -28
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/serverappio_pb2_grpc.pyi +29 -16
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/simulationio_pb2.py +3 -3
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/simulationio_pb2_grpc.py +34 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/simulationio_pb2_grpc.pyi +13 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/task_pb2.py +1 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/transport_pb2.py +1 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/app.py +152 -112
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/compat/app_utils.py +7 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/compat/driver_client_proxy.py +1 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/driver/grpc_driver.py +38 -85
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/driver/inmemory_driver.py +7 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/run_serverapp.py +8 -9
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/serverapp/app.py +37 -13
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/dpfedavg_fixed.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/driver/serverappio_grpc.py +2 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/driver/serverappio_servicer.py +148 -63
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/ffs/disk_ffs.py +1 -0
- flwr-1.15.0/src/py/flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +94 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -0
- flwr-1.15.0/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +126 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +56 -35
- flwr-1.15.0/src/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +156 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/message_handler/message_handler.py +69 -29
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +20 -19
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/vce/__init__.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/vce/backend/__init__.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/vce/vce_api.py +2 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/in_memory_linkstate.py +60 -99
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/linkstate.py +30 -36
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/sqlite_linkstate.py +105 -188
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/utils.py +18 -8
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/simulation/simulationio_grpc.py +1 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/simulation/simulationio_servicer.py +33 -0
- flwr-1.15.0/src/py/flwr/server/superlink/utils.py +65 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/utils/validator.py +9 -34
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/app.py +20 -10
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/legacy_app.py +4 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/ray_transport/ray_actor.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/ray_transport/utils.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/run_simulation.py +36 -22
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/simulationio_connection.py +5 -1
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/app.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/deployment.py +1 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/exec_grpc.py +20 -2
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/exec_servicer.py +97 -2
- flwr-1.15.0/src/py/flwr/superexec/exec_user_auth_interceptor.py +101 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/executor.py +1 -0
- flwr-1.13.1/src/py/flwr/cli/ls.py +0 -228
- flwr-1.13.1/src/py/flwr/cli/utils.py +0 -138
- flwr-1.13.1/src/py/flwr/client/grpc_rere_client/client_interceptor.py +0 -170
- flwr-1.13.1/src/py/flwr/common/grpc.py +0 -68
- flwr-1.13.1/src/py/flwr/proto/common_pb2.py +0 -36
- flwr-1.13.1/src/py/flwr/proto/common_pb2.pyi +0 -121
- flwr-1.13.1/src/py/flwr/proto/common_pb2_grpc.py +0 -4
- flwr-1.13.1/src/py/flwr/proto/common_pb2_grpc.pyi +0 -4
- flwr-1.13.1/src/py/flwr/proto/control_pb2.py +0 -27
- flwr-1.13.1/src/py/flwr/proto/control_pb2.pyi +0 -7
- flwr-1.13.1/src/py/flwr/proto/control_pb2_grpc.py +0 -135
- flwr-1.13.1/src/py/flwr/proto/control_pb2_grpc.pyi +0 -53
- flwr-1.13.1/src/py/flwr/proto/exec_pb2.py +0 -50
- flwr-1.13.1/src/py/flwr/proto/fleet_pb2.py +0 -56
- flwr-1.13.1/src/py/flwr/proto/serverappio_pb2.py +0 -52
- flwr-1.13.1/src/py/flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +0 -161
- flwr-1.13.1/src/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +0 -226
- {flwr-1.13.1 → flwr-1.15.0}/LICENSE +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/LICENSE.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/README.baseline.md.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/README.flowertune.md.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.baseline.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.huggingface.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.jax.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.mlx.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/model.baseline.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.baseline.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.huggingface.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.jax.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.mlx.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.huggingface.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.jax.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.mlx.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.numpy.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.sklearn.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/cli/new/templates/app/code/utils.baseline.py.tpl +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/client_app.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/clientapp/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/clientapp/clientappio_servicer.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/dpfedavg_numpy_client.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_adapter_client/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_client/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/grpc_rere_client/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/heartbeat.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/message_handler/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/centraldp_mods.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/mod/utils.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/nodestate/in_memory_nodestate.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/rest_client/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/run_info_store.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/supernode/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/client/typing.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/context.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/date.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/differential_privacy_constants.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/dp.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/parameter.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/configsrecord.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/conversion_utils.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/metricsrecord.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/record/typeddict.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/recordset_compat.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/quantization.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/clientappio_pb2.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/clientappio_pb2_grpc.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/clientappio_pb2_grpc.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/error_pb2.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/error_pb2_grpc.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/error_pb2_grpc.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fab_pb2_grpc.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/fab_pb2_grpc.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/grpcadapter_pb2.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/grpcadapter_pb2_grpc.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/grpcadapter_pb2_grpc.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/log_pb2.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/log_pb2_grpc.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/log_pb2_grpc.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/message_pb2.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/message_pb2_grpc.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/message_pb2_grpc.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/node_pb2_grpc.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/node_pb2_grpc.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/recordset_pb2.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/recordset_pb2_grpc.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/recordset_pb2_grpc.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/run_pb2.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/run_pb2_grpc.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/run_pb2_grpc.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/simulationio_pb2.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/task_pb2.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/task_pb2_grpc.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/task_pb2_grpc.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/transport_pb2.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/transport_pb2_grpc.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/py.typed +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/client_manager.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/client_proxy.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/compat/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/compat/app.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/compat/legacy_context.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/criterion.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/driver/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/driver/driver.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/history.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/server.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/server_app.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/server_config.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/serverapp/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/serverapp_components.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/aggregate.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/bulyan.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedadagrad.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedadam.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedavg.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedavg_android.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedavgm.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedmedian.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedopt.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedprox.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/fedyogi.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/krum.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/qfedavg.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/strategy/strategy.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/driver/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/ffs/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/ffs/ffs.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/ffs/ffs_factory.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_adapter/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/linkstate/linkstate_factory.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/superlink/simulation/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/typing.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/utils/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/utils/tensorboard.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/constant.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/default_workflows.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/ray_transport/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/__init__.py +0 -0
- {flwr-1.13.1 → flwr-1.15.0}/src/py/flwr/superexec/simulation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: flwr
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.15.0
|
|
4
4
|
Summary: Flower: A Friendly Federated AI Framework
|
|
5
5
|
Home-page: https://flower.ai
|
|
6
6
|
License: Apache-2.0
|
|
@@ -32,21 +32,22 @@ 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 (>=
|
|
36
|
-
Requires-Dist: grpcio (>=1.
|
|
35
|
+
Requires-Dist: cryptography (>=43.0.1,<44.0.0)
|
|
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)
|
|
39
39
|
Requires-Dist: pathspec (>=0.12.1,<0.13.0)
|
|
40
|
-
Requires-Dist: protobuf (>=4.
|
|
40
|
+
Requires-Dist: protobuf (>=4.21.6,<5.0.0)
|
|
41
41
|
Requires-Dist: pycryptodome (>=3.18.0,<4.0.0)
|
|
42
|
+
Requires-Dist: pyyaml (>=6.0.2,<7.0.0)
|
|
42
43
|
Requires-Dist: ray (==2.10.0) ; (python_version >= "3.9" and python_version < "3.12") and (extra == "simulation")
|
|
43
|
-
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
44
|
+
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
44
45
|
Requires-Dist: rich (>=13.5.0,<14.0.0)
|
|
45
|
-
Requires-Dist: starlette (>=0.
|
|
46
|
+
Requires-Dist: starlette (>=0.45.2,<0.46.0) ; extra == "rest"
|
|
46
47
|
Requires-Dist: tomli (>=2.0.1,<3.0.0)
|
|
47
48
|
Requires-Dist: tomli-w (>=1.0.0,<2.0.0)
|
|
48
49
|
Requires-Dist: typer (>=0.12.5,<0.13.0)
|
|
49
|
-
Requires-Dist: uvicorn[standard] (>=0.
|
|
50
|
+
Requires-Dist: uvicorn[standard] (>=0.34.0,<0.35.0) ; extra == "rest"
|
|
50
51
|
Project-URL: Documentation, https://flower.ai
|
|
51
52
|
Project-URL: Repository, https://github.com/adap/flower
|
|
52
53
|
Description-Content-Type: text/markdown
|
|
@@ -87,7 +88,7 @@ design of Flower is based on a few guiding principles:
|
|
|
87
88
|
|
|
88
89
|
- **Framework-agnostic**: Different machine learning frameworks have different
|
|
89
90
|
strengths. Flower can be used with any machine learning framework, for
|
|
90
|
-
example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
|
|
91
|
+
example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [LeRobot](https://github.com/huggingface/lerobot) for federated robots, [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
|
|
91
92
|
for users who enjoy computing gradients by hand.
|
|
92
93
|
|
|
93
94
|
- **Understandable**: Flower is written with maintainability in mind. The
|
|
@@ -101,23 +102,23 @@ Flower's goal is to make federated learning accessible to everyone. This series
|
|
|
101
102
|
|
|
102
103
|
0. **What is Federated Learning?**
|
|
103
104
|
|
|
104
|
-
[](https://colab.research.google.com/github/adap/flower/blob/main/
|
|
105
|
+
[](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-what-is-federated-learning.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-what-is-federated-learning.ipynb))
|
|
105
106
|
|
|
106
107
|
1. **An Introduction to Federated Learning**
|
|
107
108
|
|
|
108
|
-
[](https://colab.research.google.com/github/adap/flower/blob/main/
|
|
109
|
+
[](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-get-started-with-flower-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-get-started-with-flower-pytorch.ipynb))
|
|
109
110
|
|
|
110
111
|
2. **Using Strategies in Federated Learning**
|
|
111
112
|
|
|
112
|
-
[](https://colab.research.google.com/github/adap/flower/blob/main/
|
|
113
|
+
[](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb))
|
|
113
114
|
|
|
114
115
|
3. **Building Strategies for Federated Learning**
|
|
115
116
|
|
|
116
|
-
[](https://colab.research.google.com/github/adap/flower/blob/main/
|
|
117
|
+
[](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb))
|
|
117
118
|
|
|
118
119
|
4. **Custom Clients for Federated Learning**
|
|
119
120
|
|
|
120
|
-
[](https://colab.research.google.com/github/adap/flower/blob/main/
|
|
121
|
+
[](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-customize-the-client-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-customize-the-client-pytorch.ipynb))
|
|
121
122
|
|
|
122
123
|
Stay tuned, more tutorials are coming soon. Topics include **Privacy and Security in Federated Learning**, and **Scaling Federated Learning**.
|
|
123
124
|
|
|
@@ -34,7 +34,7 @@ design of Flower is based on a few guiding principles:
|
|
|
34
34
|
|
|
35
35
|
- **Framework-agnostic**: Different machine learning frameworks have different
|
|
36
36
|
strengths. Flower can be used with any machine learning framework, for
|
|
37
|
-
example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
|
|
37
|
+
example, [PyTorch](https://pytorch.org), [TensorFlow](https://tensorflow.org), [Hugging Face Transformers](https://huggingface.co/), [PyTorch Lightning](https://pytorchlightning.ai/), [scikit-learn](https://scikit-learn.org/), [JAX](https://jax.readthedocs.io/), [TFLite](https://tensorflow.org/lite/), [MONAI](https://docs.monai.io/en/latest/index.html), [fastai](https://www.fast.ai/), [MLX](https://ml-explore.github.io/mlx/build/html/index.html), [XGBoost](https://xgboost.readthedocs.io/en/stable/), [LeRobot](https://github.com/huggingface/lerobot) for federated robots, [Pandas](https://pandas.pydata.org/) for federated analytics, or even raw [NumPy](https://numpy.org/)
|
|
38
38
|
for users who enjoy computing gradients by hand.
|
|
39
39
|
|
|
40
40
|
- **Understandable**: Flower is written with maintainability in mind. The
|
|
@@ -48,23 +48,23 @@ Flower's goal is to make federated learning accessible to everyone. This series
|
|
|
48
48
|
|
|
49
49
|
0. **What is Federated Learning?**
|
|
50
50
|
|
|
51
|
-
[](https://colab.research.google.com/github/adap/flower/blob/main/
|
|
51
|
+
[](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-what-is-federated-learning.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-what-is-federated-learning.ipynb))
|
|
52
52
|
|
|
53
53
|
1. **An Introduction to Federated Learning**
|
|
54
54
|
|
|
55
|
-
[](https://colab.research.google.com/github/adap/flower/blob/main/
|
|
55
|
+
[](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-get-started-with-flower-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-get-started-with-flower-pytorch.ipynb))
|
|
56
56
|
|
|
57
57
|
2. **Using Strategies in Federated Learning**
|
|
58
58
|
|
|
59
|
-
[](https://colab.research.google.com/github/adap/flower/blob/main/
|
|
59
|
+
[](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-use-a-federated-learning-strategy-pytorch.ipynb))
|
|
60
60
|
|
|
61
61
|
3. **Building Strategies for Federated Learning**
|
|
62
62
|
|
|
63
|
-
[](https://colab.research.google.com/github/adap/flower/blob/main/
|
|
63
|
+
[](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-build-a-strategy-from-scratch-pytorch.ipynb))
|
|
64
64
|
|
|
65
65
|
4. **Custom Clients for Federated Learning**
|
|
66
66
|
|
|
67
|
-
[](https://colab.research.google.com/github/adap/flower/blob/main/
|
|
67
|
+
[](https://colab.research.google.com/github/adap/flower/blob/main/framework/docs/source/tutorial-series-customize-the-client-pytorch.ipynb) (or open the [Jupyter Notebook](https://github.com/adap/flower/blob/main/framework/docs/source/tutorial-series-customize-the-client-pytorch.ipynb))
|
|
68
68
|
|
|
69
69
|
Stay tuned, more tutorials are coming soon. Topics include **Privacy and Security in Federated Learning**, and **Scaling Federated Learning**.
|
|
70
70
|
|
|
@@ -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.15.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>"]
|
|
@@ -68,9 +68,9 @@ flower-client-app = "flwr.client.supernode:run_client_app" # Deprecated
|
|
|
68
68
|
python = "^3.9"
|
|
69
69
|
# Mandatory dependencies
|
|
70
70
|
numpy = ">=1.26.0,<3.0.0"
|
|
71
|
-
grpcio = "^1.
|
|
72
|
-
protobuf = "^4.
|
|
73
|
-
cryptography = "^
|
|
71
|
+
grpcio = "^1.62.3,!=1.65.0"
|
|
72
|
+
protobuf = "^4.21.6"
|
|
73
|
+
cryptography = "^43.0.1"
|
|
74
74
|
pycryptodome = "^3.18.0"
|
|
75
75
|
iterators = "^0.0.2"
|
|
76
76
|
typer = "^0.12.5"
|
|
@@ -78,20 +78,21 @@ tomli = "^2.0.1"
|
|
|
78
78
|
tomli-w = "^1.0.0"
|
|
79
79
|
pathspec = "^0.12.1"
|
|
80
80
|
rich = "^13.5.0"
|
|
81
|
+
pyyaml = "^6.0.2"
|
|
82
|
+
requests = "^2.31.0"
|
|
81
83
|
# Optional dependencies (Simulation Engine)
|
|
82
84
|
ray = { version = "==2.10.0", optional = true, python = ">=3.9,<3.12" }
|
|
83
85
|
# Optional dependencies (REST transport layer)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
uvicorn = { version = "^0.23.0", extras = ["standard"], optional = true }
|
|
86
|
+
starlette = { version = "^0.45.2", optional = true }
|
|
87
|
+
uvicorn = { version = "^0.34.0", extras = ["standard"], optional = true }
|
|
87
88
|
|
|
88
89
|
[tool.poetry.extras]
|
|
89
90
|
simulation = ["ray"]
|
|
90
|
-
rest = ["
|
|
91
|
+
rest = ["starlette", "uvicorn"]
|
|
91
92
|
|
|
92
93
|
[tool.poetry.group.dev.dependencies]
|
|
93
94
|
types-dataclasses = "==0.6.6"
|
|
94
|
-
types-protobuf = "==
|
|
95
|
+
types-protobuf = "==4.21.0.7"
|
|
95
96
|
types-requests = "==2.31.0.20240125"
|
|
96
97
|
types-setuptools = "==69.0.0.20240125"
|
|
97
98
|
clang-format = "==17.0.6"
|
|
@@ -105,11 +106,11 @@ flake8 = "==5.0.4"
|
|
|
105
106
|
parameterized = "==0.9.0"
|
|
106
107
|
pytest = "==7.4.4"
|
|
107
108
|
pytest-cov = "==4.1.0"
|
|
108
|
-
pytest-watcher = "==0.4.
|
|
109
|
-
grpcio-tools = "==1.
|
|
109
|
+
pytest-watcher = "==0.4.3"
|
|
110
|
+
grpcio-tools = "==1.62.3"
|
|
110
111
|
mypy-protobuf = "==3.2.0"
|
|
111
112
|
jupyterlab = "==4.0.12"
|
|
112
|
-
rope = "==1.
|
|
113
|
+
rope = "==1.13.0"
|
|
113
114
|
semver = "==3.0.2"
|
|
114
115
|
sphinx = "==7.4.7"
|
|
115
116
|
sphinx-intl = "==2.2.0"
|
|
@@ -123,7 +124,7 @@ furo = "==2024.8.6"
|
|
|
123
124
|
sphinx-reredirects = "==0.1.5"
|
|
124
125
|
nbsphinx = "==0.9.5"
|
|
125
126
|
nbstripout = "==0.6.1"
|
|
126
|
-
ruff = "==0.
|
|
127
|
+
ruff = "==0.4.5"
|
|
127
128
|
sphinx-argparse = "==0.4.0"
|
|
128
129
|
pipreqs = "==0.4.13"
|
|
129
130
|
mdformat = "==0.7.18"
|
|
@@ -131,6 +132,7 @@ mdformat-gfm = "==0.3.6"
|
|
|
131
132
|
mdformat-frontmatter = "==2.0.1"
|
|
132
133
|
mdformat-beautysh = "==0.1.1"
|
|
133
134
|
twine = "==5.1.1"
|
|
135
|
+
types-PyYAML = "^6.0.2"
|
|
134
136
|
pyroma = "==4.2"
|
|
135
137
|
check-wheel-contents = "==0.4.0"
|
|
136
138
|
GitPython = "==3.1.32"
|
|
@@ -144,10 +146,10 @@ docsig = "==0.64.0"
|
|
|
144
146
|
|
|
145
147
|
[tool.docstrfmt]
|
|
146
148
|
extend_exclude = [
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
149
|
+
"framework/docs/source/conf.py",
|
|
150
|
+
"framework/docs/source/tutorial-quickstart-huggingface.rst",
|
|
151
|
+
"framework/docs/source/_templates/autosummary/*",
|
|
152
|
+
"framework/docs/source/ref-api/*",
|
|
151
153
|
]
|
|
152
154
|
|
|
153
155
|
[tool.isort]
|
|
@@ -199,9 +201,6 @@ wrap-descriptions = 88
|
|
|
199
201
|
[tool.ruff]
|
|
200
202
|
target-version = "py39"
|
|
201
203
|
line-length = 88
|
|
202
|
-
select = ["D", "E", "F", "W", "B", "ISC", "C4", "UP"]
|
|
203
|
-
fixable = ["D", "E", "F", "W", "B", "ISC", "C4", "UP"]
|
|
204
|
-
ignore = ["B024", "B027", "D205", "D209"]
|
|
205
204
|
exclude = [
|
|
206
205
|
".bzr",
|
|
207
206
|
".direnv",
|
|
@@ -226,10 +225,15 @@ exclude = [
|
|
|
226
225
|
"proto",
|
|
227
226
|
]
|
|
228
227
|
|
|
229
|
-
[tool.ruff.
|
|
228
|
+
[tool.ruff.lint]
|
|
229
|
+
select = ["D", "E", "F", "W", "B", "ISC", "C4", "UP"]
|
|
230
|
+
fixable = ["D", "E", "F", "W", "B", "ISC", "C4", "UP"]
|
|
231
|
+
ignore = ["B024", "B027", "D205", "D209"]
|
|
232
|
+
|
|
233
|
+
[tool.ruff.lint.pydocstyle]
|
|
230
234
|
convention = "numpy"
|
|
231
235
|
|
|
232
|
-
[tool.ruff.per-file-ignores]
|
|
236
|
+
[tool.ruff.lint.per-file-ignores]
|
|
233
237
|
"src/py/flwr/server/strategy/*.py" = ["E501"]
|
|
234
238
|
|
|
235
239
|
[tool.docsig]
|
|
@@ -14,15 +14,18 @@
|
|
|
14
14
|
# ==============================================================================
|
|
15
15
|
"""Flower command line interface."""
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
import typer
|
|
18
19
|
from typer.main import get_command
|
|
19
20
|
|
|
20
21
|
from .build import build
|
|
21
22
|
from .install import install
|
|
22
23
|
from .log import log
|
|
24
|
+
from .login import login
|
|
23
25
|
from .ls import ls
|
|
24
26
|
from .new import new
|
|
25
27
|
from .run import run
|
|
28
|
+
from .stop import stop
|
|
26
29
|
|
|
27
30
|
app = typer.Typer(
|
|
28
31
|
help=typer.style(
|
|
@@ -39,6 +42,8 @@ app.command()(build)
|
|
|
39
42
|
app.command()(install)
|
|
40
43
|
app.command()(log)
|
|
41
44
|
app.command()(ls)
|
|
45
|
+
app.command()(stop)
|
|
46
|
+
app.command()(login)
|
|
42
47
|
|
|
43
48
|
typer_click_object = get_command(app)
|
|
44
49
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Flower user auth plugins."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from flwr.common.auth_plugin import CliAuthPlugin
|
|
19
|
+
from flwr.common.constant import AuthType
|
|
20
|
+
|
|
21
|
+
from .oidc_cli_plugin import OidcCliPlugin
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_cli_auth_plugins() -> dict[str, type[CliAuthPlugin]]:
|
|
25
|
+
"""Return all CLI authentication plugins."""
|
|
26
|
+
return {AuthType.OIDC: OidcCliPlugin}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"get_cli_auth_plugins",
|
|
31
|
+
]
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Flower CLI user auth plugin for OIDC."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
import json
|
|
19
|
+
import time
|
|
20
|
+
from collections.abc import Sequence
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import Any, Optional, Union
|
|
23
|
+
|
|
24
|
+
import typer
|
|
25
|
+
|
|
26
|
+
from flwr.common.auth_plugin import CliAuthPlugin
|
|
27
|
+
from flwr.common.constant import (
|
|
28
|
+
ACCESS_TOKEN_KEY,
|
|
29
|
+
AUTH_TYPE_KEY,
|
|
30
|
+
REFRESH_TOKEN_KEY,
|
|
31
|
+
AuthType,
|
|
32
|
+
)
|
|
33
|
+
from flwr.common.typing import UserAuthCredentials, UserAuthLoginDetails
|
|
34
|
+
from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
|
|
35
|
+
GetAuthTokensRequest,
|
|
36
|
+
GetAuthTokensResponse,
|
|
37
|
+
)
|
|
38
|
+
from flwr.proto.exec_pb2_grpc import ExecStub
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class OidcCliPlugin(CliAuthPlugin):
|
|
42
|
+
"""Flower OIDC auth plugin for CLI."""
|
|
43
|
+
|
|
44
|
+
def __init__(self, credentials_path: Path):
|
|
45
|
+
self.access_token: Optional[str] = None
|
|
46
|
+
self.refresh_token: Optional[str] = None
|
|
47
|
+
self.credentials_path = credentials_path
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def login(
|
|
51
|
+
login_details: UserAuthLoginDetails,
|
|
52
|
+
exec_stub: ExecStub,
|
|
53
|
+
) -> UserAuthCredentials:
|
|
54
|
+
"""Authenticate the user and retrieve authentication credentials."""
|
|
55
|
+
typer.secho(
|
|
56
|
+
"Please login with your user credentials here: "
|
|
57
|
+
f"{login_details.verification_uri_complete}",
|
|
58
|
+
fg=typer.colors.BLUE,
|
|
59
|
+
)
|
|
60
|
+
start_time = time.time()
|
|
61
|
+
time.sleep(login_details.interval)
|
|
62
|
+
|
|
63
|
+
while (time.time() - start_time) < login_details.expires_in:
|
|
64
|
+
res: GetAuthTokensResponse = exec_stub.GetAuthTokens(
|
|
65
|
+
GetAuthTokensRequest(device_code=login_details.device_code)
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
access_token = res.access_token
|
|
69
|
+
refresh_token = res.refresh_token
|
|
70
|
+
|
|
71
|
+
if access_token and refresh_token:
|
|
72
|
+
typer.secho(
|
|
73
|
+
"✅ Login successful.",
|
|
74
|
+
fg=typer.colors.GREEN,
|
|
75
|
+
bold=False,
|
|
76
|
+
)
|
|
77
|
+
return UserAuthCredentials(
|
|
78
|
+
access_token=access_token,
|
|
79
|
+
refresh_token=refresh_token,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
time.sleep(login_details.interval)
|
|
83
|
+
|
|
84
|
+
typer.secho(
|
|
85
|
+
"❌ Timeout, failed to sign in.",
|
|
86
|
+
fg=typer.colors.RED,
|
|
87
|
+
bold=True,
|
|
88
|
+
)
|
|
89
|
+
raise typer.Exit(code=1)
|
|
90
|
+
|
|
91
|
+
def store_tokens(self, credentials: UserAuthCredentials) -> None:
|
|
92
|
+
"""Store authentication tokens to the `credentials_path`.
|
|
93
|
+
|
|
94
|
+
The credentials, including tokens, will be saved as a JSON file
|
|
95
|
+
at `credentials_path`.
|
|
96
|
+
"""
|
|
97
|
+
self.access_token = credentials.access_token
|
|
98
|
+
self.refresh_token = credentials.refresh_token
|
|
99
|
+
json_dict = {
|
|
100
|
+
AUTH_TYPE_KEY: AuthType.OIDC,
|
|
101
|
+
ACCESS_TOKEN_KEY: credentials.access_token,
|
|
102
|
+
REFRESH_TOKEN_KEY: credentials.refresh_token,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
with open(self.credentials_path, "w", encoding="utf-8") as file:
|
|
106
|
+
json.dump(json_dict, file, indent=4)
|
|
107
|
+
|
|
108
|
+
def load_tokens(self) -> None:
|
|
109
|
+
"""Load authentication tokens from the `credentials_path`."""
|
|
110
|
+
with open(self.credentials_path, encoding="utf-8") as file:
|
|
111
|
+
json_dict: dict[str, Any] = json.load(file)
|
|
112
|
+
access_token = json_dict.get(ACCESS_TOKEN_KEY)
|
|
113
|
+
refresh_token = json_dict.get(REFRESH_TOKEN_KEY)
|
|
114
|
+
|
|
115
|
+
if isinstance(access_token, str) and isinstance(refresh_token, str):
|
|
116
|
+
self.access_token = access_token
|
|
117
|
+
self.refresh_token = refresh_token
|
|
118
|
+
|
|
119
|
+
def write_tokens_to_metadata(
|
|
120
|
+
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
|
121
|
+
) -> Sequence[tuple[str, Union[str, bytes]]]:
|
|
122
|
+
"""Write authentication tokens to the provided metadata."""
|
|
123
|
+
if self.access_token is None or self.refresh_token is None:
|
|
124
|
+
typer.secho(
|
|
125
|
+
"❌ Missing authentication tokens. Please login first.",
|
|
126
|
+
fg=typer.colors.RED,
|
|
127
|
+
bold=True,
|
|
128
|
+
)
|
|
129
|
+
raise typer.Exit(code=1)
|
|
130
|
+
|
|
131
|
+
return list(metadata) + [
|
|
132
|
+
(ACCESS_TOKEN_KEY, self.access_token),
|
|
133
|
+
(REFRESH_TOKEN_KEY, self.refresh_token),
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
def read_tokens_from_metadata(
|
|
137
|
+
self, metadata: Sequence[tuple[str, Union[str, bytes]]]
|
|
138
|
+
) -> Optional[UserAuthCredentials]:
|
|
139
|
+
"""Read authentication tokens from the provided metadata."""
|
|
140
|
+
metadata_dict = dict(metadata)
|
|
141
|
+
access_token = metadata_dict.get(ACCESS_TOKEN_KEY)
|
|
142
|
+
refresh_token = metadata_dict.get(REFRESH_TOKEN_KEY)
|
|
143
|
+
|
|
144
|
+
if isinstance(access_token, str) and isinstance(refresh_token, str):
|
|
145
|
+
return UserAuthCredentials(
|
|
146
|
+
access_token=access_token,
|
|
147
|
+
refresh_token=refresh_token,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return None
|
|
@@ -0,0 +1,90 @@
|
|
|
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
|
+
"""Flower run interceptor."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from typing import Any, Callable, Union
|
|
19
|
+
|
|
20
|
+
import grpc
|
|
21
|
+
|
|
22
|
+
from flwr.common.auth_plugin import CliAuthPlugin
|
|
23
|
+
from flwr.proto.exec_pb2 import ( # pylint: disable=E0611
|
|
24
|
+
StartRunRequest,
|
|
25
|
+
StreamLogsRequest,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
Request = Union[
|
|
29
|
+
StartRunRequest,
|
|
30
|
+
StreamLogsRequest,
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class CliUserAuthInterceptor(
|
|
35
|
+
grpc.UnaryUnaryClientInterceptor, grpc.UnaryStreamClientInterceptor # type: ignore
|
|
36
|
+
):
|
|
37
|
+
"""CLI interceptor for user authentication."""
|
|
38
|
+
|
|
39
|
+
def __init__(self, auth_plugin: CliAuthPlugin):
|
|
40
|
+
self.auth_plugin = auth_plugin
|
|
41
|
+
|
|
42
|
+
def _authenticated_call(
|
|
43
|
+
self,
|
|
44
|
+
continuation: Callable[[Any, Any], Any],
|
|
45
|
+
client_call_details: grpc.ClientCallDetails,
|
|
46
|
+
request: Request,
|
|
47
|
+
) -> grpc.Call:
|
|
48
|
+
"""Send and receive tokens via metadata."""
|
|
49
|
+
new_metadata = self.auth_plugin.write_tokens_to_metadata(
|
|
50
|
+
client_call_details.metadata or []
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
details = client_call_details._replace(metadata=new_metadata)
|
|
54
|
+
|
|
55
|
+
response = continuation(details, request)
|
|
56
|
+
if response.initial_metadata():
|
|
57
|
+
credentials = self.auth_plugin.read_tokens_from_metadata(
|
|
58
|
+
response.initial_metadata()
|
|
59
|
+
)
|
|
60
|
+
# The metadata contains tokens only if they have been refreshed
|
|
61
|
+
if credentials is not None:
|
|
62
|
+
self.auth_plugin.store_tokens(credentials)
|
|
63
|
+
|
|
64
|
+
return response
|
|
65
|
+
|
|
66
|
+
def intercept_unary_unary(
|
|
67
|
+
self,
|
|
68
|
+
continuation: Callable[[Any, Any], Any],
|
|
69
|
+
client_call_details: grpc.ClientCallDetails,
|
|
70
|
+
request: Request,
|
|
71
|
+
) -> grpc.Call:
|
|
72
|
+
"""Intercept a unary-unary call for user authentication.
|
|
73
|
+
|
|
74
|
+
This method intercepts a unary-unary RPC call initiated from the CLI and adds
|
|
75
|
+
the required authentication tokens to the RPC metadata.
|
|
76
|
+
"""
|
|
77
|
+
return self._authenticated_call(continuation, client_call_details, request)
|
|
78
|
+
|
|
79
|
+
def intercept_unary_stream(
|
|
80
|
+
self,
|
|
81
|
+
continuation: Callable[[Any, Any], Any],
|
|
82
|
+
client_call_details: grpc.ClientCallDetails,
|
|
83
|
+
request: Request,
|
|
84
|
+
) -> grpc.Call:
|
|
85
|
+
"""Intercept a unary-stream call for user authentication.
|
|
86
|
+
|
|
87
|
+
This method intercepts a unary-stream RPC call initiated from the CLI and adds
|
|
88
|
+
the required authentication tokens to the RPC metadata.
|
|
89
|
+
"""
|
|
90
|
+
return self._authenticated_call(continuation, client_call_details, request)
|