flwr-nightly 1.16.0.dev20250304__py3-none-any.whl → 1.16.0.dev20250306__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.
@@ -20,12 +20,21 @@ from os import urandom
20
20
  from typing import Optional, Union
21
21
  from uuid import UUID, uuid4
22
22
 
23
- from flwr.common import ConfigsRecord, Context, log, now, serde
23
+ from flwr.common import (
24
+ ConfigsRecord,
25
+ Context,
26
+ Error,
27
+ Message,
28
+ Metadata,
29
+ log,
30
+ now,
31
+ serde,
32
+ )
24
33
  from flwr.common.constant import SUPERLINK_NODE_ID, ErrorCode, Status, SubStatus
25
34
  from flwr.common.typing import RunStatus
26
35
 
27
36
  # pylint: disable=E0611
28
- from flwr.proto.error_pb2 import Error
37
+ from flwr.proto.error_pb2 import Error as ProtoError
29
38
  from flwr.proto.message_pb2 import Context as ProtoContext
30
39
  from flwr.proto.node_pb2 import Node
31
40
  from flwr.proto.recordset_pb2 import ConfigsRecord as ProtoConfigsRecord
@@ -262,7 +271,7 @@ def create_taskres_for_unavailable_taskins(taskins_id: Union[str, UUID]) -> Task
262
271
  ttl=0,
263
272
  ancestry=[str(taskins_id)],
264
273
  task_type="", # Unknown message type
