flwr-nightly 1.17.0.dev20250314__py3-none-any.whl → 1.17.0.dev20250315__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 CHANGED
@@ -28,9 +28,12 @@ from flwr.client.mod.utils import make_ffn
28
28
  from flwr.client.typing import ClientFnExt, Mod
29
29
  from flwr.common import Context, Message, MessageType
30
30
  from flwr.common.logger import warn_deprecated_feature, warn_preview_feature
31
+ from flwr.common.message import validate_message_type
31
32
 
32
33
  from .typing import ClientAppCallable
33
34
 
35
+ DEFAULT_ACTION = "default"
36
+
34
37
 
35
38
  def _alert_erroneous_client_fn() -> None:
36
39
  raise ValueError(
@@ -110,6 +113,7 @@ class ClientApp:
110
113
  mods: Optional[list[Mod]] = None,
111
114
  ) -> None:
112
115
  self._mods: list[Mod] = mods if mods is not None else []
116
+ self._registered_funcs: dict[str, ClientAppCallable] = {}
113
117
 
114
118
  # Create wrapper function for `handle`
115
119
  self._call: Optional[ClientAppCallable] = None
@@ -129,10 +133,7 @@ class ClientApp:
129
133
  # Wrap mods around the wrapped handle function
130
134
  self._call = make_ffn(ffn, mods if mods is not None else [])
131
135
 
132
- # Step functions
133
- self._train: Optional[ClientAppCallable] = None
134
- self._evaluate: Optional[ClientAppCallable] = None
135
- self._query: Optional[ClientAppCallable] = None
136
+ # Lifespan function
136
137
  self._lifespan = _empty_lifespan
137
138
 
138
139
  def __call__(self, message: Message, context: Context) -> Message:
@@ -142,27 +143,41 @@ class ClientApp:
142
143
  if self._call:
143
144
  return self._call(message, context)
144
145
 
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}")
146
+ # Get the category and the action
147
+ # A valid message type is of the form "<category>" or "<category>.<action>",
148
+ # where <category> must be "train"/"evaluate"/"query", and <action> is a
149
+ # valid Python identifier
150
+ if not validate_message_type(message.metadata.message_type):
151
+ raise ValueError(
152
+ f"Invalid message type: {message.metadata.message_type}"
153
+ )
154
+
155
+ category, action = message.metadata.message_type, DEFAULT_ACTION
156
+ if "." in category:
157
+ category, action = category.split(".")
158
+
159
+ # Check if the function is registered
160
+ if (full_name := f"{category}.{action}") in self._registered_funcs:
161
+ return self._registered_funcs[full_name](message, context)
162
+
163
+ raise ValueError(f"No {category} function registered with name '{action}'")
161
164
 
162
165
  def train(
163
- self, mods: Optional[list[Mod]] = None
166
+ self, action: str = DEFAULT_ACTION, *, mods: Optional[list[Mod]] = None
164
167
  ) -> Callable[[ClientAppCallable], ClientAppCallable]:
165
- """Return a decorator that registers the train fn with the client app.
168
+ """Register a train function with the ``ClientApp``.
169
+
170
+ Parameters
171
+ ----------
172
+ action : str (default: "default")
173
+ The action name used to route messages. Defaults to "default".
174
+ mods : Optional[list[Mod]] (default: None)
175
+ A list of function-specific modifiers.
176
+
177
+ Returns
178
+ -------
179
+ Callable[[ClientAppCallable], ClientAppCallable]
180
+ A decorator that registers a train function with the ``ClientApp``.
166
181
 
167
182
  Examples
168
183
  --------
@@ -172,42 +187,52 @@ class ClientApp:
172
187
  >>>
173
188
  >>> @app.train()
174
189
  >>> def train(message: Message, context: Context) -> Message:
175
- >>> print("ClientApp training running")
176
- >>> # Create and return an echo reply message
177
- >>> return message.create_reply(content=message.content())
190
+ >>> print("Executing default train function")
191
+ >>> # Create and return an echo reply message
192
+ >>> return message.create_reply(content=message.content)
193
+
194
+ Registering a train function with a custom action name:
178
195
 
