flwr-nightly 1.17.0.dev20250317__py3-none-any.whl → 1.17.0.dev20250318__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.
Files changed (26) hide show
  1. flwr/common/constant.py +3 -0
  2. flwr/common/record/parametersrecord.py +336 -92
  3. flwr/server/__init__.py +1 -1
  4. flwr/server/app.py +1 -1
  5. flwr/server/compat/app.py +1 -1
  6. flwr/server/compat/app_utils.py +2 -2
  7. flwr/server/compat/{driver_client_proxy.py → grid_client_proxy.py} +2 -2
  8. flwr/server/{driver → grid}/__init__.py +4 -4
  9. flwr/server/{driver/driver.py → grid/grid.py} +1 -1
  10. flwr/server/{driver/grpc_driver.py → grid/grpc_grid.py} +2 -11
  11. flwr/server/{driver/inmemory_driver.py → grid/inmemory_grid.py} +2 -10
  12. flwr/server/run_serverapp.py +1 -1
  13. flwr/server/server_app.py +2 -2
  14. flwr/server/serverapp/app.py +1 -1
  15. flwr/server/superlink/{driver → serverappio}/__init__.py +1 -1
  16. flwr/server/superlink/{driver → serverappio}/serverappio_grpc.py +1 -1
  17. flwr/server/superlink/{driver → serverappio}/serverappio_servicer.py +1 -1
  18. flwr/server/typing.py +1 -1
  19. flwr/server/workflow/default_workflows.py +1 -1
  20. flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +1 -1
  21. flwr/simulation/run_simulation.py +1 -1
  22. {flwr_nightly-1.17.0.dev20250317.dist-info → flwr_nightly-1.17.0.dev20250318.dist-info}/METADATA +1 -1
  23. {flwr_nightly-1.17.0.dev20250317.dist-info → flwr_nightly-1.17.0.dev20250318.dist-info}/RECORD +26 -26
  24. {flwr_nightly-1.17.0.dev20250317.dist-info → flwr_nightly-1.17.0.dev20250318.dist-info}/LICENSE +0 -0
  25. {flwr_nightly-1.17.0.dev20250317.dist-info → flwr_nightly-1.17.0.dev20250318.dist-info}/WHEEL +0 -0
  26. {flwr_nightly-1.17.0.dev20250317.dist-info → flwr_nightly-1.17.0.dev20250318.dist-info}/entry_points.txt +0 -0
flwr/common/constant.py CHANGED
@@ -120,6 +120,9 @@ TIMESTAMP_HEADER = "flwr-timestamp"
120
120
  TIMESTAMP_TOLERANCE = 10 # General tolerance for timestamp verification
121
121
  SYSTEM_TIME_TOLERANCE = 5 # Allowance for system time drift
122
122
 
123
+ # Constants for ParametersRecord
124
+ GC_THRESHOLD = 200_000_000 # 200 MB
125
+
123
126
 
124
127
  class MessageType:
125
128
  """Message type."""
@@ -17,22 +17,36 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
+ import gc
21
+ import sys
20
22
  from collections import OrderedDict
21
23
  from dataclasses import dataclass
22
24
  from io import BytesIO
23
- from typing import Any, cast, overload
25
+ from typing import TYPE_CHECKING, Any, cast, overload
24
26
 
25
27
  import numpy as np
26
28
 
27
- from ..constant import SType
29
+ from ..constant import GC_THRESHOLD, SType
28
30
  from ..typing import NDArray
29
31
  from .typeddict import TypedDict
30
32
 
33
+ if TYPE_CHECKING:
34
+ import torch
35
+
31
36
 
32
37
  def _raise_array_init_error() -> None:
33
38
  raise TypeError(
34
39
  f"Invalid arguments for {Array.__qualname__}. Expected either a "
35
- "NumPy ndarray, or explicit dtype/shape/stype/data values."
40
+ "PyTorch tensor, a NumPy ndarray, or explicit"
41
+ " dtype/shape/stype/data values."
42
+ )
43
+
44
+
45
+ def _raise_parameters_record_init_error() -> None:
46
+ raise TypeError(
47
+ f"Invalid arguments for {ParametersRecord.__qualname__}. Expected either "
48
+ "a list of NumPy ndarrays, a PyTorch state_dict, or a dictionary of Arrays. "
49
+ "The `keep_input` argument is keyword-only."
36
50
  )
37
51
 
38
52
 
@@ -41,37 +55,43 @@ class Array:
41
55
  """Array type.
42
56
 
43
57
  A dataclass containing serialized data from an array-like or tensor-like object
44
- along with metadata about it. The class can be initialized in one of two ways:
58
+ along with metadata about it. The class can be initialized in one of three ways:
45
59
 
46
60
  1. By specifying explicit values for `dtype`, `shape`, `stype`, and `data`.
47
61
  2. By providing a NumPy ndarray (via the `ndarray` argument).
62
+ 3. By providing a PyTorch tensor (via the `torch_tensor` argument).
48
63
 
49
- In scenario (2), the `dtype`, `shape`, `stype`, and `data` are automatically
64
+ In scenarios (2)-(3), the `dtype`, `shape`, `stype`, and `data` are automatically
50
65
  derived from the input. In scenario (1), these fields must be specified manually.
51
66
 
52
67
  Parameters
53
68
  ----------
54
69
  dtype : Optional[str] (default: None)
55
70
  A string representing the data type of the serialized object (e.g. `"float32"`).
56
- Only required if you are not passing in a ndarray.
71
+ Only required if you are not passing in a ndarray or a tensor.
57
72
 
58
73
  shape : Optional[list[int]] (default: None)
59
74
  A list representing the shape of the unserialized array-like object. Only
60
- required if you are not passing in a ndarray.
75
+ required if you are not passing in a ndarray or a tensor.
61
76
 
62
77
  stype : Optional[str] (default: None)
63
78
  A string indicating the serialization mechanism used to generate the bytes in
64
79
  `data` from an array-like or tensor-like object. Only required if you are not
65
- passing in a ndarray.
80
+ passing in a ndarray or a tensor.
66
81
 
67
82
  data : Optional[bytes] (default: None)
68
83
  A buffer of bytes containing the data. Only required if you are not passing in
69
- a ndarray.
84
+ a ndarray or a tensor.
70
85
 
71
86
  ndarray : Optional[NDArray] (default: None)
72
87
  A NumPy ndarray. If provided, the `dtype`, `shape`, `stype`, and `data`
73
88
  fields are derived automatically from it.
74
89
 
90
+ torch_tensor : Optional[torch.Tensor] (default: None)
91
+ A PyTorch tensor. If provided, it will be **detached and moved to CPU**
92
+ before conversion, and the `dtype`, `shape`, `stype`, and `data` fields
93
+ will be derived automatically from it.
94
+
75
95
  Examples
76
96
  --------
77
97
  Initializing by specifying all fields directly:
@@ -87,6 +107,11 @@ class Array:
87
107
 
88
108
  >>> import numpy as np
89
109
  >>> arr2 = Array(np.random.randn(3, 3))
110
+
111
+ Initializing with a PyTorch tensor:
112
+
113
+ >>> import torch
114
+ >>> arr3 = Array(torch.randn(3, 3))
90
115
  """