265
- error=Error(
274
+ error=ProtoError(
266
275
  code=ErrorCode.MESSAGE_UNAVAILABLE,
267
276
  reason=MESSAGE_UNAVAILABLE_ERROR_REASON,
268
277
  ),
@@ -301,7 +310,7 @@ def create_taskres_for_unavailable_taskres(ref_taskins: TaskIns) -> TaskRes:
301
310
  ttl=ttl,
302
311
  ancestry=[ref_taskins.task_id],
303
312
  task_type=ref_taskins.task.task_type,
304
- error=Error(
313
+ error=ProtoError(
305
314
  code=ErrorCode.REPLY_MESSAGE_UNAVAILABLE,
306
315
  reason=REPLY_MESSAGE_UNAVAILABLE_ERROR_REASON,
307
316
  ),
@@ -309,11 +318,64 @@ def create_taskres_for_unavailable_taskres(ref_taskins: TaskIns) -> TaskRes:
309
318
  )
310
319
 
311
320
 
321
+ def create_message_error_unavailable_res_message(ins_metadata: Metadata) -> Message:
322
+ """Generate an error Message that the SuperLink returns carrying the specified
323
+ error."""
324
+ current_time = now().timestamp()
325
+ ttl = max(ins_metadata.ttl - (current_time - ins_metadata.created_at), 0)
326
+ metadata = Metadata(
327
+ run_id=ins_metadata.run_id,
328
+ message_id=str(uuid4()),
329
+ src_node_id=SUPERLINK_NODE_ID,
330
+ dst_node_id=SUPERLINK_NODE_ID,
331
+ reply_to_message=ins_metadata.message_id,
332
+ group_id=ins_metadata.group_id,
333
+ message_type=ins_metadata.message_type,
334
+ ttl=ttl,
335
+ )
336
+
337
+ return Message(
338
+ metadata=metadata,
339
+ error=Error(
340
+ code=ErrorCode.REPLY_MESSAGE_UNAVAILABLE,
341
+ reason=REPLY_MESSAGE_UNAVAILABLE_ERROR_REASON,
342
+ ),
343
+ )
344
+
345
+
346
+ def create_message_error_unavailable_ins_message(reply_to_message: UUID) -> Message:
347
+ """Error to indicate that the enquired Message had expired before reply arrived or
348
+ that it isn't found."""
349
+ metadata = Metadata(
350
+ run_id=0, # Unknown
351
+ message_id=str(uuid4()),
352
+ src_node_id=SUPERLINK_NODE_ID,
353
+ dst_node_id=SUPERLINK_NODE_ID,
354
+ reply_to_message=str(reply_to_message),
355
+ group_id="", # Unknown
356
+ message_type="", # Unknown
357
+ ttl=0,
358
+ )
359
+
360
+ return Message(
361
+ metadata=metadata,
362
+ error=Error(
363
+ code=ErrorCode.MESSAGE_UNAVAILABLE,
364
+ reason=MESSAGE_UNAVAILABLE_ERROR_REASON,
365
+ ),
366
+ )
367
+
368
+
312
369
  def has_expired(task_ins_or_res: Union[TaskIns, TaskRes], current_time: float) -> bool:
313
370
  """Check if the TaskIns/TaskRes has expired."""
314
371
  return task_ins_or_res.task.ttl + task_ins_or_res.task.created_at < current_time
315
372
 
316
373
 
374
+ def message_ttl_has_expired(message_metadata: Metadata, current_time: float) -> bool:
375
+ """Check if the Message has expired."""
376
+ return message_metadata.ttl + message_metadata.created_at < current_time
377
+
378
+
317
379
  def verify_taskins_ids(
318
380
  inquired_taskins_ids: set[UUID],
319
381
  found_taskins_dict: dict[UUID, TaskIns],
@@ -353,6 +415,48 @@ def verify_taskins_ids(
353
415
  return ret_dict
354
416
 
355
417
 
418
+ def verify_message_ids(
419
+ inquired_message_ids: set[UUID],
420
+ found_message_ins_dict: dict[UUID, Message],
421
+ current_time: Optional[float] = None,
422
+ update_set: bool = True,
423
+ ) -> dict[UUID, Message]:
424
+ """Verify found Messages and generate error Messages for invalid ones.
425
+
426
+ Parameters
427
+ ----------
428
+ inquired_message_ids : set[UUID]
429
+ Set of Message IDs for which to generate error Message if invalid.
430
+ found_message_ins_dict : dict[UUID, Message]
431
+ Dictionary containing all found Message indexed by their IDs.
432
+ current_time : Optional[float] (default: None)
433
+ The current time to check for expiration. If set to `None`, the current time
434
+ will automatically be set to the current timestamp using `now().timestamp()`.
435
+ update_set : bool (default: True)
436
+ If True, the `inquired_message_ids` will be updated to remove invalid ones,
437
+ by default True.
438
+
439
+ Returns
440
+ -------
441
+ dict[UUID, Message]
442
+ A dictionary of error Message indexed by the corresponding ID of the message
443
+ they are a reply of.
444
+ """
445
+ ret_dict = {}
446
+ current = current_time if current_time else now().timestamp()
447
+ for message_id in list(inquired_message_ids):
448
+ # Generate error message if the inquired message doesn't exist or has expired
449
+ message_ins = found_message_ins_dict.get(message_id)
450
+ if message_ins is None or message_ttl_has_expired(
451
+ message_ins.metadata, current
452
+ ):
453
+ if update_set:
454
+ inquired_message_ids.remove(message_id)
455
+ message_res = create_message_error_unavailable_ins_message(message_id)
456
+ ret_dict[message_id] = message_res
457
+ return ret_dict
458
+
459
+
356
460
  def verify_found_taskres(
357
461
  inquired_taskins_ids: set[UUID],
358
462
  found_taskins_dict: dict[UUID, TaskIns],
@@ -397,3 +501,48 @@ def verify_found_taskres(
397
501
  taskres.task.delivered_at = now().isoformat()
398
502
  ret_dict[taskins_id] = taskres
399
503
  return ret_dict
504
+
505
+
506
+ def verify_found_message_replies(
507
+ inquired_message_ids: set[UUID],
508
+ found_message_ins_dict: dict[UUID, Message],
509
+ found_message_res_list: list[Message],
510
+ current_time: Optional[float] = None,
511
+ update_set: bool = True,
512
+ ) -> dict[UUID, Message]:
513
+ """Verify found Message replies and generate error Message for invalid ones.
514
+
515
+ Parameters
516
+ ----------
517
+ inquired_message_ids : set[UUID]
518
+ Set of Message IDs for which to generate error Message if invalid.
519
+ found_message_ins_dict : dict[UUID, Message]
520
+ Dictionary containing all found instruction Messages indexed by their IDs.
521
+ found_message_res_list : dict[Message, Message]
522
+ List of found Message to be verified.
523
+ current_time : Optional[float] (default: None)
524
+ The current time to check for expiration. If set to `None`, the current time
525
+ will automatically be set to the current timestamp using `now().timestamp()`.
526
+ update_set : bool (default: True)
527
+ If True, the `inquired_message_ids` will be updated to remove ones
528
+ that have a reply Message, by default True.
529
+
530
+ Returns
531
+ -------
532
+ dict[UUID, Message]
533
+ A dictionary of Message indexed by the corresponding Message ID.
534
+ """
535
+ ret_dict: dict[UUID, Message] = {}
536
+ current = current_time if current_time else now().timestamp()
537
+ for message_res in found_message_res_list:
538
+ message_ins_id = UUID(message_res.metadata.reply_to_message)
539
+ if update_set:
540
+ inquired_message_ids.remove(message_ins_id)
541
+ # Check if the reply Message has expired
542
+ if message_ttl_has_expired(message_res.metadata, current):
543
+ # No need to insert the error Message
544
+ message_res = create_message_error_unavailable_res_message(
545
+ found_message_ins_dict[message_ins_id].metadata
546
+ )
547
+ ret_dict[message_ins_id] = message_res
548
+ return ret_dict
@@ -64,10 +64,13 @@ class DefaultWorkflow:
64
64
  )
65
65
 
66
66
  # Start the thread updating nodes
67
- thread, f_stop = start_update_client_manager_thread(
67
+ thread, f_stop, c_done = start_update_client_manager_thread(
68
68
  driver, context.client_manager
69
69
  )
70
70
 
71
+ # Wait until the node registration done
72
+ c_done.wait()
73
+
71
74
  # Initialize parameters
72
75
  log(INFO, "[INIT]")
73
76
  default_init_params_workflow(driver, context)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.16.0.dev20250304
3
+ Version: 1.16.0.dev20250306
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -223,15 +223,15 @@ flwr/server/app.py,sha256=a_3hM-RktaPp3QTKDlBuHATB9oS2deGShZGEtmhlnX0,31005
223
223
  flwr/server/client_manager.py,sha256=7Ese0tgrH-i-ms363feYZJKwB8gWnXSmg_hYF2Bju4U,6227
224
224
  flwr/server/client_proxy.py,sha256=4G-oTwhb45sfWLx2uZdcXD98IZwdTS6F88xe3akCdUg,2399
225
225
  flwr/server/compat/__init__.py,sha256=VxnJtJyOjNFQXMNi9hIuzNlZM5n0Hj1p3aq_Pm2udw4,892
226
- flwr/server/compat/app.py,sha256=5vkHHm_h-4cMthvWD1GJo1ZW3eihytjGgvsgfXUK9gA,3298
227
- flwr/server/compat/app_utils.py,sha256=Kggcoi5vQCBQmYvXBBUxhtDUcIwFiQyfphkHp2K1WxM,3546
226
+ flwr/server/compat/app.py,sha256=Y0xAqXLn20e6XKGb2nHdeUYdCj_Dux-SyFCc-5ivhqk,3369
227
+ flwr/server/compat/app_utils.py,sha256=568PfvPME8KHjX-L5GB2rYQa_Wy8iUBGs22KJqn8Xk0,3824
228
228
  flwr/server/compat/driver_client_proxy.py,sha256=jMmrfqSm4-qW0jOCTpHhN9Kw0ohfMwsyKU9buBzrfG0,4958
229
229
  flwr/server/compat/legacy_context.py,sha256=wBzBcfV6YO6IQGriM_FdJ5XZfiBBEEJdS_OdAiF47dY,1804
230
230
  flwr/server/criterion.py,sha256=ypbAexbztzGUxNen9RCHF91QeqiEQix4t4Ih3E-42MM,1061
231
231
  flwr/server/driver/__init__.py,sha256=bikRv6CjTwSvYh7tf10gziU5o2YotOWhhftz2tr3KDc,886
232
- flwr/server/driver/driver.py,sha256=u_fMfqLYTroTafGCNwKPHI4lttRL-Z5CqeT3_FHSq-Q,5701
233
- flwr/server/driver/grpc_driver.py,sha256=3mSws0l83fWD4aq9-MmHFnIfyf4REoAXUkWfyJDHros,9864
234
- flwr/server/driver/inmemory_driver.py,sha256=7ZtWDDJa8xupPAHNaDdCE2DOIOIYgrffmJMdKjs3wdA,6616
232
+ flwr/server/driver/driver.py,sha256=X072eFWl8Kx-aZbahTkpAc1wwoojr8A4uO2yozwwSbE,5705
233
+ flwr/server/driver/grpc_driver.py,sha256=CLa9pxN2yf1lIdxkFHVVWrs_9EFHSNUU9SJluNIQwKM,9868
234
+ flwr/server/driver/inmemory_driver.py,sha256=ISdouBg6BvoUCMpUNykS2b6ncnCl_ZXcDGKLtpJUMLE,6614
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
@@ -293,11 +293,11 @@ flwr/server/superlink/fleet/vce/backend/backend.py,sha256=LBAQxnbfPAphVOVIvYMj0Q
293
293
  flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=jsUkFEVQTnrucK1jNQ_cUM8YwL7W4MQNA1GAf8ibRdg,7156
294
294
  flwr/server/superlink/fleet/vce/vce_api.py,sha256=iXNSAJ7f8Sg1hOrVuRTGRkLdSWeFIpNWbusoOTc4I8I,12971
295
295
  flwr/server/superlink/linkstate/__init__.py,sha256=v-2JyJlCB3qyhMNwMjmcNVOq4rkooqFU0LHH8Zo1jls,1064
296
- flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=4ahMj7TLe-GO2ctyeZ2BBRkviGv27s6x1NS_ETRJHP8,20514
297
- flwr/server/superlink/linkstate/linkstate.py,sha256=LWA5zRwN829GDAeSo5kmkzsMu0SkXa9qg4aG_0QN0uk,12159
296
+ flwr/server/superlink/linkstate/in_memory_linkstate.py,sha256=tw98opVU78Q9jfIORLRhwSATiMTfDa5THlcegwXSzWM,29377
297
+ flwr/server/superlink/linkstate/linkstate.py,sha256=Yi76bAq-OJmDjl1HAQInrPIU0m9dKMiYugNJXKpKyuw,15843
298
298
  flwr/server/superlink/linkstate/linkstate_factory.py,sha256=ISSMjDlwuN7swxjOeYlTNpI_kuZ8PGkMcJnf1dbhUSE,2069
299
- flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=YEXk_3avSF9T9sk5xxYwNeljLZ-qzg1zIAJOlkkmsX0,40146
300
- flwr/server/superlink/linkstate/utils.py,sha256=EpRehwI4NeEW3oINICPWP9STK49N0aszd5s5jtle7DQ,13602
299
+ flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=c33n0iOZiQwNd07KfPkQbKZ7cSEX5LGg1crlUHd1ZD0,55309
300
+ flwr/server/superlink/linkstate/utils.py,sha256=vKJYvzP_MbYD2Qo8ly6Qibyb4SI92G_4sB60ubELj64,19048
301
301
  flwr/server/superlink/simulation/__init__.py,sha256=mg-oapC9dkzEfjXPQFior5lpWj4g9kwbLovptyYM_g0,718
302
302
  flwr/server/superlink/simulation/simulationio_grpc.py,sha256=8aUrZZLdvprKUfLLqFID4aItus9beU6m1qLQYIPB7k0,2224
303
303
  flwr/server/superlink/simulation/simulationio_servicer.py,sha256=J_TmdqM-Bxgp-iPEI3tvCuBpykw1UX0FouMQalEYAF4,6907
@@ -308,7 +308,7 @@ flwr/server/utils/tensorboard.py,sha256=gEBD8w_5uaIfp5aw5RYH66lYZpd_SfkObHQ7eDd9
308
308
  flwr/server/utils/validator.py,sha256=UzYFMIyXyORXYRYXbFhOk6q6GDpOE-eIqLhlNFnR__0,7256
309
309
  flwr/server/workflow/__init__.py,sha256=SXY0XkwbkezFBxxrFB5hKUtmtAgnYISBkPouR1V71ss,902
310
310
  flwr/server/workflow/constant.py,sha256=q4DLdR8Krlxuewq2AQjwTL75hphxE5ODNz4AhViHMXk,1082
311
- flwr/server/workflow/default_workflows.py,sha256=UMC9JgdomKwxql5G0OV4AeRXWI-bMClaLAOn5OrZMnw,14073
311
+ flwr/server/workflow/default_workflows.py,sha256=RwDX7hXOI1-q4FH9A0onHvadqa5yXTzslpmShPpXodk,14152
312
312
  flwr/server/workflow/secure_aggregation/__init__.py,sha256=3XlgDOjD_hcukTGl6Bc1B-8M_dPlVSJuTbvXIbiO-Ic,880
313
313
  flwr/server/workflow/secure_aggregation/secagg_workflow.py,sha256=l2IdMdJjs1bgHs5vQgLSOVzar7v2oxUn46oCrnVE1rM,5839
314
314
  flwr/server/workflow/secure_aggregation/secaggplus_workflow.py,sha256=rfn2etO1nb7u-1oRl-H9q3enJZz3shMINZaBB7rPsC4,29671
@@ -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.dev20250304.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
333
- flwr_nightly-1.16.0.dev20250304.dist-info/METADATA,sha256=9UmUVO9D8c2kO1ENirbWqVGKtkre0B99yYfu3kfqLvs,15877
334
- flwr_nightly-1.16.0.dev20250304.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
335
- flwr_nightly-1.16.0.dev20250304.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
336
- flwr_nightly-1.16.0.dev20250304.dist-info/RECORD,,
332
+ flwr_nightly-1.16.0.dev20250306.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
333
+ flwr_nightly-1.16.0.dev20250306.dist-info/METADATA,sha256=QeUbeAdWXzaQVzTbWnix4C4edvDHIKVh_CxkJN7dTo0,15877
334
+ flwr_nightly-1.16.0.dev20250306.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
335
+ flwr_nightly-1.16.0.dev20250306.dist-info/entry_points.txt,sha256=JlNxX3qhaV18_2yj5a3kJW1ESxm31cal9iS_N_pf1Rk,538
336
+ flwr_nightly-1.16.0.dev20250306.dist-info/RECORD,,