flwr 1.17.0__py3-none-any.whl → 1.18.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 +1 -1
- flwr/cli/__init__.py +1 -1
- flwr/cli/app.py +21 -2
- flwr/cli/build.py +1 -1
- flwr/cli/cli_user_auth_interceptor.py +1 -1
- flwr/cli/config_utils.py +53 -17
- flwr/cli/example.py +1 -1
- flwr/cli/install.py +1 -1
- flwr/cli/log.py +1 -1
- flwr/cli/login/__init__.py +1 -1
- flwr/cli/login/login.py +12 -1
- flwr/cli/ls.py +1 -1
- flwr/cli/new/__init__.py +1 -1
- flwr/cli/new/new.py +4 -4
- flwr/cli/new/templates/__init__.py +1 -1
- flwr/cli/new/templates/app/__init__.py +1 -1
- flwr/cli/new/templates/app/code/__init__.py +1 -1
- flwr/cli/new/templates/app/code/flwr_tune/__init__.py +1 -1
- flwr/cli/new/templates/app/code/flwr_tune/client_app.py.tpl +4 -4
- flwr/cli/new/templates/app/code/task.sklearn.py.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +4 -4
- flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +1 -1
- flwr/cli/run/__init__.py +1 -1
- flwr/cli/run/run.py +1 -1
- flwr/cli/stop.py +1 -1
- flwr/cli/utils.py +11 -12
- flwr/client/__init__.py +1 -1
- flwr/client/app.py +52 -52
- flwr/client/client.py +1 -1
- flwr/client/client_app.py +139 -137
- flwr/client/clientapp/__init__.py +1 -1
- flwr/client/clientapp/app.py +1 -1
- flwr/client/clientapp/clientappio_servicer.py +1 -1
- flwr/client/clientapp/utils.py +1 -1
- flwr/client/dpfedavg_numpy_client.py +1 -1
- flwr/client/grpc_adapter_client/__init__.py +1 -1
- flwr/client/grpc_adapter_client/connection.py +1 -1
- flwr/client/grpc_client/__init__.py +1 -1
- flwr/client/grpc_client/connection.py +13 -13
- flwr/client/grpc_rere_client/__init__.py +1 -1
- flwr/client/grpc_rere_client/client_interceptor.py +1 -1
- flwr/client/grpc_rere_client/connection.py +1 -1
- flwr/client/grpc_rere_client/grpc_adapter.py +1 -1
- flwr/client/heartbeat.py +1 -1
- flwr/client/message_handler/__init__.py +1 -1
- flwr/client/message_handler/message_handler.py +1 -1
- flwr/client/mod/__init__.py +1 -1
- flwr/client/mod/centraldp_mods.py +1 -1
- flwr/client/mod/comms_mods.py +3 -3
- flwr/client/mod/localdp_mod.py +6 -6
- flwr/client/mod/secure_aggregation/__init__.py +1 -1
- flwr/client/mod/secure_aggregation/secagg_mod.py +1 -1
- flwr/client/mod/secure_aggregation/secaggplus_mod.py +1 -1
- flwr/client/mod/utils.py +1 -1
- flwr/client/nodestate/__init__.py +1 -1
- flwr/client/nodestate/in_memory_nodestate.py +1 -1
- flwr/client/nodestate/nodestate.py +1 -1
- flwr/client/nodestate/nodestate_factory.py +1 -1
- flwr/client/numpy_client.py +1 -1
- flwr/client/rest_client/__init__.py +1 -1
- flwr/client/rest_client/connection.py +1 -1
- flwr/client/run_info_store.py +1 -1
- flwr/client/supernode/__init__.py +1 -1
- flwr/client/supernode/app.py +1 -1
- flwr/client/typing.py +1 -1
- flwr/common/__init__.py +1 -1
- flwr/common/address.py +1 -1
- flwr/common/args.py +1 -1
- flwr/common/auth_plugin/__init__.py +1 -1
- flwr/common/auth_plugin/auth_plugin.py +1 -1
- flwr/common/config.py +1 -1
- flwr/common/constant.py +1 -1
- flwr/common/context.py +1 -1
- flwr/common/date.py +1 -1
- flwr/common/differential_privacy.py +1 -1
- flwr/common/differential_privacy_constants.py +1 -1
- flwr/common/dp.py +1 -1
- flwr/common/exit/exit.py +6 -6
- flwr/common/exit_handlers.py +1 -1
- flwr/common/grpc.py +1 -1
- flwr/common/logger.py +1 -1
- flwr/common/message.py +28 -11
- flwr/common/object_ref.py +1 -1
- flwr/common/parameter.py +1 -1
- flwr/common/pyproject.py +1 -1
- flwr/common/record/__init__.py +1 -1
- flwr/common/record/arrayrecord.py +31 -31
- flwr/common/record/configrecord.py +13 -13
- flwr/common/record/conversion_utils.py +1 -1
- flwr/common/record/metricrecord.py +16 -16
- flwr/common/record/recorddict.py +138 -89
- flwr/common/record/typeddict.py +1 -1
- flwr/common/retry_invoker.py +10 -10
- flwr/common/secure_aggregation/__init__.py +1 -1
- flwr/common/secure_aggregation/crypto/__init__.py +1 -1
- flwr/common/secure_aggregation/crypto/shamir.py +52 -30
- flwr/common/secure_aggregation/crypto/symmetric_encryption.py +1 -1
- flwr/common/secure_aggregation/ndarrays_arithmetic.py +1 -1
- flwr/common/secure_aggregation/quantization.py +1 -1
- flwr/common/secure_aggregation/secaggplus_constants.py +1 -1
- flwr/common/secure_aggregation/secaggplus_utils.py +1 -1
- flwr/common/serde.py +1 -1
- flwr/common/telemetry.py +2 -2
- flwr/common/typing.py +1 -1
- flwr/common/version.py +1 -1
- flwr/proto/__init__.py +1 -1
- flwr/server/__init__.py +1 -1
- flwr/server/app.py +11 -11
- flwr/server/client_manager.py +1 -1
- flwr/server/client_proxy.py +1 -1
- flwr/server/compat/__init__.py +1 -1
- flwr/server/compat/app.py +1 -1
- flwr/server/compat/app_utils.py +1 -1
- flwr/server/compat/legacy_context.py +1 -1
- flwr/server/criterion.py +1 -1
- flwr/server/grid/grid.py +3 -3
- flwr/server/history.py +1 -1
- flwr/server/run_serverapp.py +1 -1
- flwr/server/server.py +1 -1
- flwr/server/server_app.py +65 -58
- flwr/server/server_config.py +1 -1
- flwr/server/serverapp/__init__.py +1 -1
- flwr/server/serverapp/app.py +1 -1
- flwr/server/serverapp_components.py +1 -1
- flwr/server/strategy/__init__.py +1 -1
- flwr/server/strategy/aggregate.py +1 -1
- flwr/server/strategy/bulyan.py +2 -2
- flwr/server/strategy/dp_adaptive_clipping.py +17 -17
- flwr/server/strategy/dp_fixed_clipping.py +17 -17
- flwr/server/strategy/dpfedavg_adaptive.py +1 -1
- flwr/server/strategy/dpfedavg_fixed.py +1 -1
- flwr/server/strategy/fault_tolerant_fedavg.py +1 -1
- flwr/server/strategy/fedadagrad.py +1 -1
- flwr/server/strategy/fedadam.py +1 -1
- flwr/server/strategy/fedavg.py +1 -1
- flwr/server/strategy/fedavg_android.py +1 -1
- flwr/server/strategy/fedavgm.py +1 -1
- flwr/server/strategy/fedmedian.py +1 -1
- flwr/server/strategy/fedopt.py +1 -1
- flwr/server/strategy/fedprox.py +1 -1
- flwr/server/strategy/fedtrimmedavg.py +1 -1
- flwr/server/strategy/fedxgb_bagging.py +1 -1
- flwr/server/strategy/fedxgb_cyclic.py +1 -1
- flwr/server/strategy/fedxgb_nn_avg.py +3 -2
- flwr/server/strategy/fedyogi.py +1 -1
- flwr/server/strategy/krum.py +1 -1
- flwr/server/strategy/qfedavg.py +1 -1
- flwr/server/strategy/strategy.py +1 -1
- flwr/server/superlink/__init__.py +1 -1
- flwr/server/superlink/ffs/__init__.py +1 -1
- flwr/server/superlink/ffs/disk_ffs.py +1 -1
- flwr/server/superlink/ffs/ffs.py +1 -1
- flwr/server/superlink/ffs/ffs_factory.py +1 -1
- flwr/server/superlink/fleet/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_adapter/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +1 -1
- flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +13 -13
- flwr/server/superlink/fleet/grpc_rere/__init__.py +1 -1
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +1 -1
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +1 -1
- flwr/server/superlink/fleet/message_handler/__init__.py +1 -1
- flwr/server/superlink/fleet/message_handler/message_handler.py +1 -1
- flwr/server/superlink/fleet/rest_rere/__init__.py +1 -1
- flwr/server/superlink/fleet/rest_rere/rest_api.py +1 -1
- flwr/server/superlink/fleet/vce/__init__.py +1 -1
- flwr/server/superlink/fleet/vce/backend/__init__.py +1 -1
- flwr/server/superlink/fleet/vce/backend/backend.py +1 -1
- flwr/server/superlink/fleet/vce/backend/raybackend.py +1 -1
- flwr/server/superlink/fleet/vce/vce_api.py +1 -1
- flwr/server/superlink/linkstate/__init__.py +1 -1
- flwr/server/superlink/linkstate/in_memory_linkstate.py +1 -1
- flwr/server/superlink/linkstate/linkstate.py +1 -1
- flwr/server/superlink/linkstate/linkstate_factory.py +1 -1
- flwr/server/superlink/linkstate/sqlite_linkstate.py +1 -1
- flwr/server/superlink/linkstate/utils.py +1 -1
- flwr/server/superlink/simulation/__init__.py +1 -1
- flwr/server/superlink/simulation/simulationio_grpc.py +1 -1
- flwr/server/superlink/simulation/simulationio_servicer.py +1 -1
- flwr/server/superlink/utils.py +1 -1
- flwr/server/typing.py +1 -1
- flwr/server/utils/__init__.py +1 -1
- flwr/server/utils/tensorboard.py +1 -1
- flwr/server/utils/validator.py +1 -1
- flwr/server/workflow/__init__.py +1 -1
- flwr/server/workflow/constant.py +1 -1
- flwr/server/workflow/default_workflows.py +1 -1
- flwr/server/workflow/secure_aggregation/__init__.py +1 -1
- flwr/server/workflow/secure_aggregation/secagg_workflow.py +1 -1
- flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +1 -1
- flwr/simulation/__init__.py +1 -1
- flwr/simulation/app.py +1 -1
- flwr/simulation/legacy_app.py +1 -1
- flwr/simulation/ray_transport/__init__.py +1 -1
- flwr/simulation/ray_transport/ray_actor.py +1 -1
- flwr/simulation/ray_transport/ray_client_proxy.py +1 -1
- flwr/simulation/ray_transport/utils.py +1 -1
- flwr/simulation/run_simulation.py +2 -2
- flwr/simulation/simulationio_connection.py +1 -1
- flwr/superexec/__init__.py +1 -1
- flwr/superexec/app.py +1 -1
- flwr/superexec/deployment.py +1 -1
- flwr/superexec/exec_grpc.py +1 -1
- flwr/superexec/exec_servicer.py +1 -1
- flwr/superexec/exec_user_auth_interceptor.py +1 -1
- flwr/superexec/executor.py +1 -1
- flwr/superexec/simulation.py +1 -1
- {flwr-1.17.0.dist-info → flwr-1.18.0.dist-info}/METADATA +2 -2
- flwr-1.18.0.dist-info/RECORD +332 -0
- flwr-1.17.0.dist-info/LICENSE +0 -202
- flwr-1.17.0.dist-info/RECORD +0 -333
- {flwr-1.17.0.dist-info → flwr-1.18.0.dist-info}/WHEEL +0 -0
- {flwr-1.17.0.dist-info → flwr-1.18.0.dist-info}/entry_points.txt +0 -0
flwr/common/record/recorddict.py
CHANGED
|
@@ -29,6 +29,22 @@ from .typeddict import TypedDict
|
|
|
29
29
|
|
|
30
30
|
RecordType = Union[ArrayRecord, MetricRecord, ConfigRecord]
|
|
31
31
|
|
|
32
|
+
|
|
33
|
+
class _WarningTracker:
|
|
34
|
+
"""A class to track warnings for deprecated properties."""
|
|
35
|
+
|
|
36
|
+
def __init__(self) -> None:
|
|
37
|
+
# These variables are used to ensure that the deprecation warnings
|
|
38
|
+
# for the deprecated properties/class are logged only once.
|
|
39
|
+
self.recordset_init_logged = False
|
|
40
|
+
self.recorddict_init_logged = False
|
|
41
|
+
self.parameters_records_logged = False
|
|
42
|
+
self.metrics_records_logged = False
|
|
43
|
+
self.configs_records_logged = False
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
_warning_tracker = _WarningTracker()
|
|
47
|
+
|
|
32
48
|
T = TypeVar("T")
|
|
33
49
|
|
|
34
50
|
|
|
@@ -103,48 +119,74 @@ class RecordDict(TypedDict[str, RecordType]):
|
|
|
103
119
|
are Python dictionaries designed to ensure that each key-value pair
|
|
104
120
|
adheres to specified data types.
|
|
105
121
|
|
|
106
|
-
Let's see an example
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
122
|
+
Let's see an example::
|
|
123
|
+
|
|
124
|
+
from flwr.common import RecordDict
|
|
125
|
+
from flwr.common import ArrayRecord, ConfigRecord, MetricRecord
|
|
126
|
+
|
|
127
|
+
# Let's begin with an empty record
|
|
128
|
+
my_records = RecordDict()
|
|
129
|
+
|
|
130
|
+
# We can create a ConfigRecord
|
|
131
|
+
c_record = ConfigRecord({"lr": 0.1, "batch-size": 128})
|
|
132
|
+
# Adding it to the RecordDict would look like this
|
|
133
|
+
my_records["my_config"] = c_record
|
|
134
|
+
|
|
135
|
+
# We can create a MetricRecord following a similar process
|
|
136
|
+
m_record = MetricRecord({"accuracy": 0.93, "losses": [0.23, 0.1]})
|
|
137
|
+
# Adding it to the RecordDict would look like this
|
|
138
|
+
my_records["my_metrics"] = m_record
|
|
123
139
|
|
|
124
140
|
Adding an :code:`ArrayRecord` follows the same steps as above but first,
|
|
125
141
|
the array needs to be serialized and represented as a :code:`flwr.common.Array`.
|
|
126
|
-
For example
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
For example::
|
|
143
|
+
|
|
144
|
+
from flwr.common import Array
|
|
145
|
+
# Creating an ArrayRecord would look like this
|
|
146
|
+
arr_np = np.random.randn(3, 3)
|
|
147
|
+
|
|
148
|
+
# You can use the built-in tool to serialize the array
|
|
149
|
+
arr = Array(arr_np)
|
|
150
|
+
|
|
151
|
+
# Finally, create the record
|
|
152
|
+
arr_record = ArrayRecord({"my_array": arr})
|
|
153
|
+
|
|
154
|
+
# Adding it to the RecordDict would look like this
|
|
155
|
+
my_records["my_parameters"] = arr_record
|
|
140
156
|
|
|
141
157
|
For additional examples on how to construct each of the records types shown
|
|
142
158
|
above, please refer to the documentation for :code:`ConfigRecord`,
|
|
143
159
|
:code:`MetricRecord` and :code:`ArrayRecord`.
|
|
144
160
|
"""
|
|
145
161
|
|
|
146
|
-
def __init__(
|
|
162
|
+
def __init__(
|
|
163
|
+
self,
|
|
164
|
+
records: dict[str, RecordType] | None = None,
|
|
165
|
+
*,
|
|
166
|
+
parameters_records: dict[str, ArrayRecord] | None = None,
|
|
167
|
+
metrics_records: dict[str, MetricRecord] | None = None,
|
|
168
|
+
configs_records: dict[str, ConfigRecord] | None = None,
|
|
169
|
+
) -> None:
|
|
147
170
|
super().__init__(_check_key, _check_value)
|
|
171
|
+
|
|
172
|
+
# Warning for deprecated usage
|
|
173
|
+
if (
|
|
174
|
+
parameters_records is not None
|
|
175
|
+
or metrics_records is not None
|
|
176
|
+
or configs_records is not None
|
|
177
|
+
):
|
|
178
|
+
log(
|
|
179
|
+
WARN,
|
|
180
|
+
"The arguments `parameters_records`, `metrics_records`, and "
|
|
181
|
+
"`configs_records` of `RecordDict` are deprecated and will "
|
|
182
|
+
"be removed in a future release. "
|
|
183
|
+
"Please pass all records using the `records` argument instead.",
|
|
184
|
+
)
|
|
185
|
+
records = records or {}
|
|
186
|
+
records.update(parameters_records or {})
|
|
187
|
+
records.update(metrics_records or {})
|
|
188
|
+
records.update(configs_records or {})
|
|
189
|
+
|
|
148
190
|
if records is not None:
|
|
149
191
|
for key, record in records.items():
|
|
150
192
|
self[key] = record
|
|
@@ -196,6 +238,54 @@ class RecordDict(TypedDict[str, RecordType]):
|
|
|
196
238
|
type(value).__name__,
|
|
197
239
|
)
|
|
198
240
|
|
|
241
|
+
@property
|
|
242
|
+
def parameters_records(self) -> TypedDict[str, ArrayRecord]:
|
|
243
|
+
"""Deprecated property.
|
|
244
|
+
|
|
245
|
+
Use ``array_records`` instead.
|
|
246
|
+
"""
|
|
247
|
+
if _warning_tracker.parameters_records_logged:
|
|
248
|
+
_warning_tracker.parameters_records_logged = True
|
|
249
|
+
log(
|
|
250
|
+
WARN,
|
|
251
|
+
"The `parameters_records` property of `RecordDict` "
|
|
252
|
+
"(formerly `RecordSet`) is deprecated and will be removed in a "
|
|
253
|
+
"future release. Please use the `array_records` property instead.",
|
|
254
|
+
)
|
|
255
|
+
return self.array_records
|
|
256
|
+
|
|
257
|
+
@property
|
|
258
|
+
def metrics_records(self) -> TypedDict[str, MetricRecord]:
|
|
259
|
+
"""Deprecated property.
|
|
260
|
+
|
|
261
|
+
Use ``metric_records`` instead.
|
|
262
|
+
"""
|
|
263
|
+
if not _warning_tracker.metrics_records_logged:
|
|
264
|
+
_warning_tracker.metrics_records_logged = True
|
|
265
|
+
log(
|
|
266
|
+
WARN,
|
|
267
|
+
"The `metrics_records` property of `RecordDict` "
|
|
268
|
+
"(formerly `RecordSet`) is deprecated and will be removed in a "
|
|
269
|
+
"future release. Please use the `metric_records` property instead.",
|
|
270
|
+
)
|
|
271
|
+
return self.metric_records
|
|
272
|
+
|
|
273
|
+
@property
|
|
274
|
+
def configs_records(self) -> TypedDict[str, ConfigRecord]:
|
|
275
|
+
"""Deprecated property.
|
|
276
|
+
|
|
277
|
+
Use ``config_records`` instead.
|
|
278
|
+
"""
|
|
279
|
+
if not _warning_tracker.configs_records_logged:
|
|
280
|
+
_warning_tracker.configs_records_logged = True
|
|
281
|
+
log(
|
|
282
|
+
WARN,
|
|
283
|
+
"The `configs_records` property of `RecordDict` "
|
|
284
|
+
"(formerly `RecordSet`) is deprecated and will be removed in a "
|
|
285
|
+
"future release. Please use the `config_records` property instead.",
|
|
286
|
+
)
|
|
287
|
+
return self.config_records
|
|
288
|
+
|
|
199
289
|
|
|
200
290
|
class RecordSet(RecordDict):
|
|
201
291
|
"""Deprecated class ``RecordSet``, use ``RecordDict`` instead.
|
|
@@ -223,66 +313,25 @@ class RecordSet(RecordDict):
|
|
|
223
313
|
my_content = RecordDict()
|
|
224
314
|
"""
|
|
225
315
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
316
|
+
def __init__(
|
|
317
|
+
self,
|
|
318
|
+
records: dict[str, RecordType] | None = None,
|
|
319
|
+
*,
|
|
320
|
+
parameters_records: dict[str, ArrayRecord] | None = None,
|
|
321
|
+
metrics_records: dict[str, MetricRecord] | None = None,
|
|
322
|
+
configs_records: dict[str, ConfigRecord] | None = None,
|
|
323
|
+
) -> None:
|
|
324
|
+
if not _warning_tracker.recordset_init_logged:
|
|
325
|
+
_warning_tracker.recordset_init_logged = True
|
|
234
326
|
log(
|
|
235
327
|
WARN,
|
|
236
328
|
"The `RecordSet` class has been renamed to `RecordDict`. "
|
|
237
329
|
"Support for `RecordSet` will be removed in a future release. "
|
|
238
330
|
"Please update your code accordingly.",
|
|
239
331
|
)
|
|
240
|
-
super().__init__(
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
Use ``array_records`` instead.
|
|
247
|
-
"""
|
|
248
|
-
if not RecordSet._warning_logged_params:
|
|
249
|
-
RecordSet._warning_logged_params = True
|
|
250
|
-
log(
|
|
251
|
-
WARN,
|
|
252
|
-
"`RecordSet.parameters_records` has been deprecated "
|
|
253
|
-
"and will be removed in a future release. Please use "
|
|
254
|
-
"`RecordDict.array_records` instead.",
|
|
255
|
-
)
|
|
256
|
-
return self.array_records
|
|
257
|
-
|
|
258
|
-
@property
|
|
259
|
-
def metrics_records(self) -> TypedDict[str, MetricRecord]:
|
|
260
|
-
"""Deprecated property.
|
|
261
|
-
|
|
262
|
-
Use ``metric_records`` instead.
|
|
263
|
-
"""
|
|
264
|
-
if not RecordSet._warning_logged_metrics:
|
|
265
|
-
RecordSet._warning_logged_metrics = True
|
|
266
|
-
log(
|
|
267
|
-
WARN,
|
|
268
|
-
"`RecordSet.metrics_records` has been deprecated "
|
|
269
|
-
"and will be removed in a future release. Please use "
|
|
270
|
-
"`RecordDict.metric_records` instead.",
|
|
271
|
-
)
|
|
272
|
-
return self.metric_records
|
|
273
|
-
|
|
274
|
-
@property
|
|
275
|
-
def configs_records(self) -> TypedDict[str, ConfigRecord]:
|
|
276
|
-
"""Deprecated property.
|
|
277
|
-
|
|
278
|
-
Use ``config_records`` instead.
|
|
279
|
-
"""
|
|
280
|
-
if not RecordSet._warning_logged_configs:
|
|
281
|
-
RecordSet._warning_logged_configs = True
|
|
282
|
-
log(
|
|
283
|
-
WARN,
|
|
284
|
-
"`RecordSet.configs_records` has been deprecated "
|
|
285
|
-
"and will be removed in a future release. Please use "
|
|
286
|
-
"`RecordDict.config_records` instead.",
|
|
287
|
-
)
|
|
288
|
-
return self.config_records
|
|
332
|
+
super().__init__(
|
|
333
|
+
records,
|
|
334
|
+
parameters_records=parameters_records,
|
|
335
|
+
metrics_records=metrics_records,
|
|
336
|
+
configs_records=configs_records,
|
|
337
|
+
)
|
flwr/common/record/typeddict.py
CHANGED
flwr/common/retry_invoker.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -166,15 +166,15 @@ class RetryInvoker:
|
|
|
166
166
|
|
|
167
167
|
Examples
|
|
168
168
|
--------
|
|
169
|
-
Initialize a `RetryInvoker` with exponential backoff and invoke a function
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
169
|
+
Initialize a `RetryInvoker` with exponential backoff and invoke a function::
|
|
170
|
+
|
|
171
|
+
invoker = RetryInvoker(
|
|
172
|
+
exponential, # Or use `lambda: exponential(3, 2)` to pass arguments
|
|
173
|
+
grpc.RpcError,
|
|
174
|
+
max_tries=3,
|
|
175
|
+
max_time=None,
|
|
176
|
+
)
|
|
177
|
+
invoker.invoke(my_func, arg1, arg2, kw1=kwarg1)
|
|
178
178
|
"""
|
|
179
179
|
|
|
180
180
|
# pylint: disable-next=too-many-arguments
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -15,61 +15,83 @@
|
|
|
15
15
|
"""Shamir's secret sharing."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
import
|
|
18
|
+
import os
|
|
19
19
|
from concurrent.futures import ThreadPoolExecutor
|
|
20
|
-
from typing import cast
|
|
21
20
|
|
|
22
21
|
from Crypto.Protocol.SecretSharing import Shamir
|
|
23
22
|
from Crypto.Util.Padding import pad, unpad
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
def create_shares(secret: bytes, threshold: int, num: int) -> list[bytes]:
|
|
27
|
-
"""Return list of shares (bytes).
|
|
26
|
+
"""Return a list of shares (bytes).
|
|
27
|
+
|
|
28
|
+
Shares are created from the provided secret using Shamir's secret sharing.
|
|
29
|
+
"""
|
|
30
|
+
# Shamir's secret sharing requires the secret to be a multiple of 16 bytes
|
|
31
|
+
# (AES block size). Pad the secret to the next multiple of 16 bytes.
|
|
28
32
|
secret_padded = pad(secret, 16)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
share_list: list[
|
|
33
|
+
chunks = [secret_padded[i : i + 16] for i in range(0, len(secret_padded), 16)]
|
|
34
|
+
|
|
35
|
+
# The share list should contain shares of the secret, and each share consists of:
|
|
36
|
+
# <4 bytes of index><share of chunk1><share of chunk2>...<share of chunkN>
|
|
37
|
+
share_list: list[bytearray] = [bytearray() for _ in range(num)]
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
# Create shares for each chunk in parallel
|
|
40
|
+
max_workers = min(len(chunks), os.cpu_count() or 1)
|
|
41
|
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
36
42
|
for chunk_shares in executor.map(
|
|
37
|
-
lambda
|
|
43
|
+
lambda chunk: _shamir_split(threshold, num, chunk), chunks
|
|
38
44
|
):
|
|
39
45
|
for idx, share in chunk_shares:
|
|
40
|
-
#
|
|
41
|
-
share_list[idx - 1]
|
|
46
|
+
# Initialize the share with the index if it is empty
|
|
47
|
+
if not share_list[idx - 1]:
|
|
48
|
+
share_list[idx - 1] += idx.to_bytes(4, "little", signed=False)
|
|
42
49
|
|
|
43
|
-
|
|
50
|
+
# Append the share to the bytes
|
|
51
|
+
share_list[idx - 1] += share
|
|
52
|
+
|
|
53
|
+
return [bytes(share) for share in share_list]
|
|
44
54
|
|
|
45
55
|
|
|
46
56
|
def _shamir_split(threshold: int, num: int, chunk: bytes) -> list[tuple[int, bytes]]:
|
|
57
|
+
"""Create shares for a chunk using Shamir's secret sharing.
|
|
58
|
+
|
|
59
|
+
Each share is a tuple (index, share_bytes), where share_bytes is 16 bytes long.
|
|
60
|
+
"""
|
|
47
61
|
return Shamir.split(threshold, num, chunk, ssss=False)
|
|
48
62
|
|
|
49
63
|
|
|
50
|
-
# Reconstructing secret with PyCryptodome
|
|
51
64
|
def combine_shares(share_list: list[bytes]) -> bytes:
|
|
52
|
-
"""Reconstruct secret from shares."""
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
]
|
|
65
|
+
"""Reconstruct the secret from a list of shares."""
|
|
66
|
+
# Compute the number of chunks
|
|
67
|
+
# Each share contains 4 bytes of index and 16 bytes of share for each chunk
|
|
68
|
+
chunk_num = (len(share_list[0]) - 4) >> 4
|
|
56
69
|
|
|
57
|
-
chunk_num = len(unpickled_share_list[0])
|
|
58
70
|
secret_padded = bytearray(0)
|
|
59
|
-
chunk_shares_list: list[list[tuple[int, bytes]]] = []
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
chunk_shares_list: list[list[tuple[int, bytes]]] = [[] for _ in range(chunk_num)]
|
|
72
|
+
|
|
73
|
+
# Split shares into chunks
|
|
74
|
+
for share in share_list:
|
|
75
|
+
# The first 4 bytes are the index
|
|
76
|
+
index = int.from_bytes(share[:4], "little", signed=False)
|
|
77
|
+
for i in range(chunk_num):
|
|
78
|
+
start = (i << 4) + 4
|
|
79
|
+
chunk_shares_list[i].append((index, share[start : start + 16]))
|
|
80
|
+
|
|
81
|
+
# Combine shares for each chunk in parallel
|
|
82
|
+
max_workers = min(chunk_num, os.cpu_count() or 1)
|
|
83
|
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
67
84
|
for chunk in executor.map(_shamir_combine, chunk_shares_list):
|
|
68
85
|
secret_padded += chunk
|
|
69
86
|
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
try:
|
|
88
|
+
secret = unpad(bytes(secret_padded), 16)
|
|
89
|
+
except ValueError:
|
|
90
|
+
# If unpadding fails, it means the shares are not valid
|
|
91
|
+
raise ValueError("Failed to combine shares") from None
|
|
92
|
+
return secret
|
|
72
93
|
|
|
73
94
|
|
|
74
95
|
def _shamir_combine(shares: list[tuple[int, bytes]]) -> bytes:
|
|
96
|
+
"""Reconstruct a chunk from shares using Shamir's secret sharing."""
|
|
75
97
|
return Shamir.combine(shares, ssss=False)
|
flwr/common/serde.py
CHANGED
flwr/common/telemetry.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -124,7 +124,7 @@ class EventType(str, Enum):
|
|
|
124
124
|
# This method combined with auto() will set the property value to
|
|
125
125
|
# the property name e.g.
|
|
126
126
|
# `START_CLIENT = auto()` becomes `START_CLIENT = "START_CLIENT"`
|
|
127
|
-
# The type signature is not compatible with mypy
|
|
127
|
+
# The type signature is not compatible with mypy and pylint
|
|
128
128
|
# so each of those needs to be disabled for this line.
|
|
129
129
|
# pylint: disable-next=no-self-argument,arguments-differ,line-too-long
|
|
130
130
|
def _generate_next_value_(name: str, start: int, count: int, last_values: list[Any]) -> Any: # type: ignore # noqa: E501
|
flwr/common/typing.py
CHANGED
flwr/common/version.py
CHANGED
flwr/proto/__init__.py
CHANGED
flwr/server/__init__.py
CHANGED
flwr/server/app.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright
|
|
1
|
+
# Copyright 2025 Flower Labs GmbH. All Rights Reserved.
|
|
2
2
|
#
|
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
4
|
# you may not use this file except in compliance with the License.
|
|
@@ -183,19 +183,19 @@ def start_server( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
183
183
|
|
|
184
184
|
Examples
|
|
185
185
|
--------
|
|
186
|
-
Starting an insecure server
|
|
186
|
+
Starting an insecure server::
|
|
187
187
|
|
|
188
|
-
|
|
188
|
+
start_server()
|
|
189
189
|
|
|
190
|
-
Starting
|
|
190
|
+
Starting a TLS-enabled server::
|
|
191
191
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
192
|
+
start_server(
|
|
193
|
+
certificates=(
|
|
194
|
+
Path("/crts/root.pem").read_bytes(),
|
|
195
|
+
Path("/crts/localhost.crt").read_bytes(),
|
|
196
|
+
Path("/crts/localhost.key").read_bytes()
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
199
|
"""
|
|
200
200
|
msg = (
|
|
201
201
|
"flwr.server.start_server() is deprecated."
|
flwr/server/client_manager.py
CHANGED
flwr/server/client_proxy.py
CHANGED
flwr/server/compat/__init__.py
CHANGED
flwr/server/compat/app.py
CHANGED
flwr/server/compat/app_utils.py
CHANGED
flwr/server/criterion.py
CHANGED
flwr/server/grid/grid.py
CHANGED
|
@@ -28,11 +28,11 @@ class Grid(ABC):
|
|
|
28
28
|
|
|
29
29
|
@abstractmethod
|
|
30
30
|
def set_run(self, run_id: int) -> None:
|
|
31
|
-
"""Request a run to the SuperLink with a given
|
|
31
|
+
"""Request a run to the SuperLink with a given ``run_id``.
|
|
32
32
|
|
|
33
33
|
If a ``Run`` with the specified ``run_id`` exists, a local ``Run``
|
|
34
34
|
object will be created. It enables further functionality
|
|
35
|
-
in the grid, such as sending ``Message``
|
|
35
|
+
in the grid, such as sending ``Message`` objects.
|
|
36
36
|
|
|
37
37
|
Parameters
|
|
38
38
|
----------
|
|
@@ -172,7 +172,7 @@ class Driver(Grid):
|
|
|
172
172
|
|
|
173
173
|
.. warning::
|
|
174
174
|
``Driver`` is deprecated and will be removed in a future release.
|
|
175
|
-
Use
|
|
175
|
+
Use ``Grid`` in the signature of your ServerApp.
|
|
176
176
|
|
|
177
177
|
Examples
|
|
178
178
|
--------
|
flwr/server/history.py
CHANGED
flwr/server/run_serverapp.py
CHANGED