flwr 1.23.0__py3-none-any.whl → 1.25.0__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 +16 -5
- flwr/app/error.py +2 -2
- flwr/app/exception.py +3 -3
- flwr/cli/app.py +19 -0
- flwr/cli/{new/templates → 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/auth_plugin.py +4 -5
- flwr/cli/auth_plugin/noop_auth_plugin.py +54 -11
- flwr/cli/auth_plugin/oidc_cli_plugin.py +32 -9
- flwr/cli/build.py +60 -18
- flwr/cli/cli_account_auth_interceptor.py +24 -7
- flwr/cli/config_utils.py +101 -13
- flwr/cli/{new/templates/app/code/flwr_tune → federation}/__init__.py +10 -1
- flwr/cli/federation/ls.py +140 -0
- flwr/cli/federation/show.py +318 -0
- flwr/cli/install.py +91 -13
- flwr/cli/log.py +52 -9
- flwr/cli/login/login.py +7 -4
- flwr/cli/ls.py +211 -130
- flwr/cli/new/new.py +123 -331
- flwr/cli/pull.py +10 -5
- flwr/cli/run/run.py +71 -29
- flwr/cli/run_utils.py +148 -0
- flwr/cli/stop.py +26 -8
- flwr/cli/supernode/ls.py +25 -12
- flwr/cli/supernode/register.py +9 -4
- flwr/cli/supernode/unregister.py +5 -3
- flwr/cli/utils.py +239 -16
- flwr/client/__init__.py +1 -1
- flwr/client/dpfedavg_numpy_client.py +4 -1
- flwr/client/grpc_adapter_client/connection.py +8 -9
- flwr/client/grpc_rere_client/connection.py +16 -14
- flwr/client/grpc_rere_client/grpc_adapter.py +6 -2
- flwr/client/grpc_rere_client/node_auth_client_interceptor.py +2 -1
- flwr/client/message_handler/message_handler.py +2 -2
- flwr/client/mod/secure_aggregation/secaggplus_mod.py +3 -3
- flwr/client/numpy_client.py +1 -1
- flwr/client/rest_client/connection.py +18 -18
- flwr/client/run_info_store.py +4 -5
- flwr/client/typing.py +1 -1
- flwr/clientapp/client_app.py +9 -10
- flwr/clientapp/mod/centraldp_mods.py +16 -17
- flwr/clientapp/mod/localdp_mod.py +8 -9
- flwr/clientapp/typing.py +1 -1
- flwr/clientapp/utils.py +3 -3
- flwr/common/address.py +1 -2
- flwr/common/args.py +3 -4
- flwr/common/config.py +13 -16
- flwr/common/constant.py +5 -2
- flwr/common/differential_privacy.py +3 -4
- flwr/common/event_log_plugin/event_log_plugin.py +3 -4
- flwr/common/exit/exit.py +15 -2
- flwr/common/exit/exit_code.py +19 -0
- flwr/common/exit/exit_handler.py +6 -2
- flwr/common/exit/signal_handler.py +5 -5
- flwr/common/grpc.py +6 -6
- flwr/common/inflatable_protobuf_utils.py +1 -1
- flwr/common/inflatable_utils.py +38 -21
- flwr/common/logger.py +19 -19
- flwr/common/message.py +4 -4
- flwr/common/object_ref.py +7 -7
- flwr/common/record/array.py +3 -3
- flwr/common/record/arrayrecord.py +18 -30
- 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/ndarrays_arithmetic.py +3 -3
- flwr/common/serde.py +11 -4
- flwr/common/serde_utils.py +2 -2
- flwr/common/telemetry.py +9 -5
- flwr/common/typing.py +58 -37
- flwr/compat/client/app.py +38 -37
- flwr/compat/client/grpc_client/connection.py +11 -11
- flwr/compat/server/app.py +5 -6
- 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 +71 -52
- flwr/proto/control_pb2.pyi +277 -111
- flwr/proto/control_pb2_grpc.py +249 -40
- flwr/proto/control_pb2_grpc.pyi +185 -52
- 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 +14 -4
- flwr/proto/fab_pb2.pyi +59 -31
- 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 +24 -14
- flwr/proto/fleet_pb2.pyi +141 -61
- flwr/proto/fleet_pb2_grpc.py +189 -48
- flwr/proto/fleet_pb2_grpc.pyi +175 -61
- 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 +15 -5
- flwr/proto/node_pb2.pyi +50 -25
- 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 +39 -17
- 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 +10 -12
- 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 +10 -8
- 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 +2 -1
- 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 +4 -4
- flwr/server/superlink/fleet/grpc_rere/node_auth_server_interceptor.py +3 -2
- flwr/server/superlink/fleet/message_handler/message_handler.py +75 -30
- flwr/server/superlink/fleet/rest_rere/rest_api.py +2 -2
- flwr/server/superlink/fleet/vce/backend/backend.py +1 -1
- flwr/server/superlink/fleet/vce/backend/raybackend.py +5 -5
- flwr/server/superlink/fleet/vce/vce_api.py +15 -9
- flwr/server/superlink/linkstate/in_memory_linkstate.py +148 -149
- flwr/server/superlink/linkstate/linkstate.py +91 -43
- flwr/server/superlink/linkstate/linkstate_factory.py +22 -5
- flwr/server/superlink/linkstate/sqlite_linkstate.py +502 -436
- flwr/server/superlink/linkstate/utils.py +6 -6
- flwr/server/superlink/serverappio/serverappio_grpc.py +1 -2
- flwr/server/superlink/serverappio/serverappio_servicer.py +26 -21
- flwr/server/superlink/simulation/simulationio_grpc.py +1 -2
- flwr/server/superlink/simulation/simulationio_servicer.py +18 -13
- flwr/server/superlink/utils.py +4 -6
- flwr/server/typing.py +1 -1
- flwr/server/utils/tensorboard.py +15 -8
- flwr/server/workflow/default_workflows.py +5 -5
- flwr/server/workflow/secure_aggregation/secagg_workflow.py +2 -4
- flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +8 -8
- 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 +9 -10
- 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 +9 -9
- 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 +10 -11
- flwr/simulation/ray_transport/ray_client_proxy.py +11 -12
- flwr/simulation/run_simulation.py +43 -43
- flwr/simulation/simulationio_connection.py +4 -4
- flwr/supercore/cli/flower_superexec.py +3 -4
- flwr/supercore/constant.py +34 -1
- flwr/supercore/corestate/corestate.py +24 -3
- flwr/supercore/corestate/in_memory_corestate.py +138 -0
- flwr/supercore/corestate/sqlite_corestate.py +157 -0
- 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 -2
- flwr/supercore/object_store/object_store.py +1 -2
- flwr/supercore/object_store/object_store_factory.py +1 -2
- flwr/supercore/object_store/sqlite_object_store.py +8 -7
- flwr/supercore/primitives/asymmetric.py +1 -1
- flwr/supercore/primitives/asymmetric_ed25519.py +11 -1
- flwr/supercore/sqlite_mixin.py +37 -34
- 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 +190 -0
- flwr/superlink/artifact_provider/artifact_provider.py +1 -2
- flwr/superlink/auth_plugin/auth_plugin.py +6 -9
- flwr/superlink/auth_plugin/noop_auth_plugin.py +6 -9
- flwr/{cli/new/templates/app → superlink/federation}/__init__.py +10 -1
- flwr/superlink/federation/federation_manager.py +64 -0
- flwr/superlink/federation/noop_federation_manager.py +71 -0
- flwr/superlink/servicer/control/control_account_auth_interceptor.py +22 -13
- flwr/superlink/servicer/control/control_event_log_interceptor.py +7 -7
- flwr/superlink/servicer/control/control_grpc.py +7 -6
- flwr/superlink/servicer/control/control_license_interceptor.py +3 -3
- flwr/superlink/servicer/control/control_servicer.py +190 -23
- flwr/supernode/cli/flower_supernode.py +58 -3
- 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 +41 -22
- flwr/supernode/servicer/clientappio/clientappio_servicer.py +46 -10
- flwr/supernode/start_client_internal.py +165 -46
- {flwr-1.23.0.dist-info → flwr-1.25.0.dist-info}/METADATA +9 -11
- flwr-1.25.0.dist-info/RECORD +393 -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 +0 -15
- 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/supercore/object_store/utils.py +0 -43
- flwr-1.23.0.dist-info/RECORD +0 -439
- {flwr-1.23.0.dist-info → flwr-1.25.0.dist-info}/WHEEL +0 -0
- {flwr-1.23.0.dist-info → flwr-1.25.0.dist-info}/entry_points.txt +0 -0
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"""Contextmanager for a REST request-response channel to the Flower server."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
from collections.abc import Iterator
|
|
18
|
+
from collections.abc import Callable, Iterator
|
|
19
19
|
from contextlib import contextmanager
|
|
20
20
|
from logging import ERROR, WARN
|
|
21
|
-
from typing import
|
|
21
|
+
from typing import TypeVar
|
|
22
22
|
|
|
23
23
|
from cryptography.hazmat.primitives.asymmetric import ec
|
|
24
24
|
from google.protobuf.message import Message as GrpcMessage
|
|
@@ -27,7 +27,6 @@ from requests.exceptions import ConnectionError as RequestsConnectionError
|
|
|
27
27
|
from flwr.common import GRPC_MAX_MESSAGE_LENGTH
|
|
28
28
|
from flwr.common.constant import HEARTBEAT_DEFAULT_INTERVAL
|
|
29
29
|
from flwr.common.exit import ExitCode, flwr_exit
|
|
30
|
-
from flwr.common.heartbeat import HeartbeatSender
|
|
31
30
|
from flwr.common.inflatable_protobuf_utils import (
|
|
32
31
|
make_confirm_message_received_fn_protobuf,
|
|
33
32
|
make_pull_object_fn_protobuf,
|
|
@@ -73,6 +72,7 @@ from flwr.proto.message_pb2 import ( # pylint: disable=E0611
|
|
|
73
72
|
)
|
|
74
73
|
from flwr.proto.node_pb2 import Node # pylint: disable=E0611
|
|
75
74
|
from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
|
|
75
|
+
from flwr.supercore.heartbeat import HeartbeatSender
|
|
76
76
|
from flwr.supercore.primitives.asymmetric import generate_key_pairs, public_key_to_bytes
|
|
77
77
|
|
|
78
78
|
try:
|
|
@@ -103,17 +103,15 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
103
103
|
insecure: bool, # pylint: disable=unused-argument
|
|
104
104
|
retry_invoker: RetryInvoker,
|
|
105
105
|
max_message_length: int = GRPC_MAX_MESSAGE_LENGTH, # pylint: disable=W0613
|
|
106
|
-
root_certificates:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]
|
|
111
|
-
] = None,
|
|
106
|
+
root_certificates: bytes | str | None = None, # pylint: disable=unused-argument
|
|
107
|
+
authentication_keys: (
|
|
108
|
+
tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey] | None
|
|
109
|
+
) = None,
|
|
112
110
|
) -> Iterator[
|
|
113
111
|
tuple[
|
|
114
112
|
int,
|
|
115
|
-
Callable[[],
|
|
116
|
-
Callable[[Message, ObjectTree], set[str]],
|
|
113
|
+
Callable[[], tuple[Message, ObjectTree] | None],
|
|
114
|
+
Callable[[Message, ObjectTree, float], set[str]],
|
|
117
115
|
Callable[[int], Run],
|
|
118
116
|
Callable[[str, int], Fab],
|
|
119
117
|
Callable[[int, str], bytes],
|
|
@@ -151,7 +149,7 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
151
149
|
-------
|
|
152
150
|
node_id : int
|
|
153
151
|
receive : Callable[[], Optional[tuple[Message, ObjectTree]]]
|
|
154
|
-
send : Callable[[Message, ObjectTree], set[str]]
|
|
152
|
+
send : Callable[[Message, ObjectTree, float], set[str]]
|
|
155
153
|
get_run : Callable[[int], Run]
|
|
156
154
|
get_fab : Callable[[str, int], Fab]
|
|
157
155
|
pull_object : Callable[[str], bytes]
|
|
@@ -172,7 +170,7 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
172
170
|
# Otherwise any server can fake its identity
|
|
173
171
|
# Please refer to:
|
|
174
172
|
# https://requests.readthedocs.io/en/latest/user/advanced/#ssl-cert-verification
|
|
175
|
-
verify:
|
|
173
|
+
verify: bool | str = True
|
|
176
174
|
if isinstance(root_certificates, str):
|
|
177
175
|
verify = root_certificates
|
|
178
176
|
elif isinstance(root_certificates, bytes):
|
|
@@ -192,7 +190,7 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
192
190
|
node_pk = public_key_to_bytes(authentication_keys[1])
|
|
193
191
|
|
|
194
192
|
# Shared variables for inner functions
|
|
195
|
-
node:
|
|
193
|
+
node: Node | None = None
|
|
196
194
|
|
|
197
195
|
# Remove should_giveup from RetryInvoker as REST does not support gRPC status codes
|
|
198
196
|
retry_invoker.should_giveup = None
|
|
@@ -203,7 +201,7 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
203
201
|
|
|
204
202
|
def _request(
|
|
205
203
|
req: GrpcMessage, res_type: type[T], api_path: str, retry: bool = True
|
|
206
|
-
) ->
|
|
204
|
+
) -> T | None:
|
|
207
205
|
# Serialize the request
|
|
208
206
|
req_bytes = req.SerializeToString()
|
|
209
207
|
|
|
@@ -369,7 +367,7 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
369
367
|
# Cleanup
|
|
370
368
|
node = None
|
|
371
369
|
|
|
372
|
-
def receive() ->
|
|
370
|
+
def receive() -> tuple[Message, ObjectTree] | None:
|
|
373
371
|
"""Pull a message with its ObjectTree from SuperLink."""
|
|
374
372
|
# Get Node
|
|
375
373
|
if node is None:
|
|
@@ -395,12 +393,13 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
395
393
|
# Return the Message and its object tree
|
|
396
394
|
return in_message, object_tree
|
|
397
395
|
|
|
398
|
-
def send(
|
|
396
|
+
def send(
|
|
397
|
+
message: Message, object_tree: ObjectTree, clientapp_runtime: float
|
|
398
|
+
) -> set[str]:
|
|
399
399
|
"""Send the message with its ObjectTree to SuperLink."""
|
|
400
400
|
# Get Node
|
|
401
401
|
if node is None:
|
|
402
402
|
raise RuntimeError("Node instance missing")
|
|
403
|
-
|
|
404
403
|
# Remove the content from the message if it has
|
|
405
404
|
if message.has_content():
|
|
406
405
|
message = remove_content_from_message(message)
|
|
@@ -410,6 +409,7 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
|
|
|
410
409
|
node=node,
|
|
411
410
|
messages_list=[message_to_proto(message)],
|
|
412
411
|
message_object_trees=[object_tree],
|
|
412
|
+
clientapp_runtime_list=[clientapp_runtime],
|
|
413
413
|
)
|
|
414
414
|
res = _request(req, PushMessagesResponse, PATH_PUSH_MESSAGES)
|
|
415
415
|
if res is None:
|
flwr/client/run_info_store.py
CHANGED
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
|
|
18
18
|
from dataclasses import dataclass
|
|
19
19
|
from pathlib import Path
|
|
20
|
-
from typing import Optional
|
|
21
20
|
|
|
22
21
|
from flwr.common import Context, RecordDict
|
|
23
22
|
from flwr.common.config import (
|
|
@@ -52,10 +51,10 @@ class DeprecatedRunInfoStore:
|
|
|
52
51
|
def register_context(
|
|
53
52
|
self,
|
|
54
53
|
run_id: int,
|
|
55
|
-
run:
|
|
56
|
-
flwr_path:
|
|
57
|
-
app_dir:
|
|
58
|
-
fab:
|
|
54
|
+
run: Run | None = None,
|
|
55
|
+
flwr_path: Path | None = None,
|
|
56
|
+
app_dir: str | None = None,
|
|
57
|
+
fab: Fab | None = None,
|
|
59
58
|
) -> None:
|
|
60
59
|
"""Register new run context for this node."""
|
|
61
60
|
if run_id not in self.run_infos:
|
flwr/client/typing.py
CHANGED
flwr/clientapp/client_app.py
CHANGED
|
@@ -16,9 +16,8 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
import inspect
|
|
19
|
-
from collections.abc import Iterator
|
|
19
|
+
from collections.abc import Callable, Iterator
|
|
20
20
|
from contextlib import contextmanager
|
|
21
|
-
from typing import Callable, Optional
|
|
22
21
|
|
|
23
22
|
from flwr.app.metadata import validate_message_type
|
|
24
23
|
from flwr.client.client import Client
|
|
@@ -109,14 +108,14 @@ class ClientApp:
|
|
|
109
108
|
|
|
110
109
|
def __init__(
|
|
111
110
|
self,
|
|
112
|
-
client_fn:
|
|
113
|
-
mods:
|
|
111
|
+
client_fn: ClientFnExt | None = None, # Only for backward compatibility
|
|
112
|
+
mods: list[Mod] | None = None,
|
|
114
113
|
) -> None:
|
|
115
114
|
self._mods: list[Mod] = mods if mods is not None else []
|
|
116
115
|
self._registered_funcs: dict[str, ClientAppCallable] = {}
|
|
117
116
|
|
|
118
117
|
# Create wrapper function for `handle`
|
|
119
|
-
self._call:
|
|
118
|
+
self._call: ClientAppCallable | None = None
|
|
120
119
|
if client_fn is not None:
|
|
121
120
|
|
|
122
121
|
client_fn = _inspect_maybe_adapt_client_fn_signature(client_fn)
|
|
@@ -163,7 +162,7 @@ class ClientApp:
|
|
|
163
162
|
raise ValueError(f"No {category} function registered with name '{action}'")
|
|
164
163
|
|
|
165
164
|
def train(
|
|
166
|
-
self, action: str = DEFAULT_ACTION, *, mods:
|
|
165
|
+
self, action: str = DEFAULT_ACTION, *, mods: list[Mod] | None = None
|
|
167
166
|
) -> Callable[[ClientAppCallable], ClientAppCallable]:
|
|
168
167
|
"""Register a train function with the ``ClientApp``.
|
|
169
168
|
|
|
@@ -218,7 +217,7 @@ class ClientApp:
|
|
|
218
217
|
return _get_decorator(self, MessageType.TRAIN, action, mods)
|
|
219
218
|
|
|
220
219
|
def evaluate(
|
|
221
|
-
self, action: str = DEFAULT_ACTION, *, mods:
|
|
220
|
+
self, action: str = DEFAULT_ACTION, *, mods: list[Mod] | None = None
|
|
222
221
|
) -> Callable[[ClientAppCallable], ClientAppCallable]:
|
|
223
222
|
"""Register an evaluate function with the ``ClientApp``.
|
|
224
223
|
|
|
@@ -273,7 +272,7 @@ class ClientApp:
|
|
|
273
272
|
return _get_decorator(self, MessageType.EVALUATE, action, mods)
|
|
274
273
|
|
|
275
274
|
def query(
|
|
276
|
-
self, action: str = DEFAULT_ACTION, *, mods:
|
|
275
|
+
self, action: str = DEFAULT_ACTION, *, mods: list[Mod] | None = None
|
|
277
276
|
) -> Callable[[ClientAppCallable], ClientAppCallable]:
|
|
278
277
|
"""Register a query function with the ``ClientApp``.
|
|
279
278
|
|
|
@@ -355,7 +354,7 @@ class ClientApp:
|
|
|
355
354
|
"""
|
|
356
355
|
|
|
357
356
|
def lifespan_decorator(
|
|
358
|
-
lifespan_fn: Callable[[Context], Iterator[None]]
|
|
357
|
+
lifespan_fn: Callable[[Context], Iterator[None]],
|
|
359
358
|
) -> Callable[[Context], Iterator[None]]:
|
|
360
359
|
"""Register the lifespan fn with the ServerApp object."""
|
|
361
360
|
|
|
@@ -398,7 +397,7 @@ class LoadClientAppError(Exception):
|
|
|
398
397
|
|
|
399
398
|
|
|
400
399
|
def _get_decorator(
|
|
401
|
-
app: ClientApp, category: str, action: str, mods:
|
|
400
|
+
app: ClientApp, category: str, action: str, mods: list[Mod] | None
|
|
402
401
|
) -> Callable[[ClientAppCallable], ClientAppCallable]:
|
|
403
402
|
"""Get the decorator for the given category and action."""
|
|
404
403
|
# pylint: disable=protected-access
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"""Clipping modifiers for central DP with client-side clipping."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
from collections import OrderedDict
|
|
19
18
|
from logging import ERROR, INFO
|
|
20
19
|
from typing import cast
|
|
21
20
|
|
|
@@ -105,14 +104,14 @@ def fixedclipping_mod(
|
|
|
105
104
|
)
|
|
106
105
|
# Replace outgoing ArrayRecord's Array while preserving their keys
|
|
107
106
|
out_msg.content.array_records[new_array_record_key] = ArrayRecord(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
107
|
+
{
|
|
108
|
+
k: Array(v)
|
|
109
|
+
for k, v in zip(
|
|
110
|
+
client_to_server_arrecord.keys(),
|
|
111
|
+
client_to_server_ndarrays,
|
|
112
|
+
strict=True,
|
|
113
|
+
)
|
|
114
|
+
}
|
|
116
115
|
)
|
|
117
116
|
return out_msg
|
|
118
117
|
|
|
@@ -192,14 +191,14 @@ def adaptiveclipping_mod(
|
|
|
192
191
|
)
|
|
193
192
|
# Replace outgoing ArrayRecord's Array while preserving their keys
|
|
194
193
|
out_msg.content.array_records[new_array_record_key] = ArrayRecord(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
194
|
+
{
|
|
195
|
+
k: Array(v)
|
|
196
|
+
for k, v in zip(
|
|
197
|
+
client_to_server_arrecord.keys(),
|
|
198
|
+
client_to_server_ndarrays,
|
|
199
|
+
strict=True,
|
|
200
|
+
)
|
|
201
|
+
}
|
|
203
202
|
)
|
|
204
203
|
# Add to the MetricRecords the norm bit (recall reply messages only contain
|
|
205
204
|
# one MetricRecord)
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"""Local DP modifier."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
from collections import OrderedDict
|
|
19
18
|
from logging import INFO
|
|
20
19
|
|
|
21
20
|
import numpy as np
|
|
@@ -157,13 +156,13 @@ class LocalDpMod:
|
|
|
157
156
|
|
|
158
157
|
# Replace outgoing ArrayRecord's Array while preserving their keys
|
|
159
158
|
out_msg.content[new_array_record_key] = ArrayRecord(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
159
|
+
{
|
|
160
|
+
k: Array(v)
|
|
161
|
+
for k, v in zip(
|
|
162
|
+
client_to_server_arrecord.keys(),
|
|
163
|
+
client_to_server_ndarrays,
|
|
164
|
+
strict=True,
|
|
165
|
+
)
|
|
166
|
+
}
|
|
168
167
|
)
|
|
169
168
|
return out_msg
|
flwr/clientapp/typing.py
CHANGED
flwr/clientapp/utils.py
CHANGED
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"""Flower ClientApp loading utils."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
from collections.abc import Callable
|
|
18
19
|
from logging import DEBUG
|
|
19
20
|
from pathlib import Path
|
|
20
|
-
from typing import Callable, Optional
|
|
21
21
|
|
|
22
22
|
from flwr.clientapp.client_app import ClientApp, LoadClientAppError
|
|
23
23
|
from flwr.common.config import (
|
|
@@ -32,9 +32,9 @@ from flwr.common.object_ref import load_app, validate
|
|
|
32
32
|
|
|
33
33
|
def get_load_client_app_fn(
|
|
34
34
|
default_app_ref: str,
|
|
35
|
-
app_path:
|
|
35
|
+
app_path: str | None,
|
|
36
36
|
multi_app: bool,
|
|
37
|
-
flwr_dir:
|
|
37
|
+
flwr_dir: str | None = None,
|
|
38
38
|
) -> Callable[[str, str, str], ClientApp]:
|
|
39
39
|
"""Get the load_client_app_fn function.
|
|
40
40
|
|
flwr/common/address.py
CHANGED
|
@@ -18,14 +18,13 @@
|
|
|
18
18
|
import re
|
|
19
19
|
import socket
|
|
20
20
|
from ipaddress import ip_address
|
|
21
|
-
from typing import Optional
|
|
22
21
|
|
|
23
22
|
import grpc
|
|
24
23
|
|
|
25
24
|
IPV6: int = 6
|
|
26
25
|
|
|
27
26
|
|
|
28
|
-
def parse_address(address: str) ->
|
|
27
|
+
def parse_address(address: str) -> tuple[str, int, bool | None] | None:
|
|
29
28
|
"""Parse an IP address into host, port, and version.
|
|
30
29
|
|
|
31
30
|
Parameters
|
flwr/common/args.py
CHANGED
|
@@ -20,7 +20,6 @@ import sys
|
|
|
20
20
|
from logging import DEBUG, ERROR, INFO, WARN
|
|
21
21
|
from os.path import isfile
|
|
22
22
|
from pathlib import Path
|
|
23
|
-
from typing import Optional, Union
|
|
24
23
|
|
|
25
24
|
from flwr.common.constant import TRANSPORT_TYPE_REST
|
|
26
25
|
from flwr.common.logger import log
|
|
@@ -70,9 +69,9 @@ def add_args_flwr_app_common(parser: argparse.ArgumentParser) -> None:
|
|
|
70
69
|
def try_obtain_root_certificates(
|
|
71
70
|
args: argparse.Namespace,
|
|
72
71
|
grpc_server_address: str,
|
|
73
|
-
) ->
|
|
72
|
+
) -> bytes | str | None:
|
|
74
73
|
"""Validate and return the root certificates."""
|
|
75
|
-
root_cert_path:
|
|
74
|
+
root_cert_path: str | None = args.root_certificates
|
|
76
75
|
if args.insecure:
|
|
77
76
|
if root_cert_path is not None:
|
|
78
77
|
sys.exit(
|
|
@@ -111,7 +110,7 @@ def try_obtain_root_certificates(
|
|
|
111
110
|
|
|
112
111
|
def try_obtain_server_certificates(
|
|
113
112
|
args: argparse.Namespace,
|
|
114
|
-
) ->
|
|
113
|
+
) -> tuple[bytes, bytes, bytes] | None:
|
|
115
114
|
"""Validate and return the CA cert, server cert, and server private key."""
|
|
116
115
|
if args.insecure:
|
|
117
116
|
log(
|
flwr/common/config.py
CHANGED
|
@@ -20,7 +20,7 @@ import re
|
|
|
20
20
|
import zipfile
|
|
21
21
|
from io import BytesIO
|
|
22
22
|
from pathlib import Path
|
|
23
|
-
from typing import IO, Any,
|
|
23
|
+
from typing import IO, Any, TypeVar, cast, get_args
|
|
24
24
|
|
|
25
25
|
import tomli
|
|
26
26
|
import typer
|
|
@@ -39,7 +39,7 @@ from . import ConfigRecord, object_ref
|
|
|
39
39
|
T_dict = TypeVar("T_dict", bound=dict[str, Any]) # pylint: disable=invalid-name
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def get_flwr_dir(provided_path:
|
|
42
|
+
def get_flwr_dir(provided_path: str | None = None) -> Path:
|
|
43
43
|
"""Return the Flower home directory based on env variables."""
|
|
44
44
|
if provided_path is None or not Path(provided_path).is_dir():
|
|
45
45
|
return Path(
|
|
@@ -55,7 +55,7 @@ def get_project_dir(
|
|
|
55
55
|
fab_id: str,
|
|
56
56
|
fab_version: str,
|
|
57
57
|
fab_hash: str,
|
|
58
|
-
flwr_dir:
|
|
58
|
+
flwr_dir: str | Path | None = None,
|
|
59
59
|
) -> Path:
|
|
60
60
|
"""Return the project directory based on the given fab_id and fab_version."""
|
|
61
61
|
# Check the fab_id
|
|
@@ -73,7 +73,7 @@ def get_project_dir(
|
|
|
73
73
|
)
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
def get_project_config(project_dir:
|
|
76
|
+
def get_project_config(project_dir: str | Path) -> dict[str, Any]:
|
|
77
77
|
"""Return pyproject.toml in the given project directory."""
|
|
78
78
|
# Load pyproject.toml file
|
|
79
79
|
toml_path = Path(project_dir) / FAB_CONFIG_FILE
|
|
@@ -134,7 +134,7 @@ def get_fused_config_from_dir(
|
|
|
134
134
|
return fuse_dicts(flat_default_config, override_config)
|
|
135
135
|
|
|
136
136
|
|
|
137
|
-
def get_fused_config_from_fab(fab_file:
|
|
137
|
+
def get_fused_config_from_fab(fab_file: Path | bytes, run: Run) -> UserConfig:
|
|
138
138
|
"""Fuse default config in a `FAB` with overrides in a `Run`.
|
|
139
139
|
|
|
140
140
|
This enables obtaining a run-config without having to install the FAB. This
|
|
@@ -146,7 +146,7 @@ def get_fused_config_from_fab(fab_file: Union[Path, bytes], run: Run) -> UserCon
|
|
|
146
146
|
return fuse_dicts(flat_config_flat, run.override_config)
|
|
147
147
|
|
|
148
148
|
|
|
149
|
-
def get_fused_config(run: Run, flwr_dir:
|
|
149
|
+
def get_fused_config(run: Run, flwr_dir: Path | None) -> UserConfig:
|
|
150
150
|
"""Merge the overrides from a `Run` with the config from a FAB.
|
|
151
151
|
|
|
152
152
|
Get the config using the fab_id and the fab_version, remove the nesting by adding
|
|
@@ -165,9 +165,7 @@ def get_fused_config(run: Run, flwr_dir: Optional[Path]) -> UserConfig:
|
|
|
165
165
|
return get_fused_config_from_dir(project_dir, run.override_config)
|
|
166
166
|
|
|
167
167
|
|
|
168
|
-
def flatten_dict(
|
|
169
|
-
raw_dict: Optional[dict[str, Any]], parent_key: str = ""
|
|
170
|
-
) -> UserConfig:
|
|
168
|
+
def flatten_dict(raw_dict: dict[str, Any] | None, parent_key: str = "") -> UserConfig:
|
|
171
169
|
"""Flatten dict by joining nested keys with a given separator."""
|
|
172
170
|
if raw_dict is None:
|
|
173
171
|
return {}
|
|
@@ -205,9 +203,7 @@ def unflatten_dict(flat_dict: dict[str, Any]) -> dict[str, Any]:
|
|
|
205
203
|
return unflattened_dict
|
|
206
204
|
|
|
207
205
|
|
|
208
|
-
def parse_config_args(
|
|
209
|
-
config: Optional[list[str]], flatten: bool = True
|
|
210
|
-
) -> dict[str, Any]:
|
|
206
|
+
def parse_config_args(config: list[str] | None, flatten: bool = True) -> dict[str, Any]:
|
|
211
207
|
"""Parse separator separated list of key-value pairs separated by '='."""
|
|
212
208
|
overrides: UserConfig = {}
|
|
213
209
|
|
|
@@ -246,6 +242,7 @@ def parse_config_args(
|
|
|
246
242
|
"space-separated key-value pairs.",
|
|
247
243
|
fg=typer.colors.RED,
|
|
248
244
|
bold=True,
|
|
245
|
+
err=True,
|
|
249
246
|
)
|
|
250
247
|
raise typer.Exit(code=1) from err
|
|
251
248
|
|
|
@@ -269,7 +266,7 @@ def user_config_to_configrecord(config: UserConfig) -> ConfigRecord:
|
|
|
269
266
|
return c_record
|
|
270
267
|
|
|
271
268
|
|
|
272
|
-
def get_fab_config(fab_file:
|
|
269
|
+
def get_fab_config(fab_file: Path | bytes) -> dict[str, Any]:
|
|
273
270
|
"""Extract the config from a FAB file or path.
|
|
274
271
|
|
|
275
272
|
Parameters
|
|
@@ -283,7 +280,7 @@ def get_fab_config(fab_file: Union[Path, bytes]) -> dict[str, Any]:
|
|
|
283
280
|
Dict[str, Any]
|
|
284
281
|
The `config` of the given Flower App Bundle.
|
|
285
282
|
"""
|
|
286
|
-
fab_file_archive:
|
|
283
|
+
fab_file_archive: Path | IO[bytes]
|
|
287
284
|
if isinstance(fab_file, bytes):
|
|
288
285
|
fab_file_archive = BytesIO(fab_file)
|
|
289
286
|
elif isinstance(fab_file, Path):
|
|
@@ -319,7 +316,7 @@ def _validate_run_config(config_dict: dict[str, Any], errors: list[str]) -> None
|
|
|
319
316
|
|
|
320
317
|
# pylint: disable=too-many-branches
|
|
321
318
|
def validate_fields_in_config(
|
|
322
|
-
config: dict[str, Any]
|
|
319
|
+
config: dict[str, Any],
|
|
323
320
|
) -> tuple[bool, list[str], list[str]]:
|
|
324
321
|
"""Validate pyproject.toml fields."""
|
|
325
322
|
errors = []
|
|
@@ -368,7 +365,7 @@ def validate_fields_in_config(
|
|
|
368
365
|
def validate_config(
|
|
369
366
|
config: dict[str, Any],
|
|
370
367
|
check_module: bool = True,
|
|
371
|
-
project_dir:
|
|
368
|
+
project_dir: str | Path | None = None,
|
|
372
369
|
) -> tuple[bool, list[str], list[str]]:
|
|
373
370
|
"""Validate pyproject.toml."""
|
|
374
371
|
is_valid, errors, warnings = validate_fields_in_config(config)
|
flwr/common/constant.py
CHANGED
|
@@ -88,6 +88,7 @@ FAB_INCLUDE_PATTERNS = (
|
|
|
88
88
|
)
|
|
89
89
|
# FAB file exclude patterns (gitignore-style patterns)
|
|
90
90
|
FAB_EXCLUDE_PATTERNS = (
|
|
91
|
+
f"{FLWR_DIR}/**", # Exclude the .flwr directory
|
|
91
92
|
"**/__pycache__/**",
|
|
92
93
|
FAB_CONFIG_FILE, # Exclude the original pyproject.toml
|
|
93
94
|
)
|
|
@@ -227,6 +228,8 @@ class ErrorCode:
|
|
|
227
228
|
REPLY_MESSAGE_UNAVAILABLE = 4
|
|
228
229
|
NODE_UNAVAILABLE = 5
|
|
229
230
|
MOD_FAILED_PRECONDITION = 6
|
|
231
|
+
INVALID_FAB = 7
|
|
232
|
+
CLIENT_APP_CRASHED = 8
|
|
230
233
|
|
|
231
234
|
def __new__(cls) -> ErrorCode:
|
|
232
235
|
"""Prevent instantiation."""
|
|
@@ -319,5 +322,5 @@ class ExecPluginType:
|
|
|
319
322
|
|
|
320
323
|
|
|
321
324
|
# Constants for No-op auth plugins
|
|
322
|
-
NOOP_FLWR_AID = "<none>"
|
|
323
|
-
NOOP_ACCOUNT_NAME = "
|
|
325
|
+
NOOP_FLWR_AID = "<id:none>"
|
|
326
|
+
NOOP_ACCOUNT_NAME = "<name:none>"
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
from logging import WARNING
|
|
19
|
-
from typing import Optional
|
|
20
19
|
|
|
21
20
|
import numpy as np
|
|
22
21
|
|
|
@@ -70,7 +69,7 @@ def compute_clip_model_update(
|
|
|
70
69
|
"""Compute model update (param1 - param2) and clip it.
|
|
71
70
|
|
|
72
71
|
Then add the clipped value to param1."""
|
|
73
|
-
model_update = [np.subtract(x, y) for (x, y) in zip(param1, param2)]
|
|
72
|
+
model_update = [np.subtract(x, y) for (x, y) in zip(param1, param2, strict=True)]
|
|
74
73
|
clip_inputs_inplace(model_update, clipping_norm)
|
|
75
74
|
|
|
76
75
|
for i, _ in enumerate(param2):
|
|
@@ -98,7 +97,7 @@ def compute_adaptive_clip_model_update(
|
|
|
98
97
|
model update = param1 - param2
|
|
99
98
|
Return the norm_bit
|
|
100
99
|
"""
|
|
101
|
-
model_update = [np.subtract(x, y) for (x, y) in zip(param1, param2)]
|
|
100
|
+
model_update = [np.subtract(x, y) for (x, y) in zip(param1, param2, strict=True)]
|
|
102
101
|
norm_bit = adaptive_clip_inputs_inplace(model_update, clipping_norm)
|
|
103
102
|
|
|
104
103
|
for i, _ in enumerate(param2):
|
|
@@ -125,7 +124,7 @@ def add_gaussian_noise_to_params(
|
|
|
125
124
|
def compute_adaptive_noise_params(
|
|
126
125
|
noise_multiplier: float,
|
|
127
126
|
num_sampled_clients: float,
|
|
128
|
-
clipped_count_stddev:
|
|
127
|
+
clipped_count_stddev: float | None,
|
|
129
128
|
) -> tuple[float, float]:
|
|
130
129
|
"""Compute noising parameters for the adaptive clipping.
|
|
131
130
|
|
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
from abc import ABC, abstractmethod
|
|
19
|
-
from typing import Optional, Union
|
|
20
19
|
|
|
21
20
|
import grpc
|
|
22
21
|
from google.protobuf.message import Message as GrpcMessage
|
|
@@ -36,7 +35,7 @@ class EventLogWriterPlugin(ABC):
|
|
|
36
35
|
self,
|
|
37
36
|
request: GrpcMessage,
|
|
38
37
|
context: grpc.ServicerContext,
|
|
39
|
-
account_info:
|
|
38
|
+
account_info: AccountInfo | None,
|
|
40
39
|
method_name: str,
|
|
41
40
|
) -> LogEntry:
|
|
42
41
|
"""Compose pre-event log entry from the provided request and context."""
|
|
@@ -46,9 +45,9 @@ class EventLogWriterPlugin(ABC):
|
|
|
46
45
|
self,
|
|
47
46
|
request: GrpcMessage,
|
|
48
47
|
context: grpc.ServicerContext,
|
|
49
|
-
account_info:
|
|
48
|
+
account_info: AccountInfo | None,
|
|
50
49
|
method_name: str,
|
|
51
|
-
response:
|
|
50
|
+
response: GrpcMessage | BaseException | None,
|
|
52
51
|
) -> LogEntry:
|
|
53
52
|
"""Compose post-event log entry from the provided response and context."""
|
|
54
53
|
|
flwr/common/exit/exit.py
CHANGED
|
@@ -15,14 +15,16 @@
|
|
|
15
15
|
"""Unified exit function."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
import os
|
|
20
19
|
import sys
|
|
20
|
+
import threading
|
|
21
|
+
import time
|
|
21
22
|
from logging import ERROR, INFO
|
|
22
23
|
from typing import Any, NoReturn
|
|
23
24
|
|
|
24
25
|
from flwr.common import EventType, event
|
|
25
26
|
from flwr.common.version import package_version
|
|
27
|
+
from flwr.supercore.constant import FORCE_EXIT_TIMEOUT_SECONDS
|
|
26
28
|
|
|
27
29
|
from ..logger import log
|
|
28
30
|
from .exit_code import EXIT_CODE_HELP
|
|
@@ -53,6 +55,10 @@ def flwr_exit(
|
|
|
53
55
|
- `<message>`: Optional context or additional information about the exit.
|
|
54
56
|
- `<short-help-message>`: A brief explanation for the given exit code.
|
|
55
57
|
- `<help-page-url>`: A URL providing detailed documentation and resolution steps.
|
|
58
|
+
|
|
59
|
+
Notes
|
|
60
|
+
-----
|
|
61
|
+
This function MUST be called from the main thread.
|
|
56
62
|
"""
|
|
57
63
|
is_error = not 0 <= code < 100 # 0-99 are success exit codes
|
|
58
64
|
|
|
@@ -84,6 +90,13 @@ def flwr_exit(
|
|
|
84
90
|
# Trigger exit handlers
|
|
85
91
|
trigger_exit_handlers()
|
|
86
92
|
|
|
93
|
+
# Start a daemon thread to force exit if graceful exit fails
|
|
94
|
+
def force_exit() -> None:
|
|
95
|
+
time.sleep(FORCE_EXIT_TIMEOUT_SECONDS)
|
|
96
|
+
os._exit(sys_exit_code)
|
|
97
|
+
|
|
98
|
+
threading.Thread(target=force_exit, daemon=True).start()
|
|
99
|
+
|
|
87
100
|
# Exit
|
|
88
101
|
sys.exit(sys_exit_code)
|
|
89
102
|
|