179
- Registering a train function with a function-specific modifier:
196
+ >>> app = ClientApp()
197
+ >>>
198
+ >>> # Messages with `message_type="train.custom_action"` will be
199
+ >>> # routed to this function.
200
+ >>> @app.train("custom_action")
201
+ >>> def custom_action(message: Message, context: Context) -> Message:
202
+ >>> print("Executing train function for custom action")
203
+ >>> return message.create_reply(content=message.content)
204
+
205
+ Registering a train function with a function-specific Flower Mod:
180
206
 
181
207
  >>> from flwr.client.mod import message_size_mod
182
208
  >>>
183
209
  >>> app = ClientApp()
184
210
  >>>
211
+ >>> # Using the `mods` argument to apply a function-specific mod.
185
212
  >>> @app.train(mods=[message_size_mod])
186
213
  >>> def train(message: Message, context: Context) -> Message:
187
- >>> print("ClientApp training running with message size mod")
188
- >>> return message.create_reply(content=message.content())
214
+ >>> print("Executing train function with message size mod")
215
+ >>> # Create and return an echo reply message
216
+ >>> return message.create_reply(content=message.content)
189
217
  """
190
-
191
- def train_decorator(train_fn: ClientAppCallable) -> ClientAppCallable:
192
- """Register the train fn with the ServerApp object."""
193
- if self._call:
194
- raise _registration_error(MessageType.TRAIN)
195
-
196
- warn_preview_feature("ClientApp-register-train-function")
197
-
198
- # Register provided function with the ClientApp object
199
- # Wrap mods around the wrapped step function
200
- self._train = make_ffn(train_fn, self._mods + (mods or []))
201
-
202
- # Return provided function unmodified
203
- return train_fn
204
-
205
- return train_decorator
218
+ return _get_decorator(self, MessageType.TRAIN, action, mods)
206
219
 
207
220
  def evaluate(
208
- self, mods: Optional[list[Mod]] = None
221
+ self, action: str = DEFAULT_ACTION, *, mods: Optional[list[Mod]] = None
209
222
  ) -> Callable[[ClientAppCallable], ClientAppCallable]:
210
- """Return a decorator that registers the evaluate fn with the client app.
223
+ """Register an evaluate function with the ``ClientApp``.
224
+
225
+ Parameters
226
+ ----------
227
+ action : str (default: "default")
228
+ The action name used to route messages. Defaults to "default".
229
+ mods : Optional[list[Mod]] (default: None)
230
+ A list of function-specific modifiers.
231
+
232
+ Returns
233
+ -------
234
+ Callable[[ClientAppCallable], ClientAppCallable]
235
+ A decorator that registers an evaluate function with the ``ClientApp``.
211
236
 
212
237
  Examples
213
238
  --------
@@ -217,43 +242,52 @@ class ClientApp:
217
242
  >>>
218
243
  >>> @app.evaluate()
219
244
  >>> def evaluate(message: Message, context: Context) -> Message:
220
- >>> print("ClientApp evaluation running")
221
- >>> # Create and return an echo reply message
222
- >>> return message.create_reply(content=message.content())
245
+ >>> print("Executing default evaluate function")
246
+ >>> # Create and return an echo reply message
247
+ >>> return message.create_reply(content=message.content)
248
+
249
+ Registering an evaluate function with a custom action name:
250
+
251
+ >>> app = ClientApp()
252
+ >>>
253
+ >>> # Messages with `message_type="evaluate.custom_action"` will be
254
+ >>> # routed to this function.
255
+ >>> @app.evaluate("custom_action")
256
+ >>> def custom_action(message: Message, context: Context) -> Message:
257
+ >>> print("Executing evaluate function for custom action")
258
+ >>> return message.create_reply(content=message.content)
223
259
 
224
- Registering an evaluate function with a function-specific modifier:
260
+ Registering an evaluate function with a function-specific Flower Mod:
225
261
 
226
262
  >>> from flwr.client.mod import message_size_mod
227
263
  >>>
228
264
  >>> app = ClientApp()
229
265
  >>>
266
+ >>> # Using the `mods` argument to apply a function-specific mod.
230
267
  >>> @app.evaluate(mods=[message_size_mod])
231
268
  >>> 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())
269
+ >>> print("Executing evaluate function with message size mod")
270
+ >>> # Create and return an echo reply message
271
+ >>> return message.create_reply(content=message.content)
235
272
  """
