flwr-nightly 1.19.0.dev20250512__py3-none-any.whl → 1.19.0.dev20250513__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/common/heartbeat.py +5 -0
- flwr/common/inflatable.py +14 -1
- flwr/common/record/array.py +10 -1
- flwr/common/record/arrayrecord.py +65 -1
- flwr/common/record/configrecord.py +10 -1
- flwr/common/record/metricrecord.py +10 -1
- flwr/common/record/recorddict.py +69 -1
- {flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250513.dist-info}/METADATA +1 -1
- {flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250513.dist-info}/RECORD +11 -11
- {flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250513.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250513.dist-info}/entry_points.txt +0 -0
flwr/common/heartbeat.py
CHANGED
@@ -77,6 +77,11 @@ class HeartbeatSender:
|
|
77
77
|
self._stop_event.set()
|
78
78
|
self._thread.join()
|
79
79
|
|
80
|
+
@property
|
81
|
+
def is_running(self) -> bool:
|
82
|
+
"""Return True if the heartbeat sender is running, False otherwise."""
|
83
|
+
return self._thread.is_alive() and not self._stop_event.is_set()
|
84
|
+
|
80
85
|
def _run(self) -> None:
|
81
86
|
"""Periodically send heartbeats until stopped."""
|
82
87
|
while not self._stop_event.is_set():
|
flwr/common/inflatable.py
CHANGED
@@ -15,6 +15,8 @@
|
|
15
15
|
"""InflatableObject base class."""
|
16
16
|
|
17
17
|
|
18
|
+
from __future__ import annotations
|
19
|
+
|
18
20
|
import hashlib
|
19
21
|
from typing import TypeVar
|
20
22
|
|
@@ -31,7 +33,9 @@ class InflatableObject:
|
|
31
33
|
raise NotImplementedError()
|
32
34
|
|
33
35
|
@classmethod
|
34
|
-
def inflate(
|
36
|
+
def inflate(
|
37
|
+
cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
|
38
|
+
) -> InflatableObject:
|
35
39
|
"""Inflate the object from bytes.
|
36
40
|
|
37
41
|
Parameters
|
@@ -39,6 +43,10 @@ class InflatableObject:
|
|
39
43
|
object_content : bytes
|
40
44
|
The deflated object content.
|
41
45
|
|
46
|
+
children : Optional[dict[str, InflatableObject]] (default: None)
|
47
|
+
Dictionary of children InflatableObjects mapped to their object IDs. These
|
48
|
+
childrens enable the full inflation of the parent InflatableObject.
|
49
|
+
|
42
50
|
Returns
|
43
51
|
-------
|
44
52
|
InflatableObject
|
@@ -51,6 +59,11 @@ class InflatableObject:
|
|
51
59
|
"""Get object_id."""
|
52
60
|
return get_object_id(self.deflate())
|
53
61
|
|
62
|
+
@property
|
63
|
+
def children(self) -> dict[str, InflatableObject] | None:
|
64
|
+
"""Get all child objects as a dictionary or None if there are no children."""
|
65
|
+
return None
|
66
|
+
|
54
67
|
|
55
68
|
def get_object_id(object_content: bytes) -> str:
|
56
69
|
"""Return a SHA-256 hash of the (deflated) object content."""
|
flwr/common/record/array.py
CHANGED
@@ -265,7 +265,9 @@ class Array(InflatableObject):
|
|
265
265
|
return add_header_to_object_body(object_body=obj_body, cls=self)
|
266
266
|
|
267
267
|
@classmethod
|
268
|
-
def inflate(
|
268
|
+
def inflate(
|
269
|
+
cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
|
270
|
+
) -> Array:
|
269
271
|
"""Inflate an Array from bytes.
|
270
272
|
|
271
273
|
Parameters
|
@@ -273,11 +275,18 @@ class Array(InflatableObject):
|
|
273
275
|
object_content : bytes
|
274
276
|
The deflated object content of the Array.
|
275
277
|
|
278
|
+
children : Optional[dict[str, InflatableObject]] (default: None)
|
279
|
+
Must be ``None``. ``Array`` does not support child objects.
|
280
|
+
Providing any children will raise a ``ValueError``.
|
281
|
+
|
276
282
|
Returns
|
277
283
|
-------
|
278
284
|
Array
|
279
285
|
The inflated Array.
|
280
286
|
"""
|
287
|
+
if children is not None:
|
288
|
+
raise ValueError("`Array` objects do not have children.")
|
289
|
+
|
281
290
|
obj_body = get_object_body(object_content, cls)
|
282
291
|
proto_array = ArrayProto.FromString(obj_body)
|
283
292
|
return cls(
|
@@ -18,6 +18,7 @@
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
20
|
import gc
|
21
|
+
import json
|
21
22
|
import sys
|
22
23
|
from collections import OrderedDict
|
23
24
|
from logging import WARN
|
@@ -26,6 +27,7 @@ from typing import TYPE_CHECKING, Any, cast, overload
|
|
26
27
|
import numpy as np
|
27
28
|
|
28
29
|
from ..constant import GC_THRESHOLD
|
30
|
+
from ..inflatable import InflatableObject, add_header_to_object_body, get_object_body
|
29
31
|
from ..logger import log
|
30
32
|
from ..typing import NDArray
|
31
33
|
from .array import Array
|
@@ -56,7 +58,7 @@ def _check_value(value: Array) -> None:
|
|
56
58
|
)
|
57
59
|
|
58
60
|
|
59
|
-
class ArrayRecord(TypedDict[str, Array]):
|
61
|
+
class ArrayRecord(TypedDict[str, Array], InflatableObject):
|
60
62
|
"""Array record.
|
61
63
|
|
62
64
|
A typed dictionary (``str`` to :class:`Array`) that can store named arrays,
|
@@ -365,6 +367,68 @@ class ArrayRecord(TypedDict[str, Array]):
|
|
365
367
|
|
366
368
|
return num_bytes
|
367
369
|
|
370
|
+
@property
|
371
|
+
def children(self) -> dict[str, InflatableObject]:
|
372
|
+
"""Return a dictionary of Arrays with their Object IDs as keys."""
|
373
|
+
return {arr.object_id: arr for arr in self.values()}
|
374
|
+
|
375
|
+
def deflate(self) -> bytes:
|
376
|
+
"""Deflate the ArrayRecord."""
|
377
|
+
# array_name: array_object_id mapping
|
378
|
+
array_refs: dict[str, str] = {}
|
379
|
+
|
380
|
+
for array_name, array in self.items():
|
381
|
+
array_refs[array_name] = array.object_id
|
382
|
+
|
383
|
+
# Serialize references dict
|
384
|
+
object_body = json.dumps(array_refs).encode("utf-8")
|
385
|
+
return add_header_to_object_body(object_body=object_body, cls=self)
|
386
|
+
|
387
|
+
@classmethod
|
388
|
+
def inflate(
|
389
|
+
cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
|
390
|
+
) -> ArrayRecord:
|
391
|
+
"""Inflate an ArrayRecord from bytes.
|
392
|
+
|
393
|
+
Parameters
|
394
|
+
----------
|
395
|
+
object_content : bytes
|
396
|
+
The deflated object content of the ArrayRecord.
|
397
|
+
children : Optional[dict[str, InflatableObject]] (default: None)
|
398
|
+
Dictionary of children InflatableObjects mapped to their Object IDs.
|
399
|
+
These children enable the full inflation of the ArrayRecord.
|
400
|
+
|
401
|
+
Returns
|
402
|
+
-------
|
403
|
+
ArrayRecord
|
404
|
+
The inflated ArrayRecord.
|
405
|
+
"""
|
406
|
+
if children is None:
|
407
|
+
children = {}
|
408
|
+
|
409
|
+
# Inflate mapping of array_names (keys in the ArrayRecord) to Arrays' object IDs
|
410
|
+
obj_body = get_object_body(object_content, cls)
|
411
|
+
array_refs: dict[str, str] = json.loads(obj_body.decode(encoding="utf-8"))
|
412
|
+
|
413
|
+
unique_arrays = set(array_refs.values())
|
414
|
+
children_obj_ids = set(children.keys())
|
415
|
+
if unique_arrays != children_obj_ids:
|
416
|
+
raise ValueError(
|
417
|
+
"Unexpected set of `children`. "
|
418
|
+
f"Expected {unique_arrays} but got {children_obj_ids}."
|
419
|
+
)
|
420
|
+
|
421
|
+
# Ensure children are of type Array
|
422
|
+
if not all(isinstance(arr, Array) for arr in children.values()):
|
423
|
+
raise ValueError("`Children` are expected to be of type `Array`.")
|
424
|
+
|
425
|
+
# Instantiate new ArrayRecord
|
426
|
+
return ArrayRecord(
|
427
|
+
OrderedDict(
|
428
|
+
{name: children[object_id] for name, object_id in array_refs.items()}
|
429
|
+
)
|
430
|
+
)
|
431
|
+
|
368
432
|
|
369
433
|
class ParametersRecord(ArrayRecord):
|
370
434
|
"""Deprecated class ``ParametersRecord``, use ``ArrayRecord`` instead.
|
@@ -185,7 +185,9 @@ class ConfigRecord(TypedDict[str, ConfigRecordValues], InflatableObject):
|
|
185
185
|
return add_header_to_object_body(object_body=obj_body, cls=self)
|
186
186
|
|
187
187
|
@classmethod
|
188
|
-
def inflate(
|
188
|
+
def inflate(
|
189
|
+
cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
|
190
|
+
) -> ConfigRecord:
|
189
191
|
"""Inflate a ConfigRecord from bytes.
|
190
192
|
|
191
193
|
Parameters
|
@@ -193,11 +195,18 @@ class ConfigRecord(TypedDict[str, ConfigRecordValues], InflatableObject):
|
|
193
195
|
object_content : bytes
|
194
196
|
The deflated object content of the ConfigRecord.
|
195
197
|
|
198
|
+
children : Optional[dict[str, InflatableObject]] (default: None)
|
199
|
+
Must be ``None``. ``ConfigRecord`` does not support child objects.
|
200
|
+
Providing any children will raise a ``ValueError``.
|
201
|
+
|
196
202
|
Returns
|
197
203
|
-------
|
198
204
|
ConfigRecord
|
199
205
|
The inflated ConfigRecord.
|
200
206
|
"""
|
207
|
+
if children is not None:
|
208
|
+
raise ValueError("`ConfigRecord` objects do not have children.")
|
209
|
+
|
201
210
|
obj_body = get_object_body(object_content, cls)
|
202
211
|
config_record_proto = ProtoConfigRecord.FromString(obj_body)
|
203
212
|
|
@@ -160,7 +160,9 @@ class MetricRecord(TypedDict[str, MetricRecordValues], InflatableObject):
|
|
160
160
|
return add_header_to_object_body(object_body=obj_body, cls=self)
|
161
161
|
|
162
162
|
@classmethod
|
163
|
-
def inflate(
|
163
|
+
def inflate(
|
164
|
+
cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
|
165
|
+
) -> MetricRecord:
|
164
166
|
"""Inflate a MetricRecord from bytes.
|
165
167
|
|
166
168
|
Parameters
|
@@ -168,11 +170,18 @@ class MetricRecord(TypedDict[str, MetricRecordValues], InflatableObject):
|
|
168
170
|
object_content : bytes
|
169
171
|
The deflated object content of the MetricRecord.
|
170
172
|
|
173
|
+
children : Optional[dict[str, InflatableObject]] (default: None)
|
174
|
+
Must be ``None``. ``MetricRecord`` does not support child objects.
|
175
|
+
Providing any children will raise a ``ValueError``.
|
176
|
+
|
171
177
|
Returns
|
172
178
|
-------
|
173
179
|
MetricRecord
|
174
180
|
The inflated MetricRecord.
|
175
181
|
"""
|
182
|
+
if children is not None:
|
183
|
+
raise ValueError("`MetricRecord` objects do not have children.")
|
184
|
+
|
176
185
|
obj_body = get_object_body(object_content, cls)
|
177
186
|
metric_record_proto = ProtoMetricRecord.FromString(obj_body)
|
178
187
|
|
flwr/common/record/recorddict.py
CHANGED
@@ -17,10 +17,12 @@
|
|
17
17
|
|
18
18
|
from __future__ import annotations
|
19
19
|
|
20
|
+
import json
|
20
21
|
from logging import WARN
|
21
22
|
from textwrap import indent
|
22
23
|
from typing import TypeVar, Union, cast
|
23
24
|
|
25
|
+
from ..inflatable import InflatableObject, add_header_to_object_body, get_object_body
|
24
26
|
from ..logger import log
|
25
27
|
from .arrayrecord import ArrayRecord
|
26
28
|
from .configrecord import ConfigRecord
|
@@ -97,7 +99,7 @@ class _SyncedDict(TypedDict[str, T]):
|
|
97
99
|
)
|
98
100
|
|
99
101
|
|
100
|
-
class RecordDict(TypedDict[str, RecordType]):
|
102
|
+
class RecordDict(TypedDict[str, RecordType], InflatableObject):
|
101
103
|
"""RecordDict stores groups of arrays, metrics and configs.
|
102
104
|
|
103
105
|
A :class:`RecordDict` is the unified mechanism by which arrays,
|
@@ -286,6 +288,72 @@ class RecordDict(TypedDict[str, RecordType]):
|
|
286
288
|
)
|
287
289
|
return self.config_records
|
288
290
|
|
291
|
+
@property
|
292
|
+
def children(self) -> dict[str, InflatableObject]:
|
293
|
+
"""Return a dictionary of records with their Object IDs as keys."""
|
294
|
+
return {record.object_id: record for record in self.values()}
|
295
|
+
|
296
|
+
def deflate(self) -> bytes:
|
297
|
+
"""Deflate the RecordDict."""
|
298
|
+
# record_name: record_object_id mapping
|
299
|
+
record_refs: dict[str, str] = {}
|
300
|
+
|
301
|
+
for record_name, record in self.items():
|
302
|
+
record_refs[record_name] = record.object_id
|
303
|
+
|
304
|
+
# Serialize references dict
|
305
|
+
object_body = json.dumps(record_refs).encode("utf-8")
|
306
|
+
return add_header_to_object_body(object_body=object_body, cls=self)
|
307
|
+
|
308
|
+
@classmethod
|
309
|
+
def inflate(
|
310
|
+
cls, object_content: bytes, children: dict[str, InflatableObject] | None = None
|
311
|
+
) -> RecordDict:
|
312
|
+
"""Inflate an RecordDict from bytes.
|
313
|
+
|
314
|
+
Parameters
|
315
|
+
----------
|
316
|
+
object_content : bytes
|
317
|
+
The deflated object content of the RecordDict.
|
318
|
+
children : Optional[dict[str, InflatableObject]] (default: None)
|
319
|
+
Dictionary of children InflatableObjects mapped to their Object IDs.
|
320
|
+
These children enable the full inflation of the RecordDict. Default is None.
|
321
|
+
|
322
|
+
Returns
|
323
|
+
-------
|
324
|
+
RecordDict
|
325
|
+
The inflated RecordDict.
|
326
|
+
"""
|
327
|
+
if children is None:
|
328
|
+
children = {}
|
329
|
+
|
330
|
+
# Inflate mapping of record_names (keys in the RecordDict) to Record' object IDs
|
331
|
+
obj_body = get_object_body(object_content, cls)
|
332
|
+
record_refs: dict[str, str] = json.loads(obj_body.decode(encoding="utf-8"))
|
333
|
+
|
334
|
+
unique_records = set(record_refs.values())
|
335
|
+
children_obj_ids = set(children.keys())
|
336
|
+
if unique_records != children_obj_ids:
|
337
|
+
raise ValueError(
|
338
|
+
"Unexpected set of `children`. "
|
339
|
+
f"Expected {unique_records} but got {children_obj_ids}."
|
340
|
+
)
|
341
|
+
|
342
|
+
# Ensure children are one of the *Record objects exepecte in a RecordDict
|
343
|
+
if not all(
|
344
|
+
isinstance(ch, (ArrayRecord, ConfigRecord, MetricRecord))
|
345
|
+
for ch in children.values()
|
346
|
+
):
|
347
|
+
raise ValueError(
|
348
|
+
"`Children` are expected to be of type `ArrayRecord`, "
|
349
|
+
"`ConfigRecord` or `MetricRecord`."
|
350
|
+
)
|
351
|
+
|
352
|
+
# Instantiate new RecordDict
|
353
|
+
return RecordDict(
|
354
|
+
{name: children[object_id] for name, object_id in record_refs.items()} # type: ignore
|
355
|
+
)
|
356
|
+
|
289
357
|
|
290
358
|
class RecordSet(RecordDict):
|
291
359
|
"""Deprecated class ``RecordSet``, use ``RecordDict`` instead.
|
{flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250513.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: flwr-nightly
|
3
|
-
Version: 1.19.0.
|
3
|
+
Version: 1.19.0.dev20250513
|
4
4
|
Summary: Flower: A Friendly Federated AI Framework
|
5
5
|
License: Apache-2.0
|
6
6
|
Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
|
{flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250513.dist-info}/RECORD
RENAMED
@@ -128,20 +128,20 @@ flwr/common/exit/exit.py,sha256=mJgbqMlVlwAgYtq-Vedj53wO4VxcDcy_P-GzqGK-1GQ,3452
|
|
128
128
|
flwr/common/exit/exit_code.py,sha256=PNEnCrZfOILjfDAFu5m-2YWEJBrk97xglq4zCUlqV7E,3470
|
129
129
|
flwr/common/exit_handlers.py,sha256=MEk5_savTLphn-6lW57UQlos-XrFA39XEBn-OF1vXXg,3174
|
130
130
|
flwr/common/grpc.py,sha256=manTaHaPiyYngUq1ErZvvV2B2GxlXUUUGRy3jc3TBIQ,9798
|
131
|
-
flwr/common/heartbeat.py,sha256=
|
132
|
-
flwr/common/inflatable.py,sha256=
|
131
|
+
flwr/common/heartbeat.py,sha256=nU0SNlL0A6t736ku7D7z7UUB1vXaX9QIn2fsJJPWeBU,4125
|
132
|
+
flwr/common/inflatable.py,sha256=o3PQejN8GNm_xlHKJLB1h2wQzOXKkDfaiy6z5o142pA,3681
|
133
133
|
flwr/common/logger.py,sha256=JbRf6E2vQxXzpDBq1T8IDUJo_usu3gjWEBPQ6uKcmdg,13049
|
134
134
|
flwr/common/message.py,sha256=znr205Erq2hkxwFbvNNCsQTRS2UKv_Qsyu0sFNEhEAw,23721
|
135
135
|
flwr/common/object_ref.py,sha256=p3SfTeqo3Aj16SkB-vsnNn01zswOPdGNBitcbRnqmUk,9134
|
136
136
|
flwr/common/parameter.py,sha256=UVw6sOgehEFhFs4uUCMl2kfVq1PD6ncmWgPLMsZPKPE,2095
|
137
137
|
flwr/common/pyproject.py,sha256=2SU6yJW7059SbMXgzjOdK1GZRWO6AixDH7BmdxbMvHI,1386
|
138
138
|
flwr/common/record/__init__.py,sha256=cNGccdDoxttqgnUgyKRIqLWULjW-NaSmOufVxtXq-sw,1197
|
139
|
-
flwr/common/record/array.py,sha256=
|
140
|
-
flwr/common/record/arrayrecord.py,sha256
|
141
|
-
flwr/common/record/configrecord.py,sha256=
|
139
|
+
flwr/common/record/array.py,sha256=7c5peTvVsnhXQVvYOIFqm2UowGO-Uu0_44EeqybU0HY,10850
|
140
|
+
flwr/common/record/arrayrecord.py,sha256=-9iIfBKtCS-fGmh5NLTDS7GTHqfHA3o1MguPyyybAyI,16787
|
141
|
+
flwr/common/record/configrecord.py,sha256=2BqauemtQBsZDWLtkTZp51_4J7L9-8i5LrM9RV8nmNQ,9664
|
142
142
|
flwr/common/record/conversion_utils.py,sha256=wbNCzy7oAqaA3-arhls_EqRZYXRC4YrWIoE-Gy82fJ0,1191
|
143
|
-
flwr/common/record/metricrecord.py,sha256=
|
144
|
-
flwr/common/record/recorddict.py,sha256=
|
143
|
+
flwr/common/record/metricrecord.py,sha256=PGeYISykqf_NSyij-qXdf85Pfnder7Rw9CagIolBe30,8839
|
144
|
+
flwr/common/record/recorddict.py,sha256=qnRET_r6_7o7JSQQO2PnMAKezA4yZEy0frsfy8CKxb8,14986
|
145
145
|
flwr/common/record/typeddict.py,sha256=dDKgUThs2BscYUNcgP82KP8-qfAYXYftDrf2LszAC_o,3599
|
146
146
|
flwr/common/recorddict_compat.py,sha256=Znn1xRGiqLpPPgviVqyb-GPTM-pCK6tpnEmhWSXafy8,14119
|
147
147
|
flwr/common/retry_invoker.py,sha256=T6puUH3nCxdRzQHeanyr-0nTxhRiS1TH07rmef9vuLQ,14482
|
@@ -333,7 +333,7 @@ flwr/superexec/exec_servicer.py,sha256=Z0YYfs6eNPhqn8rY0x_R04XgR2mKFpggt07IH0EhU
|
|
333
333
|
flwr/superexec/exec_user_auth_interceptor.py,sha256=iqygALkOMBUu_s_R9G0mFThZA7HTUzuXCLgxLCefiwI,4440
|
334
334
|
flwr/superexec/executor.py,sha256=M5ucqSE53jfRtuCNf59WFLqQvA1Mln4741TySeZE7qQ,3112
|
335
335
|
flwr/superexec/simulation.py,sha256=j6YwUvBN7EQ09ID7MYOCVZ70PGbuyBy8f9bXU0EszEM,4088
|
336
|
-
flwr_nightly-1.19.0.
|
337
|
-
flwr_nightly-1.19.0.
|
338
|
-
flwr_nightly-1.19.0.
|
339
|
-
flwr_nightly-1.19.0.
|
336
|
+
flwr_nightly-1.19.0.dev20250513.dist-info/METADATA,sha256=4dlTZbixbfPDUcDbK3OBZ3JwaIFV553qWtAcY4d6zpQ,15910
|
337
|
+
flwr_nightly-1.19.0.dev20250513.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
338
|
+
flwr_nightly-1.19.0.dev20250513.dist-info/entry_points.txt,sha256=2-1L-GNKhwGw2_7_RoH55vHw2SIHjdAQy3HAVAWl9PY,374
|
339
|
+
flwr_nightly-1.19.0.dev20250513.dist-info/RECORD,,
|
{flwr_nightly-1.19.0.dev20250512.dist-info → flwr_nightly-1.19.0.dev20250513.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|