flwr-nightly 1.16.0.dev20250224__py3-none-any.whl → 1.16.0.dev20250226__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/client/client_app.py +53 -6
- flwr/common/address.py +35 -0
- flwr/common/record/conversion_utils.py +8 -17
- flwr/common/record/parametersrecord.py +151 -16
- {flwr_nightly-1.16.0.dev20250224.dist-info → flwr_nightly-1.16.0.dev20250226.dist-info}/METADATA +1 -1
- {flwr_nightly-1.16.0.dev20250224.dist-info → flwr_nightly-1.16.0.dev20250226.dist-info}/RECORD +9 -9
- {flwr_nightly-1.16.0.dev20250224.dist-info → flwr_nightly-1.16.0.dev20250226.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.16.0.dev20250224.dist-info → flwr_nightly-1.16.0.dev20250226.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.16.0.dev20250224.dist-info → flwr_nightly-1.16.0.dev20250226.dist-info}/entry_points.txt +0 -0
flwr/client/client_app.py
CHANGED
@@ -159,11 +159,15 @@ class ClientApp:
|
|
159
159
|
# Message type did not match one of the known message types abvoe
|
160
160
|
raise ValueError(f"Unknown message_type: {message.metadata.message_type}")
|
161
161
|
|
162
|
-
def train(
|
162
|
+
def train(
|
163
|
+
self, mods: Optional[list[Mod]] = None
|
164
|
+
) -> Callable[[ClientAppCallable], ClientAppCallable]:
|
163
165
|
"""Return a decorator that registers the train fn with the client app.
|
164
166
|
|
165
167
|
Examples
|
166
168
|
--------
|
169
|
+
Registering a train function:
|
170
|
+
|
167
171
|
>>> app = ClientApp()
|
168
172
|
>>>
|
169
173
|
>>> @app.train()
|
@@ -171,6 +175,17 @@ class ClientApp:
|
|
171
175
|
>>> print("ClientApp training running")
|
172
176
|
>>> # Create and return an echo reply message
|
173
177
|
>>> return message.create_reply(content=message.content())
|
178
|
+
|
179
|
+
Registering a train function with a function-specific modifier:
|
180
|
+
|
181
|
+
>>> from flwr.client.mod import message_size_mod
|
182
|
+
>>>
|
183
|
+
>>> app = ClientApp()
|
184
|
+
>>>
|
185
|
+
>>> @app.train(mods=[message_size_mod])
|
186
|
+
>>> def train(message: Message, context: Context) -> Message:
|
187
|
+
>>> print("ClientApp training running with message size mod")
|
188
|
+
>>> return message.create_reply(content=message.content())
|
174
189
|
"""
|
175
190
|
|
176
191
|
def train_decorator(train_fn: ClientAppCallable) -> ClientAppCallable:
|
@@ -182,18 +197,22 @@ class ClientApp:
|
|
182
197
|
|
183
198
|
# Register provided function with the ClientApp object
|
184
199
|
# Wrap mods around the wrapped step function
|
185
|
-
self._train = make_ffn(train_fn, self._mods)
|
200
|
+
self._train = make_ffn(train_fn, self._mods + (mods or []))
|
186
201
|
|
187
202
|
# Return provided function unmodified
|
188
203
|
return train_fn
|
189
204
|
|
190
205
|
return train_decorator
|
191
206
|
|
192
|
-
def evaluate(
|
207
|
+
def evaluate(
|
208
|
+
self, mods: Optional[list[Mod]] = None
|
209
|
+
) -> Callable[[ClientAppCallable], ClientAppCallable]:
|
193
210
|
"""Return a decorator that registers the evaluate fn with the client app.
|
194
211
|
|
195
212
|
Examples
|
196
213
|
--------
|
214
|
+
Registering an evaluate function:
|
215
|
+
|
197
216
|
>>> app = ClientApp()
|
198
217
|
>>>
|
199
218
|
>>> @app.evaluate()
|
@@ -201,6 +220,18 @@ class ClientApp:
|
|
201
220
|
>>> print("ClientApp evaluation running")
|
202
221
|
>>> # Create and return an echo reply message
|
203
222
|
>>> return message.create_reply(content=message.content())
|
223
|
+
|
224
|
+
Registering an evaluate function with a function-specific modifier:
|
225
|
+
|
226
|
+
>>> from flwr.client.mod import message_size_mod
|
227
|
+
>>>
|
228
|
+
>>> app = ClientApp()
|
229
|
+
>>>
|
230
|
+
>>> @app.evaluate(mods=[message_size_mod])
|
231
|
+
>>> def evaluate(message: Message, context: Context) -> Message:
|
232
|
+
>>> print("ClientApp evaluation running with message size mod")
|
233
|
+
>>> # Create and return an echo reply message
|
234
|
+
>>> return message.create_reply(content=message.content())
|
204
235
|
"""
|
205
236
|
|
206
237
|
def evaluate_decorator(evaluate_fn: ClientAppCallable) -> ClientAppCallable:
|
@@ -212,18 +243,22 @@ class ClientApp:
|
|
212
243
|
|
213
244
|
# Register provided function with the ClientApp object
|
214
245
|
# Wrap mods around the wrapped step function
|
215
|
-
self._evaluate = make_ffn(evaluate_fn, self._mods)
|
246
|
+
self._evaluate = make_ffn(evaluate_fn, self._mods + (mods or []))
|
216
247
|
|
217
248
|
# Return provided function unmodified
|
218
249
|
return evaluate_fn
|
219
250
|
|
220
251
|
return evaluate_decorator
|
221
252
|
|
222
|
-
def query(
|
253
|
+
def query(
|
254
|
+
self, mods: Optional[list[Mod]] = None
|
255
|
+
) -> Callable[[ClientAppCallable], ClientAppCallable]:
|
223
256
|
"""Return a decorator that registers the query fn with the client app.
|
224
257
|
|
225
258
|
Examples
|
226
259
|
--------
|
260
|
+
Registering a query function:
|
261
|
+
|
227
262
|
>>> app = ClientApp()
|
228
263
|
>>>
|
229
264
|
>>> @app.query()
|
@@ -231,6 +266,18 @@ class ClientApp:
|
|
231
266
|
>>> print("ClientApp query running")
|
232
267
|
>>> # Create and return an echo reply message
|
233
268
|
>>> return message.create_reply(content=message.content())
|
269
|
+
|
270
|
+
Registering a query function with a function-specific modifier:
|
271
|
+
|
272
|
+
>>> from flwr.client.mod import message_size_mod
|
273
|
+
>>>
|
274
|
+
>>> app = ClientApp()
|
275
|
+
>>>
|
276
|
+
>>> @app.query(mods=[message_size_mod])
|
277
|
+
>>> def query(message: Message, context: Context) -> Message:
|
278
|
+
>>> print("ClientApp query running with message size mod")
|
279
|
+
>>> # Create and return an echo reply message
|
280
|
+
>>> return message.create_reply(content=message.content())
|
234
281
|
"""
|
235
282
|
|
236
283
|
def query_decorator(query_fn: ClientAppCallable) -> ClientAppCallable:
|
@@ -242,7 +289,7 @@ class ClientApp:
|
|
242
289
|
|
243
290
|
# Register provided function with the ClientApp object
|
244
291
|
# Wrap mods around the wrapped step function
|
245
|
-
self._query = make_ffn(query_fn, self._mods)
|
292
|
+
self._query = make_ffn(query_fn, self._mods + (mods or []))
|
246
293
|
|
247
294
|
# Return provided function unmodified
|
248
295
|
return query_fn
|
flwr/common/address.py
CHANGED
@@ -15,10 +15,13 @@
|
|
15
15
|
"""Flower IP address utils."""
|
16
16
|
|
17
17
|
|
18
|
+
import re
|
18
19
|
import socket
|
19
20
|
from ipaddress import ip_address
|
20
21
|
from typing import Optional
|
21
22
|
|
23
|
+
import grpc
|
24
|
+
|
22
25
|
IPV6: int = 6
|
23
26
|
|
24
27
|
|
@@ -101,3 +104,35 @@ def is_port_in_use(address: str) -> bool:
|
|
101
104
|
return True
|
102
105
|
|
103
106
|
return False
|
107
|
+
|
108
|
+
|
109
|
+
def get_ip_address_from_servicer_context(context: grpc.ServicerContext) -> str:
|
110
|
+
"""Extract the client's IPv4 or IPv6 address from the gRPC ServicerContext.
|
111
|
+
|
112
|
+
Parameters
|
113
|
+
----------
|
114
|
+
context : grpc.ServicerContext
|
115
|
+
The gRPC ServicerContext object. The context.peer() returns a string like
|
116
|
+
"ipv4:127.0.0.1:56789" for IPv4 and "ipv6:[2001:db8::1]:54321" for IPv6.
|
117
|
+
|
118
|
+
Returns
|
119
|
+
-------
|
120
|
+
str
|
121
|
+
If one of the format matches, the function will return the client's IP address,
|
122
|
+
otherwise, it will raise a ValueError.
|
123
|
+
"""
|
124
|
+
peer: str = context.peer()
|
125
|
+
# Match IPv4: "ipv4:IP:port"
|
126
|
+
ipv4_match = re.match(r"^ipv4:(?P<ip>[^:]+):", peer)
|
127
|
+
if ipv4_match:
|
128
|
+
return ipv4_match.group("ip")
|
129
|
+
|
130
|
+
# Match IPv6: "ipv6:[IP]:port"
|
131
|
+
ipv6_match = re.match(r"^ipv6:\[(?P<ip>[^\]]+)\]:", peer)
|
132
|
+
if ipv6_match:
|
133
|
+
return ipv6_match.group("ip")
|
134
|
+
|
135
|
+
raise ValueError(
|
136
|
+
f"Unsupported peer address format: {peer} for the transport protocol. "
|
137
|
+
"The supported formats are ipv4:IP:port and ipv6:[IP]:port."
|
138
|
+
)
|
@@ -15,26 +15,17 @@
|
|
15
15
|
"""Conversion utility functions for Records."""
|
16
16
|
|
17
17
|
|
18
|
-
from
|
19
|
-
|
20
|
-
import numpy as np
|
21
|
-
|
22
|
-
from ..constant import SType
|
18
|
+
from ..logger import warn_deprecated_feature
|
23
19
|
from ..typing import NDArray
|
24
20
|
from .parametersrecord import Array
|
25
21
|
|
22
|
+
WARN_DEPRECATED_MESSAGE = (
|
23
|
+
"`array_from_numpy` is deprecated. Instead, use the `Array(ndarray)` class "
|
24
|
+
"directly or `Array.from_numpy_ndarray(ndarray)`."
|
25
|
+
)
|
26
|
+
|
26
27
|
|
27
28
|
def array_from_numpy(ndarray: NDArray) -> Array:
|
28
29
|
"""Create Array from NumPy ndarray."""
|
29
|
-
|
30
|
-
|
31
|
-
# Reason: loading pickled data can execute arbitrary code
|
32
|
-
# Source: https://numpy.org/doc/stable/reference/generated/numpy.save.html
|
33
|
-
np.save(buffer, ndarray, allow_pickle=False)
|
34
|
-
data = buffer.getvalue()
|
35
|
-
return Array(
|
36
|
-
dtype=str(ndarray.dtype),
|
37
|
-
shape=list(ndarray.shape),
|
38
|
-
stype=SType.NUMPY,
|
39
|
-
data=data,
|
40
|
-
)
|
30
|
+
warn_deprecated_feature(WARN_DEPRECATED_MESSAGE)
|
31
|
+
return Array.from_numpy_ndarray(ndarray)
|
@@ -15,10 +15,12 @@
|
|
15
15
|
"""ParametersRecord and Array."""
|
16
16
|
|
17
17
|
|
18
|
+
from __future__ import annotations
|
19
|
+
|
18
20
|
from collections import OrderedDict
|
19
21
|
from dataclasses import dataclass
|
20
22
|
from io import BytesIO
|
21
|
-
from typing import
|
23
|
+
from typing import Any, cast, overload
|
22
24
|
|
23
25
|
import numpy as np
|
24
26
|
|
@@ -27,29 +29,64 @@ from ..typing import NDArray
|
|
27
29
|
from .typeddict import TypedDict
|
28
30
|
|
29
31
|
|
32
|
+
def _raise_array_init_error() -> None:
|
33
|
+
raise TypeError(
|
34
|
+
f"Invalid arguments for {Array.__qualname__}. Expected either a "
|
35
|
+
"NumPy ndarray, or explicit dtype/shape/stype/data values."
|
36
|
+
)
|
37
|
+
|
38
|
+
|
30
39
|
@dataclass
|
31
40
|
class Array:
|
32
41
|
"""Array type.
|
33
42
|
|
34
43
|
A dataclass containing serialized data from an array-like or tensor-like object
|
35
|
-
along with
|
44
|
+
along with metadata about it. The class can be initialized in one of two ways:
|
45
|
+
|
46
|
+
1. By specifying explicit values for `dtype`, `shape`, `stype`, and `data`.
|
47
|
+
2. By providing a NumPy ndarray (via the `ndarray` argument).
|
48
|
+
|
49
|
+
In scenario (2), the `dtype`, `shape`, `stype`, and `data` are automatically
|
50
|
+
derived from the input. In scenario (1), these fields must be specified manually.
|
36
51
|
|
37
52
|
Parameters
|
38
53
|
----------
|
39
|
-
dtype : str
|
40
|
-
A string representing the data type of the
|
54
|
+
dtype : Optional[str] (default: None)
|
55
|
+
A string representing the data type of the serialized object (e.g. `"float32"`).
|
56
|
+
Only required if you are not passing in a ndarray.
|
41
57
|
|
42
|
-
shape :
|
43
|
-
A list representing the shape of the unserialized array-like object.
|
44
|
-
|
45
|
-
as a metadata field.
|
58
|
+
shape : Optional[list[int]] (default: None)
|
59
|
+
A list representing the shape of the unserialized array-like object. Only
|
60
|
+
required if you are not passing in a ndarray.
|
46
61
|
|
47
|
-
stype : str
|
48
|
-
A string indicating the
|
49
|
-
|
62
|
+
stype : Optional[str] (default: None)
|
63
|
+
A string indicating the serialization mechanism used to generate the bytes in
|
64
|
+
`data` from an array-like or tensor-like object. Only required if you are not
|
65
|
+
passing in a ndarray.
|
50
66
|
|
51
|
-
data: bytes
|
52
|
-
A buffer of bytes containing the data.
|
67
|
+
data : Optional[bytes] (default: None)
|
68
|
+
A buffer of bytes containing the data. Only required if you are not passing in
|
69
|
+
a ndarray.
|
70
|
+
|
71
|
+
ndarray : Optional[NDArray] (default: None)
|
72
|
+
A NumPy ndarray. If provided, the `dtype`, `shape`, `stype`, and `data`
|
73
|
+
fields are derived automatically from it.
|
74
|
+
|
75
|
+
Examples
|
76
|
+
--------
|
77
|
+
Initializing by specifying all fields directly:
|
78
|
+
|
79
|
+
>>> arr1 = Array(
|
80
|
+
>>> dtype="float32",
|
81
|
+
>>> shape=[3, 3],
|
82
|
+
>>> stype="numpy.ndarray",
|
83
|
+
>>> data=b"serialized_data...",
|
84
|
+
>>> )
|
85
|
+
|
86
|
+
Initializing with a NumPy ndarray:
|
87
|
+
|
88
|
+
>>> import numpy as np
|
89
|
+
>>> arr2 = Array(np.random.randn(3, 3))
|
53
90
|
"""
|
54
91
|
|
55
92
|
dtype: str
|
@@ -57,6 +94,105 @@ class Array:
|
|
57
94
|
stype: str
|
58
95
|
data: bytes
|
59
96
|
|
97
|
+
@overload
|
98
|
+
def __init__( # noqa: E704
|
99
|
+
self, dtype: str, shape: list[int], stype: str, data: bytes
|
100
|
+
) -> None: ...
|
101
|
+
|
102
|
+
@overload
|
103
|
+
def __init__(self, ndarray: NDArray) -> None: ... # noqa: E704
|
104
|
+
|
105
|
+
def __init__( # pylint: disable=too-many-arguments, too-many-locals
|
106
|
+
self,
|
107
|
+
*args: Any,
|
108
|
+
dtype: str | None = None,
|
109
|
+
shape: list[int] | None = None,
|
110
|
+
stype: str | None = None,
|
111
|
+
data: bytes | None = None,
|
112
|
+
ndarray: NDArray | None = None,
|
113
|
+
) -> None:
|
114
|
+
# Determine the initialization method and validate input arguments.
|
115
|
+
# Support two initialization formats:
|
116
|
+
# 1. Array(dtype: str, shape: list[int], stype: str, data: bytes)
|
117
|
+
# 2. Array(ndarray: NDArray)
|
118
|
+
|
119
|
+
# Initialize all arguments
|
120
|
+
# If more than 4 positional arguments are provided, raise an error.
|
121
|
+
if len(args) > 4:
|
122
|
+
_raise_array_init_error()
|
123
|
+
all_args = [None] * 4
|
124
|
+
for i, arg in enumerate(args):
|
125
|
+
all_args[i] = arg
|
126
|
+
init_method: str | None = None # Track which init method is being used
|
127
|
+
|
128
|
+
# Try to assign a value to all_args[index] if it's not already set.
|
129
|
+
# If an initialization method is provided, update init_method.
|
130
|
+
def _try_set_arg(index: int, arg: Any, method: str) -> None:
|
131
|
+
# Skip if arg is None
|
132
|
+
if arg is None:
|
133
|
+
return
|
134
|
+
# Raise an error if all_args[index] is already set
|
135
|
+
if all_args[index] is not None:
|
136
|
+
_raise_array_init_error()
|
137
|
+
# Raise an error if a different initialization method is already set
|
138
|
+
nonlocal init_method
|
139
|
+
if init_method is not None and init_method != method:
|
140
|
+
_raise_array_init_error()
|
141
|
+
# Set init_method and all_args[index]
|
142
|
+
if init_method is None:
|
143
|
+
init_method = method
|
144
|
+
all_args[index] = arg
|
145
|
+
|
146
|
+
# Try to set keyword arguments in all_args
|
147
|
+
_try_set_arg(0, dtype, "direct")
|
148
|
+
_try_set_arg(1, shape, "direct")
|
149
|
+
_try_set_arg(2, stype, "direct")
|
150
|
+
_try_set_arg(3, data, "direct")
|
151
|
+
_try_set_arg(0, ndarray, "ndarray")
|
152
|
+
|
153
|
+
# Check if all arguments are correctly set
|
154
|
+
all_args = [arg for arg in all_args if arg is not None]
|
155
|
+
|
156
|
+
# Handle direct field initialization
|
157
|
+
if not init_method or init_method == "direct":
|
158
|
+
if (
|
159
|
+
len(all_args) == 4 # pylint: disable=too-many-boolean-expressions
|
160
|
+
and isinstance(all_args[0], str)
|
161
|
+
and isinstance(all_args[1], list)
|
162
|
+
and all(isinstance(i, int) for i in all_args[1])
|
163
|
+
and isinstance(all_args[2], str)
|
164
|
+
and isinstance(all_args[3], bytes)
|
165
|
+
):
|
166
|
+
self.dtype, self.shape, self.stype, self.data = all_args
|
167
|
+
return
|
168
|
+
|
169
|
+
# Handle NumPy array
|
170
|
+
if not init_method or init_method == "ndarray":
|
171
|
+
if len(all_args) == 1 and isinstance(all_args[0], np.ndarray):
|
172
|
+
self.__dict__.update(self.from_numpy_ndarray(all_args[0]).__dict__)
|
173
|
+
return
|
174
|
+
|
175
|
+
_raise_array_init_error()
|
176
|
+
|
177
|
+
@classmethod
|
178
|
+
def from_numpy_ndarray(cls, ndarray: NDArray) -> Array:
|
179
|
+
"""Create Array from NumPy ndarray."""
|
180
|
+
assert isinstance(
|
181
|
+
ndarray, np.ndarray
|
182
|
+
), f"Expected NumPy ndarray, got {type(ndarray)}"
|
183
|
+
buffer = BytesIO()
|
184
|
+
# WARNING: NEVER set allow_pickle to true.
|
185
|
+
# Reason: loading pickled data can execute arbitrary code
|
186
|
+
# Source: https://numpy.org/doc/stable/reference/generated/numpy.save.html
|
187
|
+
np.save(buffer, ndarray, allow_pickle=False)
|
188
|
+
data = buffer.getvalue()
|
189
|
+
return Array(
|
190
|
+
dtype=str(ndarray.dtype),
|
191
|
+
shape=list(ndarray.shape),
|
192
|
+
stype=SType.NUMPY,
|
193
|
+
data=data,
|
194
|
+
)
|
195
|
+
|
60
196
|
def numpy(self) -> NDArray:
|
61
197
|
"""Return the array as a NumPy array."""
|
62
198
|
if self.stype != SType.NUMPY:
|
@@ -117,7 +253,6 @@ class ParametersRecord(TypedDict[str, Array]):
|
|
117
253
|
|
118
254
|
>>> import numpy as np
|
119
255
|
>>> from flwr.common import ParametersRecord
|
120
|
-
>>> from flwr.common import array_from_numpy
|
121
256
|
>>>
|
122
257
|
>>> # Let's create a simple NumPy array
|
123
258
|
>>> arr_np = np.random.randn(3, 3)
|
@@ -128,7 +263,7 @@ class ParametersRecord(TypedDict[str, Array]):
|
|
128
263
|
>>> [-0.10758364, 1.97619858, -0.37120501]])
|
129
264
|
>>>
|
130
265
|
>>> # Let's create an Array out of it
|
131
|
-
>>> arr =
|
266
|
+
>>> arr = Array(arr_np)
|
132
267
|
>>>
|
133
268
|
>>> # If we print it you'll see (note the binary data)
|
134
269
|
>>> Array(dtype='float64', shape=[3,3], stype='numpy.ndarray', data=b'@\x99\x18...')
|
@@ -176,7 +311,7 @@ class ParametersRecord(TypedDict[str, Array]):
|
|
176
311
|
|
177
312
|
def __init__(
|
178
313
|
self,
|
179
|
-
array_dict:
|
314
|
+
array_dict: OrderedDict[str, Array] | None = None,
|
180
315
|
keep_input: bool = False,
|
181
316
|
) -> None:
|
182
317
|
super().__init__(_check_key, _check_value)
|
{flwr_nightly-1.16.0.dev20250224.dist-info → flwr_nightly-1.16.0.dev20250226.dist-info}/RECORD
RENAMED
@@ -74,7 +74,7 @@ flwr/cli/utils.py,sha256=D9XcpxzwkGPNdwX16o0kI-sYnRDMlWYyKNIpz6npRhQ,11236
|
|
74
74
|
flwr/client/__init__.py,sha256=DGDoO0AEAfz-0CUFmLdyUUweAS64-07AOnmDfWUefK4,1192
|
75
75
|
flwr/client/app.py,sha256=tNnef5wGVfqMiiGiWzAuULyy1QpvCKukiRmNi_a2cQc,34261
|
76
76
|
flwr/client/client.py,sha256=8o58nd9o6ZFcMIaVYPGcV4MSjBG4H0oFgWiv8ZEO3oA,7895
|
77
|
-
flwr/client/client_app.py,sha256=
|
77
|
+
flwr/client/client_app.py,sha256=Vv4rfDcV9ycb9ZuUkhT_8wX7W1GIrALwlvRcUeVel3Y,12161
|
78
78
|
flwr/client/clientapp/__init__.py,sha256=kZqChGnTChQ1WGSUkIlW2S5bc0d0mzDubCAmZUGRpEY,800
|
79
79
|
flwr/client/clientapp/app.py,sha256=Us5Mw3wvGd_6P1zHOf3TNcRGBBulVZDo3LuZOs17WgM,8963
|
80
80
|
flwr/client/clientapp/clientappio_servicer.py,sha256=5L6bjw_j3Mnx9kRFwYwxDNABKurBO5q1jZOWE_X11wQ,8522
|
@@ -112,7 +112,7 @@ flwr/client/supernode/__init__.py,sha256=SUhWOzcgXRNXk1V9UgB5-FaWukqqrOEajVUHEcP
|
|
112
112
|
flwr/client/supernode/app.py,sha256=oBbggh56HoieksBkTdDHAJC8VUFbrmGOP0-D9wdcZek,9265
|
113
113
|
flwr/client/typing.py,sha256=dxoTBnTMfqXr5J7G3y-uNjqxYCddvxhu89spfj4Lm2U,1048
|
114
114
|
flwr/common/__init__.py,sha256=TVaoFEJE158aui1TPZQiJCDZX4RNHRyI8I55VC80HhI,3901
|
115
|
-
flwr/common/address.py,sha256=
|
115
|
+
flwr/common/address.py,sha256=rRaN1JpiCJnit7ImEqZVxURQ69dPihRoyyWn_3I2wh4,4119
|
116
116
|
flwr/common/args.py,sha256=MgkTUXACuySHyNdxrb7-pK0_R-S2Q7W5MnE3onYUf5I,5183
|
117
117
|
flwr/common/auth_plugin/__init__.py,sha256=1Y8Oj3iB49IHDu9tvDih1J74Ygu7k85V9s2A4WORPyA,887
|
118
118
|
flwr/common/auth_plugin/auth_plugin.py,sha256=wgDorBUB4IkK6twQ8vNawRVz7BDPmKdXZBNLqhU9RSs,3871
|
@@ -135,9 +135,9 @@ flwr/common/parameter.py,sha256=-bFAUayToYDF50FZGrBC1hQYJCQDtB2bbr3ZuVLMtdE,2095
|
|
135
135
|
flwr/common/pyproject.py,sha256=vEAxl800XiJ1JNJDui8vuVV-08msnB6hLt7o95viZl0,1386
|
136
136
|
flwr/common/record/__init__.py,sha256=LUixpq0Z-lMJwCIu1-4u5HfvRPjRMRgoAc6YJQ6UEOs,1055
|
137
137
|
flwr/common/record/configsrecord.py,sha256=i40jOzBx04ysZKECwaw4FdUXMdY9HgdY8GAqKdTO1Lw,6486
|
138
|
-
flwr/common/record/conversion_utils.py,sha256=
|
138
|
+
flwr/common/record/conversion_utils.py,sha256=ZcsM-vTm_rVtLXLFD2RY3N47V_hUr3ywTdtnpVXnOGU,1202
|
139
139
|
flwr/common/record/metricsrecord.py,sha256=UywkEPbifiu_IyPUFoDJCi8WEVLujlqZERUWAWpc3vs,5752
|
140
|
-
flwr/common/record/parametersrecord.py,sha256=
|
140
|
+
flwr/common/record/parametersrecord.py,sha256=rR0LbeNrKrdK37CiAA56Z5WBq-ZzZ2YNSUkcmr5i2lI,12950
|
141
141
|
flwr/common/record/recordset.py,sha256=qqIFdRZ0ivQhUhztpdxNIvCRDZQXY_zX0kKDEU9mhfM,8319
|
142
142
|
flwr/common/record/typeddict.py,sha256=q5hL2xkXymuiCprHWb69mUmLpWQk_XXQq0hGQ69YPaw,3599
|
143
143
|
flwr/common/recordset_compat.py,sha256=ViSwA26h6Q55ZmV1LLjSJpcKiipV-p_JpCj4wxdE-Ow,14230
|
@@ -327,8 +327,8 @@ flwr/superexec/exec_servicer.py,sha256=X10ILT-AoGMrB3IgI2mBe9i-QcIVUAl9bucuqVOPY
|
|
327
327
|
flwr/superexec/exec_user_auth_interceptor.py,sha256=K06OU-l4LnYhTDg071hGJuOaQWEJbZsYi5qxUmmtiG0,3704
|
328
328
|
flwr/superexec/executor.py,sha256=_B55WW2TD1fBINpabSSDRenVHXYmvlfhv-k8hJKU4lQ,3115
|
329
329
|
flwr/superexec/simulation.py,sha256=WQDon15oqpMopAZnwRZoTICYCfHqtkvFSqiTQ2hLD_g,4088
|
330
|
-
flwr_nightly-1.16.0.
|
331
|
-
flwr_nightly-1.16.0.
|
332
|
-
flwr_nightly-1.16.0.
|
333
|
-
flwr_nightly-1.16.0.
|
334
|
-
flwr_nightly-1.16.0.
|
330
|
+
flwr_nightly-1.16.0.dev20250226.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
331
|
+
flwr_nightly-1.16.0.dev20250226.dist-info/METADATA,sha256=9351LF7XOp_SkK7kJWKK2985bCbPYRocxMjwx2UE0bs,15877
|
332
|
+
flwr_nightly-1.16.0.dev20250226.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
333
|
+
flwr_nightly-1.16.0.dev20250226.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
|
334
|
+
flwr_nightly-1.16.0.dev20250226.dist-info/RECORD,,
|
{flwr_nightly-1.16.0.dev20250224.dist-info → flwr_nightly-1.16.0.dev20250226.dist-info}/LICENSE
RENAMED
File without changes
|
{flwr_nightly-1.16.0.dev20250224.dist-info → flwr_nightly-1.16.0.dev20250226.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|