236
-
237
- def evaluate_decorator(evaluate_fn: ClientAppCallable) -> ClientAppCallable:
238
- """Register the evaluate fn with the ServerApp object."""
239
- if self._call:
240
- raise _registration_error(MessageType.EVALUATE)
241
-
242
- warn_preview_feature("ClientApp-register-evaluate-function")
243
-
244
- # Register provided function with the ClientApp object
245
- # Wrap mods around the wrapped step function
246
- self._evaluate = make_ffn(evaluate_fn, self._mods + (mods or []))
247
-
248
- # Return provided function unmodified
249
- return evaluate_fn
250
-
251
- return evaluate_decorator
273
+ return _get_decorator(self, MessageType.EVALUATE, action, mods)
252
274
 
253
275
  def query(
254
- self, mods: Optional[list[Mod]] = None
276
+ self, action: str = DEFAULT_ACTION, *, mods: Optional[list[Mod]] = None
255
277
  ) -> Callable[[ClientAppCallable], ClientAppCallable]:
256
- """Return a decorator that registers the query fn with the client app.
278
+ """Register a query function with the ``ClientApp``.
279
+
280
+ Parameters
281
+ ----------
282
+ action : str (default: "default")
283
+ The action name used to route messages. Defaults to "default".
284
+ mods : Optional[list[Mod]] (default: None)
285
+ A list of function-specific modifiers.
286
+
287
+ Returns
288
+ -------
289
+ Callable[[ClientAppCallable], ClientAppCallable]
290
+ A decorator that registers a query function with the ``ClientApp``.
257
291
 
258
292
  Examples
259
293
  --------
@@ -263,38 +297,35 @@ class ClientApp:
263
297
  >>>
264
298
  >>> @app.query()
265
299
  >>> def query(message: Message, context: Context) -> Message:
266
- >>> print("ClientApp query running")
267
- >>> # Create and return an echo reply message
268
- >>> return message.create_reply(content=message.content())
300
+ >>> print("Executing default query function")
301
+ >>> # Create and return an echo reply message
302
+ >>> return message.create_reply(content=message.content)
269
303
 
270
- Registering a query function with a function-specific modifier:
304
+ Registering a query function with a custom action name:
305
+
306
+ >>> app = ClientApp()
307
+ >>>
308
+ >>> # Messages with `message_type="query.custom_action"` will be
309
+ >>> # routed to this function.
310
+ >>> @app.query("custom_action")
311
+ >>> def custom_action(message: Message, context: Context) -> Message:
312
+ >>> print("Executing query function for custom action")
313
+ >>> return message.create_reply(content=message.content)
314
+
315
+ Registering a query function with a function-specific Flower Mod:
271
316
 
272
317
  >>> from flwr.client.mod import message_size_mod
273
318
  >>>
274
319
  >>> app = ClientApp()
275
320
  >>>
321
+ >>> # Using the `mods` argument to apply a function-specific mod.
276
322
  >>> @app.query(mods=[message_size_mod])
277
323
  >>> 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())
