flwr-nightly 1.8.0.dev20240315__py3-none-any.whl → 1.15.0.dev20250115__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- flwr/cli/app.py +16 -2
- flwr/cli/build.py +181 -0
- flwr/cli/cli_user_auth_interceptor.py +90 -0
- flwr/cli/config_utils.py +343 -0
- flwr/cli/example.py +4 -1
- flwr/cli/install.py +253 -0
- flwr/cli/log.py +182 -0
- flwr/{server/superlink/state → cli/login}/__init__.py +4 -10
- flwr/cli/login/login.py +88 -0
- flwr/cli/ls.py +327 -0
- flwr/cli/new/__init__.py +1 -0
- flwr/cli/new/new.py +210 -66
- flwr/cli/new/templates/app/.gitignore.tpl +163 -0
- flwr/cli/new/templates/app/LICENSE.tpl +202 -0
- flwr/cli/new/templates/app/README.baseline.md.tpl +127 -0
- flwr/cli/new/templates/app/README.flowertune.md.tpl +66 -0
- flwr/cli/new/templates/app/README.md.tpl +16 -32
- flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +1 -0
- flwr/cli/new/templates/app/code/__init__.py.tpl +1 -1
- flwr/cli/new/templates/app/code/client.baseline.py.tpl +58 -0
- flwr/cli/new/templates/app/code/client.huggingface.py.tpl +55 -0
- flwr/cli/new/templates/app/code/client.jax.py.tpl +50 -0
- flwr/cli/new/templates/app/code/client.mlx.py.tpl +73 -0
- flwr/cli/new/templates/app/code/client.numpy.py.tpl +7 -7
- flwr/cli/new/templates/app/code/client.pytorch.py.tpl +30 -21
- flwr/cli/new/templates/app/code/client.sklearn.py.tpl +63 -0
- flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +57 -1
- flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +36 -0
- flwr/cli/new/templates/app/code/flwr_tune/__init__.py +15 -0
- flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +126 -0
- flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +87 -0
- flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl +78 -0
- flwr/cli/new/templates/app/code/flwr_tune/server_app.py.tpl +94 -0
- flwr/cli/new/templates/app/code/flwr_tune/strategy.py.tpl +83 -0
- flwr/cli/new/templates/app/code/model.baseline.py.tpl +80 -0
- flwr/cli/new/templates/app/code/server.baseline.py.tpl +46 -0
- flwr/cli/new/templates/app/code/server.huggingface.py.tpl +38 -0
- flwr/cli/new/templates/app/code/server.jax.py.tpl +26 -0
- flwr/cli/new/templates/app/code/server.mlx.py.tpl +31 -0
- flwr/cli/new/templates/app/code/server.numpy.py.tpl +22 -9
- flwr/cli/new/templates/app/code/server.pytorch.py.tpl +21 -18
- flwr/cli/new/templates/app/code/server.sklearn.py.tpl +36 -0
- flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +29 -1
- flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +1 -0
- flwr/cli/new/templates/app/code/task.huggingface.py.tpl +102 -0
- flwr/cli/new/templates/app/code/task.jax.py.tpl +57 -0
- flwr/cli/new/templates/app/code/task.mlx.py.tpl +102 -0
- flwr/cli/new/templates/app/code/task.numpy.py.tpl +7 -0
- flwr/cli/new/templates/app/code/task.pytorch.py.tpl +29 -24
- flwr/cli/new/templates/app/code/task.sklearn.py.tpl +67 -0
- flwr/cli/new/templates/app/code/task.tensorflow.py.tpl +53 -0
- flwr/cli/new/templates/app/code/utils.baseline.py.tpl +1 -0
- flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +138 -0
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +68 -0
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +46 -0
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +35 -0
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +39 -0
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +25 -12
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +29 -14
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +35 -0
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +29 -14
- flwr/cli/run/__init__.py +1 -0
- flwr/cli/run/run.py +212 -34
- flwr/cli/stop.py +130 -0
- flwr/cli/utils.py +240 -5
- flwr/client/__init__.py +3 -2
- flwr/client/app.py +432 -255
- flwr/client/client.py +1 -11
- flwr/client/client_app.py +74 -13
- flwr/client/clientapp/__init__.py +22 -0
- flwr/client/clientapp/app.py +259 -0
- flwr/client/clientapp/clientappio_servicer.py +244 -0
- flwr/client/clientapp/utils.py +115 -0
- flwr/client/dpfedavg_numpy_client.py +7 -8
- flwr/client/grpc_adapter_client/__init__.py +15 -0
- flwr/client/grpc_adapter_client/connection.py +98 -0
- flwr/client/grpc_client/connection.py +21 -7
- flwr/client/grpc_rere_client/__init__.py +1 -1
- flwr/client/grpc_rere_client/client_interceptor.py +176 -0
- flwr/client/grpc_rere_client/connection.py +163 -56
- flwr/client/grpc_rere_client/grpc_adapter.py +167 -0
- flwr/client/heartbeat.py +74 -0
- flwr/client/message_handler/__init__.py +1 -1
- flwr/client/message_handler/message_handler.py +10 -11
- flwr/client/mod/__init__.py +5 -5
- flwr/client/mod/centraldp_mods.py +4 -2
- flwr/client/mod/comms_mods.py +5 -4
- flwr/client/mod/localdp_mod.py +10 -5
- flwr/client/mod/secure_aggregation/__init__.py +1 -1
- flwr/client/mod/secure_aggregation/secaggplus_mod.py +26 -26
- flwr/client/mod/utils.py +2 -4
- flwr/client/nodestate/__init__.py +26 -0
- flwr/client/nodestate/in_memory_nodestate.py +38 -0
- flwr/client/nodestate/nodestate.py +31 -0
- flwr/client/nodestate/nodestate_factory.py +38 -0
- flwr/client/numpy_client.py +8 -31
- flwr/client/rest_client/__init__.py +1 -1
- flwr/client/rest_client/connection.py +199 -176
- flwr/client/run_info_store.py +112 -0
- flwr/client/supernode/__init__.py +24 -0
- flwr/client/supernode/app.py +321 -0
- flwr/client/typing.py +1 -0
- flwr/common/__init__.py +17 -11
- flwr/common/address.py +47 -3
- flwr/common/args.py +153 -0
- flwr/common/auth_plugin/__init__.py +24 -0
- flwr/common/auth_plugin/auth_plugin.py +121 -0
- flwr/common/config.py +243 -0
- flwr/common/constant.py +135 -1
- flwr/common/context.py +32 -2
- flwr/common/date.py +22 -4
- flwr/common/differential_privacy.py +2 -2
- flwr/common/dp.py +2 -4
- flwr/common/exit_handlers.py +3 -3
- flwr/common/grpc.py +164 -5
- flwr/common/logger.py +230 -12
- flwr/common/message.py +191 -106
- flwr/common/object_ref.py +179 -44
- flwr/common/pyproject.py +1 -0
- flwr/common/record/__init__.py +2 -1
- flwr/common/record/configsrecord.py +58 -18
- flwr/common/record/metricsrecord.py +57 -17
- flwr/common/record/parametersrecord.py +88 -20
- flwr/common/record/recordset.py +153 -30
- flwr/common/record/typeddict.py +30 -55
- flwr/common/recordset_compat.py +31 -12
- flwr/common/retry_invoker.py +123 -30
- flwr/common/secure_aggregation/__init__.py +1 -1
- flwr/common/secure_aggregation/crypto/__init__.py +1 -1
- flwr/common/secure_aggregation/crypto/shamir.py +11 -11
- flwr/common/secure_aggregation/crypto/symmetric_encryption.py +68 -4
- flwr/common/secure_aggregation/ndarrays_arithmetic.py +17 -17
- flwr/common/secure_aggregation/quantization.py +8 -8
- flwr/common/secure_aggregation/secaggplus_constants.py +1 -1
- flwr/common/secure_aggregation/secaggplus_utils.py +10 -12
- flwr/common/serde.py +304 -23
- flwr/common/telemetry.py +65 -29
- flwr/common/typing.py +120 -19
- flwr/common/version.py +17 -3
- flwr/proto/clientappio_pb2.py +45 -0
- flwr/proto/clientappio_pb2.pyi +132 -0
- flwr/proto/clientappio_pb2_grpc.py +135 -0
- flwr/proto/clientappio_pb2_grpc.pyi +53 -0
- flwr/proto/exec_pb2.py +62 -0
- flwr/proto/exec_pb2.pyi +212 -0
- flwr/proto/exec_pb2_grpc.py +237 -0
- flwr/proto/exec_pb2_grpc.pyi +93 -0
- flwr/proto/fab_pb2.py +31 -0
- flwr/proto/fab_pb2.pyi +65 -0
- flwr/proto/fab_pb2_grpc.py +4 -0
- flwr/proto/fab_pb2_grpc.pyi +4 -0
- flwr/proto/fleet_pb2.py +42 -23
- flwr/proto/fleet_pb2.pyi +123 -1
- flwr/proto/fleet_pb2_grpc.py +170 -0
- flwr/proto/fleet_pb2_grpc.pyi +61 -0
- flwr/proto/grpcadapter_pb2.py +32 -0
- flwr/proto/grpcadapter_pb2.pyi +43 -0
- flwr/proto/grpcadapter_pb2_grpc.py +66 -0
- flwr/proto/grpcadapter_pb2_grpc.pyi +24 -0
- flwr/proto/log_pb2.py +29 -0
- flwr/proto/log_pb2.pyi +39 -0
- flwr/proto/log_pb2_grpc.py +4 -0
- flwr/proto/log_pb2_grpc.pyi +4 -0
- flwr/proto/message_pb2.py +41 -0
- flwr/proto/message_pb2.pyi +128 -0
- flwr/proto/message_pb2_grpc.py +4 -0
- flwr/proto/message_pb2_grpc.pyi +4 -0
- flwr/proto/node_pb2.py +2 -2
- flwr/proto/node_pb2.pyi +1 -4
- flwr/proto/recordset_pb2.py +35 -33
- flwr/proto/recordset_pb2.pyi +40 -14
- flwr/proto/run_pb2.py +64 -0
- flwr/proto/run_pb2.pyi +268 -0
- flwr/proto/run_pb2_grpc.py +4 -0
- flwr/proto/run_pb2_grpc.pyi +4 -0
- flwr/proto/serverappio_pb2.py +52 -0
- flwr/proto/{driver_pb2.pyi → serverappio_pb2.pyi} +62 -20
- flwr/proto/serverappio_pb2_grpc.py +410 -0
- flwr/proto/serverappio_pb2_grpc.pyi +160 -0
- flwr/proto/simulationio_pb2.py +38 -0
- flwr/proto/simulationio_pb2.pyi +65 -0
- flwr/proto/simulationio_pb2_grpc.py +239 -0
- flwr/proto/simulationio_pb2_grpc.pyi +94 -0
- flwr/proto/task_pb2.py +7 -8
- flwr/proto/task_pb2.pyi +8 -5
- flwr/proto/transport_pb2.py +8 -8
- flwr/proto/transport_pb2.pyi +9 -6
- flwr/server/__init__.py +2 -10
- flwr/server/app.py +579 -402
- flwr/server/client_manager.py +8 -6
- flwr/server/compat/app.py +6 -62
- flwr/server/compat/app_utils.py +14 -9
- flwr/server/compat/driver_client_proxy.py +25 -59
- flwr/server/compat/legacy_context.py +5 -4
- flwr/server/driver/__init__.py +2 -0
- flwr/server/driver/driver.py +36 -131
- flwr/server/driver/grpc_driver.py +220 -81
- flwr/server/driver/inmemory_driver.py +183 -0
- flwr/server/history.py +28 -29
- flwr/server/run_serverapp.py +15 -126
- flwr/server/server.py +50 -44
- flwr/server/server_app.py +59 -10
- flwr/server/serverapp/__init__.py +22 -0
- flwr/server/serverapp/app.py +256 -0
- flwr/server/serverapp_components.py +52 -0
- flwr/server/strategy/__init__.py +2 -2
- flwr/server/strategy/aggregate.py +37 -23
- flwr/server/strategy/bulyan.py +9 -9
- flwr/server/strategy/dp_adaptive_clipping.py +25 -25
- flwr/server/strategy/dp_fixed_clipping.py +23 -22
- flwr/server/strategy/dpfedavg_adaptive.py +8 -8
- flwr/server/strategy/dpfedavg_fixed.py +13 -12
- flwr/server/strategy/fault_tolerant_fedavg.py +11 -11
- flwr/server/strategy/fedadagrad.py +9 -9
- flwr/server/strategy/fedadam.py +20 -10
- flwr/server/strategy/fedavg.py +16 -16
- flwr/server/strategy/fedavg_android.py +17 -17
- flwr/server/strategy/fedavgm.py +9 -9
- flwr/server/strategy/fedmedian.py +5 -5
- flwr/server/strategy/fedopt.py +6 -6
- flwr/server/strategy/fedprox.py +7 -7
- flwr/server/strategy/fedtrimmedavg.py +8 -8
- flwr/server/strategy/fedxgb_bagging.py +12 -12
- flwr/server/strategy/fedxgb_cyclic.py +10 -10
- flwr/server/strategy/fedxgb_nn_avg.py +6 -6
- flwr/server/strategy/fedyogi.py +9 -9
- flwr/server/strategy/krum.py +9 -9
- flwr/server/strategy/qfedavg.py +16 -16
- flwr/server/strategy/strategy.py +10 -10
- flwr/server/superlink/driver/__init__.py +2 -2
- flwr/server/superlink/driver/serverappio_grpc.py +61 -0
- flwr/server/superlink/driver/serverappio_servicer.py +361 -0
- flwr/server/superlink/ffs/__init__.py +24 -0
- flwr/server/superlink/ffs/disk_ffs.py +108 -0
- flwr/server/superlink/ffs/ffs.py +79 -0
- flwr/server/superlink/ffs/ffs_factory.py +47 -0
- flwr/server/superlink/fleet/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_adapter/__init__.py +15 -0
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +162 -0
- flwr/server/superlink/fleet/grpc_bidi/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +4 -2
- flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +3 -2
- flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +5 -154
- flwr/server/superlink/fleet/grpc_rere/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +120 -13
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +228 -0
- flwr/server/superlink/fleet/message_handler/__init__.py +1 -1
- flwr/server/superlink/fleet/message_handler/message_handler.py +156 -13
- flwr/server/superlink/fleet/rest_rere/__init__.py +1 -1
- flwr/server/superlink/fleet/rest_rere/rest_api.py +119 -81
- flwr/server/superlink/fleet/vce/__init__.py +1 -0
- flwr/server/superlink/fleet/vce/backend/__init__.py +4 -4
- flwr/server/superlink/fleet/vce/backend/backend.py +8 -9
- flwr/server/superlink/fleet/vce/backend/raybackend.py +87 -68
- flwr/server/superlink/fleet/vce/vce_api.py +208 -146
- flwr/server/superlink/linkstate/__init__.py +28 -0
- flwr/server/superlink/linkstate/in_memory_linkstate.py +569 -0
- flwr/server/superlink/linkstate/linkstate.py +376 -0
- flwr/server/superlink/{state/state_factory.py → linkstate/linkstate_factory.py} +19 -10
- flwr/server/superlink/linkstate/sqlite_linkstate.py +1196 -0
- flwr/server/superlink/linkstate/utils.py +399 -0
- flwr/server/superlink/simulation/__init__.py +15 -0
- flwr/server/superlink/simulation/simulationio_grpc.py +65 -0
- flwr/server/superlink/simulation/simulationio_servicer.py +186 -0
- flwr/server/superlink/utils.py +65 -0
- flwr/server/typing.py +2 -0
- flwr/server/utils/__init__.py +1 -1
- flwr/server/utils/tensorboard.py +5 -5
- flwr/server/utils/validator.py +40 -45
- flwr/server/workflow/default_workflows.py +70 -26
- flwr/server/workflow/secure_aggregation/secagg_workflow.py +1 -0
- flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +40 -27
- flwr/simulation/__init__.py +12 -5
- flwr/simulation/app.py +247 -315
- flwr/simulation/legacy_app.py +404 -0
- flwr/simulation/ray_transport/__init__.py +1 -1
- flwr/simulation/ray_transport/ray_actor.py +42 -67
- flwr/simulation/ray_transport/ray_client_proxy.py +37 -17
- flwr/simulation/ray_transport/utils.py +1 -0
- flwr/simulation/run_simulation.py +306 -163
- flwr/simulation/simulationio_connection.py +89 -0
- flwr/superexec/__init__.py +15 -0
- flwr/superexec/app.py +59 -0
- flwr/superexec/deployment.py +188 -0
- flwr/superexec/exec_grpc.py +80 -0
- flwr/superexec/exec_servicer.py +231 -0
- flwr/superexec/exec_user_auth_interceptor.py +101 -0
- flwr/superexec/executor.py +96 -0
- flwr/superexec/simulation.py +124 -0
- {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.15.0.dev20250115.dist-info}/METADATA +33 -26
- flwr_nightly-1.15.0.dev20250115.dist-info/RECORD +328 -0
- flwr_nightly-1.15.0.dev20250115.dist-info/entry_points.txt +12 -0
- flwr/cli/flower_toml.py +0 -140
- flwr/cli/new/templates/app/flower.toml.tpl +0 -13
- flwr/cli/new/templates/app/requirements.numpy.txt.tpl +0 -2
- flwr/cli/new/templates/app/requirements.pytorch.txt.tpl +0 -4
- flwr/cli/new/templates/app/requirements.tensorflow.txt.tpl +0 -4
- flwr/client/node_state.py +0 -48
- flwr/client/node_state_tests.py +0 -65
- flwr/proto/driver_pb2.py +0 -44
- flwr/proto/driver_pb2_grpc.py +0 -169
- flwr/proto/driver_pb2_grpc.pyi +0 -66
- flwr/server/superlink/driver/driver_grpc.py +0 -54
- flwr/server/superlink/driver/driver_servicer.py +0 -129
- flwr/server/superlink/state/in_memory_state.py +0 -230
- flwr/server/superlink/state/sqlite_state.py +0 -630
- flwr/server/superlink/state/state.py +0 -154
- flwr_nightly-1.8.0.dev20240315.dist-info/RECORD +0 -211
- flwr_nightly-1.8.0.dev20240315.dist-info/entry_points.txt +0 -9
- {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.15.0.dev20250115.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.8.0.dev20240315.dist-info → flwr_nightly-1.15.0.dev20250115.dist-info}/WHEEL +0 -0
flwr/common/serde.py
CHANGED
@@ -15,12 +15,21 @@
|
|
15
15
|
"""ProtoBuf serialization and deserialization."""
|
16
16
|
|
17
17
|
|
18
|
-
from
|
18
|
+
from collections import OrderedDict
|
19
|
+
from collections.abc import MutableMapping
|
20
|
+
from typing import Any, TypeVar, cast
|
19
21
|
|
20
22
|
from google.protobuf.message import Message as GrpcMessage
|
21
23
|
|
24
|
+
from flwr.common.constant import SUPERLINK_NODE_ID
|
25
|
+
|
22
26
|
# pylint: disable=E0611
|
27
|
+
from flwr.proto.clientappio_pb2 import ClientAppOutputCode, ClientAppOutputStatus
|
23
28
|
from flwr.proto.error_pb2 import Error as ProtoError
|
29
|
+
from flwr.proto.fab_pb2 import Fab as ProtoFab
|
30
|
+
from flwr.proto.message_pb2 import Context as ProtoContext
|
31
|
+
from flwr.proto.message_pb2 import Message as ProtoMessage
|
32
|
+
from flwr.proto.message_pb2 import Metadata as ProtoMetadata
|
24
33
|
from flwr.proto.node_pb2 import Node
|
25
34
|
from flwr.proto.recordset_pb2 import Array as ProtoArray
|
26
35
|
from flwr.proto.recordset_pb2 import BoolList, BytesList
|
@@ -31,7 +40,9 @@ from flwr.proto.recordset_pb2 import MetricsRecord as ProtoMetricsRecord
|
|
31
40
|
from flwr.proto.recordset_pb2 import MetricsRecordValue as ProtoMetricsRecordValue
|
32
41
|
from flwr.proto.recordset_pb2 import ParametersRecord as ProtoParametersRecord
|
33
42
|
from flwr.proto.recordset_pb2 import RecordSet as ProtoRecordSet
|
34
|
-
from flwr.proto.recordset_pb2 import
|
43
|
+
from flwr.proto.recordset_pb2 import SintList, StringList, UintList
|
44
|
+
from flwr.proto.run_pb2 import Run as ProtoRun
|
45
|
+
from flwr.proto.run_pb2 import RunStatus as ProtoRunStatus
|
35
46
|
from flwr.proto.task_pb2 import Task, TaskIns, TaskRes
|
36
47
|
from flwr.proto.transport_pb2 import (
|
37
48
|
ClientMessage,
|
@@ -44,7 +55,15 @@ from flwr.proto.transport_pb2 import (
|
|
44
55
|
)
|
45
56
|
|
46
57
|
# pylint: enable=E0611
|
47
|
-
from . import
|
58
|
+
from . import (
|
59
|
+
Array,
|
60
|
+
ConfigsRecord,
|
61
|
+
Context,
|
62
|
+
MetricsRecord,
|
63
|
+
ParametersRecord,
|
64
|
+
RecordSet,
|
65
|
+
typing,
|
66
|
+
)
|
48
67
|
from .message import Error, Message, Metadata
|
49
68
|
from .record.typeddict import TypedDict
|
50
69
|
|
@@ -58,7 +77,7 @@ def parameters_to_proto(parameters: typing.Parameters) -> Parameters:
|
|
58
77
|
|
59
78
|
def parameters_from_proto(msg: Parameters) -> typing.Parameters:
|
60
79
|
"""Deserialize `Parameters` from ProtoBuf."""
|
61
|
-
tensors:
|
80
|
+
tensors: list[bytes] = list(msg.tensors)
|
62
81
|
return typing.Parameters(tensors=tensors, tensor_type=msg.tensor_type)
|
63
82
|
|
64
83
|
|
@@ -324,6 +343,7 @@ def metrics_from_proto(proto: Any) -> typing.Metrics:
|
|
324
343
|
|
325
344
|
|
326
345
|
# === Scalar messages ===
|
346
|
+
INT64_MAX_VALUE = 9223372036854775807 # (1 << 63) - 1
|
327
347
|
|
328
348
|
|
329
349
|
def scalar_to_proto(scalar: typing.Scalar) -> Scalar:
|
@@ -338,6 +358,9 @@ def scalar_to_proto(scalar: typing.Scalar) -> Scalar:
|
|
338
358
|
return Scalar(double=scalar)
|
339
359
|
|
340
360
|
if isinstance(scalar, int):
|
361
|
+
# Use uint64 for integers larger than the maximum value of sint64
|
362
|
+
if scalar > INT64_MAX_VALUE:
|
363
|
+
return Scalar(uint64=scalar)
|
341
364
|
return Scalar(sint64=scalar)
|
342
365
|
|
343
366
|
if isinstance(scalar, str):
|
@@ -358,16 +381,16 @@ def scalar_from_proto(scalar_msg: Scalar) -> typing.Scalar:
|
|
358
381
|
# === Record messages ===
|
359
382
|
|
360
383
|
|
361
|
-
_type_to_field = {
|
384
|
+
_type_to_field: dict[type, str] = {
|
362
385
|
float: "double",
|
363
386
|
int: "sint64",
|
364
387
|
bool: "bool",
|
365
388
|
str: "string",
|
366
389
|
bytes: "bytes",
|
367
390
|
}
|
368
|
-
_list_type_to_class_and_field = {
|
391
|
+
_list_type_to_class_and_field: dict[type, tuple[type[GrpcMessage], str]] = {
|
369
392
|
float: (DoubleList, "double_list"),
|
370
|
-
int: (
|
393
|
+
int: (SintList, "sint_list"),
|
371
394
|
bool: (BoolList, "bool_list"),
|
372
395
|
str: (StringList, "string_list"),
|
373
396
|
bytes: (BytesList, "bytes_list"),
|
@@ -375,8 +398,13 @@ _list_type_to_class_and_field = {
|
|
375
398
|
T = TypeVar("T")
|
376
399
|
|
377
400
|
|
401
|
+
def _is_uint64(value: Any) -> bool:
|
402
|
+
"""Check if a value is uint64."""
|
403
|
+
return isinstance(value, int) and value > INT64_MAX_VALUE
|
404
|
+
|
405
|
+
|
378
406
|
def _record_value_to_proto(
|
379
|
-
value: Any, allowed_types:
|
407
|
+
value: Any, allowed_types: list[type], proto_class: type[T]
|
380
408
|
) -> T:
|
381
409
|
"""Serialize `*RecordValue` to ProtoBuf.
|
382
410
|
|
@@ -387,12 +415,18 @@ def _record_value_to_proto(
|
|
387
415
|
# Single element
|
388
416
|
# Note: `isinstance(False, int) == True`.
|
389
417
|
if isinstance(value, t):
|
390
|
-
|
418
|
+
fld = _type_to_field[t]
|
419
|
+
if t is int and _is_uint64(value):
|
420
|
+
fld = "uint64"
|
421
|
+
arg[fld] = value
|
391
422
|
return proto_class(**arg)
|
392
423
|
# List
|
393
424
|
if isinstance(value, list) and all(isinstance(item, t) for item in value):
|
394
|
-
list_class,
|
395
|
-
|
425
|
+
list_class, fld = _list_type_to_class_and_field[t]
|
426
|
+
# Use UintList if any element is of type `uint64`.
|
427
|
+
if t is int and any(_is_uint64(v) for v in value):
|
428
|
+
list_class, fld = UintList, "uint_list"
|
429
|
+
arg[fld] = list_class(vals=value)
|
396
430
|
return proto_class(**arg)
|
397
431
|
# Invalid types
|
398
432
|
raise TypeError(
|
@@ -413,9 +447,9 @@ def _record_value_from_proto(value_proto: GrpcMessage) -> Any:
|
|
413
447
|
|
414
448
|
def _record_value_dict_to_proto(
|
415
449
|
value_dict: TypedDict[str, Any],
|
416
|
-
allowed_types:
|
417
|
-
value_proto_class:
|
418
|
-
) ->
|
450
|
+
allowed_types: list[type],
|
451
|
+
value_proto_class: type[T],
|
452
|
+
) -> dict[str, T]:
|
419
453
|
"""Serialize the record value dict to ProtoBuf.
|
420
454
|
|
421
455
|
Note: `bool` MUST be put in the front of allowd_types if it exists.
|
@@ -433,7 +467,7 @@ def _record_value_dict_to_proto(
|
|
433
467
|
|
434
468
|
def _record_value_dict_from_proto(
|
435
469
|
value_dict_proto: MutableMapping[str, Any]
|
436
|
-
) ->
|
470
|
+
) -> dict[str, Any]:
|
437
471
|
"""Deserialize the record value dict from ProtoBuf."""
|
438
472
|
return {k: _record_value_from_proto(v) for k, v in value_dict_proto.items()}
|
439
473
|
|
@@ -484,7 +518,7 @@ def metrics_record_from_proto(record_proto: ProtoMetricsRecord) -> MetricsRecord
|
|
484
518
|
"""Deserialize MetricsRecord from ProtoBuf."""
|
485
519
|
return MetricsRecord(
|
486
520
|
metrics_dict=cast(
|
487
|
-
|
521
|
+
dict[str, typing.MetricsRecordValues],
|
488
522
|
_record_value_dict_from_proto(record_proto.data),
|
489
523
|
),
|
490
524
|
keep_input=False,
|
@@ -506,7 +540,7 @@ def configs_record_from_proto(record_proto: ProtoConfigsRecord) -> ConfigsRecord
|
|
506
540
|
"""Deserialize ConfigsRecord from ProtoBuf."""
|
507
541
|
return ConfigsRecord(
|
508
542
|
configs_dict=cast(
|
509
|
-
|
543
|
+
dict[str, typing.ConfigsRecordValues],
|
510
544
|
_record_value_dict_from_proto(record_proto.data),
|
511
545
|
),
|
512
546
|
keep_input=False,
|
@@ -573,8 +607,9 @@ def message_to_taskins(message: Message) -> TaskIns:
|
|
573
607
|
group_id=md.group_id,
|
574
608
|
run_id=md.run_id,
|
575
609
|
task=Task(
|
576
|
-
producer=Node(node_id=
|
577
|
-
consumer=Node(node_id=md.dst_node_id
|
610
|
+
producer=Node(node_id=SUPERLINK_NODE_ID), # Assume driver node
|
611
|
+
consumer=Node(node_id=md.dst_node_id),
|
612
|
+
created_at=md.created_at,
|
578
613
|
ttl=md.ttl,
|
579
614
|
ancestry=[md.reply_to_message] if md.reply_to_message != "" else [],
|
580
615
|
task_type=md.message_type,
|
@@ -601,7 +636,7 @@ def message_from_taskins(taskins: TaskIns) -> Message:
|
|
601
636
|
)
|
602
637
|
|
603
638
|
# Construct Message
|
604
|
-
|
639
|
+
message = Message(
|
605
640
|
metadata=metadata,
|
606
641
|
content=(
|
607
642
|
recordset_from_proto(taskins.task.recordset)
|
@@ -614,6 +649,8 @@ def message_from_taskins(taskins: TaskIns) -> Message:
|
|
614
649
|
else None
|
615
650
|
),
|
616
651
|
)
|
652
|
+
message.metadata.created_at = taskins.task.created_at
|
653
|
+
return message
|
617
654
|
|
618
655
|
|
619
656
|
def message_to_taskres(message: Message) -> TaskRes:
|
@@ -624,8 +661,9 @@ def message_to_taskres(message: Message) -> TaskRes:
|
|
624
661
|
group_id=md.group_id,
|
625
662
|
run_id=md.run_id,
|
626
663
|
task=Task(
|
627
|
-
producer=Node(node_id=md.src_node_id
|
628
|
-
consumer=Node(node_id=
|
664
|
+
producer=Node(node_id=md.src_node_id),
|
665
|
+
consumer=Node(node_id=SUPERLINK_NODE_ID), # Assume driver node
|
666
|
+
created_at=md.created_at,
|
629
667
|
ttl=md.ttl,
|
630
668
|
ancestry=[md.reply_to_message] if md.reply_to_message != "" else [],
|
631
669
|
task_type=md.message_type,
|
@@ -652,7 +690,7 @@ def message_from_taskres(taskres: TaskRes) -> Message:
|
|
652
690
|
)
|
653
691
|
|
654
692
|
# Construct the Message
|
655
|
-
|
693
|
+
message = Message(
|
656
694
|
metadata=metadata,
|
657
695
|
content=(
|
658
696
|
recordset_from_proto(taskres.task.recordset)
|
@@ -665,3 +703,246 @@ def message_from_taskres(taskres: TaskRes) -> Message:
|
|
665
703
|
else None
|
666
704
|
),
|
667
705
|
)
|
706
|
+
message.metadata.created_at = taskres.task.created_at
|
707
|
+
return message
|
708
|
+
|
709
|
+
|
710
|
+
# === FAB ===
|
711
|
+
|
712
|
+
|
713
|
+
def fab_to_proto(fab: typing.Fab) -> ProtoFab:
|
714
|
+
"""Create a proto Fab object from a Python Fab."""
|
715
|
+
return ProtoFab(hash_str=fab.hash_str, content=fab.content)
|
716
|
+
|
717
|
+
|
718
|
+
def fab_from_proto(fab: ProtoFab) -> typing.Fab:
|
719
|
+
"""Create a Python Fab object from a proto Fab."""
|
720
|
+
return typing.Fab(fab.hash_str, fab.content)
|
721
|
+
|
722
|
+
|
723
|
+
# === User configs ===
|
724
|
+
|
725
|
+
|
726
|
+
def user_config_to_proto(user_config: typing.UserConfig) -> Any:
|
727
|
+
"""Serialize `UserConfig` to ProtoBuf."""
|
728
|
+
proto = {}
|
729
|
+
for key, value in user_config.items():
|
730
|
+
proto[key] = user_config_value_to_proto(value)
|
731
|
+
return proto
|
732
|
+
|
733
|
+
|
734
|
+
def user_config_from_proto(proto: Any) -> typing.UserConfig:
|
735
|
+
"""Deserialize `UserConfig` from ProtoBuf."""
|
736
|
+
metrics = {}
|
737
|
+
for key, value in proto.items():
|
738
|
+
metrics[key] = user_config_value_from_proto(value)
|
739
|
+
return metrics
|
740
|
+
|
741
|
+
|
742
|
+
def user_config_value_to_proto(user_config_value: typing.UserConfigValue) -> Scalar:
|
743
|
+
"""Serialize `UserConfigValue` to ProtoBuf."""
|
744
|
+
if isinstance(user_config_value, bool):
|
745
|
+
return Scalar(bool=user_config_value)
|
746
|
+
|
747
|
+
if isinstance(user_config_value, float):
|
748
|
+
return Scalar(double=user_config_value)
|
749
|
+
|
750
|
+
if isinstance(user_config_value, int):
|
751
|
+
return Scalar(sint64=user_config_value)
|
752
|
+
|
753
|
+
if isinstance(user_config_value, str):
|
754
|
+
return Scalar(string=user_config_value)
|
755
|
+
|
756
|
+
raise ValueError(
|
757
|
+
f"Accepted types: {bool, float, int, str} (but not {type(user_config_value)})"
|
758
|
+
)
|
759
|
+
|
760
|
+
|
761
|
+
def user_config_value_from_proto(scalar_msg: Scalar) -> typing.UserConfigValue:
|
762
|
+
"""Deserialize `UserConfigValue` from ProtoBuf."""
|
763
|
+
scalar_field = scalar_msg.WhichOneof("scalar")
|
764
|
+
scalar = getattr(scalar_msg, cast(str, scalar_field))
|
765
|
+
return cast(typing.UserConfigValue, scalar)
|
766
|
+
|
767
|
+
|
768
|
+
# === Metadata messages ===
|
769
|
+
|
770
|
+
|
771
|
+
def metadata_to_proto(metadata: Metadata) -> ProtoMetadata:
|
772
|
+
"""Serialize `Metadata` to ProtoBuf."""
|
773
|
+
proto = ProtoMetadata( # pylint: disable=E1101
|
774
|
+
run_id=metadata.run_id,
|
775
|
+
message_id=metadata.message_id,
|
776
|
+
src_node_id=metadata.src_node_id,
|
777
|
+
dst_node_id=metadata.dst_node_id,
|
778
|
+
reply_to_message=metadata.reply_to_message,
|
779
|
+
group_id=metadata.group_id,
|
780
|
+
ttl=metadata.ttl,
|
781
|
+
message_type=metadata.message_type,
|
782
|
+
created_at=metadata.created_at,
|
783
|
+
)
|
784
|
+
return proto
|
785
|
+
|
786
|
+
|
787
|
+
def metadata_from_proto(metadata_proto: ProtoMetadata) -> Metadata:
|
788
|
+
"""Deserialize `Metadata` from ProtoBuf."""
|
789
|
+
metadata = Metadata(
|
790
|
+
run_id=metadata_proto.run_id,
|
791
|
+
message_id=metadata_proto.message_id,
|
792
|
+
src_node_id=metadata_proto.src_node_id,
|
793
|
+
dst_node_id=metadata_proto.dst_node_id,
|
794
|
+
reply_to_message=metadata_proto.reply_to_message,
|
795
|
+
group_id=metadata_proto.group_id,
|
796
|
+
ttl=metadata_proto.ttl,
|
797
|
+
message_type=metadata_proto.message_type,
|
798
|
+
)
|
799
|
+
return metadata
|
800
|
+
|
801
|
+
|
802
|
+
# === Message messages ===
|
803
|
+
|
804
|
+
|
805
|
+
def message_to_proto(message: Message) -> ProtoMessage:
|
806
|
+
"""Serialize `Message` to ProtoBuf."""
|
807
|
+
proto = ProtoMessage(
|
808
|
+
metadata=metadata_to_proto(message.metadata),
|
809
|
+
content=(
|
810
|
+
recordset_to_proto(message.content) if message.has_content() else None
|
811
|
+
),
|
812
|
+
error=error_to_proto(message.error) if message.has_error() else None,
|
813
|
+
)
|
814
|
+
return proto
|
815
|
+
|
816
|
+
|
817
|
+
def message_from_proto(message_proto: ProtoMessage) -> Message:
|
818
|
+
"""Deserialize `Message` from ProtoBuf."""
|
819
|
+
created_at = message_proto.metadata.created_at
|
820
|
+
message = Message(
|
821
|
+
metadata=metadata_from_proto(message_proto.metadata),
|
822
|
+
content=(
|
823
|
+
recordset_from_proto(message_proto.content)
|
824
|
+
if message_proto.HasField("content")
|
825
|
+
else None
|
826
|
+
),
|
827
|
+
error=(
|
828
|
+
error_from_proto(message_proto.error)
|
829
|
+
if message_proto.HasField("error")
|
830
|
+
else None
|
831
|
+
),
|
832
|
+
)
|
833
|
+
# `.created_at` is set upon Message object construction
|
834
|
+
# we need to manually set it to the original value
|
835
|
+
message.metadata.created_at = created_at
|
836
|
+
return message
|
837
|
+
|
838
|
+
|
839
|
+
# === Context messages ===
|
840
|
+
|
841
|
+
|
842
|
+
def context_to_proto(context: Context) -> ProtoContext:
|
843
|
+
"""Serialize `Context` to ProtoBuf."""
|
844
|
+
proto = ProtoContext(
|
845
|
+
run_id=context.run_id,
|
846
|
+
node_id=context.node_id,
|
847
|
+
node_config=user_config_to_proto(context.node_config),
|
848
|
+
state=recordset_to_proto(context.state),
|
849
|
+
run_config=user_config_to_proto(context.run_config),
|
850
|
+
)
|
851
|
+
return proto
|
852
|
+
|
853
|
+
|
854
|
+
def context_from_proto(context_proto: ProtoContext) -> Context:
|
855
|
+
"""Deserialize `Context` from ProtoBuf."""
|
856
|
+
context = Context(
|
857
|
+
run_id=context_proto.run_id,
|
858
|
+
node_id=context_proto.node_id,
|
859
|
+
node_config=user_config_from_proto(context_proto.node_config),
|
860
|
+
state=recordset_from_proto(context_proto.state),
|
861
|
+
run_config=user_config_from_proto(context_proto.run_config),
|
862
|
+
)
|
863
|
+
return context
|
864
|
+
|
865
|
+
|
866
|
+
# === Run messages ===
|
867
|
+
|
868
|
+
|
869
|
+
def run_to_proto(run: typing.Run) -> ProtoRun:
|
870
|
+
"""Serialize `Run` to ProtoBuf."""
|
871
|
+
proto = ProtoRun(
|
872
|
+
run_id=run.run_id,
|
873
|
+
fab_id=run.fab_id,
|
874
|
+
fab_version=run.fab_version,
|
875
|
+
fab_hash=run.fab_hash,
|
876
|
+
override_config=user_config_to_proto(run.override_config),
|
877
|
+
pending_at=run.pending_at,
|
878
|
+
starting_at=run.starting_at,
|
879
|
+
running_at=run.running_at,
|
880
|
+
finished_at=run.finished_at,
|
881
|
+
status=run_status_to_proto(run.status),
|
882
|
+
)
|
883
|
+
return proto
|
884
|
+
|
885
|
+
|
886
|
+
def run_from_proto(run_proto: ProtoRun) -> typing.Run:
|
887
|
+
"""Deserialize `Run` from ProtoBuf."""
|
888
|
+
run = typing.Run(
|
889
|
+
run_id=run_proto.run_id,
|
890
|
+
fab_id=run_proto.fab_id,
|
891
|
+
fab_version=run_proto.fab_version,
|
892
|
+
fab_hash=run_proto.fab_hash,
|
893
|
+
override_config=user_config_from_proto(run_proto.override_config),
|
894
|
+
pending_at=run_proto.pending_at,
|
895
|
+
starting_at=run_proto.starting_at,
|
896
|
+
running_at=run_proto.running_at,
|
897
|
+
finished_at=run_proto.finished_at,
|
898
|
+
status=run_status_from_proto(run_proto.status),
|
899
|
+
)
|
900
|
+
return run
|
901
|
+
|
902
|
+
|
903
|
+
# === ClientApp status messages ===
|
904
|
+
|
905
|
+
|
906
|
+
def clientappstatus_to_proto(
|
907
|
+
status: typing.ClientAppOutputStatus,
|
908
|
+
) -> ClientAppOutputStatus:
|
909
|
+
"""Serialize `ClientAppOutputStatus` to ProtoBuf."""
|
910
|
+
code = ClientAppOutputCode.SUCCESS
|
911
|
+
if status.code == typing.ClientAppOutputCode.DEADLINE_EXCEEDED:
|
912
|
+
code = ClientAppOutputCode.DEADLINE_EXCEEDED
|
913
|
+
if status.code == typing.ClientAppOutputCode.UNKNOWN_ERROR:
|
914
|
+
code = ClientAppOutputCode.UNKNOWN_ERROR
|
915
|
+
return ClientAppOutputStatus(code=code, message=status.message)
|
916
|
+
|
917
|
+
|
918
|
+
def clientappstatus_from_proto(
|
919
|
+
msg: ClientAppOutputStatus,
|
920
|
+
) -> typing.ClientAppOutputStatus:
|
921
|
+
"""Deserialize `ClientAppOutputStatus` from ProtoBuf."""
|
922
|
+
code = typing.ClientAppOutputCode.SUCCESS
|
923
|
+
if msg.code == ClientAppOutputCode.DEADLINE_EXCEEDED:
|
924
|
+
code = typing.ClientAppOutputCode.DEADLINE_EXCEEDED
|
925
|
+
if msg.code == ClientAppOutputCode.UNKNOWN_ERROR:
|
926
|
+
code = typing.ClientAppOutputCode.UNKNOWN_ERROR
|
927
|
+
return typing.ClientAppOutputStatus(code=code, message=msg.message)
|
928
|
+
|
929
|
+
|
930
|
+
# === Run status ===
|
931
|
+
|
932
|
+
|
933
|
+
def run_status_to_proto(run_status: typing.RunStatus) -> ProtoRunStatus:
|
934
|
+
"""Serialize `RunStatus` to ProtoBuf."""
|
935
|
+
return ProtoRunStatus(
|
936
|
+
status=run_status.status,
|
937
|
+
sub_status=run_status.sub_status,
|
938
|
+
details=run_status.details,
|
939
|
+
)
|
940
|
+
|
941
|
+
|
942
|
+
def run_status_from_proto(run_status_proto: ProtoRunStatus) -> typing.RunStatus:
|
943
|
+
"""Deserialize `RunStatus` from ProtoBuf."""
|
944
|
+
return typing.RunStatus(
|
945
|
+
status=run_status_proto.status,
|
946
|
+
sub_status=run_status_proto.sub_status,
|
947
|
+
details=run_status_proto.details,
|
948
|
+
)
|
flwr/common/telemetry.py
CHANGED
@@ -25,8 +25,9 @@ import uuid
|
|
25
25
|
from concurrent.futures import Future, ThreadPoolExecutor
|
26
26
|
from enum import Enum, auto
|
27
27
|
from pathlib import Path
|
28
|
-
from typing import Any,
|
28
|
+
from typing import Any, Optional, Union, cast
|
29
29
|
|
30
|
+
from flwr.common.constant import FLWR_DIR
|
30
31
|
from flwr.common.version import package_name, package_version
|
31
32
|
|
32
33
|
FLWR_TELEMETRY_ENABLED = os.getenv("FLWR_TELEMETRY_ENABLED", "1")
|
@@ -64,6 +65,18 @@ def _get_home() -> Path:
|
|
64
65
|
return Path().home()
|
65
66
|
|
66
67
|
|
68
|
+
def _get_partner_id() -> str:
|
69
|
+
"""Get partner ID."""
|
70
|
+
partner_id = os.getenv("FLWR_TELEMETRY_PARTNER_ID")
|
71
|
+
if not partner_id:
|
72
|
+
return "unavailable"
|
73
|
+
try:
|
74
|
+
uuid.UUID(partner_id)
|
75
|
+
except ValueError:
|
76
|
+
partner_id = "invalid"
|
77
|
+
return partner_id
|
78
|
+
|
79
|
+
|
67
80
|
def _get_source_id() -> str:
|
68
81
|
"""Get existing or new source ID."""
|
69
82
|
source_id = "unavailable"
|
@@ -74,7 +87,7 @@ def _get_source_id() -> str:
|
|
74
87
|
# If the home directory can’t be resolved, RuntimeError is raised.
|
75
88
|
return source_id
|
76
89
|
|
77
|
-
flwr_dir = home.joinpath(
|
90
|
+
flwr_dir = home.joinpath(FLWR_DIR)
|
78
91
|
# Create .flwr directory if it does not exist yet.
|
79
92
|
try:
|
80
93
|
flwr_dir.mkdir(parents=True, exist_ok=True)
|
@@ -114,67 +127,86 @@ class EventType(str, Enum):
|
|
114
127
|
# The type signature is not compatible with mypy, pylint and flake8
|
115
128
|
# so each of those needs to be disabled for this line.
|
116
129
|
# pylint: disable-next=no-self-argument,arguments-differ,line-too-long
|
117
|
-
def _generate_next_value_(name: str, start: int, count: int, last_values:
|
130
|
+
def _generate_next_value_(name: str, start: int, count: int, last_values: list[Any]) -> Any: # type: ignore # noqa: E501
|
118
131
|
return name
|
119
132
|
|
120
133
|
# Ping
|
121
134
|
PING = auto()
|
122
135
|
|
123
|
-
#
|
136
|
+
# --- LEGACY FUNCTIONS -------------------------------------------------------------
|
137
|
+
|
138
|
+
# Legacy: `start_client` function
|
124
139
|
START_CLIENT_ENTER = auto()
|
125
140
|
START_CLIENT_LEAVE = auto()
|
126
141
|
|
127
|
-
#
|
142
|
+
# Legacy: `start_server` function
|
128
143
|
START_SERVER_ENTER = auto()
|
129
144
|
START_SERVER_LEAVE = auto()
|
130
145
|
|
131
|
-
#
|
132
|
-
|
133
|
-
|
146
|
+
# Legacy: `start_simulation` function
|
147
|
+
START_SIMULATION_ENTER = auto()
|
148
|
+
START_SIMULATION_LEAVE = auto()
|
149
|
+
|
150
|
+
# --- `flwr` CLI -------------------------------------------------------------------
|
151
|
+
|
152
|
+
# Not yet implemented
|
153
|
+
|
154
|
+
# --- `flwr-*` commands ------------------------------------------------------------
|
155
|
+
|
156
|
+
# CLI: flwr-simulation
|
157
|
+
FLWR_SIMULATION_RUN_ENTER = auto()
|
158
|
+
FLWR_SIMULATION_RUN_LEAVE = auto()
|
159
|
+
|
160
|
+
# CLI: flwr-serverapp
|
161
|
+
FLWR_SERVERAPP_RUN_ENTER = auto()
|
162
|
+
FLWR_SERVERAPP_RUN_LEAVE = auto()
|
134
163
|
|
135
|
-
#
|
136
|
-
RUN_FLEET_API_ENTER = auto()
|
137
|
-
RUN_FLEET_API_LEAVE = auto()
|
164
|
+
# --- Simulation Engine ------------------------------------------------------------
|
138
165
|
|
139
|
-
#
|
166
|
+
# CLI: flower-simulation
|
167
|
+
CLI_FLOWER_SIMULATION_ENTER = auto()
|
168
|
+
CLI_FLOWER_SIMULATION_LEAVE = auto()
|
169
|
+
|
170
|
+
# Python API: `run_simulation`
|
171
|
+
PYTHON_API_RUN_SIMULATION_ENTER = auto()
|
172
|
+
PYTHON_API_RUN_SIMULATION_LEAVE = auto()
|
173
|
+
|
174
|
+
# --- Deployment Engine ------------------------------------------------------------
|
175
|
+
|
176
|
+
# CLI: `flower-superlink`
|
140
177
|
RUN_SUPERLINK_ENTER = auto()
|
141
178
|
RUN_SUPERLINK_LEAVE = auto()
|
142
179
|
|
143
|
-
#
|
144
|
-
|
145
|
-
|
180
|
+
# CLI: `flower-supernode`
|
181
|
+
RUN_SUPERNODE_ENTER = auto()
|
182
|
+
RUN_SUPERNODE_LEAVE = auto()
|
146
183
|
|
147
|
-
#
|
148
|
-
DRIVER_CONNECT = auto()
|
149
|
-
DRIVER_DISCONNECT = auto()
|
184
|
+
# --- DEPRECATED -------------------------------------------------------------------
|
150
185
|
|
151
|
-
#
|
152
|
-
|
153
|
-
|
186
|
+
# [DEPRECATED] CLI: `flower-server-app`
|
187
|
+
RUN_SERVER_APP_ENTER = auto()
|
188
|
+
RUN_SERVER_APP_LEAVE = auto()
|
154
189
|
|
155
|
-
# flower-client-app
|
190
|
+
# [DEPRECATED] CLI: `flower-client-app`
|
156
191
|
RUN_CLIENT_APP_ENTER = auto()
|
157
192
|
RUN_CLIENT_APP_LEAVE = auto()
|
158
193
|
|
159
|
-
# flower-server-app
|
160
|
-
RUN_SERVER_APP_ENTER = auto()
|
161
|
-
RUN_SERVER_APP_LEAVE = auto()
|
162
|
-
|
163
194
|
|
164
195
|
# Use the ThreadPoolExecutor with max_workers=1 to have a queue
|
165
196
|
# and also ensure that telemetry calls are not blocking.
|
166
|
-
state:
|
197
|
+
state: dict[str, Union[Optional[str], Optional[ThreadPoolExecutor]]] = {
|
167
198
|
# Will be assigned ThreadPoolExecutor(max_workers=1)
|
168
199
|
# in event() the first time it's required
|
169
200
|
"executor": None,
|
170
201
|
"source": None,
|
171
202
|
"cluster": None,
|
203
|
+
"partner": None,
|
172
204
|
}
|
173
205
|
|
174
206
|
|
175
207
|
def event(
|
176
208
|
event_type: EventType,
|
177
|
-
event_details: Optional[
|
209
|
+
event_details: Optional[dict[str, Any]] = None,
|
178
210
|
) -> Future: # type: ignore
|
179
211
|
"""Submit create_event to ThreadPoolExecutor to avoid blocking."""
|
180
212
|
if state["executor"] is None:
|
@@ -186,7 +218,7 @@ def event(
|
|
186
218
|
return result
|
187
219
|
|
188
220
|
|
189
|
-
def create_event(event_type: EventType, event_details: Optional[
|
221
|
+
def create_event(event_type: EventType, event_details: Optional[dict[str, Any]]) -> str:
|
190
222
|
"""Create telemetry event."""
|
191
223
|
if state["source"] is None:
|
192
224
|
state["source"] = _get_source_id()
|
@@ -194,11 +226,15 @@ def create_event(event_type: EventType, event_details: Optional[Dict[str, Any]])
|
|
194
226
|
if state["cluster"] is None:
|
195
227
|
state["cluster"] = str(uuid.uuid4())
|
196
228
|
|
229
|
+
if state["partner"] is None:
|
230
|
+
state["partner"] = _get_partner_id()
|
231
|
+
|
197
232
|
if event_details is None:
|
198
233
|
event_details = {}
|
199
234
|
|
200
235
|
date = datetime.datetime.now(tz=datetime.timezone.utc).isoformat()
|
201
236
|
context = {
|
237
|
+
"partner": state["partner"],
|
202
238
|
"source": state["source"],
|
203
239
|
"cluster": state["cluster"],
|
204
240
|
"date": date,
|