flwr-nightly 1.23.0.dev20250930__py3-none-any.whl → 1.26.0.dev20260121__py3-none-any.whl
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/__init__.py +17 -6
- flwr/app/__init__.py +4 -1
- flwr/app/error.py +2 -2
- flwr/app/exception.py +3 -3
- flwr/app/message_type.py +29 -0
- flwr/app/metadata.py +5 -2
- flwr/app/user_config.py +19 -0
- flwr/cli/app.py +62 -9
- flwr/cli/{new/templates/app/code → app_cmd}/__init__.py +9 -1
- flwr/cli/app_cmd/publish.py +285 -0
- flwr/cli/app_cmd/review.py +262 -0
- flwr/cli/auth_plugin/__init__.py +13 -6
- flwr/cli/auth_plugin/auth_plugin.py +26 -15
- flwr/cli/auth_plugin/noop_auth_plugin.py +101 -0
- flwr/cli/auth_plugin/oidc_cli_plugin.py +52 -32
- flwr/cli/build.py +166 -53
- flwr/cli/{cli_user_auth_interceptor.py → cli_account_auth_interceptor.py} +27 -10
- flwr/cli/config/__init__.py +21 -0
- flwr/cli/config/ls.py +104 -0
- flwr/cli/config_migration.py +300 -0
- flwr/cli/config_utils.py +154 -13
- flwr/cli/constant.py +67 -0
- flwr/cli/{new/templates/app/code/flwr_tune → federation}/__init__.py +8 -1
- flwr/cli/federation/ls.py +361 -0
- flwr/cli/flower_config.py +447 -0
- flwr/cli/install.py +91 -13
- flwr/cli/log.py +65 -36
- flwr/cli/login/login.py +41 -27
- flwr/cli/ls.py +232 -158
- flwr/cli/new/new.py +188 -244
- flwr/cli/pull.py +25 -34
- flwr/cli/run/run.py +106 -74
- flwr/cli/run_utils.py +148 -0
- flwr/cli/stop.py +46 -37
- flwr/cli/supernode/__init__.py +25 -0
- flwr/cli/supernode/ls.py +273 -0
- flwr/cli/supernode/register.py +190 -0
- flwr/cli/supernode/unregister.py +140 -0
- flwr/cli/typing.py +211 -0
- flwr/cli/utils.py +428 -80
- flwr/client/__init__.py +2 -1
- flwr/client/dpfedavg_numpy_client.py +4 -1
- flwr/client/grpc_adapter_client/connection.py +14 -17
- flwr/client/grpc_rere_client/connection.py +73 -43
- flwr/client/grpc_rere_client/grpc_adapter.py +35 -15
- flwr/client/grpc_rere_client/{client_interceptor.py → node_auth_client_interceptor.py} +5 -7
- flwr/client/message_handler/message_handler.py +4 -3
- flwr/client/mod/centraldp_mods.py +1 -1
- flwr/client/mod/localdp_mod.py +1 -1
- flwr/client/mod/secure_aggregation/secaggplus_mod.py +11 -9
- flwr/client/numpy_client.py +1 -1
- flwr/client/rest_client/connection.py +99 -54
- flwr/client/run_info_store.py +6 -6
- flwr/client/typing.py +1 -1
- flwr/clientapp/__init__.py +1 -2
- flwr/{client → clientapp}/client_app.py +11 -11
- flwr/clientapp/mod/centraldp_mods.py +16 -17
- flwr/clientapp/mod/localdp_mod.py +8 -9
- flwr/clientapp/typing.py +1 -1
- flwr/{client/clientapp → clientapp}/utils.py +4 -4
- flwr/common/__init__.py +3 -2
- flwr/common/args.py +3 -4
- flwr/common/config.py +15 -17
- flwr/common/constant.py +56 -28
- flwr/common/context.py +2 -1
- flwr/common/differential_privacy.py +3 -4
- flwr/common/event_log_plugin/event_log_plugin.py +3 -4
- flwr/common/exit/exit.py +16 -3
- flwr/common/exit/exit_code.py +39 -10
- flwr/common/exit/exit_handler.py +6 -2
- flwr/common/exit/signal_handler.py +5 -5
- flwr/common/grpc.py +8 -7
- flwr/common/inflatable_protobuf_utils.py +1 -1
- flwr/common/inflatable_utils.py +48 -31
- flwr/common/logger.py +19 -19
- flwr/common/message.py +5 -5
- flwr/common/object_ref.py +7 -7
- flwr/common/record/array.py +6 -6
- flwr/common/record/arrayrecord.py +18 -21
- flwr/common/record/configrecord.py +3 -3
- flwr/common/record/recorddict.py +5 -5
- flwr/common/record/typeddict.py +9 -2
- flwr/common/recorddict_compat.py +7 -10
- flwr/common/retry_invoker.py +20 -20
- flwr/common/secure_aggregation/crypto/symmetric_encryption.py +1 -89
- flwr/common/secure_aggregation/ndarrays_arithmetic.py +8 -5
- flwr/common/serde.py +22 -11
- flwr/common/serde_utils.py +2 -2
- flwr/common/telemetry.py +10 -6
- flwr/common/typing.py +65 -44
- flwr/compat/client/app.py +45 -47
- flwr/compat/client/grpc_client/connection.py +15 -14
- flwr/compat/common/constant.py +29 -0
- flwr/compat/server/app.py +6 -7
- flwr/proto/appio_pb2.py +13 -3
- flwr/proto/appio_pb2.pyi +134 -65
- flwr/proto/appio_pb2_grpc.py +20 -0
- flwr/proto/appio_pb2_grpc.pyi +27 -0
- flwr/proto/clientappio_pb2.py +17 -7
- flwr/proto/clientappio_pb2.pyi +15 -0
- flwr/proto/clientappio_pb2_grpc.py +206 -40
- flwr/proto/clientappio_pb2_grpc.pyi +168 -53
- flwr/proto/control_pb2.py +72 -40
- flwr/proto/control_pb2.pyi +319 -87
- flwr/proto/control_pb2_grpc.py +339 -28
- flwr/proto/control_pb2_grpc.pyi +209 -37
- flwr/proto/error_pb2.py +13 -3
- flwr/proto/error_pb2.pyi +24 -6
- flwr/proto/error_pb2_grpc.py +20 -0
- flwr/proto/error_pb2_grpc.pyi +27 -0
- flwr/proto/fab_pb2.py +24 -10
- flwr/proto/fab_pb2.pyi +68 -20
- flwr/proto/fab_pb2_grpc.py +20 -0
- flwr/proto/fab_pb2_grpc.pyi +27 -0
- flwr/proto/federation_pb2.py +38 -0
- flwr/proto/federation_pb2.pyi +56 -0
- flwr/proto/federation_pb2_grpc.py +24 -0
- flwr/proto/federation_pb2_grpc.pyi +31 -0
- flwr/proto/fleet_pb2.py +45 -27
- flwr/proto/fleet_pb2.pyi +190 -70
- flwr/proto/fleet_pb2_grpc.py +277 -66
- flwr/proto/fleet_pb2_grpc.pyi +201 -55
- flwr/proto/grpcadapter_pb2.py +14 -4
- flwr/proto/grpcadapter_pb2.pyi +38 -16
- flwr/proto/grpcadapter_pb2_grpc.py +35 -4
- flwr/proto/grpcadapter_pb2_grpc.pyi +38 -7
- flwr/proto/heartbeat_pb2.py +17 -7
- flwr/proto/heartbeat_pb2.pyi +51 -22
- flwr/proto/heartbeat_pb2_grpc.py +20 -0
- flwr/proto/heartbeat_pb2_grpc.pyi +27 -0
- flwr/proto/log_pb2.py +13 -3
- flwr/proto/log_pb2.pyi +34 -11
- flwr/proto/log_pb2_grpc.py +20 -0
- flwr/proto/log_pb2_grpc.pyi +27 -0
- flwr/proto/message_pb2.py +15 -5
- flwr/proto/message_pb2.pyi +154 -86
- flwr/proto/message_pb2_grpc.py +20 -0
- flwr/proto/message_pb2_grpc.pyi +27 -0
- flwr/proto/node_pb2.py +16 -4
- flwr/proto/node_pb2.pyi +77 -4
- flwr/proto/node_pb2_grpc.py +20 -0
- flwr/proto/node_pb2_grpc.pyi +27 -0
- flwr/proto/recorddict_pb2.py +13 -3
- flwr/proto/recorddict_pb2.pyi +184 -107
- flwr/proto/recorddict_pb2_grpc.py +20 -0
- flwr/proto/recorddict_pb2_grpc.pyi +27 -0
- flwr/proto/run_pb2.py +40 -31
- flwr/proto/run_pb2.pyi +158 -84
- flwr/proto/run_pb2_grpc.py +20 -0
- flwr/proto/run_pb2_grpc.pyi +27 -0
- flwr/proto/serverappio_pb2.py +13 -3
- flwr/proto/serverappio_pb2.pyi +32 -8
- flwr/proto/serverappio_pb2_grpc.py +246 -65
- flwr/proto/serverappio_pb2_grpc.pyi +221 -85
- flwr/proto/simulationio_pb2.py +16 -8
- flwr/proto/simulationio_pb2.pyi +15 -0
- flwr/proto/simulationio_pb2_grpc.py +162 -41
- flwr/proto/simulationio_pb2_grpc.pyi +149 -55
- flwr/proto/transport_pb2.py +20 -10
- flwr/proto/transport_pb2.pyi +249 -160
- flwr/proto/transport_pb2_grpc.py +35 -4
- flwr/proto/transport_pb2_grpc.pyi +38 -8
- flwr/server/app.py +175 -128
- flwr/server/client_manager.py +4 -5
- flwr/server/client_proxy.py +10 -11
- flwr/server/compat/app.py +4 -5
- flwr/server/compat/app_utils.py +2 -1
- flwr/server/compat/grid_client_proxy.py +12 -13
- flwr/server/compat/legacy_context.py +3 -4
- flwr/server/fleet_event_log_interceptor.py +2 -1
- flwr/server/grid/grid.py +2 -3
- flwr/server/grid/grpc_grid.py +12 -10
- flwr/server/grid/inmemory_grid.py +4 -4
- flwr/server/run_serverapp.py +2 -3
- flwr/server/server.py +34 -39
- flwr/server/server_app.py +7 -8
- flwr/server/server_config.py +1 -2
- flwr/server/serverapp/app.py +34 -28
- flwr/server/serverapp_components.py +4 -5
- flwr/server/strategy/aggregate.py +9 -8
- flwr/server/strategy/bulyan.py +13 -11
- flwr/server/strategy/dp_adaptive_clipping.py +16 -20
- flwr/server/strategy/dp_fixed_clipping.py +12 -17
- flwr/server/strategy/dpfedavg_adaptive.py +3 -4
- flwr/server/strategy/dpfedavg_fixed.py +6 -10
- flwr/server/strategy/fault_tolerant_fedavg.py +14 -13
- flwr/server/strategy/fedadagrad.py +18 -14
- flwr/server/strategy/fedadam.py +16 -14
- flwr/server/strategy/fedavg.py +16 -17
- flwr/server/strategy/fedavg_android.py +15 -15
- flwr/server/strategy/fedavgm.py +21 -18
- flwr/server/strategy/fedmedian.py +2 -3
- flwr/server/strategy/fedopt.py +11 -10
- flwr/server/strategy/fedprox.py +10 -9
- flwr/server/strategy/fedtrimmedavg.py +12 -11
- flwr/server/strategy/fedxgb_bagging.py +13 -11
- flwr/server/strategy/fedxgb_cyclic.py +6 -6
- flwr/server/strategy/fedxgb_nn_avg.py +4 -4
- flwr/server/strategy/fedyogi.py +16 -14
- flwr/server/strategy/krum.py +12 -11
- flwr/server/strategy/qfedavg.py +16 -15
- flwr/server/strategy/strategy.py +6 -9
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +20 -9
- flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -2
- flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +3 -4
- flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +10 -12
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +1 -3
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +136 -42
- flwr/server/superlink/fleet/grpc_rere/{server_interceptor.py → node_auth_server_interceptor.py} +28 -50
- flwr/server/superlink/fleet/message_handler/message_handler.py +141 -51
- flwr/server/superlink/fleet/rest_rere/rest_api.py +54 -33
- flwr/server/superlink/fleet/vce/backend/backend.py +2 -2
- flwr/server/superlink/fleet/vce/backend/raybackend.py +6 -6
- flwr/server/superlink/fleet/vce/vce_api.py +32 -13
- flwr/server/superlink/linkstate/__init__.py +2 -0
- flwr/server/superlink/linkstate/in_memory_linkstate.py +293 -208
- flwr/server/superlink/linkstate/linkstate.py +176 -64
- flwr/server/superlink/linkstate/linkstate_factory.py +24 -6
- flwr/server/superlink/linkstate/sql_linkstate.py +221 -0
- flwr/server/superlink/linkstate/sqlite_linkstate.py +743 -648
- flwr/server/superlink/linkstate/utils.py +11 -62
- flwr/server/superlink/serverappio/serverappio_grpc.py +1 -2
- flwr/server/superlink/serverappio/serverappio_servicer.py +28 -23
- flwr/server/superlink/simulation/simulationio_grpc.py +1 -2
- flwr/server/superlink/simulation/simulationio_servicer.py +19 -14
- flwr/server/superlink/utils.py +4 -6
- flwr/server/typing.py +1 -1
- flwr/server/utils/tensorboard.py +15 -8
- flwr/server/utils/validator.py +2 -3
- flwr/server/workflow/default_workflows.py +7 -6
- flwr/server/workflow/secure_aggregation/secagg_workflow.py +2 -4
- flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +13 -11
- flwr/serverapp/strategy/bulyan.py +16 -15
- flwr/serverapp/strategy/dp_adaptive_clipping.py +12 -11
- flwr/serverapp/strategy/dp_fixed_clipping.py +11 -14
- flwr/serverapp/strategy/fedadagrad.py +10 -11
- flwr/serverapp/strategy/fedadam.py +10 -11
- flwr/serverapp/strategy/fedavg.py +10 -11
- flwr/serverapp/strategy/fedavgm.py +17 -16
- flwr/serverapp/strategy/fedmedian.py +2 -2
- flwr/serverapp/strategy/fedopt.py +10 -11
- flwr/serverapp/strategy/fedprox.py +7 -8
- flwr/serverapp/strategy/fedtrimmedavg.py +9 -9
- flwr/serverapp/strategy/fedxgb_bagging.py +3 -3
- flwr/serverapp/strategy/fedxgb_cyclic.py +10 -10
- flwr/serverapp/strategy/fedyogi.py +9 -11
- flwr/serverapp/strategy/krum.py +7 -7
- flwr/serverapp/strategy/multikrum.py +9 -9
- flwr/serverapp/strategy/qfedavg.py +17 -16
- flwr/serverapp/strategy/strategy.py +6 -9
- flwr/serverapp/strategy/strategy_utils.py +7 -8
- flwr/simulation/app.py +46 -42
- flwr/simulation/legacy_app.py +12 -12
- flwr/simulation/ray_transport/ray_actor.py +11 -12
- flwr/simulation/ray_transport/ray_client_proxy.py +14 -19
- flwr/simulation/run_simulation.py +46 -44
- flwr/simulation/simulationio_connection.py +4 -4
- flwr/{common → supercore}/address.py +1 -37
- flwr/supercore/cli/flower_superexec.py +3 -4
- flwr/supercore/constant.py +69 -0
- flwr/supercore/corestate/corestate.py +24 -3
- flwr/supercore/corestate/in_memory_corestate.py +138 -0
- flwr/supercore/corestate/sql_corestate.py +153 -0
- flwr/supercore/corestate/sqlite_corestate.py +157 -0
- flwr/supercore/credential_store/__init__.py +33 -0
- flwr/supercore/credential_store/credential_store.py +34 -0
- flwr/supercore/credential_store/file_credential_store.py +76 -0
- flwr/{common → supercore}/date.py +0 -11
- flwr/supercore/ffs/disk_ffs.py +1 -2
- flwr/supercore/ffs/ffs.py +1 -2
- flwr/supercore/ffs/ffs_factory.py +1 -2
- flwr/{common → supercore}/heartbeat.py +20 -25
- flwr/supercore/object_store/in_memory_object_store.py +1 -6
- flwr/supercore/object_store/object_store.py +1 -2
- flwr/supercore/object_store/object_store_factory.py +27 -8
- flwr/supercore/object_store/sqlite_object_store.py +253 -0
- flwr/{cli/new/templates/app → supercore/primitives}/__init__.py +1 -1
- flwr/supercore/primitives/asymmetric.py +117 -0
- flwr/supercore/primitives/asymmetric_ed25519.py +175 -0
- flwr/supercore/sql_mixin.py +292 -0
- flwr/supercore/sqlite_mixin.py +156 -0
- flwr/{client/clientapp → supercore/state}/__init__.py +2 -2
- flwr/supercore/state/schema/README.md +125 -0
- flwr/{cli/new/templates → supercore/state/schema}/__init__.py +2 -2
- flwr/supercore/state/schema/corestate_tables.py +36 -0
- flwr/supercore/state/schema/linkstate_tables.py +152 -0
- flwr/supercore/state/schema/objectstore_tables.py +90 -0
- flwr/supercore/superexec/plugin/base_exec_plugin.py +1 -2
- flwr/supercore/superexec/plugin/exec_plugin.py +3 -3
- flwr/supercore/superexec/run_superexec.py +9 -13
- flwr/supercore/utils.py +224 -0
- flwr/superlink/artifact_provider/artifact_provider.py +1 -2
- flwr/superlink/auth_plugin/__init__.py +5 -2
- flwr/superlink/auth_plugin/auth_plugin.py +20 -19
- flwr/superlink/auth_plugin/noop_auth_plugin.py +84 -0
- flwr/superlink/federation/__init__.py +24 -0
- flwr/superlink/federation/federation_manager.py +64 -0
- flwr/superlink/federation/noop_federation_manager.py +71 -0
- flwr/superlink/servicer/control/{control_user_auth_interceptor.py → control_account_auth_interceptor.py} +41 -32
- flwr/superlink/servicer/control/control_event_log_interceptor.py +7 -7
- flwr/superlink/servicer/control/control_grpc.py +20 -17
- flwr/superlink/servicer/control/control_license_interceptor.py +3 -3
- flwr/superlink/servicer/control/control_servicer.py +328 -68
- flwr/supernode/cli/flower_supernode.py +74 -26
- flwr/supernode/nodestate/in_memory_nodestate.py +121 -49
- flwr/supernode/nodestate/nodestate.py +52 -8
- flwr/supernode/nodestate/nodestate_factory.py +7 -4
- flwr/supernode/runtime/run_clientapp.py +43 -24
- flwr/supernode/servicer/clientappio/clientappio_servicer.py +48 -10
- flwr/supernode/start_client_internal.py +185 -57
- {flwr_nightly-1.23.0.dev20250930.dist-info → flwr_nightly-1.26.0.dev20260121.dist-info}/METADATA +10 -11
- flwr_nightly-1.26.0.dev20260121.dist-info/RECORD +411 -0
- flwr/cli/new/templates/app/.gitignore.tpl +0 -163
- flwr/cli/new/templates/app/LICENSE.tpl +0 -202
- flwr/cli/new/templates/app/README.baseline.md.tpl +0 -127
- flwr/cli/new/templates/app/README.flowertune.md.tpl +0 -68
- flwr/cli/new/templates/app/README.md.tpl +0 -37
- flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +0 -1
- flwr/cli/new/templates/app/code/__init__.py.tpl +0 -1
- flwr/cli/new/templates/app/code/__init__.pytorch_legacy_api.py.tpl +0 -1
- flwr/cli/new/templates/app/code/client.baseline.py.tpl +0 -75
- flwr/cli/new/templates/app/code/client.huggingface.py.tpl +0 -93
- flwr/cli/new/templates/app/code/client.jax.py.tpl +0 -71
- flwr/cli/new/templates/app/code/client.mlx.py.tpl +0 -102
- flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -46
- flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -80
- flwr/cli/new/templates/app/code/client.pytorch_legacy_api.py.tpl +0 -55
- flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -108
- flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -82
- flwr/cli/new/templates/app/code/client.xgboost.py.tpl +0 -110
- flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +0 -36
- flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +0 -92
- flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +0 -87
- flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +0 -56
- flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +0 -73
- flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +0 -78
- flwr/cli/new/templates/app/code/model.baseline.py.tpl +0 -66
- flwr/cli/new/templates/app/code/server.baseline.py.tpl +0 -43
- flwr/cli/new/templates/app/code/server.huggingface.py.tpl +0 -42
- flwr/cli/new/templates/app/code/server.jax.py.tpl +0 -39
- flwr/cli/new/templates/app/code/server.mlx.py.tpl +0 -41
- flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -38
- flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -41
- flwr/cli/new/templates/app/code/server.pytorch_legacy_api.py.tpl +0 -31
- flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -44
- flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -38
- flwr/cli/new/templates/app/code/server.xgboost.py.tpl +0 -56
- flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +0 -1
- flwr/cli/new/templates/app/code/task.huggingface.py.tpl +0 -98
- flwr/cli/new/templates/app/code/task.jax.py.tpl +0 -57
- flwr/cli/new/templates/app/code/task.mlx.py.tpl +0 -102
- flwr/cli/new/templates/app/code/task.numpy.py.tpl +0 -7
- flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -98
- flwr/cli/new/templates/app/code/task.pytorch_legacy_api.py.tpl +0 -111
- flwr/cli/new/templates/app/code/task.sklearn.py.tpl +0 -67
- flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +0 -52
- flwr/cli/new/templates/app/code/task.xgboost.py.tpl +0 -67
- flwr/cli/new/templates/app/code/utils.baseline.py.tpl +0 -1
- flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +0 -146
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +0 -80
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +0 -65
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +0 -52
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +0 -56
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +0 -49
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +0 -53
- flwr/cli/new/templates/app/pyproject.pytorch_legacy_api.toml.tpl +0 -53
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +0 -52
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +0 -53
- flwr/cli/new/templates/app/pyproject.xgboost.toml.tpl +0 -61
- flwr/common/pyproject.py +0 -42
- flwr/supercore/object_store/utils.py +0 -43
- flwr_nightly-1.23.0.dev20250930.dist-info/RECORD +0 -429
- /flwr/{common → supercore}/version.py +0 -0
- {flwr_nightly-1.23.0.dev20250930.dist-info → flwr_nightly-1.26.0.dev20260121.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.23.0.dev20250930.dist-info → flwr_nightly-1.26.0.dev20260121.dist-info}/entry_points.txt +0 -0
flwr/cli/run/run.py
CHANGED
|
@@ -15,53 +15,57 @@
|
|
|
15
15
|
"""Flower command line interface `run` command."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
import hashlib
|
|
18
19
|
import io
|
|
19
20
|
import json
|
|
20
21
|
import subprocess
|
|
21
22
|
from pathlib import Path
|
|
22
|
-
from typing import Annotated, Any,
|
|
23
|
+
from typing import Annotated, Any, cast
|
|
23
24
|
|
|
24
25
|
import typer
|
|
25
26
|
from rich.console import Console
|
|
26
27
|
|
|
27
|
-
from flwr.cli.build import
|
|
28
|
-
from flwr.cli.
|
|
29
|
-
|
|
30
|
-
process_loaded_project_config,
|
|
31
|
-
validate_federation_in_project_config,
|
|
32
|
-
)
|
|
28
|
+
from flwr.cli.build import build_fab_from_disk, get_fab_filename
|
|
29
|
+
from flwr.cli.config_migration import migrate, warn_if_federation_config_overrides
|
|
30
|
+
from flwr.cli.config_utils import load as load_toml
|
|
33
31
|
from flwr.cli.constant import FEDERATION_CONFIG_HELP_MESSAGE, RUN_CONFIG_HELP_MESSAGE
|
|
32
|
+
from flwr.cli.flower_config import (
|
|
33
|
+
_serialize_simulation_options,
|
|
34
|
+
read_superlink_connection,
|
|
35
|
+
)
|
|
36
|
+
from flwr.cli.typing import SuperLinkConnection, SuperLinkSimulationOptions
|
|
34
37
|
from flwr.common.config import (
|
|
35
|
-
flatten_dict,
|
|
36
38
|
get_metadata_from_config,
|
|
37
39
|
parse_config_args,
|
|
38
40
|
user_config_to_configrecord,
|
|
39
41
|
)
|
|
40
|
-
from flwr.common.constant import CliOutputFormat
|
|
42
|
+
from flwr.common.constant import FAB_CONFIG_FILE, CliOutputFormat
|
|
41
43
|
from flwr.common.logger import print_json_error, redirect_output, restore_output
|
|
42
44
|
from flwr.common.serde import config_record_to_proto, fab_to_proto, user_config_to_proto
|
|
43
45
|
from flwr.common.typing import Fab
|
|
44
46
|
from flwr.proto.control_pb2 import StartRunRequest # pylint: disable=E0611
|
|
45
47
|
from flwr.proto.control_pb2_grpc import ControlStub
|
|
48
|
+
from flwr.supercore.constant import NOOP_FEDERATION
|
|
49
|
+
from flwr.supercore.utils import parse_app_spec
|
|
46
50
|
|
|
47
51
|
from ..log import start_stream
|
|
48
|
-
from ..utils import flwr_cli_grpc_exc_handler,
|
|
52
|
+
from ..utils import flwr_cli_grpc_exc_handler, init_channel_from_connection
|
|
49
53
|
|
|
50
54
|
CONN_REFRESH_PERIOD = 60 # Connection refresh period for log streaming (seconds)
|
|
51
55
|
|
|
52
56
|
|
|
53
|
-
# pylint: disable-next=too-many-locals, R0913, R0917
|
|
57
|
+
# pylint: disable-next=too-many-locals, too-many-branches, R0913, R0917
|
|
54
58
|
def run(
|
|
55
59
|
app: Annotated[
|
|
56
60
|
Path,
|
|
57
61
|
typer.Argument(help="Path of the Flower App to run."),
|
|
58
62
|
] = Path("."),
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
typer.Argument(help="Name of the
|
|
63
|
+
superlink: Annotated[
|
|
64
|
+
str | None,
|
|
65
|
+
typer.Argument(help="Name of the SuperLink connection."),
|
|
62
66
|
] = None,
|
|
63
67
|
run_config_overrides: Annotated[
|
|
64
|
-
|
|
68
|
+
list[str] | None,
|
|
65
69
|
typer.Option(
|
|
66
70
|
"--run-config",
|
|
67
71
|
"-c",
|
|
@@ -69,10 +73,11 @@ def run(
|
|
|
69
73
|
),
|
|
70
74
|
] = None,
|
|
71
75
|
federation_config_overrides: Annotated[
|
|
72
|
-
|
|
76
|
+
list[str] | None,
|
|
73
77
|
typer.Option(
|
|
74
78
|
"--federation-config",
|
|
75
79
|
help=FEDERATION_CONFIG_HELP_MESSAGE,
|
|
80
|
+
hidden=True,
|
|
76
81
|
),
|
|
77
82
|
] = None,
|
|
78
83
|
stream: Annotated[
|
|
@@ -95,30 +100,49 @@ def run(
|
|
|
95
100
|
"""Run Flower App."""
|
|
96
101
|
suppress_output = output_format == CliOutputFormat.JSON
|
|
97
102
|
captured_output = io.StringIO()
|
|
103
|
+
|
|
104
|
+
if suppress_output:
|
|
105
|
+
redirect_output(captured_output)
|
|
106
|
+
|
|
107
|
+
# Warn `--federation-config` is ignored
|
|
108
|
+
warn_if_federation_config_overrides(federation_config_overrides)
|
|
109
|
+
|
|
110
|
+
# Migrate legacy usage if any
|
|
111
|
+
migrate(str(app), [], ignore_legacy_usage=True)
|
|
112
|
+
|
|
113
|
+
# Read superlink connection configuration
|
|
114
|
+
superlink_connection = read_superlink_connection(superlink)
|
|
115
|
+
|
|
98
116
|
try:
|
|
99
|
-
if suppress_output:
|
|
100
|
-
redirect_output(captured_output)
|
|
101
|
-
typer.secho("Loading project configuration... ", fg=typer.colors.BLUE)
|
|
102
|
-
|
|
103
|
-
pyproject_path = app / "pyproject.toml" if app else None
|
|
104
|
-
config, errors, warnings = load_and_validate(path=pyproject_path)
|
|
105
|
-
config = process_loaded_project_config(config, errors, warnings)
|
|
106
|
-
federation, federation_config = validate_federation_in_project_config(
|
|
107
|
-
federation, config, federation_config_overrides
|
|
108
|
-
)
|
|
109
117
|
|
|
110
|
-
if
|
|
118
|
+
# Determine if app is remote
|
|
119
|
+
app_spec = None
|
|
120
|
+
if (app_str := str(app)).startswith("@"):
|
|
121
|
+
# Validate app version and ID format
|
|
122
|
+
try:
|
|
123
|
+
_ = parse_app_spec(app_str)
|
|
124
|
+
except ValueError as e:
|
|
125
|
+
typer.secho(f"❌ {e}", fg=typer.colors.RED, err=True)
|
|
126
|
+
raise typer.Exit(code=1) from e
|
|
127
|
+
|
|
128
|
+
app_spec = app_str
|
|
129
|
+
# Set `app` to current directory for credential storage
|
|
130
|
+
app = Path(".")
|
|
131
|
+
|
|
132
|
+
if superlink_connection.address:
|
|
111
133
|
_run_with_control_api(
|
|
112
134
|
app,
|
|
113
|
-
|
|
114
|
-
federation_config,
|
|
135
|
+
superlink_connection,
|
|
115
136
|
run_config_overrides,
|
|
116
137
|
stream,
|
|
117
138
|
output_format,
|
|
139
|
+
app_spec,
|
|
118
140
|
)
|
|
119
141
|
else:
|
|
120
142
|
_run_without_control_api(
|
|
121
|
-
app,
|
|
143
|
+
app=app,
|
|
144
|
+
simulation_options=superlink_connection.options, # type: ignore
|
|
145
|
+
config_overrides=run_config_overrides,
|
|
122
146
|
)
|
|
123
147
|
except (typer.Exit, Exception) as err: # pylint: disable=broad-except
|
|
124
148
|
if suppress_output:
|
|
@@ -130,6 +154,7 @@ def run(
|
|
|
130
154
|
f"{err}",
|
|
131
155
|
fg=typer.colors.RED,
|
|
132
156
|
bold=True,
|
|
157
|
+
err=True,
|
|
133
158
|
)
|
|
134
159
|
finally:
|
|
135
160
|
if suppress_output:
|
|
@@ -140,31 +165,46 @@ def run(
|
|
|
140
165
|
# pylint: disable-next=R0913, R0914, R0917
|
|
141
166
|
def _run_with_control_api(
|
|
142
167
|
app: Path,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
config_overrides: Optional[list[str]],
|
|
168
|
+
superlink_connection: SuperLinkConnection,
|
|
169
|
+
config_overrides: list[str] | None,
|
|
146
170
|
stream: bool,
|
|
147
171
|
output_format: str,
|
|
172
|
+
app_spec: str | None,
|
|
148
173
|
) -> None:
|
|
149
174
|
channel = None
|
|
175
|
+
is_remote_app = app_spec is not None
|
|
150
176
|
try:
|
|
151
|
-
|
|
152
|
-
channel = init_channel(app, federation_config, auth_plugin)
|
|
177
|
+
channel = init_channel_from_connection(superlink_connection)
|
|
153
178
|
stub = ControlStub(channel)
|
|
154
179
|
|
|
155
|
-
|
|
156
|
-
|
|
180
|
+
# Build FAB if local app
|
|
181
|
+
if not is_remote_app:
|
|
182
|
+
fab_bytes = build_fab_from_disk(app)
|
|
183
|
+
fab_hash = hashlib.sha256(fab_bytes).hexdigest()
|
|
184
|
+
config = cast(dict[str, Any], load_toml(app / FAB_CONFIG_FILE))
|
|
185
|
+
fab_id, fab_version = get_metadata_from_config(config)
|
|
186
|
+
fab = Fab(fab_hash, fab_bytes, {})
|
|
187
|
+
# Skip FAB build if remote app
|
|
188
|
+
else:
|
|
189
|
+
# Use empty values for FAB
|
|
190
|
+
fab_id = fab_version = fab_hash = ""
|
|
191
|
+
fab = Fab(fab_hash, b"", {})
|
|
157
192
|
|
|
158
|
-
|
|
193
|
+
federation: str = superlink_connection.federation or NOOP_FEDERATION
|
|
159
194
|
|
|
160
195
|
# Construct a `ConfigRecord` out of a flattened `UserConfig`
|
|
161
|
-
|
|
162
|
-
|
|
196
|
+
options = {}
|
|
197
|
+
if superlink_connection.options:
|
|
198
|
+
options = _serialize_simulation_options(superlink_connection.options)
|
|
199
|
+
|
|
200
|
+
c_record = user_config_to_configrecord(options)
|
|
163
201
|
|
|
164
202
|
req = StartRunRequest(
|
|
165
203
|
fab=fab_to_proto(fab),
|
|
166
204
|
override_config=user_config_to_proto(parse_config_args(config_overrides)),
|
|
205
|
+
federation=federation,
|
|
167
206
|
federation_options=config_record_to_proto(c_record),
|
|
207
|
+
app_spec=app_spec or "",
|
|
168
208
|
)
|
|
169
209
|
with flwr_cli_grpc_exc_handler():
|
|
170
210
|
res = stub.StartRun(req)
|
|
@@ -174,23 +214,27 @@ def _run_with_control_api(
|
|
|
174
214
|
f"🎊 Successfully started run {res.run_id}", fg=typer.colors.GREEN
|
|
175
215
|
)
|
|
176
216
|
else:
|
|
177
|
-
typer.secho("❌ Failed to start run", fg=typer.colors.RED)
|
|
217
|
+
typer.secho("❌ Failed to start run", fg=typer.colors.RED, err=True)
|
|
178
218
|
raise typer.Exit(code=1)
|
|
179
219
|
|
|
180
220
|
if output_format == CliOutputFormat.JSON:
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
221
|
+
# Only include FAB metadata if we actually built a local FAB
|
|
222
|
+
payload: dict[str, Any] = {
|
|
223
|
+
"success": res.HasField("run_id"),
|
|
224
|
+
"run-id": f"{res.run_id}" if res.HasField("run_id") else None,
|
|
225
|
+
}
|
|
226
|
+
if not is_remote_app:
|
|
227
|
+
payload.update(
|
|
228
|
+
{
|
|
229
|
+
"fab-id": fab_id,
|
|
230
|
+
"fab-name": fab_id.rsplit("/", maxsplit=1)[-1],
|
|
231
|
+
"fab-version": fab_version,
|
|
232
|
+
"fab-hash": fab_hash[:8],
|
|
233
|
+
"fab-filename": get_fab_filename(config, fab_hash),
|
|
234
|
+
}
|
|
235
|
+
)
|
|
192
236
|
restore_output()
|
|
193
|
-
Console().print_json(
|
|
237
|
+
Console().print_json(json.dumps(payload))
|
|
194
238
|
|
|
195
239
|
if stream:
|
|
196
240
|
start_stream(res.run_id, channel, CONN_REFRESH_PERIOD)
|
|
@@ -200,26 +244,13 @@ def _run_with_control_api(
|
|
|
200
244
|
|
|
201
245
|
|
|
202
246
|
def _run_without_control_api(
|
|
203
|
-
app:
|
|
204
|
-
|
|
205
|
-
config_overrides:
|
|
206
|
-
federation: str,
|
|
247
|
+
app: Path | None,
|
|
248
|
+
simulation_options: SuperLinkSimulationOptions,
|
|
249
|
+
config_overrides: list[str] | None,
|
|
207
250
|
) -> None:
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
backend_cfg = federation_config["options"].get("backend", {})
|
|
212
|
-
except KeyError as err:
|
|
213
|
-
typer.secho(
|
|
214
|
-
"❌ The project's `pyproject.toml` needs to declare the number of"
|
|
215
|
-
" SuperNodes in the simulation. To simulate 10 SuperNodes,"
|
|
216
|
-
" use the following notation:\n\n"
|
|
217
|
-
f"[tool.flwr.federations.{federation}]\n"
|
|
218
|
-
"options.num-supernodes = 10\n",
|
|
219
|
-
fg=typer.colors.RED,
|
|
220
|
-
bold=True,
|
|
221
|
-
)
|
|
222
|
-
raise typer.Exit(code=1) from err
|
|
251
|
+
|
|
252
|
+
num_supernodes = simulation_options.num_supernodes
|
|
253
|
+
verbose = False # bool | None = superlink_connection.options.verbose
|
|
223
254
|
|
|
224
255
|
command = [
|
|
225
256
|
"flower-simulation",
|
|
@@ -229,9 +260,10 @@ def _run_without_control_api(
|
|
|
229
260
|
f"{num_supernodes}",
|
|
230
261
|
]
|
|
231
262
|
|
|
232
|
-
if
|
|
263
|
+
if simulation_options.backend:
|
|
233
264
|
# Stringify as JSON
|
|
234
|
-
|
|
265
|
+
backend_serial = _serialize_simulation_options(simulation_options)
|
|
266
|
+
command.extend(["--backend-config", json.dumps(backend_serial)])
|
|
235
267
|
|
|
236
268
|
if verbose:
|
|
237
269
|
command.extend(["--verbose"])
|
flwr/cli/run_utils.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
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 command line interface utils."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from datetime import datetime, timedelta
|
|
20
|
+
|
|
21
|
+
from flwr.common.typing import Run
|
|
22
|
+
from flwr.supercore.date import isoformat8601_utc
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class RunRow: # pylint: disable=too-many-instance-attributes
|
|
27
|
+
"""Represents a single run's data for display.
|
|
28
|
+
|
|
29
|
+
Attributes
|
|
30
|
+
----------
|
|
31
|
+
run_id : int
|
|
32
|
+
The unique identifier for the run.
|
|
33
|
+
federation : str
|
|
34
|
+
The federation name.
|
|
35
|
+
fab_id : str
|
|
36
|
+
The Flower App Bundle identifier.
|
|
37
|
+
fab_version : str
|
|
38
|
+
The FAB version string.
|
|
39
|
+
fab_hash : str
|
|
40
|
+
The SHA-256 hash of the FAB.
|
|
41
|
+
status_text : str
|
|
42
|
+
The formatted status text.
|
|
43
|
+
elapsed : float
|
|
44
|
+
The elapsed time in seconds.
|
|
45
|
+
pending_at : str
|
|
46
|
+
Timestamp when run entered pending state.
|
|
47
|
+
starting_at : str
|
|
48
|
+
Timestamp when run entered starting state.
|
|
49
|
+
running_at : str
|
|
50
|
+
Timestamp when run entered running state.
|
|
51
|
+
finished_at : str
|
|
52
|
+
Timestamp when run finished.
|
|
53
|
+
network_traffic_inbound : int
|
|
54
|
+
The total inbound network traffic (in bytes) used during the run.
|
|
55
|
+
It includes the traffic from SuperNodes to SuperLink.
|
|
56
|
+
network_traffic_outbound : int
|
|
57
|
+
The total outbound network traffic (in bytes) used during the run.
|
|
58
|
+
It includes the traffic from SuperLink to SuperNodes.
|
|
59
|
+
compute_time_serverapp : float
|
|
60
|
+
The total compute time (in seconds) of the ServerApp during the run.
|
|
61
|
+
compute_time_clientapp : float
|
|
62
|
+
The total compute time (in seconds) of all ClientApps during the run.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
run_id: int
|
|
66
|
+
federation: str
|
|
67
|
+
fab_id: str
|
|
68
|
+
fab_version: str
|
|
69
|
+
fab_hash: str
|
|
70
|
+
status_text: str
|
|
71
|
+
elapsed: float
|
|
72
|
+
pending_at: str
|
|
73
|
+
starting_at: str
|
|
74
|
+
running_at: str
|
|
75
|
+
finished_at: str
|
|
76
|
+
network_traffic_inbound: int
|
|
77
|
+
network_traffic_outbound: int
|
|
78
|
+
compute_time_serverapp: float
|
|
79
|
+
compute_time_clientapp: float
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def format_runs(runs: list[Run], now_isoformat: str) -> list[RunRow]:
|
|
83
|
+
"""Format runs to a list of RunRow objects.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
runs : list[Run]
|
|
88
|
+
List of Run objects to format.
|
|
89
|
+
now_isoformat : str
|
|
90
|
+
Current timestamp in ISO format for calculating elapsed time.
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
list[RunRow]
|
|
95
|
+
List of formatted RunRow objects sorted by pending_at timestamp.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
def _format_datetime(dt: datetime | None) -> str:
|
|
99
|
+
return isoformat8601_utc(dt).replace("T", " ") if dt else "N/A"
|
|
100
|
+
|
|
101
|
+
run_list: list[RunRow] = []
|
|
102
|
+
|
|
103
|
+
# Add rows
|
|
104
|
+
for run in sorted(runs, key=lambda x: datetime.fromisoformat(x.pending_at)):
|
|
105
|
+
# Combine status and sub-status into a single string
|
|
106
|
+
if run.status.sub_status == "":
|
|
107
|
+
status_text = run.status.status
|
|
108
|
+
else:
|
|
109
|
+
status_text = f"{run.status.status}:{run.status.sub_status}"
|
|
110
|
+
|
|
111
|
+
# Convert isoformat to datetime
|
|
112
|
+
pending_at = datetime.fromisoformat(run.pending_at) if run.pending_at else None
|
|
113
|
+
starting_at = (
|
|
114
|
+
datetime.fromisoformat(run.starting_at) if run.starting_at else None
|
|
115
|
+
)
|
|
116
|
+
running_at = datetime.fromisoformat(run.running_at) if run.running_at else None
|
|
117
|
+
finished_at = (
|
|
118
|
+
datetime.fromisoformat(run.finished_at) if run.finished_at else None
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Calculate elapsed time
|
|
122
|
+
elapsed_time = timedelta()
|
|
123
|
+
if running_at:
|
|
124
|
+
if finished_at:
|
|
125
|
+
end_time = finished_at
|
|
126
|
+
else:
|
|
127
|
+
end_time = datetime.fromisoformat(now_isoformat)
|
|
128
|
+
elapsed_time = end_time - running_at
|
|
129
|
+
|
|
130
|
+
row = RunRow(
|
|
131
|
+
run_id=run.run_id,
|
|
132
|
+
federation=run.federation,
|
|
133
|
+
fab_id=run.fab_id,
|
|
134
|
+
fab_version=run.fab_version,
|
|
135
|
+
fab_hash=run.fab_hash,
|
|
136
|
+
status_text=status_text,
|
|
137
|
+
elapsed=elapsed_time.total_seconds(),
|
|
138
|
+
pending_at=_format_datetime(pending_at),
|
|
139
|
+
starting_at=_format_datetime(starting_at),
|
|
140
|
+
running_at=_format_datetime(running_at),
|
|
141
|
+
finished_at=_format_datetime(finished_at),
|
|
142
|
+
network_traffic_inbound=run.bytes_recv,
|
|
143
|
+
network_traffic_outbound=run.bytes_sent,
|
|
144
|
+
compute_time_serverapp=elapsed_time.total_seconds(),
|
|
145
|
+
compute_time_clientapp=run.clientapp_runtime,
|
|
146
|
+
)
|
|
147
|
+
run_list.append(row)
|
|
148
|
+
return run_list
|
flwr/cli/stop.py
CHANGED
|
@@ -17,20 +17,15 @@
|
|
|
17
17
|
|
|
18
18
|
import io
|
|
19
19
|
import json
|
|
20
|
-
from
|
|
21
|
-
from typing import Annotated, Optional
|
|
20
|
+
from typing import Annotated
|
|
22
21
|
|
|
23
22
|
import typer
|
|
24
23
|
from rich.console import Console
|
|
25
24
|
|
|
26
|
-
from flwr.cli.
|
|
27
|
-
exit_if_no_address,
|
|
28
|
-
load_and_validate,
|
|
29
|
-
process_loaded_project_config,
|
|
30
|
-
validate_federation_in_project_config,
|
|
31
|
-
)
|
|
25
|
+
from flwr.cli.config_migration import migrate, warn_if_federation_config_overrides
|
|
32
26
|
from flwr.cli.constant import FEDERATION_CONFIG_HELP_MESSAGE
|
|
33
|
-
from flwr.
|
|
27
|
+
from flwr.cli.flower_config import read_superlink_connection
|
|
28
|
+
from flwr.common.constant import CliOutputFormat
|
|
34
29
|
from flwr.common.logger import print_json_error, redirect_output, restore_output
|
|
35
30
|
from flwr.proto.control_pb2 import ( # pylint: disable=E0611
|
|
36
31
|
StopRunRequest,
|
|
@@ -38,27 +33,25 @@ from flwr.proto.control_pb2 import ( # pylint: disable=E0611
|
|
|
38
33
|
)
|
|
39
34
|
from flwr.proto.control_pb2_grpc import ControlStub
|
|
40
35
|
|
|
41
|
-
from .utils import flwr_cli_grpc_exc_handler,
|
|
36
|
+
from .utils import flwr_cli_grpc_exc_handler, init_channel_from_connection
|
|
42
37
|
|
|
43
38
|
|
|
44
39
|
def stop( # pylint: disable=R0914
|
|
40
|
+
ctx: typer.Context,
|
|
45
41
|
run_id: Annotated[ # pylint: disable=unused-argument
|
|
46
42
|
int,
|
|
47
43
|
typer.Argument(help="The Flower run ID to stop"),
|
|
48
44
|
],
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
typer.Argument(help="
|
|
52
|
-
] = Path("."),
|
|
53
|
-
federation: Annotated[
|
|
54
|
-
Optional[str],
|
|
55
|
-
typer.Argument(help="Name of the federation"),
|
|
45
|
+
superlink: Annotated[
|
|
46
|
+
str | None,
|
|
47
|
+
typer.Argument(help="Name of the SuperLink connection."),
|
|
56
48
|
] = None,
|
|
57
49
|
federation_config_overrides: Annotated[
|
|
58
|
-
|
|
50
|
+
list[str] | None,
|
|
59
51
|
typer.Option(
|
|
60
52
|
"--federation-config",
|
|
61
53
|
help=FEDERATION_CONFIG_HELP_MESSAGE,
|
|
54
|
+
hidden=True,
|
|
62
55
|
),
|
|
63
56
|
] = None,
|
|
64
57
|
output_format: Annotated[
|
|
@@ -70,27 +63,29 @@ def stop( # pylint: disable=R0914
|
|
|
70
63
|
),
|
|
71
64
|
] = CliOutputFormat.DEFAULT,
|
|
72
65
|
) -> None:
|
|
73
|
-
"""Stop a run.
|
|
66
|
+
"""Stop a Flower run.
|
|
67
|
+
|
|
68
|
+
This command stops a running Flower App execution by sending a stop request to the
|
|
69
|
+
SuperLink via the Control API.
|
|
70
|
+
"""
|
|
74
71
|
suppress_output = output_format == CliOutputFormat.JSON
|
|
75
72
|
captured_output = io.StringIO()
|
|
76
|
-
try:
|
|
77
|
-
if suppress_output:
|
|
78
|
-
redirect_output(captured_output)
|
|
79
73
|
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
if suppress_output:
|
|
75
|
+
redirect_output(captured_output)
|
|
82
76
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
77
|
+
# Warn `--federation-config` is ignored
|
|
78
|
+
warn_if_federation_config_overrides(federation_config_overrides)
|
|
79
|
+
|
|
80
|
+
migrate(superlink, args=ctx.args)
|
|
81
|
+
|
|
82
|
+
# Read superlink connection configuration
|
|
83
|
+
superlink_connection = read_superlink_connection(superlink)
|
|
84
|
+
channel = None
|
|
85
|
+
|
|
86
|
+
try:
|
|
91
87
|
try:
|
|
92
|
-
|
|
93
|
-
channel = init_channel(app, federation_config, auth_plugin)
|
|
88
|
+
channel = init_channel_from_connection(superlink_connection)
|
|
94
89
|
stub = ControlStub(channel) # pylint: disable=unused-variable # noqa: F841
|
|
95
90
|
|
|
96
91
|
typer.secho(f"✋ Stopping run ID {run_id}...", fg=typer.colors.GREEN)
|
|
@@ -101,6 +96,7 @@ def stop( # pylint: disable=R0914
|
|
|
101
96
|
f"❌ {err}",
|
|
102
97
|
fg=typer.colors.RED,
|
|
103
98
|
bold=True,
|
|
99
|
+
err=True,
|
|
104
100
|
)
|
|
105
101
|
raise typer.Exit(code=1) from err
|
|
106
102
|
finally:
|
|
@@ -116,6 +112,7 @@ def stop( # pylint: disable=R0914
|
|
|
116
112
|
f"{err}",
|
|
117
113
|
fg=typer.colors.RED,
|
|
118
114
|
bold=True,
|
|
115
|
+
err=True,
|
|
119
116
|
)
|
|
120
117
|
finally:
|
|
121
118
|
if suppress_output:
|
|
@@ -124,7 +121,17 @@ def stop( # pylint: disable=R0914
|
|
|
124
121
|
|
|
125
122
|
|
|
126
123
|
def _stop_run(stub: ControlStub, run_id: int, output_format: str) -> None:
|
|
127
|
-
"""Stop a run.
|
|
124
|
+
"""Stop a run and display the result.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
stub : ControlStub
|
|
129
|
+
The gRPC stub for Control API communication.
|
|
130
|
+
run_id : int
|
|
131
|
+
The unique identifier of the run to stop.
|
|
132
|
+
output_format : str
|
|
133
|
+
Output format ('default' or 'json').
|
|
134
|
+
"""
|
|
128
135
|
with flwr_cli_grpc_exc_handler():
|
|
129
136
|
response: StopRunResponse = stub.StopRun(request=StopRunRequest(run_id=run_id))
|
|
130
137
|
if response.success:
|
|
@@ -133,10 +140,12 @@ def _stop_run(stub: ControlStub, run_id: int, output_format: str) -> None:
|
|
|
133
140
|
run_output = json.dumps(
|
|
134
141
|
{
|
|
135
142
|
"success": True,
|
|
136
|
-
"run-id": run_id,
|
|
143
|
+
"run-id": f"{run_id}",
|
|
137
144
|
}
|
|
138
145
|
)
|
|
139
146
|
restore_output()
|
|
140
147
|
Console().print_json(run_output)
|
|
141
148
|
else:
|
|
142
|
-
typer.secho(
|
|
149
|
+
typer.secho(
|
|
150
|
+
f"❌ Run {run_id} couldn't be stopped.", fg=typer.colors.RED, err=True
|
|
151
|
+
)
|
|
@@ -0,0 +1,25 @@
|
|
|
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 command line interface `supernode` command."""
|
|
16
|
+
|
|
17
|
+
from .ls import ls as ls
|
|
18
|
+
from .register import register as register
|
|
19
|
+
from .unregister import unregister as unregister
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"ls",
|
|
23
|
+
"register",
|
|
24
|
+
"unregister",
|
|
25
|
+
]
|