324
+ >>> print("Executing query function with message size mod")
325
+ >>> # Create and return an echo reply message
326
+ >>> return message.create_reply(content=message.content)
281
327
  """
282
-
283
- def query_decorator(query_fn: ClientAppCallable) -> ClientAppCallable:
284
- """Register the query fn with the ServerApp object."""
285
- if self._call:
286
- raise _registration_error(MessageType.QUERY)
287
-
288
- warn_preview_feature("ClientApp-register-query-function")
289
-
290
- # Register provided function with the ClientApp object
291
- # Wrap mods around the wrapped step function
292
- self._query = make_ffn(query_fn, self._mods + (mods or []))
293
-
294
- # Return provided function unmodified
295
- return query_fn
296
-
297
- return query_decorator
328
+ return _get_decorator(self, MessageType.QUERY, action, mods)
298
329
 
299
330
  def lifespan(
300
331
  self,
@@ -365,6 +396,42 @@ class LoadClientAppError(Exception):
365
396
  """Error when trying to load `ClientApp`."""
366
397
 
367
398
 
399
+ def _get_decorator(
400
+ app: ClientApp, category: str, action: str, mods: Optional[list[Mod]]
401
+ ) -> Callable[[ClientAppCallable], ClientAppCallable]:
402
+ """Get the decorator for the given category and action."""
403
+ # pylint: disable=protected-access
404
+ if app._call:
405
+ raise _registration_error(category)
406
+
407
+ def decorator(fn: ClientAppCallable) -> ClientAppCallable:
408
+ warn_preview_feature(f"ClientApp-register-{category}-function")
409
+
410
+ # Check if the name is a valid Python identifier
411
+ if not action.isidentifier():
412
+ raise ValueError(
413
+ f"Cannot register {category} function with name '{action}'. "
414
+ "The name must follow Python's function naming rules."
415
+ )
416
+
417
+ # Check if the name is already registered
418
+ full_name = f"{category}.{action}" # Full name of the message type
419
+ if full_name in app._registered_funcs:
420
+ raise ValueError(
421
+ f"Cannot register {category} function with name '{action}'. "
422
+ f"A {category} function with the name '{action}' is already registered."
423
+ )
424
+
425
+ # Register provided function with the ClientApp object
426
+ app._registered_funcs[full_name] = make_ffn(fn, app._mods + (mods or []))
427
+
428
+ # Return provided function unmodified
429
+ return fn
430
+
431
+ # pylint: enable=protected-access
432
+ return decorator
433
+
434
+
368
435
  def _registration_error(fn_name: str) -> ValueError:
369
436
  return ValueError(
370
437
  f"""Use either `@app.{fn_name}()` or `client_fn`, but not both.
flwr/common/constant.py CHANGED
@@ -127,6 +127,7 @@ class MessageType:
127
127
  TRAIN = "train"
128
128
  EVALUATE = "evaluate"
129
129
  QUERY = "query"
130
+ SYSTEM = "system"
130
131
 
131
132
  def __new__(cls) -> MessageType:
132
133
  """Prevent instantiation."""
flwr/common/message.py CHANGED
@@ -21,7 +21,7 @@ import time
21
21
  from logging import WARNING
22
22
  from typing import Optional, cast
23
23
 
24
- from .constant import MESSAGE_TTL_TOLERANCE
24
+ from .constant import MESSAGE_TTL_TOLERANCE, MessageType, MessageTypeLegacy
25
25
  from .logger import log
26
26
  from .record import RecordSet
27
27
 
@@ -75,6 +75,7 @@ class Metadata: # pylint: disable=too-many-instance-attributes
75
75
  "_message_type": message_type,
76
76
  }
77
77
  self.__dict__.update(var_dict)
78
+ self.message_type = message_type # Trigger validation
78
79
 
79
80
  @property
80
81
  def run_id(self) -> int:
@@ -154,6 +155,17 @@ class Metadata: # pylint: disable=too-many-instance-attributes
154
155
  @message_type.setter
155
156
  def message_type(self, value: str) -> None:
156
157
  """Set message_type."""
158
+ # Validate message type
159
+ if validate_legacy_message_type(value):
160
+ pass # Backward compatibility for legacy message types
161
+ elif not validate_message_type(value):
162
+ raise ValueError(
163
+ f"Invalid message type: '{value}'. "
164
+ "Expected format: '<category>' or '<category>.<action>', "
165
+ "where <category> must be 'train', 'evaluate', or 'query', "
166
+ "and <action> must be a valid Python identifier."
167
+ )
168
+
157
169
  self.__dict__["_message_type"] = value
