flwr-nightly 1.16.0.dev20250227__py3-none-any.whl → 1.16.0.dev20250301__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/log.py CHANGED
@@ -38,6 +38,10 @@ from flwr.proto.exec_pb2_grpc import ExecStub
38
38
  from .utils import init_channel, try_obtain_cli_auth_plugin, unauthenticated_exc_handler
39
39
 
40
40
 
41
+ class AllLogsRetrieved(BaseException):
42
+ """Raised when all logs are retrieved."""
43
+
44
+
41
45
  def start_stream(
42
46
  run_id: int, channel: grpc.Channel, refresh_period: int = CONN_REFRESH_PERIOD
43
47
  ) -> None:
@@ -56,10 +60,10 @@ def start_stream(
56
60
  # pylint: disable=E1101
57
61
  if e.code() == grpc.StatusCode.NOT_FOUND:
58
62
  logger(ERROR, "Invalid run_id `%s`, exiting", run_id)
59
- if e.code() == grpc.StatusCode.CANCELLED:
60
- pass
61
63
  else:
62
64
  raise e
65
+ except AllLogsRetrieved:
66
+ pass
63
67
  finally:
64
68
  channel.close()
65
69
 
@@ -94,6 +98,7 @@ def stream_logs(
94
98
  with unauthenticated_exc_handler():
95
99
  for res in stub.StreamLogs(req, timeout=duration):
96
100
  print(res.log_output, end="")
101
+ raise AllLogsRetrieved()
97
102
  except grpc.RpcError as e:
98
103
  # pylint: disable=E1101
99
104
  if e.code() != grpc.StatusCode.DEADLINE_EXCEEDED:
@@ -108,27 +113,21 @@ def stream_logs(
108
113
  def print_logs(run_id: int, channel: grpc.Channel, timeout: int) -> None:
109
114
  """Print logs from the beginning of a run."""
110
115
  stub = ExecStub(channel)
111
- req = StreamLogsRequest(run_id=run_id)
116
+ req = StreamLogsRequest(run_id=run_id, after_timestamp=0.0)
112
117
 
113
118
  try:
114
- while True:
115
- try:
116
- with unauthenticated_exc_handler():
117
- # Enforce timeout for graceful exit
118
- for res in stub.StreamLogs(req, timeout=timeout):
119
- print(res.log_output)
120
- except grpc.RpcError as e:
121
- # pylint: disable=E1101
122
- if e.code() == grpc.StatusCode.DEADLINE_EXCEEDED:
123
- break
124
- if e.code() == grpc.StatusCode.NOT_FOUND:
125
- logger(ERROR, "Invalid run_id `%s`, exiting", run_id)
126
- break
127
- if e.code() == grpc.StatusCode.CANCELLED:
128
- break
129
- raise e
130
- except KeyboardInterrupt:
131
- logger(DEBUG, "Stream interrupted by user")
119
+ with unauthenticated_exc_handler():
120
+ # Enforce timeout for graceful exit
121
+ for res in stub.StreamLogs(req, timeout=timeout):
122
+ print(res.log_output)
123
+ break
124
+ except grpc.RpcError as e:
125
+ if e.code() == grpc.StatusCode.NOT_FOUND: # pylint: disable=E1101
126
+ logger(ERROR, "Invalid run_id `%s`, exiting", run_id)
127
+ elif e.code() == grpc.StatusCode.DEADLINE_EXCEEDED: # pylint: disable=E1101
128
+ pass
129
+ else:
130
+ raise e
132
131
  finally:
133
132
  channel.close()
134
133
  logger(DEBUG, "Channel closed")
flwr/client/client_app.py CHANGED
@@ -16,6 +16,8 @@
16
16
 
17
17
 
18
18
  import inspect
19
+ from collections.abc import Iterator
20
+ from contextlib import contextmanager
19
21
  from typing import Callable, Optional
20
22
 
21
23
  from flwr.client.client import Client
@@ -71,6 +73,11 @@ def _inspect_maybe_adapt_client_fn_signature(client_fn: ClientFnExt) -> ClientFn
71
73
  return client_fn
72
74
 
73
75
 
76
+ @contextmanager
77
+ def _empty_lifecycle(_: Context) -> Iterator[None]:
78
+ yield
79
+
80
+
74
81
  class ClientAppException(Exception):
75
82
  """Exception raised when an exception is raised while executing a ClientApp."""
76
83
 
@@ -135,29 +142,31 @@ class ClientApp:
135
142
  self._train: Optional[ClientAppCallable] = None
136
143
  self._evaluate: Optional[ClientAppCallable] = None
137
144
  self._query: Optional[ClientAppCallable] = None
145
+ self._lifecycle = _empty_lifecycle
138
146
 
139
147
  def __call__(self, message: Message, context: Context) -> Message:
140
148
  """Execute `ClientApp`."""
141
- # Execute message using `client_fn`
142
- if self._call:
143
- return self._call(message, context)
144
-
145
- # Execute message using a new
146
- if message.metadata.message_type == MessageType.TRAIN:
147
- if self._train:
148
- return self._train(message, context)
149
- raise ValueError("No `train` function registered")
150
- if message.metadata.message_type == MessageType.EVALUATE:
151
- if self._evaluate:
152
- return self._evaluate(message, context)
153
- raise ValueError("No `evaluate` function registered")
154
- if message.metadata.message_type == MessageType.QUERY:
155
- if self._query:
156
- return self._query(message, context)
157
- raise ValueError("No `query` function registered")
158
-
159
- # Message type did not match one of the known message types abvoe
160
- raise ValueError(f"Unknown message_type: {message.metadata.message_type}")
149
+ with self._lifecycle(context):
150
+ # Execute message using `client_fn`
151
+ if self._call:
152
+ return self._call(message, context)
153
+
154
+ # Execute message using a new
155
+ if message.metadata.message_type == MessageType.TRAIN:
156
+ if self._train:
157
+ return self._train(message, context)
158
+ raise ValueError("No `train` function registered")
159
+ if message.metadata.message_type == MessageType.EVALUATE:
160
+ if self._evaluate:
161
+ return self._evaluate(message, context)
162
+ raise ValueError("No `evaluate` function registered")
163
+ if message.metadata.message_type == MessageType.QUERY:
164
+ if self._query:
165
+ return self._query(message, context)
166
+ raise ValueError("No `query` function registered")
167
+
168
+ # Message type did not match one of the known message types abvoe
169
+ raise ValueError(f"Unknown message_type: {message.metadata.message_type}")
161
170
 
162
171
  def train(
163
172
  self, mods: Optional[list[Mod]] = None
@@ -296,6 +305,66 @@ class ClientApp:
296
305
 
297
306
  return query_decorator
298
307
 
308
+ def lifecycle(
309
+ self,
310
+ ) -> Callable[
311
+ [Callable[[Context], Iterator[None]]], Callable[[Context], Iterator[None]]
312
+ ]:
313
+ """Return a decorator that registers the lifecycle fn with the client app.
314
+
315
+ The decorated function should accept a `Context` object and use `yield`
316
+ to define enter and exit behavior.
317
+
318
+ Examples
319
+ --------
320
+ >>> app = ClientApp()
321
+ >>>
322
+ >>> @app.lifecycle()
323
+ >>> def lifecycle(context: Context) -> None:
324
+ >>> print("Initializing ClientApp")
325
+ >>> yield
326
+ >>> print("Cleaning up ClientApp")
327
+ """
328
+
329
+ def lifecycle_decorator(
330
+ lifecycle_fn: Callable[[Context], Iterator[None]]
331
+ ) -> Callable[[Context], Iterator[None]]:
332
+ """Register the lifecycle fn with the ServerApp object."""
333
+ warn_preview_feature("ClientApp-register-lifecycle-function")
334
+
335
+ @contextmanager
336
+ def decorated_lifecycle(context: Context) -> Iterator[None]:
337
+ # Execute the code before `yield` in lifecycle_fn
338
+ try:
339
+ if not isinstance(it := lifecycle_fn(context), Iterator):
340
+ raise StopIteration
341
+ next(it)
342
+ except StopIteration:
343
+ raise RuntimeError(
344
+ "Lifecycle function should yield at least once."
345
+ ) from None
346
+
347
+ try:
348
+ # Enter the context
349
+ yield
350
+ finally:
351
+ try:
352
+ # Execute the code after `yield` in lifecycle_fn
353
+ next(it)
354
+ except StopIteration:
355
+ pass
356
+ else:
357
+ raise RuntimeError("Lifecycle function should only yield once.")
358
+
359
+ # Register provided function with the ClientApp object
360
+ # Ignore mypy error because of different argument names (`_` vs `context`)
361
+ self._lifecycle = decorated_lifecycle # type: ignore
362
+
363
+ # Return provided function unmodified
364
+ return lifecycle_fn
365
+
366
+ return lifecycle_decorator
367
+
299
368
 
300
369
  class LoadClientAppError(Exception):
301
370
  """Error when trying to load `ClientApp`."""
flwr/common/object_ref.py CHANGED
@@ -170,7 +170,6 @@ def load_app( # pylint: disable= too-many-branches
170
170
  module = importlib.import_module(module_str)
171
171
  else:
172
172
  module = sys.modules[module_str]
173
- _reload_modules(project_dir)
174
173
 
175
174
  except ModuleNotFoundError as err:
176
175
  raise error_type(
@@ -200,15 +199,6 @@ def _unload_modules(project_dir: Path) -> None:
200
199
  del sys.modules[name]
201
200
 
202
201
 
203
- def _reload_modules(project_dir: Path) -> None:
204
- """Reload modules from the project directory."""
205
- dir_str = str(project_dir.absolute())
206
- for m in list(sys.modules.values()):
207
- path: Optional[str] = getattr(m, "__file__", None)
208
- if path is not None and path.startswith(dir_str):
209
- importlib.reload(m)
210
-
211
-
212
202
  def _set_sys_path(directory: Optional[Union[str, Path]]) -> None:
213
203
  """Set the system path."""
214
204
  if directory is None:
flwr/server/server_app.py CHANGED
@@ -15,6 +15,8 @@
15
15
  """Flower ServerApp."""
16
16
 
17
17
 
18
+ from collections.abc import Iterator
19
+ from contextlib import contextmanager
18
20
  from typing import Callable, Optional
19
21
 
20
22
  from flwr.common import Context
@@ -45,7 +47,12 @@ SERVER_FN_USAGE_EXAMPLE = """
45
47
  """
46
48
 
47
49
 
48
- class ServerApp:
50
+ @contextmanager
51
+ def _empty_lifecycle(_: Context) -> Iterator[None]:
52
+ yield
53
+
54
+
55
+ class ServerApp: # pylint: disable=too-many-instance-attributes
49
56
  """Flower ServerApp.
50
57
 
51
58
  Examples
@@ -105,29 +112,31 @@ class ServerApp:
105
112
  self._client_manager = client_manager
106
113
  self._server_fn = server_fn
107
114
  self._main: Optional[ServerAppCallable] = None
115
+ self._lifecycle = _empty_lifecycle
108
116
 
109
117
  def __call__(self, driver: Driver, context: Context) -> None:
110
118
  """Execute `ServerApp`."""
111
- # Compatibility mode
112
- if not self._main:
113
- if self._server_fn:
114
- # Execute server_fn()
115
- components = self._server_fn(context)
116
- self._server = components.server
117
- self._config = components.config
118
- self._strategy = components.strategy
119
- self._client_manager = components.client_manager
120
- start_driver(
121
- server=self._server,
122
- config=self._config,
123
- strategy=self._strategy,
124
- client_manager=self._client_manager,
125
- driver=driver,
126
- )
127
- return
119
+ with self._lifecycle(context):
120
+ # Compatibility mode
121
+ if not self._main:
122
+ if self._server_fn:
123
+ # Execute server_fn()
124
+ components = self._server_fn(context)
125
+ self._server = components.server
126
+ self._config = components.config
127
+ self._strategy = components.strategy
128
+ self._client_manager = components.client_manager
129
+ start_driver(
130
+ server=self._server,
131
+ config=self._config,
132
+ strategy=self._strategy,
133
+ client_manager=self._client_manager,
134
+ driver=driver,
135
+ )
136
+ return
128
137
 
129
- # New execution mode
130
- self._main(driver, context)
138
+ # New execution mode
139
+ self._main(driver, context)
131
140
 
132
141
  def main(self) -> Callable[[ServerAppCallable], ServerAppCallable]:
133
142
  """Return a decorator that registers the main fn with the server app.
@@ -177,6 +186,66 @@ class ServerApp:
177
186
 
178
187
  return main_decorator
179
188
 
189
+ def lifecycle(
190
+ self,
191
+ ) -> Callable[
192
+ [Callable[[Context], Iterator[None]]], Callable[[Context], Iterator[None]]
193
+ ]:
194
+ """Return a decorator that registers the lifecycle fn with the server app.
195
+
196
+ The decorated function should accept a `Context` object and use `yield`
197
+ to define enter and exit behavior.
198
+
199
+ Examples
200
+ --------
201
+ >>> app = ServerApp()
202
+ >>>
203
+ >>> @app.lifecycle()
204
+ >>> def lifecycle(context: Context) -> None:
205
+ >>> print("Initializing ServerApp")
206
+ >>> yield
207
+ >>> print("Cleaning up ServerApp")
208
+ """
209
+
210
+ def lifecycle_decorator(
211
+ lifecycle_fn: Callable[[Context], Iterator[None]]
212
+ ) -> Callable[[Context], Iterator[None]]:
213
+ """Register the lifecycle fn with the ServerApp object."""
214
+ warn_preview_feature("ServerApp-register-lifecycle-function")
215
+
216
+ @contextmanager
217
+ def decorated_lifecycle(context: Context) -> Iterator[None]:
218
+ # Execute the code before `yield` in lifecycle_fn
219
+ try:
220
+ if not isinstance(it := lifecycle_fn(context), Iterator):
221
+ raise StopIteration
222
+ next(it)
223
+ except StopIteration:
224
+ raise RuntimeError(
225
+ "Lifecycle function should yield at least once."
226
+ ) from None
227
+
228
+ try:
229
+ # Enter the context
230
+ yield
231
+ finally:
232
+ try:
233
+ # Execute the code after `yield` in lifecycle_fn
234
+ next(it)
235
+ except StopIteration:
236
+ pass
237
+ else:
238
+ raise RuntimeError("Lifecycle function should only yield once.")
239
+
240
+ # Register provided function with the ServerApp object
241
+ # Ignore mypy error because of different argument names (`_` vs `context`)
242
+ self._lifecycle = decorated_lifecycle # type: ignore
243
+
244
+ # Return provided function unmodified
245
+ return lifecycle_fn
246
+
247
+ return lifecycle_decorator
248
+
180
249
 
181
250
  class LoadServerAppError(Exception):
182
251
  """Error when trying to load `ServerApp`."""
@@ -120,7 +120,7 @@ class ExecServicer(exec_pb2_grpc.ExecServicer):
120
120
  run_status = state.get_run_status({run_id})[run_id]
121
121
  if run_status.status == Status.FINISHED:
122
122
  log(INFO, "All logs for run ID `%s` returned", request.run_id)
123
- context.cancel()
123
+ break
124
124
 
125
125
  time.sleep(LOG_STREAM_INTERVAL) # Sleep briefly to avoid busy waiting
126
126
 
@@ -77,15 +77,17 @@ class ExecUserAuthInterceptor(grpc.ServerInterceptor): # type: ignore
77
77
  ) -> Response:
78
78
  call = method_handler.unary_unary or method_handler.unary_stream
79
79
  metadata = context.invocation_metadata()
80
- if isinstance(
81
- request, (GetLoginDetailsRequest, GetAuthTokensRequest)
82
- ) or self.auth_plugin.validate_tokens_in_metadata(metadata):
80
+ if isinstance(request, (GetLoginDetailsRequest, GetAuthTokensRequest)):
81
+ return call(request, context) # type: ignore
82
+
83
+ valid_tokens, _ = self.auth_plugin.validate_tokens_in_metadata(metadata)
84
+ if valid_tokens:
83
85
  return call(request, context) # type: ignore
84
86
 
85
87
  tokens = self.auth_plugin.refresh_tokens(context.invocation_metadata())
86
88
  if tokens is not None:
87
89
  context.send_initial_metadata(tokens)
88
- return call(request, context)
90
+ return call(request, context) # type: ignore
89
91
 
90
92
  context.abort(grpc.StatusCode.UNAUTHENTICATED, "Access denied")
91
93
  raise grpc.RpcError() # This line is unreachable
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.16.0.dev20250227
3
+ Version: 1.16.0.dev20250301
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -9,7 +9,7 @@ flwr/cli/config_utils.py,sha256=LelRR960I36n1IPw7BIu79fKoOh0JePA58kAtoXSTH0,7518
9
9
  flwr/cli/constant.py,sha256=g7Ad7o3DJDkJNrWS0T3SSJETWSTkkVJWGpLM8zlbpcY,1289
10
10
  flwr/cli/example.py,sha256=uk5CoD0ZITgpY_ffsTbEKf8XOOCSUzByjHPcMSPqV18,2216
11
11
  flwr/cli/install.py,sha256=-RnrYGejN_zyXXp_CoddSQwoQfRTWWyt9WYlxphJzyU,8180
12
- flwr/cli/log.py,sha256=vcO-r5EIc127mOQ26uxKVITX-w_Zib7AxSVuuN70_JY,6671
12
+ flwr/cli/log.py,sha256=Huy02o2xGbbBVIBZhcC18qXEo_IUvPcVas77MnDE9Vo,6529
13
13
  flwr/cli/login/__init__.py,sha256=6_9zOzbPOAH72K2wX3-9dXTAbS7Mjpa5sEn2lA6eHHI,800
14
14
  flwr/cli/login/login.py,sha256=iNnNF1bvV0n8Z-vNc89azFNA73JqKZlO1s5OF2atsTc,3917
15
15
  flwr/cli/ls.py,sha256=cm3NuY1sFq51xVRhUG0MbAfVTrRSjJ1HMIubde80LuY,11433
@@ -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=Vv4rfDcV9ycb9ZuUkhT_8wX7W1GIrALwlvRcUeVel3Y,12161
77
+ flwr/client/client_app.py,sha256=WwKvP-22FRP1419oGYZdvRV5Z3JTNDDUse-Z8ikPkZA,14692
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
@@ -132,7 +132,7 @@ flwr/common/exit_handlers.py,sha256=yclujry30954o0lI7vtknTajskPCvK8TXw2V3RdldXU,
132
132
  flwr/common/grpc.py,sha256=K60AIvIqH0CvkkiqBfw5HoxQfbFOL2DrhKPjbZ8raIE,9786
133
133
  flwr/common/logger.py,sha256=Hund1C6bEhMw3GemlzuFK22tXZ27YeHLrFB0b4LP5f8,13041
134
134
  flwr/common/message.py,sha256=Zv4ID2BLQsbff0F03DI_MeFoHbSqVZAdDD9NcKYv6Zo,13832
135
- flwr/common/object_ref.py,sha256=Mv8OE6f9wmLs_KQWt8aPV5aw-g6fgWDfj28L2b8Jl-Y,9514
135
+ flwr/common/object_ref.py,sha256=DXL8NtbN17DSYaR-Zc8WYhaG8rv0_D_cclvP7Sa66So,9134
136
136
  flwr/common/parameter.py,sha256=-bFAUayToYDF50FZGrBC1hQYJCQDtB2bbr3ZuVLMtdE,2095
137
137
  flwr/common/pyproject.py,sha256=vEAxl800XiJ1JNJDui8vuVV-08msnB6hLt7o95viZl0,1386
138
138
  flwr/common/record/__init__.py,sha256=LUixpq0Z-lMJwCIu1-4u5HfvRPjRMRgoAc6YJQ6UEOs,1055
@@ -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=RsgS6PRS5Z74cMUAHzsm8r3LWddwn00MjRs6rlacHt8,6297
238
+ flwr/server/server_app.py,sha256=QtxZKdqP8GUDBIilKRLP7smLjabHPnzS8XhtdqRWbIU,8880
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
@@ -325,12 +325,12 @@ flwr/superexec/__init__.py,sha256=fcj366jh4RFby_vDwLroU4kepzqbnJgseZD_jUr_Mko,71
325
325
  flwr/superexec/app.py,sha256=Z6kYHWd62YL0Q4YKyCAbt_BcefNfbKH6V-jCC-1NkZM,1842
326
326
  flwr/superexec/deployment.py,sha256=wZ9G42gGS91knfplswh95MnQ83Fzu-rs6wcuNgDmmvY,6735
327
327
  flwr/superexec/exec_grpc.py,sha256=ttA9qoZzSLF0Mfk1L4hzOkMSNuj5rR58_kKBYwcyrAg,2864
328
- flwr/superexec/exec_servicer.py,sha256=X10ILT-AoGMrB3IgI2mBe9i-QcIVUAl9bucuqVOPYkU,8341
329
- flwr/superexec/exec_user_auth_interceptor.py,sha256=XvLRxIsZ5m90pg6COx-tKkixFWxF-FaBeP3PqJFtksw,3688
328
+ flwr/superexec/exec_servicer.py,sha256=72AL60LBbWD-OTxTvtPBrnb_M5rccMtU_JAYcEVQVNg,8330
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.dev20250227.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
333
- flwr_nightly-1.16.0.dev20250227.dist-info/METADATA,sha256=E--UFuJfhErjNYm6D4cvC1efJ_ZXAFNGII1jKTbC6mc,15877
334
- flwr_nightly-1.16.0.dev20250227.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
335
- flwr_nightly-1.16.0.dev20250227.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
336
- flwr_nightly-1.16.0.dev20250227.dist-info/RECORD,,
332
+ flwr_nightly-1.16.0.dev20250301.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
333
+ flwr_nightly-1.16.0.dev20250301.dist-info/METADATA,sha256=7SD9nmJ4XJXWi7PwV6MkAC_L-4mFriQVvn2823eLLmE,15877
334
+ flwr_nightly-1.16.0.dev20250301.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
335
+ flwr_nightly-1.16.0.dev20250301.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
336
+ flwr_nightly-1.16.0.dev20250301.dist-info/RECORD,,