flwr-nightly 1.16.0.dev20250228__py3-none-any.whl → 1.16.0.dev20250303__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/cli/build.py +2 -0
- flwr/client/client_app.py +25 -21
- flwr/server/server_app.py +25 -21
- flwr/server/utils/__init__.py +2 -0
- flwr/server/utils/validator.py +71 -0
- {flwr_nightly-1.16.0.dev20250228.dist-info → flwr_nightly-1.16.0.dev20250303.dist-info}/METADATA +1 -1
- {flwr_nightly-1.16.0.dev20250228.dist-info → flwr_nightly-1.16.0.dev20250303.dist-info}/RECORD +10 -10
- {flwr_nightly-1.16.0.dev20250228.dist-info → flwr_nightly-1.16.0.dev20250303.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.16.0.dev20250228.dist-info → flwr_nightly-1.16.0.dev20250303.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.16.0.dev20250228.dist-info → flwr_nightly-1.16.0.dev20250303.dist-info}/entry_points.txt +0 -0
flwr/cli/build.py
CHANGED
flwr/client/client_app.py
CHANGED
@@ -74,7 +74,7 @@ def _inspect_maybe_adapt_client_fn_signature(client_fn: ClientFnExt) -> ClientFn
|
|
74
74
|
|
75
75
|
|
76
76
|
@contextmanager
|
77
|
-
def
|
77
|
+
def _empty_lifespan(_: Context) -> Iterator[None]:
|
78
78
|
yield
|
79
79
|
|
80
80
|
|
@@ -142,11 +142,11 @@ class ClientApp:
|
|
142
142
|
self._train: Optional[ClientAppCallable] = None
|
143
143
|
self._evaluate: Optional[ClientAppCallable] = None
|
144
144
|
self._query: Optional[ClientAppCallable] = None
|
145
|
-
self.
|
145
|
+
self._lifespan = _empty_lifespan
|
146
146
|
|
147
147
|
def __call__(self, message: Message, context: Context) -> Message:
|
148
148
|
"""Execute `ClientApp`."""
|
149
|
-
with self.
|
149
|
+
with self._lifespan(context):
|
150
150
|
# Execute message using `client_fn`
|
151
151
|
if self._call:
|
152
152
|
return self._call(message, context)
|
@@ -305,12 +305,12 @@ class ClientApp:
|
|
305
305
|
|
306
306
|
return query_decorator
|
307
307
|
|
308
|
-
def
|
308
|
+
def lifespan(
|
309
309
|
self,
|
310
310
|
) -> Callable[
|
311
311
|
[Callable[[Context], Iterator[None]]], Callable[[Context], Iterator[None]]
|
312
312
|
]:
|
313
|
-
"""Return a decorator that registers the
|
313
|
+
"""Return a decorator that registers the lifespan fn with the client app.
|
314
314
|
|
315
315
|
The decorated function should accept a `Context` object and use `yield`
|
316
316
|
to define enter and exit behavior.
|
@@ -319,29 +319,33 @@ class ClientApp:
|
|
319
319
|
--------
|
320
320
|
>>> app = ClientApp()
|
321
321
|
>>>
|
322
|
-
>>> @app.
|
323
|
-
>>> def
|
322
|
+
>>> @app.lifespan()
|
323
|
+
>>> def lifespan(context: Context) -> None:
|
324
|
+
>>> # Perform initialization tasks before the app starts
|
324
325
|
>>> print("Initializing ClientApp")
|
325
|
-
>>>
|
326
|
+
>>>
|
327
|
+
>>> yield # ClientApp is running
|
328
|
+
>>>
|
329
|
+
>>> # Perform cleanup tasks after the app stops
|
326
330
|
>>> print("Cleaning up ClientApp")
|
327
331
|
"""
|
328
332
|
|
329
|
-
def
|
330
|
-
|
333
|
+
def lifespan_decorator(
|
334
|
+
lifespan_fn: Callable[[Context], Iterator[None]]
|
331
335
|
) -> Callable[[Context], Iterator[None]]:
|
332
|
-
"""Register the
|
333
|
-
warn_preview_feature("ClientApp-register-
|
336
|
+
"""Register the lifespan fn with the ServerApp object."""
|
337
|
+
warn_preview_feature("ClientApp-register-lifespan-function")
|
334
338
|
|
335
339
|
@contextmanager
|
336
|
-
def
|
337
|
-
# Execute the code before `yield` in
|
340
|
+
def decorated_lifespan(context: Context) -> Iterator[None]:
|
341
|
+
# Execute the code before `yield` in lifespan_fn
|
338
342
|
try:
|
339
|
-
if not isinstance(it :=
|
343
|
+
if not isinstance(it := lifespan_fn(context), Iterator):
|
340
344
|
raise StopIteration
|
341
345
|
next(it)
|
342
346
|
except StopIteration:
|
343
347
|
raise RuntimeError(
|
344
|
-
"
|
348
|
+
"lifespan function should yield at least once."
|
345
349
|
) from None
|
346
350
|
|
347
351
|
try:
|
@@ -349,21 +353,21 @@ class ClientApp:
|
|
349
353
|
yield
|
350
354
|
finally:
|
351
355
|
try:
|
352
|
-
# Execute the code after `yield` in
|
356
|
+
# Execute the code after `yield` in lifespan_fn
|
353
357
|
next(it)
|
354
358
|
except StopIteration:
|
355
359
|
pass
|
356
360
|
else:
|
357
|
-
raise RuntimeError("
|
361
|
+
raise RuntimeError("lifespan function should only yield once.")
|
358
362
|
|
359
363
|
# Register provided function with the ClientApp object
|
360
364
|
# Ignore mypy error because of different argument names (`_` vs `context`)
|
361
|
-
self.
|
365
|
+
self._lifespan = decorated_lifespan # type: ignore
|
362
366
|
|
363
367
|
# Return provided function unmodified
|
364
|
-
return
|
368
|
+
return lifespan_fn
|
365
369
|
|
366
|
-
return
|
370
|
+
return lifespan_decorator
|
367
371
|
|
368
372
|
|
369
373
|
class LoadClientAppError(Exception):
|
flwr/server/server_app.py
CHANGED
@@ -48,7 +48,7 @@ SERVER_FN_USAGE_EXAMPLE = """
|
|
48
48
|
|
49
49
|
|
50
50
|
@contextmanager
|
51
|
-
def
|
51
|
+
def _empty_lifespan(_: Context) -> Iterator[None]:
|
52
52
|
yield
|
53
53
|
|
54
54
|
|
@@ -112,11 +112,11 @@ class ServerApp: # pylint: disable=too-many-instance-attributes
|
|
112
112
|
self._client_manager = client_manager
|
113
113
|
self._server_fn = server_fn
|
114
114
|
self._main: Optional[ServerAppCallable] = None
|
115
|
-
self.
|
115
|
+
self._lifespan = _empty_lifespan
|
116
116
|
|
117
117
|
def __call__(self, driver: Driver, context: Context) -> None:
|
118
118
|
"""Execute `ServerApp`."""
|
119
|
-
with self.
|
119
|
+
with self._lifespan(context):
|
120
120
|
# Compatibility mode
|
121
121
|
if not self._main:
|
122
122
|
if self._server_fn:
|
@@ -186,12 +186,12 @@ class ServerApp: # pylint: disable=too-many-instance-attributes
|
|
186
186
|
|
187
187
|
return main_decorator
|
188
188
|
|
189
|
-
def
|
189
|
+
def lifespan(
|
190
190
|
self,
|
191
191
|
) -> Callable[
|
192
192
|
[Callable[[Context], Iterator[None]]], Callable[[Context], Iterator[None]]
|
193
193
|
]:
|
194
|
-
"""Return a decorator that registers the
|
194
|
+
"""Return a decorator that registers the lifespan fn with the server app.
|
195
195
|
|
196
196
|
The decorated function should accept a `Context` object and use `yield`
|
197
197
|
to define enter and exit behavior.
|
@@ -200,29 +200,33 @@ class ServerApp: # pylint: disable=too-many-instance-attributes
|
|
200
200
|
--------
|
201
201
|
>>> app = ServerApp()
|
202
202
|
>>>
|
203
|
-
>>> @app.
|
204
|
-
>>> def
|
203
|
+
>>> @app.lifespan()
|
204
|
+
>>> def lifespan(context: Context) -> None:
|
205
|
+
>>> # Perform initialization tasks before the app starts
|
205
206
|
>>> print("Initializing ServerApp")
|
206
|
-
>>>
|
207
|
+
>>>
|
208
|
+
>>> yield # ServerApp is running
|
209
|
+
>>>
|
210
|
+
>>> # Perform cleanup tasks after the app stops
|
207
211
|
>>> print("Cleaning up ServerApp")
|
208
212
|
"""
|
209
213
|
|
210
|
-
def
|
211
|
-
|
214
|
+
def lifespan_decorator(
|
215
|
+
lifespan_fn: Callable[[Context], Iterator[None]]
|
212
216
|
) -> Callable[[Context], Iterator[None]]:
|
213
|
-
"""Register the
|
214
|
-
warn_preview_feature("ServerApp-register-
|
217
|
+
"""Register the lifespan fn with the ServerApp object."""
|
218
|
+
warn_preview_feature("ServerApp-register-lifespan-function")
|
215
219
|
|
216
220
|
@contextmanager
|
217
|
-
def
|
218
|
-
# Execute the code before `yield` in
|
221
|
+
def decorated_lifespan(context: Context) -> Iterator[None]:
|
222
|
+
# Execute the code before `yield` in lifespan_fn
|
219
223
|
try:
|
220
|
-
if not isinstance(it :=
|
224
|
+
if not isinstance(it := lifespan_fn(context), Iterator):
|
221
225
|
raise StopIteration
|
222
226
|
next(it)
|
223
227
|
except StopIteration:
|
224
228
|
raise RuntimeError(
|
225
|
-
"
|
229
|
+
"lifespan function should yield at least once."
|
226
230
|
) from None
|
227
231
|
|
228
232
|
try:
|
@@ -230,21 +234,21 @@ class ServerApp: # pylint: disable=too-many-instance-attributes
|
|
230
234
|
yield
|
231
235
|
finally:
|
232
236
|
try:
|
233
|
-
# Execute the code after `yield` in
|
237
|
+
# Execute the code after `yield` in lifespan_fn
|
234
238
|
next(it)
|
235
239
|
except StopIteration:
|
236
240
|
pass
|
237
241
|
else:
|
238
|
-
raise RuntimeError("
|
242
|
+
raise RuntimeError("lifespan function should only yield once.")
|
239
243
|
|
240
244
|
# Register provided function with the ServerApp object
|
241
245
|
# Ignore mypy error because of different argument names (`_` vs `context`)
|
242
|
-
self.
|
246
|
+
self._lifespan = decorated_lifespan # type: ignore
|
243
247
|
|
244
248
|
# Return provided function unmodified
|
245
|
-
return
|
249
|
+
return lifespan_fn
|
246
250
|
|
247
|
-
return
|
251
|
+
return lifespan_decorator
|
248
252
|
|
249
253
|
|
250
254
|
class LoadServerAppError(Exception):
|
flwr/server/utils/__init__.py
CHANGED
@@ -16,9 +16,11 @@
|
|
16
16
|
|
17
17
|
|
18
18
|
from .tensorboard import tensorboard as tensorboard
|
19
|
+
from .validator import validate_message as validate_message
|
19
20
|
from .validator import validate_task_ins_or_res as validate_task_ins_or_res
|
20
21
|
|
21
22
|
__all__ = [
|
22
23
|
"tensorboard",
|
24
|
+
"validate_message",
|
23
25
|
"validate_task_ins_or_res",
|
24
26
|
]
|
flwr/server/utils/validator.py
CHANGED
@@ -18,6 +18,7 @@
|
|
18
18
|
import time
|
19
19
|
from typing import Union
|
20
20
|
|
21
|
+
from flwr.common import Message
|
21
22
|
from flwr.common.constant import SUPERLINK_NODE_ID
|
22
23
|
from flwr.proto.task_pb2 import TaskIns, TaskRes # pylint: disable=E0611
|
23
24
|
|
@@ -106,3 +107,73 @@ def validate_task_ins_or_res(tasks_ins_res: Union[TaskIns, TaskRes]) -> list[str
|
|
106
107
|
validation_errors.append("`ancestry` is empty")
|
107
108
|
|
108
109
|
return validation_errors
|
110
|
+
|
111
|
+
|
112
|
+
# pylint: disable-next=too-many-branches
|
113
|
+
def validate_message(message: Message, is_reply_message: bool) -> list[str]:
|
114
|
+
"""Validate a Message."""
|
115
|
+
validation_errors = []
|
116
|
+
metadata = message.metadata
|
117
|
+
|
118
|
+
if metadata.message_id != "":
|
119
|
+
validation_errors.append("non-empty `metadata.message_id`")
|
120
|
+
|
121
|
+
# Created/delivered/TTL/Pushed
|
122
|
+
if (
|
123
|
+
metadata.created_at < 1740700800.0
|
124
|
+
): # unix timestamp of 28 February 2025 00h:00m:00s UTC
|
125
|
+
validation_errors.append(
|
126
|
+
"`metadata.created_at` must be a float that records the unix timestamp "
|
127
|
+
"in seconds when the message was created."
|
128
|
+
)
|
129
|
+
if metadata.ttl <= 0:
|
130
|
+
validation_errors.append("`metadata.ttl` must be higher than zero")
|
131
|
+
|
132
|
+
# Verify TTL and created_at time
|
133
|
+
current_time = time.time()
|
134
|
+
if metadata.created_at + metadata.ttl <= current_time:
|
135
|
+
validation_errors.append("Message TTL has expired")
|
136
|
+
|
137
|
+
# Source node is set and is not zero
|
138
|
+
if not metadata.src_node_id:
|
139
|
+
validation_errors.append("`metadata.src_node_id` is not set.")
|
140
|
+
|
141
|
+
# Destination node is set and is not zero
|
142
|
+
if not metadata.dst_node_id:
|
143
|
+
validation_errors.append("`metadata.dst_node_id` is not set.")
|
144
|
+
|
145
|
+
# Message type
|
146
|
+
if metadata.message_type == "":
|
147
|
+
validation_errors.append("`metadata.message_type` MUST be set")
|
148
|
+
|
149
|
+
# Content
|
150
|
+
if not message.has_content() != message.has_error():
|
151
|
+
validation_errors.append(
|
152
|
+
"Either message `content` or `error` MUST be set (but not both)"
|
153
|
+
)
|
154
|
+
|
155
|
+
# Link respose to original message
|
156
|
+
if not is_reply_message:
|
157
|
+
if metadata.reply_to_message != "":
|
158
|
+
validation_errors.append("`metadata.reply_to_message` MUST not be set.")
|
159
|
+
if metadata.src_node_id != SUPERLINK_NODE_ID:
|
160
|
+
validation_errors.append(
|
161
|
+
f"`metadata.src_node_id` is not {SUPERLINK_NODE_ID} (SuperLink node ID)"
|
162
|
+
)
|
163
|
+
if metadata.dst_node_id == SUPERLINK_NODE_ID:
|
164
|
+
validation_errors.append(
|
165
|
+
f"`metadata.dst_node_id` is {SUPERLINK_NODE_ID} (SuperLink node ID)"
|
166
|
+
)
|
167
|
+
else:
|
168
|
+
if metadata.reply_to_message == "":
|
169
|
+
validation_errors.append("`metadata.reply_to_message` MUST be set.")
|
170
|
+
if metadata.src_node_id == SUPERLINK_NODE_ID:
|
171
|
+
validation_errors.append(
|
172
|
+
f"`metadata.src_node_id` is {SUPERLINK_NODE_ID} (SuperLink node ID)"
|
173
|
+
)
|
174
|
+
if metadata.dst_node_id != SUPERLINK_NODE_ID:
|
175
|
+
validation_errors.append(
|
176
|
+
f"`metadata.dst_node_id` is not {SUPERLINK_NODE_ID} (SuperLink node ID)"
|
177
|
+
)
|
178
|
+
|
179
|
+
return validation_errors
|
{flwr_nightly-1.16.0.dev20250228.dist-info → flwr_nightly-1.16.0.dev20250303.dist-info}/RECORD
RENAMED
@@ -3,7 +3,7 @@ flwr/cli/__init__.py,sha256=cZJVgozlkC6Ni2Hd_FAIrqefrkCGOV18fikToq-6iLw,720
|
|
3
3
|
flwr/cli/app.py,sha256=UeXrW5gxrUnFViDjAMIxGNZZKwu3a1oAj83v53IWIWM,1382
|
4
4
|
flwr/cli/auth_plugin/__init__.py,sha256=FyaoqPzcxlBTFfJ2sBRC5USwQLmAhFr5KuBwfMO4bmo,1052
|
5
5
|
flwr/cli/auth_plugin/oidc_cli_plugin.py,sha256=gIhW6Jg9QAo-jL43LYPpw_kn7pdUZZae0s0H8dEgjLM,5384
|
6
|
-
flwr/cli/build.py,sha256=
|
6
|
+
flwr/cli/build.py,sha256=BbS6yrBz0Q0PkNqaEk_VD261iRMfMmkEuQ3GdJpZW54,6375
|
7
7
|
flwr/cli/cli_user_auth_interceptor.py,sha256=aZepPA298s-HjGmkJGMvI_uZe72O5aLC3jri-ilG53o,3126
|
8
8
|
flwr/cli/config_utils.py,sha256=LelRR960I36n1IPw7BIu79fKoOh0JePA58kAtoXSTH0,7518
|
9
9
|
flwr/cli/constant.py,sha256=g7Ad7o3DJDkJNrWS0T3SSJETWSTkkVJWGpLM8zlbpcY,1289
|
@@ -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=glgQOWgFB_6NQ3YAzekXJDoy8R5T1JPhOSiFem1-fS8,14847
|
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
|
@@ -235,7 +235,7 @@ flwr/server/driver/inmemory_driver.py,sha256=7ZtWDDJa8xupPAHNaDdCE2DOIOIYgrffmJM
|
|
235
235
|
flwr/server/history.py,sha256=qSb5_pPTrwofpSYGsZWzMPkl_4uJ4mJFWesxXDrEvDU,5026
|
236
236
|
flwr/server/run_serverapp.py,sha256=vIPhvJx0i5sEZO4IKM6ruCXmx4ncat76rh0B4KhdhhM,2446
|
237
237
|
flwr/server/server.py,sha256=1ZsFEptmAV-L2vP2etNC9Ed5CLSxpuKzUFkAPQ4l5Xc,17893
|
238
|
-
flwr/server/server_app.py,sha256=
|
238
|
+
flwr/server/server_app.py,sha256=Kb0ayKy19awnkslwN9Jx3eBWZJvDeA8VfFBvImmMf_E,9035
|
239
239
|
flwr/server/server_config.py,sha256=CZaHVAsMvGLjpWVcLPkiYxgJN4xfIyAiUrCI3fETKY4,1349
|
240
240
|
flwr/server/serverapp/__init__.py,sha256=L0K-94UDdTyEZ8LDtYybGIIIv3HW6AhSVjXMUfYJQnQ,800
|
241
241
|
flwr/server/serverapp/app.py,sha256=5nFRYYzC2vh0l1fKJofBfKwFam93In4b80wvH9eFfQ8,8651
|
@@ -303,9 +303,9 @@ flwr/server/superlink/simulation/simulationio_grpc.py,sha256=8aUrZZLdvprKUfLLqFI
|
|
303
303
|
flwr/server/superlink/simulation/simulationio_servicer.py,sha256=J_TmdqM-Bxgp-iPEI3tvCuBpykw1UX0FouMQalEYAF4,6907
|
304
304
|
flwr/server/superlink/utils.py,sha256=KVb3K_g2vYfu9TnftcN0ewmev133WZcjuEePMm8d7GE,2137
|
305
305
|
flwr/server/typing.py,sha256=5kaRLZuxTEse9A0g7aVna2VhYxU3wTq1f3d3mtw7kXs,1019
|
306
|
-
flwr/server/utils/__init__.py,sha256=
|
306
|
+
flwr/server/utils/__init__.py,sha256=myLB6L0ycQ0rd_nnL1pI-NLdFoOfXcj_z4gIqqj8Ye4,992
|
307
307
|
flwr/server/utils/tensorboard.py,sha256=gEBD8w_5uaIfp5aw5RYH66lYZpd_SfkObHQ7eDd9MUk,5466
|
308
|
-
flwr/server/utils/validator.py,sha256=
|
308
|
+
flwr/server/utils/validator.py,sha256=G5l9v_1hNDV6t2Q2xqNAmrg6UuXtw8JE74xzf3-kvao,7139
|
309
309
|
flwr/server/workflow/__init__.py,sha256=SXY0XkwbkezFBxxrFB5hKUtmtAgnYISBkPouR1V71ss,902
|
310
310
|
flwr/server/workflow/constant.py,sha256=q4DLdR8Krlxuewq2AQjwTL75hphxE5ODNz4AhViHMXk,1082
|
311
311
|
flwr/server/workflow/default_workflows.py,sha256=UMC9JgdomKwxql5G0OV4AeRXWI-bMClaLAOn5OrZMnw,14073
|
@@ -329,8 +329,8 @@ flwr/superexec/exec_servicer.py,sha256=72AL60LBbWD-OTxTvtPBrnb_M5rccMtU_JAYcEVQV
|
|
329
329
|
flwr/superexec/exec_user_auth_interceptor.py,sha256=YtvcjrD2hMVmZ3y9wHuGI6FwmG_Y__q112t4fFnypy0,3793
|
330
330
|
flwr/superexec/executor.py,sha256=_B55WW2TD1fBINpabSSDRenVHXYmvlfhv-k8hJKU4lQ,3115
|
331
331
|
flwr/superexec/simulation.py,sha256=WQDon15oqpMopAZnwRZoTICYCfHqtkvFSqiTQ2hLD_g,4088
|
332
|
-
flwr_nightly-1.16.0.
|
333
|
-
flwr_nightly-1.16.0.
|
334
|
-
flwr_nightly-1.16.0.
|
335
|
-
flwr_nightly-1.16.0.
|
336
|
-
flwr_nightly-1.16.0.
|
332
|
+
flwr_nightly-1.16.0.dev20250303.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
333
|
+
flwr_nightly-1.16.0.dev20250303.dist-info/METADATA,sha256=i43BozJ1cgF5yLrg9INuDSDe0kGuso5_USwV_N-Z_rI,15877
|
334
|
+
flwr_nightly-1.16.0.dev20250303.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
335
|
+
flwr_nightly-1.16.0.dev20250303.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
|
336
|
+
flwr_nightly-1.16.0.dev20250303.dist-info/RECORD,,
|
{flwr_nightly-1.16.0.dev20250228.dist-info → flwr_nightly-1.16.0.dev20250303.dist-info}/LICENSE
RENAMED
File without changes
|
{flwr_nightly-1.16.0.dev20250228.dist-info → flwr_nightly-1.16.0.dev20250303.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|