158
170
 
159
171
  def __repr__(self) -> str:
@@ -417,3 +429,48 @@ def _create_reply_metadata(msg: Message, ttl: float) -> Metadata:
417
429
  ttl=ttl,
418
430
  message_type=msg.metadata.message_type,
419
431
  )
432
+
433
+
434
+ def validate_message_type(message_type: str) -> bool:
435
+ """Validate if the message type is valid.
436
+
437
+ A valid message type format must be one of the following:
438
+
439
+ - "<category>"
440
+ - "<category>.<action>"
441
+
442
+ where `category` must be one of "train", "evaluate", or "query",
443
+ and `action` must be a valid Python identifier.
444
+ """
445
+ # Check if conforming to the format "<category>"
446
+ valid_types = {
447
+ MessageType.TRAIN,
448
+ MessageType.EVALUATE,
449
+ MessageType.QUERY,
450
+ MessageType.SYSTEM,
451
+ }
452
+ if message_type in valid_types:
453
+ return True
454
+
455
+ # Check if conforming to the format "<category>.<action>"
456
+ if message_type.count(".") != 1:
457
+ return False
458
+
459
+ category, action = message_type.split(".")
460
+ if category in valid_types and action.isidentifier():
461
+ return True
462
+
463
+ return False
464
+
465
+
466
+ def validate_legacy_message_type(message_type: str) -> bool:
467
+ """Validate if the legacy message type is valid."""
468
+ # Backward compatibility for legacy message types
469
+ if message_type in (
470
+ MessageTypeLegacy.GET_PARAMETERS,
471
+ MessageTypeLegacy.GET_PROPERTIES,
472
+ "reconnect",
473
+ ):
474
+ return True
475
+
476
+ return False
@@ -20,7 +20,13 @@ from typing import Optional
20
20
  from uuid import UUID, uuid4
21
21
 
22
22
  from flwr.common import ConfigsRecord, Context, Error, Message, Metadata, now, serde
23
- from flwr.common.constant import SUPERLINK_NODE_ID, ErrorCode, Status, SubStatus
23
+ from flwr.common.constant import (
24
+ SUPERLINK_NODE_ID,
25
+ ErrorCode,
26
+ MessageType,
27
+ Status,
28
+ SubStatus,
29
+ )
24
30
  from flwr.common.typing import RunStatus
25
31
 
26
32
  # pylint: disable=E0611
@@ -266,7 +272,7 @@ def create_message_error_unavailable_ins_message(reply_to_message: UUID) -> Mess
266
272
  dst_node_id=SUPERLINK_NODE_ID,
267
273
  reply_to_message=str(reply_to_message),
268
274
  group_id="", # Unknown
269
- message_type="", # Unknown
275
+ message_type=MessageType.SYSTEM,
270
276
  ttl=0,
271
277
  )
272
278
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.17.0.dev20250314
3
+ Version: 1.17.0.dev20250315
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -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=mRj5AXokCV9WYivgkNEdBPUHXjNr_ZOQ50Dou0REhkw,14481
77
+ flwr/client/client_app.py,sha256=8PpAlN7KT8oNFBFVWbGGi39Zw-fhKBZYLGAs4s1aMdY,17312
78
78
  flwr/client/clientapp/__init__.py,sha256=kZqChGnTChQ1WGSUkIlW2S5bc0d0mzDubCAmZUGRpEY,800
79
79
  flwr/client/clientapp/app.py,sha256=B3GrIMP8BMvltYf4n4xbtlRR1jEPT5-F93KnBCPuPJM,9069
80
80
  flwr/client/clientapp/clientappio_servicer.py,sha256=5L6bjw_j3Mnx9kRFwYwxDNABKurBO5q1jZOWE_X11wQ,8522