91
116
 
92
117
  dtype: str
@@ -102,6 +127,9 @@ class Array:
102
127
  @overload
103
128
  def __init__(self, ndarray: NDArray) -> None: ... # noqa: E704
104
129
 
130
+ @overload
131
+ def __init__(self, torch_tensor: torch.Tensor) -> None: ... # noqa: E704
132
+
105
133
  def __init__( # pylint: disable=too-many-arguments, too-many-locals
106
134
  self,
107
135
  *args: Any,
@@ -110,11 +138,13 @@ class Array:
110
138
  stype: str | None = None,
111
139
  data: bytes | None = None,
112
140
  ndarray: NDArray | None = None,
141
+ torch_tensor: torch.Tensor | None = None,
113
142
  ) -> None:
114
143
  # Determine the initialization method and validate input arguments.
115
- # Support two initialization formats:
144
+ # Support three initialization formats:
116
145
  # 1. Array(dtype: str, shape: list[int], stype: str, data: bytes)
117
146
  # 2. Array(ndarray: NDArray)
147
+ # 3. Array(torch_tensor: torch.Tensor)
118
148
 
119
149
  # Initialize all arguments
120
150
  # If more than 4 positional arguments are provided, raise an error.
@@ -149,6 +179,7 @@ class Array:
149
179
  _try_set_arg(2, stype, "direct")
150
180
  _try_set_arg(3, data, "direct")
151
181
  _try_set_arg(0, ndarray, "ndarray")
182
+ _try_set_arg(0, torch_tensor, "torch_tensor")
152
183
 
153
184
  # Check if all arguments are correctly set
154
185
  all_args = [arg for arg in all_args if arg is not None]
@@ -172,6 +203,16 @@ class Array:
172
203
  self.__dict__.update(self.from_numpy_ndarray(all_args[0]).__dict__)
173
204
  return
174
205
 
206
+ # Handle PyTorch tensor
207
+ if not init_method or init_method == "torch_tensor":
208
+ if (
209
+ len(all_args) == 1
210
+ and "torch" in sys.modules
211
+ and isinstance(all_args[0], sys.modules["torch"].Tensor)
212
+ ):
213
+ self.__dict__.update(self.from_torch_tensor(all_args[0]).__dict__)
214
+ return
215
+
175
216
  _raise_array_init_error()
176
217
 
177
218
  @classmethod
@@ -193,6 +234,19 @@ class Array:
193
234
  data=data,
194
235
  )
195
236
 
237
+ @classmethod
238
+ def from_torch_tensor(cls, tensor: torch.Tensor) -> Array:
239
+ """Create Array from PyTorch tensor."""
240
+ if not (torch := sys.modules.get("torch")):
241
+ raise RuntimeError(
242
+ f"PyTorch is required to use {cls.from_torch_tensor.__name__}"
243
+ )
244
+
245
+ assert isinstance(
246
+ tensor, torch.Tensor
247
+ ), f"Expected PyTorch Tensor, got {type(tensor)}"
248
+ return cls.from_numpy_ndarray(tensor.detach().cpu().numpy())
249
+
196
250
  def numpy(self) -> NDArray:
197
251
  """Return the array as a NumPy array."""
198
252
  if self.stype != SType.NUMPY:
@@ -223,103 +277,293 @@ def _check_value(value: Array) -> None:
223
277
  class ParametersRecord(TypedDict[str, Array]):
224
278
  r"""Parameters record.
225
279
 
226
- A dataclass storing named Arrays in order. This means that it holds entries as an
227
- OrderedDict[str, Array]. ParametersRecord objects can be viewed as an equivalent to
228
- PyTorch's state_dict, but holding serialised tensors instead. A
229
- :code:`ParametersRecord` is one of the types of records that a
230
- `flwr.common.RecordSet <flwr.common.RecordSet.html#recordset>`_ supports and
231
- can therefore be used to construct :code:`common.Message` objects.
280
+ A typed dictionary (``str`` to :class:`Array`) that can store named parameters
281
+ as serialized tensors. Internally, this behaves similarly to an
282
+ ``OrderedDict[str, Array]``. A ``ParametersRecord`` can be viewed as an
283
+ equivalent to PyTorch's ``state_dict``, but it holds arrays in serialized form.
284
+
285
+ This object is one of the record types supported by :class:`RecordSet` and can
286
+ therefore be stored in the ``content`` of a :class:`Message` or the ``state``
287
+ of a :class:`Context`.
288
+
289
+ This class can be instantiated in multiple ways:
290
+
291
+ 1. By providing nothing (empty container).
292
+ 2. By providing a dictionary of :class:`Array` (via the ``array_dict`` argument).
293
+ 3. By providing a list of NumPy ``ndarray`` (via the ``numpy_ndarrays`` argument).
294
+ 4. By providing a PyTorch ``state_dict`` (via the ``torch_state_dict`` argument).
232
295
 
233
296
  Parameters
234
297
  ----------
235
- array_dict : Optional[OrderedDict[str, Array]]
236
- A dictionary that stores serialized array-like or tensor-like objects.
237
- keep_input : bool (default: False)
238
- A boolean indicating whether parameters should be deleted from the input
239
- dictionary immediately after adding them to the record. If False, the
240
- dictionary passed to `set_parameters()` will be empty once exiting from that
241
- function. This is the desired behaviour when working with very large
242
- models/tensors/arrays. However, if you plan to continue working with your
243
- parameters after adding it to the record, set this flag to True. When set
244
- to True, the data is duplicated in memory.
298
+ array_dict : Optional[OrderedDict[str, Array]] (default: None)
299
+ An existing dictionary containing named :class:`Array` instances. If
300
+ provided, these entries will be used directly to populate the record.
301
+ numpy_ndarrays : Optional[list[NDArray]] (default: None)
302
+ A list of NumPy arrays. Each array will be automatically converted
303
+ into an :class:`Array` and stored in this record with generated keys.
304
+ torch_state_dict : Optional[OrderedDict[str, torch.Tensor]] (default: None)
305
+ A PyTorch ``state_dict`` (``str`` keys to ``torch.Tensor`` values). Each
306
+ tensor will be converted into an :class:`Array` and stored in this record.
307
+ keep_input : bool (default: True)
308
+ If ``False``, entries from the input are removed after being added to
309
+ this record to free up memory. If ``True``, the input remains unchanged.
310
+ Regardless of this value, no duplicate memory is used if the input is a
311
+ dictionary of :class:`Array`, i.e., ``array_dict``.
245
312
 
246
313
  Examples
247
314
  --------
248
- The usage of :code:`ParametersRecord` is envisioned for storing data arrays (e.g.
249
- parameters of a machine learning model). These first need to be serialized into
250
- a :code:`flwr.common.Array` data structure.
315
+ Initializing an empty ParametersRecord:
316
+
317
+ >>> p_record = ParametersRecord()
318
+
319
+ Initializing with a dictionary of :class:`Array`:
320
+
321
+ >>> arr = Array("float32", [5, 5], "numpy.ndarray", b"serialized_data...")
322
+ >>> p_record = ParametersRecord({"weight": arr})
251
323
 
252
- Let's see some examples:
324
+ Initializing with a list of NumPy arrays:
253
325
 
254
326
  >>> import numpy as np
255
- >>> from flwr.common import ParametersRecord
256
- >>>
257
- >>> # Let's create a simple NumPy array
258
- >>> arr_np = np.random.randn(3, 3)
259
- >>>
260
- >>> # If we print it
261
- >>> array([[-1.84242409, -1.01539537, -0.46528405],
262
- >>> [ 0.32991896, 0.55540414, 0.44085534],
263
- >>> [-0.10758364, 1.97619858, -0.37120501]])
264
- >>>
265
- >>> # Let's create an Array out of it
266
- >>> arr = Array(arr_np)
267
- >>>
268
- >>> # If we print it you'll see (note the binary data)
269
- >>> Array(dtype='float64', shape=[3,3], stype='numpy.ndarray', data=b'@\x99\x18...')
270
- >>>
271
- >>> # Adding it to a ParametersRecord:
272
- >>> p_record = ParametersRecord({"my_array": arr})
273
-
274
- Now that the NumPy array is embedded into a :code:`ParametersRecord` it could be
275
- sent if added as part of a :code:`common.Message` or it could be saved as a
276
- persistent state of a :code:`ClientApp` via its context. Regardless of the usecase,
277
- we will sooner or later want to recover the array in its original NumPy
278
- representation. For the example above, where the array was serialized using the
279
- built-in utility function, deserialization can be done as follows:
280
-
281
- >>> # Use the Array's built-in method
282
- >>> arr_np_d = arr.numpy()
283
- >>>
284
- >>> # If printed, it will show the exact same data as above:
285
- >>> array([[-1.84242409, -1.01539537, -0.46528405],
286
- >>> [ 0.32991896, 0.55540414, 0.44085534],
287
- >>> [-0.10758364, 1.97619858, -0.37120501]])
288
-
289
- If you need finer control on how your arrays are serialized and deserialized, you
290
- can construct :code:`Array` objects directly like this:
291
-
292
- >>> from flwr.common import Array
293
- >>> # Serialize your array and construct Array object
294
- >>> arr = Array(
295
- >>> data=ndarray.tobytes(),
296
- >>> dtype=str(ndarray.dtype),
297
- >>> stype="", # Could be used in a deserialization function
298
- >>> shape=list(ndarray.shape),
299
- >>> )
300
- >>>
301
- >>> # Then you can deserialize it like this
302
- >>> arr_np_d = np.frombuffer(
303
- >>> buffer=array.data,
304
- >>> dtype=array.dtype,
305
- >>> ).reshape(array.shape)
306
-
307
- Note that different arrays (e.g. from PyTorch, Tensorflow) might require different
308
- serialization mechanism. Howerver, they often support a conversion to NumPy,
309
- therefore allowing to use the same or similar steps as in the example above.
327
+ >>> arr1 = np.random.randn(3, 3)
328
+ >>> arr2 = np.random.randn(2, 2)
329
+ >>> p_record = ParametersRecord([arr1, arr2])
330
+
331
+ Initializing with a PyTorch model state_dict:
332
+
333
+ >>> import torch.nn as nn
334
+ >>> model = nn.Linear(10, 5)
335
+ >>> p_record = ParametersRecord(model.state_dict())
336
+
337
+ Initializing with a TensorFlow model weights (a list of NumPy arrays):
338
+
339
+ >>> import tensorflow as tf
340
+ >>> model = tf.keras.Sequential([tf.keras.layers.Dense(5, input_shape=(10,))])
341
+ >>> p_record = ParametersRecord(model.get_weights())
310
342
  """