@@ -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=lAnqe63ZzW0NcS306rnEVICpJSXCFNoPj4L1X-p0FCA,6853
119
+ flwr/common/constant.py,sha256=2AHf9ujmfkf9YerhtqBe8hAW6iMDJTmnKnyYdlEXEM0,6875
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
@@ -130,7 +130,7 @@ flwr/common/exit/exit_code.py,sha256=PNEnCrZfOILjfDAFu5m-2YWEJBrk97xglq4zCUlqV7E
130
130
  flwr/common/exit_handlers.py,sha256=yclujry30954o0lI7vtknTajskPCvK8TXw2V3RdldXU,3174
131
131
  flwr/common/grpc.py,sha256=7sHNP34LcNZv7J1GewJxXh509XTEbYvoHvXL5tQ3tcw,9798
132
132
  flwr/common/logger.py,sha256=Hund1C6bEhMw3GemlzuFK22tXZ27YeHLrFB0b4LP5f8,13041
133
- flwr/common/message.py,sha256=rWH_JIPnIo263-pC6Ps6XWmIgakRJA_AMBYwhE0qHcQ,14251
133
+ flwr/common/message.py,sha256=dbaIKvw1hJZrLpipbdX6hUw1nhzrxDMXCS7EADQUwE8,16060
134
134
  flwr/common/object_ref.py,sha256=DXL8NtbN17DSYaR-Zc8WYhaG8rv0_D_cclvP7Sa66So,9134
135
135
  flwr/common/parameter.py,sha256=-bFAUayToYDF50FZGrBC1hQYJCQDtB2bbr3ZuVLMtdE,2095
136
136
  flwr/common/pyproject.py,sha256=vEAxl800XiJ1JNJDui8vuVV-08msnB6hLt7o95viZl0,1386
@@ -293,7 +293,7 @@ flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=Ss64nq7MgbHwx4LOER
293
293
  flwr/server/superlink/linkstate/linkstate.py,sha256=YB3SryGNvt-bE-unYjoloJt9d3xAUPBNLK4mor8gk3M,11851
294
294
  flwr/server/superlink/linkstate/linkstate_factory.py,sha256=ISSMjDlwuN7swxjOeYlTNpI_kuZ8PGkMcJnf1dbhUSE,2069
295
295
  flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=Wsx5gD6WRIMLlKarvVV1_dlS7jmfno-yTVW1-rgcIto,38276
296
- flwr/server/superlink/linkstate/utils.py,sha256=UunwphV90p9XzvGFJpZr3C64HgIyXjhRPNBVS3HSL8M,12696
296
+ flwr/server/superlink/linkstate/utils.py,sha256=b26MJdMQyt83EDnhB7FAiq8BFttV_qNHF_E_3d3oBlA,12739
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
@@ -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.dev20250314.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
330
- flwr_nightly-1.17.0.dev20250314.dist-info/METADATA,sha256=PsL8Jgg_8fxGXcMbpUmfL8DJpXTNmAh2d0N97QtQYqE,15877
331
- flwr_nightly-1.17.0.dev20250314.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
332
- flwr_nightly-1.17.0.dev20250314.dist-info/entry_points.txt,sha256=2-1L-GNKhwGw2_7_RoH55vHw2SIHjdAQy3HAVAWl9PY,374
333
- flwr_nightly-1.17.0.dev20250314.dist-info/RECORD,,
329
+ flwr_nightly-1.17.0.dev20250315.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
330
+ flwr_nightly-1.17.0.dev20250315.dist-info/METADATA,sha256=CGDY38Gu3jFMjObvNjdT4pV4OJ2kHHdlpoN1qfodszc,15877
331
+ flwr_nightly-1.17.0.dev20250315.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
332
+ flwr_nightly-1.17.0.dev20250315.dist-info/entry_points.txt,sha256=2-1L-GNKhwGw2_7_RoH55vHw2SIHjdAQy3HAVAWl9PY,374
333
+ flwr_nightly-1.17.0.dev20250315.dist-info/RECORD,,