311
343
 
312
- def __init__(
344
+ @overload
345
+ def __init__(self) -> None: ... # noqa: E704
346
+
347
+ @overload
348
+ def __init__( # noqa: E704
349
+ self, array_dict: OrderedDict[str, Array], *, keep_input: bool = True
350
+ ) -> None: ...
351
+
352
+ @overload
353
+ def __init__( # noqa: E704
354
+ self, numpy_ndarrays: list[NDArray], *, keep_input: bool = True
355
+ ) -> None: ...
356
+
357
+ @overload
358
+ def __init__( # noqa: E704
359
+ self,
360
+ torch_state_dict: OrderedDict[str, torch.Tensor],
361
+ *,
362
+ keep_input: bool = True,
363
+ ) -> None: ...
364
+
365
+ def __init__( # pylint: disable=too-many-arguments
313
366
  self,
367
+ *args: Any,
368
+ numpy_ndarrays: list[NDArray] | None = None,
369
+ torch_state_dict: OrderedDict[str, torch.Tensor] | None = None,
314
370
  array_dict: OrderedDict[str, Array] | None = None,
315
- keep_input: bool = False,
371
+ keep_input: bool = True,
316
372
  ) -> None:
317
373
  super().__init__(_check_key, _check_value)
318
- if array_dict:
319
- for k in list(array_dict.keys()):
320
- self[k] = array_dict[k]
321
- if not keep_input:
322
- del array_dict[k]
374
+
375
+ # Determine the initialization method and validates input arguments.
376
+ # Support the following initialization formats:
377
+ # 1. cls(array_dict: OrderedDict[str, Array], keep_input: bool)
378
+ # 2. cls(numpy_ndarrays: list[NDArray], keep_input: bool)
379
+ # 3. cls(torch_state_dict: dict[str, torch.Tensor], keep_input: bool)
380
+
381
+ # Init the argument
382
+ if len(args) > 1:
383
+ _raise_parameters_record_init_error()
384
+ arg = args[0] if args else None
385
+ init_method: str | None = None # Track which init method is being used
386
+
387
+ # Try to assign a value to arg if it's not already set.
388
+ # If an initialization method is provided, update init_method.
389
+ def _try_set_arg(_arg: Any, method: str) -> None:
390
+ # Skip if _arg is None
391
+ if _arg is None:
392
+ return
393
+ nonlocal arg, init_method
394
+ # Raise an error if arg is already set
395
+ if arg is not None:
396
+ _raise_parameters_record_init_error()
397
+ # Raise an error if a different initialization method is already set
398
+ if init_method is not None:
399
+ _raise_parameters_record_init_error()
400
+ # Set init_method and arg
401
+ if init_method is None:
402
+ init_method = method
403
+ arg = _arg
404
+
405
+ # Try to set keyword arguments
406
+ _try_set_arg(array_dict, "array_dict")
407
+ _try_set_arg(numpy_ndarrays, "numpy_ndarrays")
408
+ _try_set_arg(torch_state_dict, "state_dict")
409
+
410
+ # If no arguments are provided, return and keep self empty
411
+ if arg is None:
412
+ return
413
+
414
+ # Handle dictionary of Arrays
415
+ if not init_method or init_method == "array_dict":
416
+ # Type check the input
417
+ if (
418
+ isinstance(arg, dict)
419
+ and all(isinstance(k, str) for k in arg.keys())
420
+ and all(isinstance(v, Array) for v in arg.values())
421
+ ):
422
+ array_dict = cast(OrderedDict[str, Array], arg)
423
+ converted = self.from_array_dict(array_dict, keep_input=keep_input)
424
+ self.__dict__.update(converted.__dict__)
425
+ return
426
+
427
+ # Handle NumPy ndarrays
428
+ if not init_method or init_method == "numpy_ndarrays":
429
+ # Type check the input
430
+ # pylint: disable-next=not-an-iterable
431
+ if isinstance(arg, list) and all(isinstance(v, np.ndarray) for v in arg):
432
+ numpy_ndarrays = cast(list[NDArray], arg)
433
+ converted = self.from_numpy_ndarrays(
434
+ numpy_ndarrays, keep_input=keep_input
435
+ )
436
+ self.__dict__.update(converted.__dict__)
437
+ return
438
+
439
+ # Handle PyTorch state_dict
440
+ if not init_method or init_method == "state_dict":
441
+ # Type check the input
442
+ if (
443
+ (torch := sys.modules.get("torch")) is not None
444
+ and isinstance(arg, dict)
445
+ and all(isinstance(k, str) for k in arg.keys())
446
+ and all(isinstance(v, torch.Tensor) for v in arg.values())
447
+ ):
448
+ torch_state_dict = cast(
449
+ OrderedDict[str, torch.Tensor], arg # type: ignore
450
+ )
451
+ converted = self.from_torch_state_dict(
452
+ torch_state_dict, keep_input=keep_input
453
+ )
454
+ self.__dict__.update(converted.__dict__)
455
+ return
456
+
457
+ _raise_parameters_record_init_error()
458
+
459
+ @classmethod
460
+ def from_array_dict(
461
+ cls,
462
+ array_dict: OrderedDict[str, Array],
463
+ *,
464
+ keep_input: bool = True,
465
+ ) -> ParametersRecord:
466
+ """Create ParametersRecord from a dictionary of :class:`Array`."""
467
+ record = ParametersRecord()
468
+ for k, v in array_dict.items():
469
+ record[k] = Array(
470
+ dtype=v.dtype, shape=list(v.shape), stype=v.stype, data=v.data
471
+ )
472
+ if not keep_input:
473
+ array_dict.clear()
474
+ return record
475
+
476
+ @classmethod
477
+ def from_numpy_ndarrays(
478
+ cls,
479
+ ndarrays: list[NDArray],
480
+ *,
481
+ keep_input: bool = True,
482
+ ) -> ParametersRecord:
483
+ """Create ParametersRecord from a list of NumPy ``ndarray``."""
484
+ record = ParametersRecord()
485
+ total_serialized_bytes = 0
486
+
487
+ for i in range(len(ndarrays)): # pylint: disable=C0200
488
+ record[str(i)] = Array.from_numpy_ndarray(ndarrays[i])
489
+
490
+ if not keep_input:
491
+ # Remove the reference
492
+ ndarrays[i] = None # type: ignore
493
+ total_serialized_bytes += len(record[str(i)].data)
494
+
495
+ # If total serialized data exceeds the threshold, trigger GC
496
+ if total_serialized_bytes > GC_THRESHOLD:
497
+ total_serialized_bytes = 0
498
+ gc.collect()
499
+
500
+ if not keep_input:
501
+ # Clear the entire list to remove all references and force GC
502
+ ndarrays.clear()
503
+ gc.collect()
504
+ return record
505
+
506
+ @classmethod
507
+ def from_torch_state_dict(
508
+ cls,
509
+ state_dict: OrderedDict[str, torch.Tensor],
510
+ *,
511
+ keep_input: bool = True,
512
+ ) -> ParametersRecord:
513
+ """Create ParametersRecord from PyTorch ``state_dict``."""
514
+ if "torch" not in sys.modules:
515
+ raise RuntimeError(
516
+ f"PyTorch is required to use {cls.from_torch_state_dict.__name__}"
517
+ )
518
+
519
+ record = ParametersRecord()
520
+
521
+ for k in list(state_dict.keys()):
522
+ v = state_dict[k] if keep_input else state_dict.pop(k)
523
+ record[k] = Array.from_numpy_ndarray(v.detach().cpu().numpy())
524
+
525
+ return record
526
+
527
+ def to_numpy_ndarrays(self, *, keep_input: bool = True) -> list[NDArray]:
528
+ """Return the ParametersRecord as a list of NumPy ``ndarray``."""
529
+ if keep_input:
530
+ return [v.numpy() for v in self.values()]
531
+
532
+ # Clear the record and return the list of NumPy arrays
533
+ ret: list[NDArray] = []
534
+ total_serialized_bytes = 0
535
+ for k in list(self.keys()):
536
+ arr = self.pop(k)
537
+ ret.append(arr.numpy())
538
+ total_serialized_bytes += len(arr.data)
539
+ del arr
540
+
541
+ # If total serialized data exceeds the threshold, trigger GC
542
+ if total_serialized_bytes > GC_THRESHOLD:
543
+ total_serialized_bytes = 0
544
+ gc.collect()
545
+
546
+ if not keep_input:
547
+ # Force GC
548
+ gc.collect()
549
+ return ret
550
+
551
+ def to_torch_state_dict(
552
+ self, *, keep_input: bool = True
553
+ ) -> OrderedDict[str, torch.Tensor]:
554
+ """Return the ParametersRecord as a PyTorch ``state_dict``."""
555
+ if not (torch := sys.modules.get("torch")):
556
+ raise RuntimeError(
557
+ f"PyTorch is required to use {self.to_torch_state_dict.__name__}"
558
+ )
559
+
560
+ state_dict = OrderedDict()
561
+
562
+ for k in list(self.keys()):
563
+ arr = self[k] if keep_input else self.pop(k)
564
+ state_dict[k] = torch.from_numpy(arr.numpy())
565
+
566
+ return state_dict
323
567
 
324
568
  def count_bytes(self) -> int:
325
569
  """Return number of Bytes stored in this object.
flwr/server/__init__.py CHANGED
@@ -21,7 +21,7 @@ from .app import start_server as start_server
21
21
  from .client_manager import ClientManager as ClientManager
22
22
  from .client_manager import SimpleClientManager as SimpleClientManager
23
23
  from .compat import LegacyContext as LegacyContext
24
- from .driver import Driver as Driver
24
+ from .grid import Driver as Driver
25
25
  from .history import History as History
26
26
  from .server import Server as Server
27
27
  from .server_app import ServerApp as ServerApp
flwr/server/app.py CHANGED
@@ -79,13 +79,13 @@ from .history import History
79
79
  from .server import Server, init_defaults, run_fl
80
80
  from .server_config import ServerConfig
81
81
  from .strategy import Strategy
82
- from .superlink.driver.serverappio_grpc import run_serverappio_api_grpc
83
82
  from .superlink.ffs.ffs_factory import FfsFactory
84
83
  from .superlink.fleet.grpc_adapter.grpc_adapter_servicer import GrpcAdapterServicer
85
84
  from .superlink.fleet.grpc_bidi.grpc_server import start_grpc_server
86
85
  from .superlink.fleet.grpc_rere.fleet_servicer import FleetServicer
87
86
  from .superlink.fleet.grpc_rere.server_interceptor import AuthenticateServerInterceptor
88
87
  from .superlink.linkstate import LinkStateFactory
88
+ from .superlink.serverappio.serverappio_grpc import run_serverappio_api_grpc
89
89
  from .superlink.simulation.simulationio_grpc import run_simulationio_api_grpc
90
90
 
91
91
  DATABASE = ":flwr-in-memory-state:"
flwr/server/compat/app.py CHANGED
@@ -25,7 +25,7 @@ from flwr.server.server import Server, init_defaults, run_fl
25
25
  from flwr.server.server_config import ServerConfig
26
26
  from flwr.server.strategy import Strategy
27
27
 
28
- from ..driver import Driver
28
+ from ..grid import Driver
29
29
  from .app_utils import start_update_client_manager_thread
30
30
 
31
31
 
@@ -20,8 +20,8 @@ import threading
20
20
  from flwr.common.typing import RunNotRunningException
21
21
 
22
22
  from ..client_manager import ClientManager
23
- from ..compat.driver_client_proxy import DriverClientProxy
24
- from ..driver import Driver
23
+ from ..grid import Driver
24
+ from .grid_client_proxy import DriverClientProxy
25
25
 
26
26
 
27
27
  def start_update_client_manager_thread(
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
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.
@@ -22,7 +22,7 @@ from flwr.common import Message, MessageType, MessageTypeLegacy, RecordSet
22
22
  from flwr.common import recordset_compat as compat
23
23
  from flwr.server.client_proxy import ClientProxy
24
24
 
25
- from ..driver.driver import Driver
25
+ from ..grid.grid import Driver
26
26
 
27
27
 
28
28
  class DriverClientProxy(ClientProxy):
@@ -1,4 +1,4 @@
1
- # Copyright 2022 Flower Labs GmbH. All Rights Reserved.
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,9 +15,9 @@
15
15
  """Flower driver SDK."""
16
16
 
17
17
 
18
- from .driver import Driver
19
- from .grpc_driver import GrpcDriver
20
- from .inmemory_driver import InMemoryDriver
18
+ from .grid import Driver
19
+ from .grpc_grid import GrpcDriver
20
+ from .inmemory_grid import InMemoryDriver
21
21
 
22
22
  __all__ = [
23
23
  "Driver",
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
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.
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
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.
@@ -16,7 +16,6 @@
16
16
 
17
17
 
18
18
  import time
19
- import warnings
20
19
  from collections.abc import Iterable
21
20
  from logging import DEBUG, ERROR, WARNING
22
21
  from typing import Optional, cast
@@ -46,7 +45,7 @@ from flwr.proto.serverappio_pb2 import ( # pylint: disable=E0611
46
45
  )
47
46
  from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub # pylint: disable=E0611
48
47
 
49
- from .driver import Driver
48
+ from .grid import Driver
50
49
 
51
50
  ERROR_MESSAGE_PUSH_MESSAGES_RESOURCE_EXHAUSTED = """
52
51
 
@@ -183,14 +182,6 @@ class GrpcDriver(Driver):
183
182
  This method constructs a new `Message` with given content and metadata.
184
183
  The `run_id` and `src_node_id` will be set automatically.
185
184
  """
186
- if ttl:
187
- warnings.warn(
188
- "A custom TTL was set, but note that the SuperLink does not enforce "
189
- "the TTL yet. The SuperLink will start enforcing the TTL in a future "
190
- "version of Flower.",
191
- stacklevel=2,
192
- )
193
-
194
185
  ttl_ = DEFAULT_TTL if ttl is None else ttl
195
186
  metadata = Metadata(
196
187
  run_id=cast(Run, self._run).run_id,
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
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.
@@ -16,7 +16,6 @@
16
16
 
17
17
 
18
18
  import time
19
- import warnings
20
19
  from collections.abc import Iterable
21
20
  from typing import Optional, cast
22
21
  from uuid import UUID
@@ -27,7 +26,7 @@ from flwr.common.typing import Run
27
26
  from flwr.proto.node_pb2 import Node # pylint: disable=E0611
28
27
  from flwr.server.superlink.linkstate import LinkStateFactory
29
28
 
30
- from .driver import Driver
29
+ from .grid import Driver
31
30
 
32
31
 
33
32
  class InMemoryDriver(Driver):
@@ -88,13 +87,6 @@ class InMemoryDriver(Driver):
88
87
  This method constructs a new `Message` with given content and metadata.
89
88
  The `run_id` and `src_node_id` will be set automatically.
90
89
  """
91
- if ttl:
92
- warnings.warn(
93
- "A custom TTL was set, but note that the SuperLink does not enforce "
94
- "the TTL yet. The SuperLink will start enforcing the TTL in a future "
95
- "version of Flower.",
96
- stacklevel=2,
97
- )
98
90
  ttl_ = DEFAULT_TTL if ttl is None else ttl
99
91
 
100
92
  metadata = Metadata(
@@ -22,7 +22,7 @@ from flwr.common import Context
22
22
  from flwr.common.logger import log
23
23
  from flwr.common.object_ref import load_app
24
24
 
25
- from .driver import Driver
25
+ from .grid import Driver
26
26
  from .server_app import LoadServerAppError, ServerApp
27
27
 
28
28
 
flwr/server/server_app.py CHANGED
@@ -25,7 +25,7 @@ from flwr.server.strategy import Strategy
25
25
 
26
26
  from .client_manager import ClientManager
27
27
  from .compat import start_driver
28
- from .driver import Driver
28
+ from .grid import Driver
29
29
  from .server import Server
30
30
  from .server_config import ServerConfig
31
31
  from .typing import ServerAppCallable, ServerFn
@@ -207,7 +207,7 @@ class ServerApp: # pylint: disable=too-many-instance-attributes
207
207
  """
208
208
 
209
209
  def lifespan_decorator(
210
- lifespan_fn: Callable[[Context], Iterator[None]]
210
+ lifespan_fn: Callable[[Context], Iterator[None]],
211
211
  ) -> Callable[[Context], Iterator[None]]:
212
212
  """Register the lifespan fn with the ServerApp object."""
213
213
 
@@ -60,7 +60,7 @@ from flwr.proto.serverappio_pb2 import ( # pylint: disable=E0611
60
60
  PullServerAppInputsResponse,
61
61
  PushServerAppOutputsRequest,
62
62
  )
63
- from flwr.server.driver.grpc_driver import GrpcDriver
63
+ from flwr.server.grid.grpc_grid import GrpcDriver
64
64
  from flwr.server.run_serverapp import run as run_
65
65
 
66
66
 
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
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.
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
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.
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
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.
flwr/server/typing.py CHANGED
@@ -19,7 +19,7 @@ from typing import Callable
19
19
 
20
20
  from flwr.common import Context
21
21
 
22
- from .driver import Driver
22
+ from .grid import Driver
23
23
  from .serverapp_components import ServerAppComponents
24
24
 
25
25
  ServerAppCallable = Callable[[Driver, Context], None]
@@ -36,7 +36,7 @@ from flwr.common.constant import MessageType, MessageTypeLegacy
36
36
  from ..client_proxy import ClientProxy
37
37
  from ..compat.app_utils import start_update_client_manager_thread
38
38
  from ..compat.legacy_context import LegacyContext
39
- from ..driver import Driver
39
+ from ..grid import Driver
40
40
  from ..typing import Workflow
41
41
  from .constant import MAIN_CONFIGS_RECORD, MAIN_PARAMS_RECORD, Key
42
42
 
@@ -55,7 +55,7 @@ from flwr.common.secure_aggregation.secaggplus_constants import (
55
55
  from flwr.common.secure_aggregation.secaggplus_utils import pseudo_rand_gen
56
56
  from flwr.server.client_proxy import ClientProxy
57
57
  from flwr.server.compat.legacy_context import LegacyContext
58
- from flwr.server.driver import Driver
58
+ from flwr.server.grid import Driver
59
59
 
60
60
  from ..constant import MAIN_CONFIGS_RECORD, MAIN_PARAMS_RECORD
61
61
  from ..constant import Key as WorkflowKey
@@ -39,7 +39,7 @@ from flwr.common.logger import (
39
39
  warn_deprecated_feature_with_example,
40
40
  )
41
41
  from flwr.common.typing import Run, RunStatus, UserConfig
42
- from flwr.server.driver import Driver, InMemoryDriver
42
+ from flwr.server.grid import Driver, InMemoryDriver
43
43
  from flwr.server.run_serverapp import run as _run
44
44
  from flwr.server.server_app import ServerApp
45
45
  from flwr.server.superlink.fleet import vce
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.17.0.dev20250317
3
+ Version: 1.17.0.dev20250318
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -116,7 +116,7 @@ flwr/common/args.py,sha256=2gGT2a3SPJ0-LTNKnhBsZ-ESIoW9FGpw-9xkUSs8qwk,5417
116
116
  flwr/common/auth_plugin/__init__.py,sha256=1Y8Oj3iB49IHDu9tvDih1J74Ygu7k85V9s2A4WORPyA,887
117
117
  flwr/common/auth_plugin/auth_plugin.py,sha256=dQU5U4uJIA5XqgOJ3PankHWq-uXCaMvO74khaMPGdiU,3938
118
118
  flwr/common/config.py,sha256=SAkG3BztnA6iupXxF3GAIpGmWVVCH0ptyMpC9yjr_14,13965
119
- flwr/common/constant.py,sha256=2AHf9ujmfkf9YerhtqBe8hAW6iMDJTmnKnyYdlEXEM0,6875
119
+ flwr/common/constant.py,sha256=PvW7StHhK4QuqyDlDpsvLbCxVGG2Dau6z6s1m8MGvfU,6946
120
120
  flwr/common/context.py,sha256=uJ-mnoC_8y_udEb3kAX-r8CPphNTWM72z1AlsvQEu54,2403
121
121
  flwr/common/date.py,sha256=NHHpESce5wYqEwoDXf09gp9U9l_5Bmlh2BsOcwS-kDM,1554
122
122
  flwr/common/differential_privacy.py,sha256=YA01NqjddKNAEVmf7hXmOVxOjhekgzvJudk3mBGq-2k,6148
@@ -138,7 +138,7 @@ flwr/common/record/__init__.py,sha256=LUixpq0Z-lMJwCIu1-4u5HfvRPjRMRgoAc6YJQ6UEO
138
138
  flwr/common/record/configsrecord.py,sha256=i40jOzBx04ysZKECwaw4FdUXMdY9HgdY8GAqKdTO1Lw,6486
139
139
  flwr/common/record/conversion_utils.py,sha256=ZcsM-vTm_rVtLXLFD2RY3N47V_hUr3ywTdtnpVXnOGU,1202
140
140
  flwr/common/record/metricsrecord.py,sha256=UywkEPbifiu_IyPUFoDJCi8WEVLujlqZERUWAWpc3vs,5752
141
- flwr/common/record/parametersrecord.py,sha256=rR0LbeNrKrdK37CiAA56Z5WBq-ZzZ2YNSUkcmr5i2lI,12950
141
+ flwr/common/record/parametersrecord.py,sha256=EGnpnfw68P22qqbUWuDFjURMqDOvSUkfZGq7lYQLbUI,21597
142
142
  flwr/common/record/recordset.py,sha256=ambtB74uF1pooQTfcBt1_xWsjvyDjGMc6awEt20ur2A,8547
143
143
  flwr/common/record/typeddict.py,sha256=q5hL2xkXymuiCprHWb69mUmLpWQk_XXQq0hGQ69YPaw,3599
144
144
  flwr/common/recordset_compat.py,sha256=ViSwA26h6Q55ZmV1LLjSJpcKiipV-p_JpCj4wxdE-Ow,14230
@@ -213,28 +213,28 @@ flwr/proto/transport_pb2.pyi,sha256=ipHQ03eFBqsxtAuAVefZ2lVr04BZ4YifJCS2eauNmy8,
213
213
  flwr/proto/transport_pb2_grpc.py,sha256=vLN3EHtx2aEEMCO4f1Upu-l27BPzd3-5pV-u8wPcosk,2598
214
214
  flwr/proto/transport_pb2_grpc.pyi,sha256=AGXf8RiIiW2J5IKMlm_3qT3AzcDa4F3P5IqUjve_esA,766
215
215
  flwr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
216
- flwr/server/__init__.py,sha256=cEg1oecBu4cKB69iJCqWEylC8b5XW47bl7rQiJsdTvM,1528
217
- flwr/server/app.py,sha256=yCfZSKCSu2w7jJYIj-dpF0inyPpsY-KkjgVcmMVcZiY,33614
216
+ flwr/server/__init__.py,sha256=ISimHyzdi2Xnh-WObEdqOwRmhZ7xZzgqWddcq9ixZ3M,1526
217
+ flwr/server/app.py,sha256=Hc5FIcGPoeKk7D2Mqp-qgDJUHh-I3uAWG7MDuqeasUo,33619
218
218
  flwr/server/client_manager.py,sha256=7Ese0tgrH-i-ms363feYZJKwB8gWnXSmg_hYF2Bju4U,6227
219
219
  flwr/server/client_proxy.py,sha256=4G-oTwhb45sfWLx2uZdcXD98IZwdTS6F88xe3akCdUg,2399
220
220
  flwr/server/compat/__init__.py,sha256=VxnJtJyOjNFQXMNi9hIuzNlZM5n0Hj1p3aq_Pm2udw4,892
221
- flwr/server/compat/app.py,sha256=Y0xAqXLn20e6XKGb2nHdeUYdCj_Dux-SyFCc-5ivhqk,3369
222
- flwr/server/compat/app_utils.py,sha256=568PfvPME8KHjX-L5GB2rYQa_Wy8iUBGs22KJqn8Xk0,3824
223
- flwr/server/compat/driver_client_proxy.py,sha256=1ElUYvn85iMbxfyjbPiGGlmdWzNqKIIgrGJgZ18uS4E,4964
221
+ flwr/server/compat/app.py,sha256=dBxWAkPy4Bc1ExDemdDaZt3xu5osVSOur0YvETgQT4w,3367
222
+ flwr/server/compat/app_utils.py,sha256=fTuoCe-3IAgHRhbIy2JL0M2_v_jR6HwAAs6R2yZ7uPQ,3812
223
+ flwr/server/compat/grid_client_proxy.py,sha256=fiibkMOk_gbX1SMm16H5DPwpjirD5uq423wMn56b_bQ,4960
224
224
  flwr/server/compat/legacy_context.py,sha256=wBzBcfV6YO6IQGriM_FdJ5XZfiBBEEJdS_OdAiF47dY,1804
225
225
  flwr/server/criterion.py,sha256=ypbAexbztzGUxNen9RCHF91QeqiEQix4t4Ih3E-42MM,1061
226
- flwr/server/driver/__init__.py,sha256=bikRv6CjTwSvYh7tf10gziU5o2YotOWhhftz2tr3KDc,886
227
- flwr/server/driver/driver.py,sha256=X072eFWl8Kx-aZbahTkpAc1wwoojr8A4uO2yozwwSbE,5705
228
- flwr/server/driver/grpc_driver.py,sha256=rbSqFhT2ULLQhgIeX24Yt1wZje4bzV4EUoOmbIuVYro,11507
229
- flwr/server/driver/inmemory_driver.py,sha256=p6p9RykDfoty94izzD4i11Xp7A8t1KUaHpbKbbVZAdU,6407
230
226
  flwr/server/fleet_event_log_interceptor.py,sha256=AkL7Y5d3xm2vRhL3ahmEVVoOvAP7PA7dRgB-je4v-Ys,3774
227
+ flwr/server/grid/__init__.py,sha256=AiZbyU5kWlpjmI-eDWqztz6EBKoTm0kvRphydiibi08,880
228
+ flwr/server/grid/grid.py,sha256=fnHtnReACB7aUxcWmbGfI2elHsk5HOp7q8BpbwWMfvc,5705
229
+ flwr/server/grid/grpc_grid.py,sha256=OR9AxXn1YI5SilROntnpduoOoZzE3eDjM-JCqetHfHM,11190
230
+ flwr/server/grid/inmemory_grid.py,sha256=ClnJwdFTnTyAKN7M2jsd2ZKArgslySkcwFab2kXAND0,6091
231
231
  flwr/server/history.py,sha256=qSb5_pPTrwofpSYGsZWzMPkl_4uJ4mJFWesxXDrEvDU,5026
232
- flwr/server/run_serverapp.py,sha256=tyAYB5UEiUd63VG4XiYBUUiivh77SpIol1cGS4xtYdk,2077
232
+ flwr/server/run_serverapp.py,sha256=LxHIeMLKXbzt2V5vK2x8wJLZt1dQ_0YiMD1lP0PZ27I,2075
233
233
  flwr/server/server.py,sha256=1ZsFEptmAV-L2vP2etNC9Ed5CLSxpuKzUFkAPQ4l5Xc,17893
234
- flwr/server/server_app.py,sha256=y6v1WEE7fkJbO9VNGafznm3QfUM3ifpdBcgauKmB4hU,8857
234
+ flwr/server/server_app.py,sha256=WOCUOB_Onf_p5qp_QBaRu-LmsMpFIn-Hd4HcWIxN1YE,8856
235
235
  flwr/server/server_config.py,sha256=CZaHVAsMvGLjpWVcLPkiYxgJN4xfIyAiUrCI3fETKY4,1349
236
236
  flwr/server/serverapp/__init__.py,sha256=L0K-94UDdTyEZ8LDtYybGIIIv3HW6AhSVjXMUfYJQnQ,800
237
- flwr/server/serverapp/app.py,sha256=5nFRYYzC2vh0l1fKJofBfKwFam93In4b80wvH9eFfQ8,8651
237
+ flwr/server/serverapp/app.py,sha256=NoBpAokHP5-Gw8-wrm0H1Pqf_VXZLs9yp7RM13f4I9Y,8647
238
238
  flwr/server/serverapp_components.py,sha256=-IV_CitOfrJclJj2jNdbN1Q65PyFmtKtrTIg1hc6WQw,2118
239
239
  flwr/server/strategy/__init__.py,sha256=tQer2SwjDnvgFFuJMZM-S01Z615N5XK6MaCvpm4BMU0,2836
240
240
  flwr/server/strategy/aggregate.py,sha256=PDvekufza13s9AsVmz9WASunaBs3yCtl8JVliFx9j6Q,13978
@@ -261,9 +261,6 @@ flwr/server/strategy/krum.py,sha256=Gct2OdnvZEnCPKMyIC330baOKabpDrKiCfVXIkr4S0c,
261
261
  flwr/server/strategy/qfedavg.py,sha256=2ijNNc2vVODWLAaoYo9PCoaFvlanq0lbJ7I7Albdudg,10131
262
262
  flwr/server/strategy/strategy.py,sha256=cXapkD5uDrt5C-RbmWDn9FLoap3Q41i7GKvbmfbCKtk,7524
263
263
  flwr/server/superlink/__init__.py,sha256=8tHYCfodUlRD8PCP9fHgvu8cz5N31A2QoRVL0jDJ15E,707
264
- flwr/server/superlink/driver/__init__.py,sha256=5soEK5QSvxNjmJQ-CGTWROc4alSAeU0e9Ad9RDhsd3E,717
265
- flwr/server/superlink/driver/serverappio_grpc.py,sha256=UzHwo6qYZMeOhr7nn1iZbcyDSmwvnq_kpYH0mEAndW0,2173
266
- flwr/server/superlink/driver/serverappio_servicer.py,sha256=Y-L0SiaP1p4yEi6r6MWOMiW10nsu_TlAcj_0miaEYSo,13121
267
264
  flwr/server/superlink/ffs/__init__.py,sha256=FAY-zShcfPmOxosok2QyT6hTNMNctG8cH9s_nIl8jkI,840
268
265
  flwr/server/superlink/ffs/disk_ffs.py,sha256=n_Ah0sQwXGVQ9wj5965nLjdkQQbpoHCljjXKFnwftsU,3297
269
266
  flwr/server/superlink/ffs/ffs.py,sha256=qLI1UfosJugu2BKOJWqHIhafTm-YiuKqGf3OGWPH0NM,2395
@@ -294,20 +291,23 @@ flwr/server/superlink/linkstate/linkstate.py,sha256=YB3SryGNvt-bE-unYjoloJt9d3xA
294
291
  flwr/server/superlink/linkstate/linkstate_factory.py,sha256=ISSMjDlwuN7swxjOeYlTNpI_kuZ8PGkMcJnf1dbhUSE,2069
295
292
  flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=Wsx5gD6WRIMLlKarvVV1_dlS7jmfno-yTVW1-rgcIto,38276
296
293
  flwr/server/superlink/linkstate/utils.py,sha256=b26MJdMQyt83EDnhB7FAiq8BFttV_qNHF_E_3d3oBlA,12739
294
+ flwr/server/superlink/serverappio/__init__.py,sha256=Fy4zJuoccZe5mZSEIpOmQvU6YeXFBa1M4eZuXXmJcn8,717
295
+ flwr/server/superlink/serverappio/serverappio_grpc.py,sha256=opJ6SYwIAbu4NWEo3K-VxFO-tMSFmE4H3i2HwHIVRzw,2173
296
+ flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=71s1SijefpTpJC2mZD3Y0CZBK9PtK0Yxc4aXawdvEDQ,13121
297
297
  flwr/server/superlink/simulation/__init__.py,sha256=mg-oapC9dkzEfjXPQFior5lpWj4g9kwbLovptyYM_g0,718
298
298
  flwr/server/superlink/simulation/simulationio_grpc.py,sha256=8aUrZZLdvprKUfLLqFID4aItus9beU6m1qLQYIPB7k0,2224
299
299
  flwr/server/superlink/simulation/simulationio_servicer.py,sha256=J_TmdqM-Bxgp-iPEI3tvCuBpykw1UX0FouMQalEYAF4,6907
300
300
  flwr/server/superlink/utils.py,sha256=KVb3K_g2vYfu9TnftcN0ewmev133WZcjuEePMm8d7GE,2137
301
- flwr/server/typing.py,sha256=5kaRLZuxTEse9A0g7aVna2VhYxU3wTq1f3d3mtw7kXs,1019
301
+ flwr/server/typing.py,sha256=Xhcda1Bg2w8C2nZAdoMWsZqQibzJrnLBP60yzyRa7QE,1017
302
302
  flwr/server/utils/__init__.py,sha256=vnS9EAyVUsBOmWeYZXMoBcjeEFhqN4_KQQVk5EBiWG0,884
303
303
  flwr/server/utils/tensorboard.py,sha256=gEBD8w_5uaIfp5aw5RYH66lYZpd_SfkObHQ7eDd9MUk,5466
304
304
  flwr/server/utils/validator.py,sha256=11olMv1UyeaxLa1ci5gsJ0WALk7VwWGCQYCvLsZ56LY,3604
305
305
  flwr/server/workflow/__init__.py,sha256=SXY0XkwbkezFBxxrFB5hKUtmtAgnYISBkPouR1V71ss,902
306
306
  flwr/server/workflow/constant.py,sha256=q4DLdR8Krlxuewq2AQjwTL75hphxE5ODNz4AhViHMXk,1082
307
- flwr/server/workflow/default_workflows.py,sha256=RwDX7hXOI1-q4FH9A0onHvadqa5yXTzslpmShPpXodk,14152
307
+ flwr/server/workflow/default_workflows.py,sha256=2c_T5NxjIn--zBWAcVWLKHJ9001qV92nCGNvbok_ooo,14150
308
308
  flwr/server/workflow/secure_aggregation/__init__.py,sha256=3XlgDOjD_hcukTGl6Bc1B-8M_dPlVSJuTbvXIbiO-Ic,880
309
309
  flwr/server/workflow/secure_aggregation/secagg_workflow.py,sha256=l2IdMdJjs1bgHs5vQgLSOVzar7v2oxUn46oCrnVE1rM,5839
310
- flwr/server/workflow/secure_aggregation/secaggplus_workflow.py,sha256=acfqyzOebe0WvXG2Z7yd7WtEtGJI3eNK2f0d_kjSdnM,29623
310
+ flwr/server/workflow/secure_aggregation/secaggplus_workflow.py,sha256=SmZnmmQv4D85NwqFhXfycrgSxZ3sGLJCdbI4bUKhM3E,29621
311
311
  flwr/simulation/__init__.py,sha256=5UcDVJNjFoSwWqHbGM1hKfTTUUNdwAtuoNvNrfvdkUY,1556
312
312
  flwr/simulation/app.py,sha256=xRVSJBnTXQUqWIYOzENfTnJlZ24CSNhWkhVEFxIu4I0,9758
313
313
  flwr/simulation/legacy_app.py,sha256=qpZI4Vvzr5TyWSLTRrMP-jN4rH2C25JI9nVSSjhFwSQ,15861
@@ -315,7 +315,7 @@ flwr/simulation/ray_transport/__init__.py,sha256=wzcEEwUUlulnXsg6raCA1nGpP3LlAQD
315
315
  flwr/simulation/ray_transport/ray_actor.py,sha256=k11yoAPQzFGQU-KnCCP0ZrfPPdUPXXrBe-1DKM5VdW4,18997
316
316
  flwr/simulation/ray_transport/ray_client_proxy.py,sha256=2vjOKoom3B74C6XU-jC3N6DwYmsLdB-lmkHZ_Xrv96o,7367
317
317
  flwr/simulation/ray_transport/utils.py,sha256=wtbQhKQ4jGoiQDLJNQP17m1DSfL22ERhDBGuoeUFaAQ,2393
318
- flwr/simulation/run_simulation.py,sha256=KFpdL_RxE8NHZ68ZdghmFS6rccmWkO_iQ-kLLE1WUn8,20336
318
+ flwr/simulation/run_simulation.py,sha256=SmhU83eQKwGcf4qZy4drXptGRhGQHNd38LpK0qrOvUU,20334
319
319
  flwr/simulation/simulationio_connection.py,sha256=lcbEmdjb9RVEF2W5vSbf_J1zlTuv_ZAT_HLox1mqcfY,3494
320
320
  flwr/superexec/__init__.py,sha256=fcj366jh4RFby_vDwLroU4kepzqbnJgseZD_jUr_Mko,715
321
321
  flwr/superexec/app.py,sha256=C0T2LMjuyF__I5V1FKfjtWtbsQPxK_EgL4vuhWIwG8s,1465
@@ -326,8 +326,8 @@ flwr/superexec/exec_servicer.py,sha256=4UpzJqPUHkBG2PZNe2lrX7XFVDOL6yw_HcoBHxuXE
326
326
  flwr/superexec/exec_user_auth_interceptor.py,sha256=2kXjjJcrZyff893QTFLQD6zxC4pdVwtN4Rc66jHptfE,4440
327
327
  flwr/superexec/executor.py,sha256=_B55WW2TD1fBINpabSSDRenVHXYmvlfhv-k8hJKU4lQ,3115
328
328
  flwr/superexec/simulation.py,sha256=WQDon15oqpMopAZnwRZoTICYCfHqtkvFSqiTQ2hLD_g,4088
329
- flwr_nightly-1.17.0.dev20250317.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
330
- flwr_nightly-1.17.0.dev20250317.dist-info/METADATA,sha256=BK-20xmip40rp16IosnE5QCL4tnXqfYn0Td2M8Crka8,15878
331
- flwr_nightly-1.17.0.dev20250317.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
332
- flwr_nightly-1.17.0.dev20250317.dist-info/entry_points.txt,sha256=2-1L-GNKhwGw2_7_RoH55vHw2SIHjdAQy3HAVAWl9PY,374
333
- flwr_nightly-1.17.0.dev20250317.dist-info/RECORD,,
329
+ flwr_nightly-1.17.0.dev20250318.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
330
+ flwr_nightly-1.17.0.dev20250318.dist-info/METADATA,sha256=b0bYyeMvfyIYiTRIxjtTqkYBBt2zsXMF_J8XhVGEuAc,15878
331
+ flwr_nightly-1.17.0.dev20250318.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
332
+ flwr_nightly-1.17.0.dev20250318.dist-info/entry_points.txt,sha256=2-1L-GNKhwGw2_7_RoH55vHw2SIHjdAQy3HAVAWl9PY,374
333
+ flwr_nightly-1.17.0.dev20250318.dist-info/RECORD,,