flwr-nightly 1.20.0.dev20250714__py3-none-any.whl → 1.20.0.dev20250716__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.
@@ -31,11 +31,12 @@ from flwr.common.heartbeat import HeartbeatSender
31
31
  from flwr.common.inflatable import (
32
32
  get_all_nested_objects,
33
33
  get_object_tree,
34
+ iterate_object_tree,
34
35
  no_object_id_recompute,
35
36
  )
36
- from flwr.common.inflatable_grpc_utils import (
37
- make_pull_object_fn_grpc,
38
- make_push_object_fn_grpc,
37
+ from flwr.common.inflatable_protobuf_utils import (
38
+ make_pull_object_fn_protobuf,
39
+ make_push_object_fn_protobuf,
39
40
  )
40
41
  from flwr.common.inflatable_utils import (
41
42
  inflate_object_from_contents,
@@ -273,10 +274,11 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
273
274
  if message_proto:
274
275
  msg_id = message_proto.metadata.message_id
275
276
  run_id = message_proto.metadata.run_id
277
+ object_tree = response.message_object_trees[0]
276
278
  all_object_contents = pull_objects(
277
- list(response.objects_to_pull[msg_id].object_ids) + [msg_id],
278
- pull_object_fn=make_pull_object_fn_grpc(
279
- pull_object_grpc=stub.PullObject,
279
+ [tree.object_id for tree in iterate_object_tree(object_tree)],
280
+ pull_object_fn=make_pull_object_fn_protobuf(
281
+ pull_object_protobuf=stub.PullObject,
280
282
  node=node,
281
283
  run_id=run_id,
282
284
  ),
@@ -328,8 +330,8 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
328
330
  )
329
331
  push_objects(
330
332
  all_objects,
331
- push_object_fn=make_push_object_fn_grpc(
332
- push_object_grpc=stub.PushObject,
333
+ push_object_fn=make_push_object_fn_protobuf(
334
+ push_object_protobuf=stub.PushObject,
333
335
  node=node,
334
336
  run_id=message.metadata.run_id,
335
337
  ),
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """Contextmanager for a REST request-response channel to the Flower server."""
16
16
 
17
+
17
18
  from collections.abc import Iterator
18
19
  from contextlib import contextmanager
19
20
  from logging import DEBUG, ERROR, INFO, WARN
@@ -30,11 +31,12 @@ from flwr.common.heartbeat import HeartbeatSender
30
31
  from flwr.common.inflatable import (
31
32
  get_all_nested_objects,
32
33
  get_object_tree,
34
+ iterate_object_tree,
33
35
  no_object_id_recompute,
34
36
  )
35
- from flwr.common.inflatable_rest_utils import (
36
- make_pull_object_fn_rest,
37
- make_push_object_fn_rest,
37
+ from flwr.common.inflatable_protobuf_utils import (
38
+ make_pull_object_fn_protobuf,
39
+ make_push_object_fn_protobuf,
38
40
  )
39
41
  from flwr.common.inflatable_utils import (
40
42
  inflate_object_from_contents,
@@ -333,10 +335,11 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
333
335
  return res
334
336
 
335
337
  try:
338
+ object_tree = res.message_object_trees[0]
336
339
  all_object_contents = pull_objects(
337
- list(res.objects_to_pull[msg_id].object_ids) + [msg_id],
338
- pull_object_fn=make_pull_object_fn_rest(
339
- pull_object_rest=fn,
340
+ [tree.object_id for tree in iterate_object_tree(object_tree)],
341
+ pull_object_fn=make_pull_object_fn_protobuf(
342
+ pull_object_protobuf=fn,
340
343
  node=node,
341
344
  run_id=run_id,
342
345
  ),
@@ -413,8 +416,8 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
413
416
  try:
414
417
  push_objects(
415
418
  all_objects,
416
- push_object_fn=make_push_object_fn_rest(
417
- push_object_rest=fn,
419
+ push_object_fn=make_push_object_fn_protobuf(
420
+ push_object_protobuf=fn,
418
421
  node=node,
419
422
  run_id=message_proto.metadata.run_id,
420
423
  ),
flwr/common/grpc.py CHANGED
@@ -23,6 +23,9 @@ from logging import DEBUG, ERROR
23
23
  from typing import Any, Callable, Optional
24
24
 
25
25
  import grpc
26
+ from grpc_health.v1.health_pb2_grpc import add_HealthServicer_to_server
27
+
28
+ from flwr.supercore.grpc_health import SimpleHealthServicer
26
29
 
27
30
  from .address import is_port_in_use
28
31
  from .logger import log
@@ -98,7 +101,7 @@ def valid_certificates(certificates: tuple[bytes, bytes, bytes]) -> bool:
98
101
  return is_valid
99
102
 
100
103
 
101
- def generic_create_grpc_server( # pylint: disable=too-many-arguments,R0917
104
+ def generic_create_grpc_server( # pylint: disable=too-many-arguments, R0914, R0917
102
105
  servicer_and_add_fn: tuple[Any, AddServicerToServerFn],
103
106
  server_address: str,
104
107
  max_concurrent_workers: int = 1000,
@@ -106,6 +109,7 @@ def generic_create_grpc_server( # pylint: disable=too-many-arguments,R0917
106
109
  keepalive_time_ms: int = 210000,
107
110
  certificates: Optional[tuple[bytes, bytes, bytes]] = None,
108
111
  interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None,
112
+ health_servicer: Optional[Any] = None,
109
113
  ) -> grpc.Server:
110
114
  """Create a gRPC server with a single servicer.
111
115
 
@@ -153,6 +157,10 @@ def generic_create_grpc_server( # pylint: disable=too-many-arguments,R0917
153
157
  * server private key.
154
158
  interceptors : Optional[Sequence[grpc.ServerInterceptor]] (default: None)
155
159
  A list of gRPC interceptors.
160
+ health_servicer : Optional[Any] (default: None)
161
+ An optional health servicer to add to the server. If provided, it should be an
162
+ instance of a class that inherits the `HealthServicer` class.
163
+ If None is provided, `SimpleHealthServicer` will be used by default.
156
164
 
157
165
  Returns
158
166
  -------
@@ -203,6 +211,9 @@ def generic_create_grpc_server( # pylint: disable=too-many-arguments,R0917
203
211
  )
204
212
  add_servicer_to_server_fn(servicer, server)
205
213
 
214
+ # Enable health service
215
+ add_HealthServicer_to_server(health_servicer or SimpleHealthServicer(), server)
216
+
206
217
  if certificates is not None:
207
218
  if not valid_certificates(certificates):
208
219
  sys.exit(1)
@@ -28,8 +28,8 @@ from flwr.proto.node_pb2 import Node # pylint: disable=E0611
28
28
  from .inflatable_utils import ObjectIdNotPreregisteredError, ObjectUnavailableError
29
29
 
30
30
 
31
- def make_pull_object_fn_grpc(
32
- pull_object_grpc: Callable[[PullObjectRequest], PullObjectResponse],
31
+ def make_pull_object_fn_protobuf(
32
+ pull_object_protobuf: Callable[[PullObjectRequest], PullObjectResponse],
33
33
  node: Node,
34
34
  run_id: int,
35
35
  ) -> Callable[[str], bytes]:
@@ -37,8 +37,9 @@ def make_pull_object_fn_grpc(
37
37
 
38
38
  Parameters
39
39
  ----------
40
- pull_object_grpc : Callable[[PullObjectRequest], PullObjectResponse]
41
- The gRPC function to pull objects, e.g., `FleetStub.PullObject`.
40
+ pull_object_protobuf : Callable[[PullObjectRequest], PullObjectResponse]
41
+ A callable that takes a `PullObjectRequest` and returns a `PullObjectResponse`.
42
+ This function is typically backed by a gRPC client stub.
42
43
  node : Node
43
44
  The node making the request.
44
45
  run_id : int
@@ -54,7 +55,7 @@ def make_pull_object_fn_grpc(
54
55
 
55
56
  def pull_object_fn(object_id: str) -> bytes:
56
57
  request = PullObjectRequest(node=node, run_id=run_id, object_id=object_id)
57
- response: PullObjectResponse = pull_object_grpc(request)
58
+ response: PullObjectResponse = pull_object_protobuf(request)
58
59
  if not response.object_found:
59
60
  raise ObjectIdNotPreregisteredError(object_id)
60
61
  if not response.object_available:
@@ -64,8 +65,8 @@ def make_pull_object_fn_grpc(
64
65
  return pull_object_fn
65
66
 
66
67
 
67
- def make_push_object_fn_grpc(
68
- push_object_grpc: Callable[[PushObjectRequest], PushObjectResponse],
68
+ def make_push_object_fn_protobuf(
69
+ push_object_protobuf: Callable[[PushObjectRequest], PushObjectResponse],
69
70
  node: Node,
70
71
  run_id: int,
71
72
  ) -> Callable[[str, bytes], None]:
@@ -73,8 +74,9 @@ def make_push_object_fn_grpc(
73
74
 
74
75
  Parameters
75
76
  ----------
76
- push_object_grpc : Callable[[PushObjectRequest], PushObjectResponse]
77
- The gRPC function to push objects, e.g., `FleetStub.PushObject`.
77
+ push_object_protobuf : Callable[[PushObjectRequest], PushObjectResponse]
78
+ A callable that takes a `PushObjectRequest` and returns a `PushObjectResponse`.
79
+ This function is typically backed by a gRPC client stub.
78
80
  node : Node
79
81
  The node making the request.
80
82
  run_id : int
@@ -92,7 +94,7 @@ def make_push_object_fn_grpc(
92
94
  request = PushObjectRequest(
93
95
  node=node, run_id=run_id, object_id=object_id, object_content=object_content
94
96
  )
95
- response: PushObjectResponse = push_object_grpc(request)
97
+ response: PushObjectResponse = push_object_protobuf(request)
96
98
  if not response.stored:
97
99
  raise ObjectIdNotPreregisteredError(object_id)
98
100
 
flwr/proto/fleet_pb2.py CHANGED
@@ -19,15 +19,13 @@ from flwr.proto import fab_pb2 as flwr_dot_proto_dot_fab__pb2
19
19
  from flwr.proto import message_pb2 as flwr_dot_proto_dot_message__pb2
20
20
 
21
21
 
22
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x1a\x66lwr/proto/heartbeat.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x18\x66lwr/proto/message.proto\"/\n\x11\x43reateNodeRequest\x12\x1a\n\x12heartbeat_interval\x18\x01 \x01(\x01\"4\n\x12\x43reateNodeResponse\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"3\n\x11\x44\x65leteNodeRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"\x14\n\x12\x44\x65leteNodeResponse\"J\n\x13PullMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x13\n\x0bmessage_ids\x18\x02 \x03(\t\"\x87\x02\n\x14PullMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\x12L\n\x0fobjects_to_pull\x18\x03 \x03(\x0b\x32\x33.flwr.proto.PullMessagesResponse.ObjectsToPullEntry\x1aK\n\x12ObjectsToPullEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.flwr.proto.ObjectIDs:\x02\x38\x01\"\x97\x01\n\x13PushMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\x12\x34\n\x14message_object_trees\x18\x03 \x03(\x0b\x32\x16.flwr.proto.ObjectTree\"\xcb\x02\n\x14PushMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12>\n\x07results\x18\x02 \x03(\x0b\x32-.flwr.proto.PushMessagesResponse.ResultsEntry\x12L\n\x0fobjects_to_push\x18\x03 \x03(\x0b\x32\x33.flwr.proto.PushMessagesResponse.ObjectsToPushEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\x1aK\n\x12ObjectsToPushEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.flwr.proto.ObjectIDs:\x02\x38\x01\"\x1e\n\tReconnect\x12\x11\n\treconnect\x18\x01 \x01(\x04\x32\xca\x06\n\x05\x46leet\x12M\n\nCreateNode\x12\x1d.flwr.proto.CreateNodeRequest\x1a\x1e.flwr.proto.CreateNodeResponse\"\x00\x12M\n\nDeleteNode\x12\x1d.flwr.proto.DeleteNodeRequest\x1a\x1e.flwr.proto.DeleteNodeResponse\"\x00\x12\x62\n\x11SendNodeHeartbeat\x12$.flwr.proto.SendNodeHeartbeatRequest\x1a%.flwr.proto.SendNodeHeartbeatResponse\"\x00\x12S\n\x0cPullMessages\x12\x1f.flwr.proto.PullMessagesRequest\x1a .flwr.proto.PullMessagesResponse\"\x00\x12S\n\x0cPushMessages\x12\x1f.flwr.proto.PushMessagesRequest\x1a .flwr.proto.PushMessagesResponse\"\x00\x12\x41\n\x06GetRun\x12\x19.flwr.proto.GetRunRequest\x1a\x1a.flwr.proto.GetRunResponse\"\x00\x12\x41\n\x06GetFab\x12\x19.flwr.proto.GetFabRequest\x1a\x1a.flwr.proto.GetFabResponse\"\x00\x12M\n\nPushObject\x12\x1d.flwr.proto.PushObjectRequest\x1a\x1e.flwr.proto.PushObjectResponse\"\x00\x12M\n\nPullObject\x12\x1d.flwr.proto.PullObjectRequest\x1a\x1e.flwr.proto.PullObjectResponse\"\x00\x12q\n\x16\x43onfirmMessageReceived\x12).flwr.proto.ConfirmMessageReceivedRequest\x1a*.flwr.proto.ConfirmMessageReceivedResponse\"\x00\x62\x06proto3')
22
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16\x66lwr/proto/fleet.proto\x12\nflwr.proto\x1a\x1a\x66lwr/proto/heartbeat.proto\x1a\x15\x66lwr/proto/node.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x18\x66lwr/proto/message.proto\"/\n\x11\x43reateNodeRequest\x12\x1a\n\x12heartbeat_interval\x18\x01 \x01(\x01\"4\n\x12\x43reateNodeResponse\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"3\n\x11\x44\x65leteNodeRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\"\x14\n\x12\x44\x65leteNodeResponse\"J\n\x13PullMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x13\n\x0bmessage_ids\x18\x02 \x03(\t\"\xa2\x01\n\x14PullMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\x12\x34\n\x14message_object_trees\x18\x03 \x03(\x0b\x32\x16.flwr.proto.ObjectTree\"\x97\x01\n\x13PushMessagesRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12*\n\rmessages_list\x18\x02 \x03(\x0b\x32\x13.flwr.proto.Message\x12\x34\n\x14message_object_trees\x18\x03 \x03(\x0b\x32\x16.flwr.proto.ObjectTree\"\xcb\x02\n\x14PushMessagesResponse\x12(\n\treconnect\x18\x01 \x01(\x0b\x32\x15.flwr.proto.Reconnect\x12>\n\x07results\x18\x02 \x03(\x0b\x32-.flwr.proto.PushMessagesResponse.ResultsEntry\x12L\n\x0fobjects_to_push\x18\x03 \x03(\x0b\x32\x33.flwr.proto.PushMessagesResponse.ObjectsToPushEntry\x1a.\n\x0cResultsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\r:\x02\x38\x01\x1aK\n\x12ObjectsToPushEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12$\n\x05value\x18\x02 \x01(\x0b\x32\x15.flwr.proto.ObjectIDs:\x02\x38\x01\"\x1e\n\tReconnect\x12\x11\n\treconnect\x18\x01 \x01(\x04\x32\xca\x06\n\x05\x46leet\x12M\n\nCreateNode\x12\x1d.flwr.proto.CreateNodeRequest\x1a\x1e.flwr.proto.CreateNodeResponse\"\x00\x12M\n\nDeleteNode\x12\x1d.flwr.proto.DeleteNodeRequest\x1a\x1e.flwr.proto.DeleteNodeResponse\"\x00\x12\x62\n\x11SendNodeHeartbeat\x12$.flwr.proto.SendNodeHeartbeatRequest\x1a%.flwr.proto.SendNodeHeartbeatResponse\"\x00\x12S\n\x0cPullMessages\x12\x1f.flwr.proto.PullMessagesRequest\x1a .flwr.proto.PullMessagesResponse\"\x00\x12S\n\x0cPushMessages\x12\x1f.flwr.proto.PushMessagesRequest\x1a .flwr.proto.PushMessagesResponse\"\x00\x12\x41\n\x06GetRun\x12\x19.flwr.proto.GetRunRequest\x1a\x1a.flwr.proto.GetRunResponse\"\x00\x12\x41\n\x06GetFab\x12\x19.flwr.proto.GetFabRequest\x1a\x1a.flwr.proto.GetFabResponse\"\x00\x12M\n\nPushObject\x12\x1d.flwr.proto.PushObjectRequest\x1a\x1e.flwr.proto.PushObjectResponse\"\x00\x12M\n\nPullObject\x12\x1d.flwr.proto.PullObjectRequest\x1a\x1e.flwr.proto.PullObjectResponse\"\x00\x12q\n\x16\x43onfirmMessageReceived\x12).flwr.proto.ConfirmMessageReceivedRequest\x1a*.flwr.proto.ConfirmMessageReceivedResponse\"\x00\x62\x06proto3')
23
23
 
24
24
  _globals = globals()
25
25
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
26
26
  _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.fleet_pb2', _globals)
27
27
  if _descriptor._USE_C_DESCRIPTORS == False:
28
28
  DESCRIPTOR._options = None
29
- _globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._options = None
30
- _globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._serialized_options = b'8\001'
31
29
  _globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._options = None
32
30
  _globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_options = b'8\001'
33
31
  _globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._options = None
@@ -43,19 +41,17 @@ if _descriptor._USE_C_DESCRIPTORS == False:
43
41
  _globals['_PULLMESSAGESREQUEST']._serialized_start=337
44
42
  _globals['_PULLMESSAGESREQUEST']._serialized_end=411
45
43
  _globals['_PULLMESSAGESRESPONSE']._serialized_start=414
46
- _globals['_PULLMESSAGESRESPONSE']._serialized_end=677
47
- _globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._serialized_start=602
48
- _globals['_PULLMESSAGESRESPONSE_OBJECTSTOPULLENTRY']._serialized_end=677
49
- _globals['_PUSHMESSAGESREQUEST']._serialized_start=680
50
- _globals['_PUSHMESSAGESREQUEST']._serialized_end=831
51
- _globals['_PUSHMESSAGESRESPONSE']._serialized_start=834
52
- _globals['_PUSHMESSAGESRESPONSE']._serialized_end=1165
53
- _globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_start=1042
54
- _globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_end=1088
55
- _globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._serialized_start=1090
56
- _globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._serialized_end=1165
57
- _globals['_RECONNECT']._serialized_start=1167
58
- _globals['_RECONNECT']._serialized_end=1197
59
- _globals['_FLEET']._serialized_start=1200
60
- _globals['_FLEET']._serialized_end=2042
44
+ _globals['_PULLMESSAGESRESPONSE']._serialized_end=576
45
+ _globals['_PUSHMESSAGESREQUEST']._serialized_start=579
46
+ _globals['_PUSHMESSAGESREQUEST']._serialized_end=730
47
+ _globals['_PUSHMESSAGESRESPONSE']._serialized_start=733
48
+ _globals['_PUSHMESSAGESRESPONSE']._serialized_end=1064
49
+ _globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_start=941
50
+ _globals['_PUSHMESSAGESRESPONSE_RESULTSENTRY']._serialized_end=987
51
+ _globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._serialized_start=989
52
+ _globals['_PUSHMESSAGESRESPONSE_OBJECTSTOPUSHENTRY']._serialized_end=1064
53
+ _globals['_RECONNECT']._serialized_start=1066
54
+ _globals['_RECONNECT']._serialized_end=1096
55
+ _globals['_FLEET']._serialized_start=1099
56
+ _globals['_FLEET']._serialized_end=1941
61
57
  # @@protoc_insertion_point(module_scope)
flwr/proto/fleet_pb2.pyi CHANGED
@@ -78,38 +78,23 @@ global___PullMessagesRequest = PullMessagesRequest
78
78
 
79
79
  class PullMessagesResponse(google.protobuf.message.Message):
80
80
  DESCRIPTOR: google.protobuf.descriptor.Descriptor
81
- class ObjectsToPullEntry(google.protobuf.message.Message):
82
- DESCRIPTOR: google.protobuf.descriptor.Descriptor
83
- KEY_FIELD_NUMBER: builtins.int
84
- VALUE_FIELD_NUMBER: builtins.int
85
- key: typing.Text
86
- @property
87
- def value(self) -> flwr.proto.message_pb2.ObjectIDs: ...
88
- def __init__(self,
89
- *,
90
- key: typing.Text = ...,
91
- value: typing.Optional[flwr.proto.message_pb2.ObjectIDs] = ...,
92
- ) -> None: ...
93
- def HasField(self, field_name: typing_extensions.Literal["value",b"value"]) -> builtins.bool: ...
94
- def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ...
95
-
96
81
  RECONNECT_FIELD_NUMBER: builtins.int
97
82
  MESSAGES_LIST_FIELD_NUMBER: builtins.int
98
- OBJECTS_TO_PULL_FIELD_NUMBER: builtins.int
83
+ MESSAGE_OBJECT_TREES_FIELD_NUMBER: builtins.int
99
84
  @property
100
85
  def reconnect(self) -> global___Reconnect: ...
101
86
  @property
102
87
  def messages_list(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[flwr.proto.message_pb2.Message]: ...
103
88
  @property
104
- def objects_to_pull(self) -> google.protobuf.internal.containers.MessageMap[typing.Text, flwr.proto.message_pb2.ObjectIDs]: ...
89
+ def message_object_trees(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[flwr.proto.message_pb2.ObjectTree]: ...
105
90
  def __init__(self,
106
91
  *,
107
92
  reconnect: typing.Optional[global___Reconnect] = ...,
108
93
  messages_list: typing.Optional[typing.Iterable[flwr.proto.message_pb2.Message]] = ...,
109
- objects_to_pull: typing.Optional[typing.Mapping[typing.Text, flwr.proto.message_pb2.ObjectIDs]] = ...,
94
+ message_object_trees: typing.Optional[typing.Iterable[flwr.proto.message_pb2.ObjectTree]] = ...,
110
95
  ) -> None: ...
111
96
  def HasField(self, field_name: typing_extensions.Literal["reconnect",b"reconnect"]) -> builtins.bool: ...
112
- def ClearField(self, field_name: typing_extensions.Literal["messages_list",b"messages_list","objects_to_pull",b"objects_to_pull","reconnect",b"reconnect"]) -> None: ...
97
+ def ClearField(self, field_name: typing_extensions.Literal["message_object_trees",b"message_object_trees","messages_list",b"messages_list","reconnect",b"reconnect"]) -> None: ...
113
98
  global___PullMessagesResponse = PullMessagesResponse
114
99
 
115
100
  class PushMessagesRequest(google.protobuf.message.Message):
@@ -33,9 +33,9 @@ from flwr.common.inflatable import (
33
33
  get_object_tree,
34
34
  no_object_id_recompute,
35
35
  )
36
- from flwr.common.inflatable_grpc_utils import (
37
- make_pull_object_fn_grpc,
38
- make_push_object_fn_grpc,
36
+ from flwr.common.inflatable_protobuf_utils import (
37
+ make_pull_object_fn_protobuf,
38
+ make_push_object_fn_protobuf,
39
39
  )
40
40
  from flwr.common.inflatable_utils import (
41
41
  inflate_object_from_contents,
@@ -240,8 +240,8 @@ class GrpcGrid(Grid):
240
240
  # Push only object that are not in the store
241
241
  push_objects(
242
242
  all_objects,
243
- push_object_fn=make_push_object_fn_grpc(
244
- push_object_grpc=self._stub.PushObject,
243
+ push_object_fn=make_push_object_fn_protobuf(
244
+ push_object_protobuf=self._stub.PushObject,
245
245
  node=self.node,
246
246
  run_id=run_id,
247
247
  ),
@@ -308,8 +308,8 @@ class GrpcGrid(Grid):
308
308
  msg_id = msg_proto.metadata.message_id
309
309
  all_object_contents = pull_objects(
310
310
  list(res.objects_to_pull[msg_id].object_ids) + [msg_id],
311
- pull_object_fn=make_pull_object_fn_grpc(
312
- pull_object_grpc=self._stub.PullObject,
311
+ pull_object_fn=make_pull_object_fn_protobuf(
312
+ pull_object_protobuf=self._stub.PullObject,
313
313
  node=self.node,
314
314
  run_id=run_id,
315
315
  ),
@@ -46,7 +46,6 @@ from flwr.proto.heartbeat_pb2 import ( # pylint: disable=E0611
46
46
  from flwr.proto.message_pb2 import ( # pylint: disable=E0611
47
47
  ConfirmMessageReceivedRequest,
48
48
  ConfirmMessageReceivedResponse,
49
- ObjectIDs,
50
49
  PullObjectRequest,
51
50
  PullObjectResponse,
52
51
  PushObjectRequest,
@@ -113,25 +112,22 @@ def pull_messages(
113
112
 
114
113
  # Convert to Messages
115
114
  msg_proto = []
116
- objects_to_pull: dict[str, ObjectIDs] = {}
115
+ trees = []
117
116
  for msg in message_list:
118
117
  try:
119
- msg_proto.append(message_to_proto(msg))
120
-
118
+ # Retrieve Message object tree from ObjectStore
121
119
  msg_object_id = msg.metadata.message_id
122
- descendants = store.get_message_descendant_ids(msg_object_id)
123
- # Include the object_id of the message itself
124
- objects_to_pull[msg_object_id] = ObjectIDs(
125
- object_ids=descendants + [msg_object_id]
126
- )
120
+ obj_tree = store.get_object_tree(msg_object_id)
121
+
122
+ # Add Message and its object tree to the response
123
+ msg_proto.append(message_to_proto(msg))
124
+ trees.append(obj_tree)
127
125
  except NoObjectInStoreError as e:
128
126
  log(ERROR, e.message)
129
127
  # Delete message ins from state
130
128
  state.delete_messages(message_ins_ids={msg_object_id})
131
129
 
132
- return PullMessagesResponse(
133
- messages_list=msg_proto, objects_to_pull=objects_to_pull
134
- )
130
+ return PullMessagesResponse(messages_list=msg_proto, message_object_trees=trees)
135
131
 
136
132
 
137
133
  def push_messages(
@@ -287,6 +283,5 @@ def confirm_message_received(
287
283
 
288
284
  # Delete the message object
289
285
  store.delete(request.message_object_id)
290
- store.delete_message_descendant_ids(request.message_object_id)
291
286
 
292
287
  return ConfirmMessageReceivedResponse()
@@ -27,6 +27,7 @@ from flwr.common.inflatable import (
27
27
  UnexpectedObjectContentError,
28
28
  get_all_nested_objects,
29
29
  get_object_tree,
30
+ iterate_object_tree,
30
31
  no_object_id_recompute,
31
32
  )
32
33
  from flwr.common.logger import log
@@ -211,12 +212,6 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
211
212
  if msg_res.metadata.src_node_id == SUPERLINK_NODE_ID:
212
213
  with no_object_id_recompute():
213
214
  all_objects = get_all_nested_objects(msg_res)
214
- descendants = list(all_objects.keys())[:-1]
215
- message_obj_id = msg_res.metadata.message_id
216
- # Store mapping
217
- store.set_message_descendant_ids(
218
- msg_object_id=message_obj_id, descendant_ids=descendants
219
- )
220
215
  # Preregister
221
216
  store.preregister(request.run_id, get_object_tree(msg_res))
222
217
  # Store objects
@@ -247,7 +242,9 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
247
242
 
248
243
  try:
249
244
  msg_object_id = msg.metadata.message_id
250
- descendants = store.get_message_descendant_ids(msg_object_id)
245
+ obj_tree = store.get_object_tree(msg_object_id)
246
+ descendants = [node.object_id for node in iterate_object_tree(obj_tree)]
247
+ descendants = descendants[:-1] # Exclude the message itself
251
248
  # Add mapping of message object ID to its descendants
252
249
  objects_to_pull[msg_object_id] = ObjectIDs(object_ids=descendants)
253
250
  except NoObjectInStoreError as e:
@@ -513,7 +510,6 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
513
510
 
514
511
  # Delete the message object
515
512
  store.delete(request.message_object_id)
516
- store.delete_message_descendant_ids(request.message_object_id)
517
513
 
518
514
  return ConfirmMessageReceivedResponse()
519
515
 
@@ -20,7 +20,6 @@ from typing import Optional, Union
20
20
  import grpc
21
21
 
22
22
  from flwr.common.constant import Status, SubStatus
23
- from flwr.common.inflatable import iterate_object_tree
24
23
  from flwr.common.typing import RunStatus
25
24
  from flwr.proto.appio_pb2 import PushAppMessagesRequest # pylint: disable=E0611
26
25
  from flwr.proto.fleet_pb2 import PushMessagesRequest # pylint: disable=E0611
@@ -90,17 +89,10 @@ def store_mapping_and_register_objects(
90
89
  run_id = request.messages_list[0].metadata.run_id
91
90
 
92
91
  for object_tree in request.message_object_trees:
93
- all_object_ids = [obj.object_id for obj in iterate_object_tree(object_tree)]
94
- msg_object_id, descendant_ids = all_object_ids[-1], all_object_ids[:-1]
95
- # Store mapping
96
- store.set_message_descendant_ids(
97
- msg_object_id=msg_object_id, descendant_ids=descendant_ids
98
- )
99
-
100
92
  # Preregister
101
93
  object_ids_just_registered = store.preregister(run_id, object_tree)
102
94
  # Keep track of objects that need to be pushed
103
- objects_to_push[msg_object_id] = ObjectIDs(
95
+ objects_to_push[object_tree.object_id] = ObjectIDs(
104
96
  object_ids=object_ids_just_registered
105
97
  )
106
98
 
@@ -0,0 +1,22 @@
1
+ # Copyright 2025 Flower Labs GmbH. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """GRPC health servicers."""
16
+
17
+
18
+ from .simple_health_servicer import SimpleHealthServicer
19
+
20
+ __all__ = [
21
+ "SimpleHealthServicer",
22
+ ]
@@ -0,0 +1,38 @@
1
+ # Copyright 2025 Flower Labs GmbH. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """Simple gRPC health servicers."""
16
+
17
+
18
+ import grpc
19
+
20
+ # pylint: disable=E0611
21
+ from grpc_health.v1.health_pb2 import HealthCheckRequest, HealthCheckResponse
22
+ from grpc_health.v1.health_pb2_grpc import HealthServicer
23
+
24
+ # pylint: enable=E0611
25
+
26
+
27
+ class SimpleHealthServicer(HealthServicer): # type: ignore
28
+ """A simple gRPC health servicer that always returns SERVING."""
29
+
30
+ def Check(
31
+ self, request: HealthCheckRequest, context: grpc.RpcContext
32
+ ) -> HealthCheckResponse:
33
+ """Return a HealthCheckResponse with SERVING status."""
34
+ return HealthCheckResponse(status=HealthCheckResponse.SERVING)
35
+
36
+ def Watch(self, request: HealthCheckRequest, context: grpc.RpcContext) -> None:
37
+ """Watch the health status (not implemented)."""
38
+ context.abort(grpc.StatusCode.UNIMPLEMENTED, "Watch is not implemented")
@@ -20,7 +20,6 @@ from dataclasses import dataclass
20
20
  from typing import Optional
21
21
 
22
22
  from flwr.common.inflatable import (
23
- get_object_children_ids_from_object_content,
24
23
  get_object_id,
25
24
  is_valid_sha256_hash,
26
25
  iterate_object_tree,
@@ -37,6 +36,7 @@ class ObjectEntry:
37
36
 
38
37
  content: bytes
39
38
  is_available: bool
39
+ child_object_ids: list[str] # List of child object IDs
40
40
  ref_count: int # Number of references (direct parents) to this object
41
41
  runs: set[int] # Set of run IDs that used this object
42
42
 
@@ -70,6 +70,9 @@ class InMemoryObjectStore(ObjectStore):
70
70
  self.store[obj_id] = ObjectEntry(
71
71
  content=b"", # Initially empty content
72
72
  is_available=False, # Initially not available
73
+ child_object_ids=[ # List of child object IDs
74
+ child.object_id for child in tree_node.children
75
+ ],
73
76
  ref_count=0, # Reference count starts at 0
74
77
  runs={run_id}, # Start with the current run ID
75
78
  )
@@ -102,6 +105,32 @@ class InMemoryObjectStore(ObjectStore):
102
105
 
103
106
  return new_objects
104
107
 
108
+ def get_object_tree(self, object_id: str) -> ObjectTree:
109
+ """Get the object tree for a given object ID."""
110
+ with self.lock_store:
111
+ # Raise an exception if there's no object with the given ID
112
+ if not (object_entry := self.store.get(object_id)):
113
+ raise NoObjectInStoreError(
114
+ f"Object with ID '{object_id}' was not pre-registered."
115
+ )
116
+
117
+ # Build the object trees of all children
118
+ try:
119
+ child_trees = [
120
+ self.get_object_tree(child_id)
121
+ for child_id in object_entry.child_object_ids
122
+ ]
123
+ except NoObjectInStoreError as e:
124
+ # Raise an error if any child object is missing
125
+ # This indicates an integrity issue
126
+ raise NoObjectInStoreError(
127
+ f"Object tree for object ID '{object_id}' contains missing "
128
+ "children. This may indicate a corrupted object store."
129
+ ) from e
130
+
131
+ # Create and return the ObjectTree for the current object
132
+ return ObjectTree(object_id=object_id, children=child_trees)
133
+
105
134
  def put(self, object_id: str, object_content: bytes) -> None:
106
135
  """Put an object into the store."""
107
136
  if self.verify:
@@ -128,29 +157,6 @@ class InMemoryObjectStore(ObjectStore):
128
157
  self.store[object_id].content = object_content
129
158
  self.store[object_id].is_available = True
130
159
 
131
- def set_message_descendant_ids(
132
- self, msg_object_id: str, descendant_ids: list[str]
133
- ) -> None:
134
- """Store the mapping from a ``Message`` object ID to the object IDs of its
135
- descendants."""
136
- with self.lock_msg_mapping:
137
- self.msg_descendant_objects_mapping[msg_object_id] = descendant_ids
138
-
139
- def get_message_descendant_ids(self, msg_object_id: str) -> list[str]:
140
- """Retrieve the object IDs of all descendants of a given Message."""
141
- with self.lock_msg_mapping:
142
- if msg_object_id not in self.msg_descendant_objects_mapping:
143
- raise NoObjectInStoreError(
144
- f"No message registered in Object Store with ID '{msg_object_id}'. "
145
- "Mapping to descendants could not be found."
146
- )
147
- return self.msg_descendant_objects_mapping[msg_object_id]
148
-
149
- def delete_message_descendant_ids(self, msg_object_id: str) -> None:
150
- """Delete the mapping from a ``Message`` object ID to its descendants."""
151
- with self.lock_msg_mapping:
152
- self.msg_descendant_objects_mapping.pop(msg_object_id, None)
153
-
154
160
  def get(self, object_id: str) -> Optional[bytes]:
155
161
  """Get an object from the store."""
156
162
  with self.lock_store:
@@ -177,10 +183,7 @@ class InMemoryObjectStore(ObjectStore):
177
183
  self.run_objects_mapping[run_id].discard(object_id)
178
184
 
179
185
  # Decrease the reference count of its children
180
- children_ids = get_object_children_ids_from_object_content(
181
- object_entry.content
182
- )
183
- for child_id in children_ids:
186
+ for child_id in object_entry.child_object_ids:
184
187
  self.store[child_id].ref_count -= 1
185
188
 
186
189
  # Recursively try to delete the child object
@@ -205,9 +208,6 @@ class InMemoryObjectStore(ObjectStore):
205
208
  # Delete the message object and its unreferenced descendants
206
209
  self.delete(object_id)
207
210
 
208
- # Delete the message's descendants mapping
209
- self.delete_message_descendant_ids(object_id)
210
-
211
211
  # Remove the run from the mapping
212
212
  del self.run_objects_mapping[run_id]
213
213
 
@@ -60,6 +60,22 @@ class ObjectStore(abc.ABC):
60
60
  in the `ObjectStore`, or were preregistered but are not yet available.
61
61
  """
62
62
 
63
+ @abc.abstractmethod
64
+ def get_object_tree(self, object_id: str) -> ObjectTree:
65
+ """Get the object tree for a given object ID.
66
+
67
+ Parameters
68
+ ----------
69
+ object_id : str
70
+ The ID of the object for which to retrieve the object tree.
71
+
72
+ Returns
73
+ -------
74
+ ObjectTree
75
+ An ObjectTree representing the hierarchical structure of the object with
76
+ the given ID and its descendants.
77
+ """
78
+
63
79
  @abc.abstractmethod
64
80
  def put(self, object_id: str, object_content: bytes) -> None:
65
81
  """Put an object into the store.
@@ -126,46 +142,6 @@ class ObjectStore(abc.ABC):
126
142
  This method should remove all objects from the store.
127
143
  """
128
144
 
129
- @abc.abstractmethod
130
- def set_message_descendant_ids(
131
- self, msg_object_id: str, descendant_ids: list[str]
132
- ) -> None:
133
- """Store the mapping from a ``Message`` object ID to the object IDs of its
134
- descendants.
135
-
136
- Parameters
137
- ----------
138
- msg_object_id : str
139
- The object ID of the ``Message``.
140
- descendant_ids : list[str]
141
- A list of object IDs representing all descendant objects of the ``Message``.
142
- """
143
-
144
- @abc.abstractmethod
145
- def get_message_descendant_ids(self, msg_object_id: str) -> list[str]:
146
- """Retrieve the object IDs of all descendants of a given ``Message``.
147
-
148
- Parameters
149
- ----------
150
- msg_object_id : str
151
- The object ID of the ``Message``.
152
-
153
- Returns
154
- -------
155
- list[str]
156
- A list of object IDs of all descendant objects of the ``Message``.
157
- """
158
-
159
- @abc.abstractmethod
160
- def delete_message_descendant_ids(self, msg_object_id: str) -> None:
161
- """Delete the mapping from a ``Message`` object ID to its descendants.
162
-
163
- Parameters
164
- ----------
165
- msg_object_id : str
166
- The object ID of the ``Message``.
167
- """
168
-
169
145
  @abc.abstractmethod
170
146
  def __contains__(self, object_id: str) -> bool:
171
147
  """Check if an object_id is in the store.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flwr-nightly
3
- Version: 1.20.0.dev20250714
3
+ Version: 1.20.0.dev20250716
4
4
  Summary: Flower: A Friendly Federated AI Framework
5
5
  License: Apache-2.0
6
6
  Keywords: Artificial Intelligence,Federated AI,Federated Analytics,Federated Evaluation,Federated Learning,Flower,Machine Learning
@@ -34,6 +34,7 @@ Provides-Extra: simulation
34
34
  Requires-Dist: click (<8.2.0)
35
35
  Requires-Dist: cryptography (>=44.0.1,<45.0.0)
36
36
  Requires-Dist: grpcio (>=1.62.3,<2.0.0,!=1.65.0)
37
+ Requires-Dist: grpcio-health-checking (>=1.62.3,<2.0.0)
37
38
  Requires-Dist: iterators (>=0.0.2,<0.0.3)
38
39
  Requires-Dist: numpy (>=1.26.0,<3.0.0)
39
40
  Requires-Dist: pathspec (>=0.12.1,<0.13.0)
@@ -84,7 +84,7 @@ flwr/client/grpc_adapter_client/__init__.py,sha256=RQWP5mFPROLHKgombiRvPXVWSoVrQ
84
84
  flwr/client/grpc_adapter_client/connection.py,sha256=aj5tTYyE8z2hQLXPPydsJiz8gBDIWLUhfWvqYkAL1L4,3966
85
85
  flwr/client/grpc_rere_client/__init__.py,sha256=i7iS0Lt8B7q0E2L72e4F_YrKm6ClRKnd71PNA6PW2O0,752
86
86
  flwr/client/grpc_rere_client/client_interceptor.py,sha256=zFaVHw6AxeNO-7eCKKb-RxrPa7zbM5Z-2-1Efc4adQY,2451
87
- flwr/client/grpc_rere_client/connection.py,sha256=5XNwDiac3YEXjyosSmiGz3lJyGNzA8I1I-ft4z08uIw,13619
87
+ flwr/client/grpc_rere_client/connection.py,sha256=jndP_Z8yNGHocJfucUspk2bcrjPeI3s-nOb1tEeDlT4,13732
88
88
  flwr/client/grpc_rere_client/grpc_adapter.py,sha256=dLGB5GriszAmtgvuFGuz_F7rIwpzLfDxhJ7T3Un-Ce0,6694
89
89
  flwr/client/message_handler/__init__.py,sha256=0lyljDVqre3WljiZbPcwCCf8GiIaSVI_yo_ylEyPwSE,719
90
90
  flwr/client/message_handler/message_handler.py,sha256=X9SXX6et97Lw9_DGD93HKsEBGNjXClcFgc_5aLK0oiU,6541
@@ -98,7 +98,7 @@ flwr/client/mod/secure_aggregation/secaggplus_mod.py,sha256=aKqjZCrikF73y3E-7h40
98
98
  flwr/client/mod/utils.py,sha256=FUgD2TfcWqSeF6jUKZ4i6Ke56U4Nrv85AeVb93s6R9g,1201
99
99
  flwr/client/numpy_client.py,sha256=Qq6ghsIAop2slKqAfgiI5NiHJ4LIxGmrik3Ror4_XVc,9581
100
100
  flwr/client/rest_client/__init__.py,sha256=MBiuK62hj439m9rtwSwI184Hth6Tt5GbmpNMyl3zkZY,735
101
- flwr/client/rest_client/connection.py,sha256=hp-bVcqG0Ul4OmITxcqEHOsGtJuyNevndP-B8trwlns,16270
101
+ flwr/client/rest_client/connection.py,sha256=zZ-HYLPCQxKtTo1Sc-n8jkl_GB4bpfViuif8h9HFSqI,16388
102
102
  flwr/client/run_info_store.py,sha256=MaJ3UQ-07hWtK67wnWu0zR29jrk0fsfgJX506dvEOfE,4042
103
103
  flwr/client/typing.py,sha256=Jw3rawDzI_-ZDcRmEQcs5gZModY7oeQlEeltYsdOhlU,1048
104
104
  flwr/clientapp/__init__.py,sha256=zGW4z49Ojzoi1hDiRC7kyhLjijUilc6fqHhtM_ATRVA,719
@@ -120,11 +120,10 @@ flwr/common/exit/__init__.py,sha256=-ZOJYLaNnR729a7VzZiFsLiqngzKQh3xc27svYStZ_Q,
120
120
  flwr/common/exit/exit.py,sha256=mJgbqMlVlwAgYtq-Vedj53wO4VxcDcy_P-GzqGK-1GQ,3452
121
121
  flwr/common/exit/exit_code.py,sha256=qpOQsh2-TNJosxrGpR-rKnLBiv5lnl_2sClNoDblAW4,3882
122
122
  flwr/common/exit_handlers.py,sha256=IaqJ60fXZuu7McaRYnoYKtlbH9t4Yl9goNExKqtmQbs,4304
123
- flwr/common/grpc.py,sha256=manTaHaPiyYngUq1ErZvvV2B2GxlXUUUGRy3jc3TBIQ,9798
123
+ flwr/common/grpc.py,sha256=y70hUFvXkIf3l03xOhlb7qhS6W1UJZRSZqCdB0ir0v8,10381
124
124
  flwr/common/heartbeat.py,sha256=SyEpNDnmJ0lni0cWO67rcoJVKasCLmkNHm3dKLeNrLU,5749
125
125
  flwr/common/inflatable.py,sha256=GDL9oBKs16_yyVdlH6kBf493O5xll_h9V7XB5Mpx1Hc,9524
126
- flwr/common/inflatable_grpc_utils.py,sha256=ZpwtgF1tGD6NwQkCidbhbeBPDBZ1Nx9eGMHQ04eNEE8,3554
127
- flwr/common/inflatable_rest_utils.py,sha256=KiZd06XRiXcl_WewOrag0JTvUQt5kZ74UIsQ3FCAXGc,3580
126
+ flwr/common/inflatable_protobuf_utils.py,sha256=lvKR5jD5P8AlpknD_1BlvUoTuT6Iyd8oodXfUQvjDRU,3746
128
127
  flwr/common/inflatable_utils.py,sha256=yew5VU8po8yZsmoTVxg-tB5vrvnb2mvBAE55qjiOAq8,12840
129
128
  flwr/common/logger.py,sha256=JbRf6E2vQxXzpDBq1T8IDUJo_usu3gjWEBPQ6uKcmdg,13049
130
129
  flwr/common/message.py,sha256=xAL7iZN5-n-xPQpgoSFvxNrzs8fmiiPfoU0DjNQEhRw,19953
@@ -185,8 +184,8 @@ flwr/proto/fab_pb2.py,sha256=2Nu0WaWxDZ8TbutMtctjdcGM7OtXiyP4kmCgg5o7Jjw,1627
185
184
  flwr/proto/fab_pb2.pyi,sha256=AMXpiDK0fo3nZWjxsC2E4otSaVjyQbU7iiWKrsSZavs,2395
186
185
  flwr/proto/fab_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
187
186
  flwr/proto/fab_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
188
- flwr/proto/fleet_pb2.py,sha256=bXqfcyKYFaXYt3V1XMe600xdXb66swYPa6hByEA05e0,6131
189
- flwr/proto/fleet_pb2.pyi,sha256=1zAv5BD0-iXNVvd6EXQIxRei_axG7k_RdXeiCwneT-U,9241
187
+ flwr/proto/fleet_pb2.py,sha256=GbPhzqW-yBYduHcmlgc3YiXOeOZ_ThT46QfE6ck7jak,5660
188
+ flwr/proto/fleet_pb2.pyi,sha256=K6Qt5lb_wVekUbgNA5Y5ora4N4Ow9bclp2h85VKiZBU,8555
190
189
  flwr/proto/fleet_pb2_grpc.py,sha256=NmzrDYxyM3MQNh3vwYczQNuFimZz3prU6ke3E-fKk_g,17539
191
190
  flwr/proto/fleet_pb2_grpc.pyi,sha256=PDERhzOrBCMAytTLS65Qck8A45bTIYni7Lotq6_I0sM,4721
192
191
  flwr/proto/grpcadapter_pb2.py,sha256=PJ8DtfeV29g_y4Z3aNZlSZocLqSxeLmTsYCdOZDYCiE,1843
@@ -243,7 +242,7 @@ flwr/server/criterion.py,sha256=G4e-6B48Pc7d5rmGVUpIzNKb6UF88O3VmTRuUltgjzM,1061
243
242
  flwr/server/fleet_event_log_interceptor.py,sha256=ifV4gUB_hSg7QPLIrAyDpjciqZBOKb0L0abZno3GTwA,3780
244
243
  flwr/server/grid/__init__.py,sha256=aWZHezoR2UGMJISB_gPMCm2N_2GSbm97A3lAp7ruhRQ,888
245
244
  flwr/server/grid/grid.py,sha256=naGCYt5J6dnmUvrcGkdNyKPe3MBd-0awGm1ALmgahqY,6625
246
- flwr/server/grid/grpc_grid.py,sha256=-SLS1VifRo1uxgjRWQJSshkTm5t0s8Wrj2ZZcbSu86I,13581
245
+ flwr/server/grid/grpc_grid.py,sha256=6w-X6mRyAmaWyrUaBnRp3enM4e63iEMUUWPIRFqO1qw,13609
247
246
  flwr/server/grid/inmemory_grid.py,sha256=RjejYT-d-hHuTs1KSs_5wvOdAWKLus8w5_UAcnGt4iw,6168
248
247
  flwr/server/history.py,sha256=cCkFhBN4GoHsYYNk5GG1Y089eKJh2DH_ZJbYPwLaGyk,5026
249
248
  flwr/server/run_serverapp.py,sha256=v0p6jXj2dFxlRUdoEeF1mnaFd9XRQi6dZCflPY6d3qI,2063
@@ -290,7 +289,7 @@ flwr/server/superlink/fleet/grpc_rere/__init__.py,sha256=ahDJJ1e-lDxBpeBMgPk7YZt
290
289
  flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=X7-z4oReIH5ghMfmMXML3SSpa2bhRsuIvt2OZs82BUk,8675
291
290
  flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=DrHubsaLgJCwCeeJPYogQTiP0xYqjxwnT9rh7OP7BoU,6984
292
291
  flwr/server/superlink/fleet/message_handler/__init__.py,sha256=fHsRV0KvJ8HtgSA4_YBsEzuhJLjO8p6xx4aCY2oE1p4,731
293
- flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=pbsKY-maXIPCihre42VeUcjVFg3bexCrfOCnKA5UPNM,8842
292
+ flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=k_okVvuvbQgnBAWtXpOf0UrXcMQmRZtKKTS-as1xjig,8667
294
293
  flwr/server/superlink/fleet/rest_rere/__init__.py,sha256=Lzc93nA7tDqoy-zRUaPG316oqFiZX1HUCL5ELaXY_xw,735
295
294
  flwr/server/superlink/fleet/rest_rere/rest_api.py,sha256=mxWKwGpgHPqd7cGFqd2ASnR-KZduIzLfT-d2yiNCqQ0,9257
296
295
  flwr/server/superlink/fleet/vce/__init__.py,sha256=XOKbAWOzlCqEOQ3M2cBYkH7HKA7PxlbCJMunt-ty-DY,784
@@ -306,11 +305,11 @@ flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=E699Ak0jMF3N7i1SIeFRu
306
305
  flwr/server/superlink/linkstate/utils.py,sha256=IeLh7iGRCHU5MEWOl7iriaSE4L__8GWOa2OleXadK5M,15444
307
306
  flwr/server/superlink/serverappio/__init__.py,sha256=Fy4zJuoccZe5mZSEIpOmQvU6YeXFBa1M4eZuXXmJcn8,717
308
307
  flwr/server/superlink/serverappio/serverappio_grpc.py,sha256=zcvzDhCAnlFxAwCiJUHNm6IE7-rk5jeZqSmPgjEY3AU,2307
309
- flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=BBDxoYj1BlNtT7wOr9TUGJUHP6MS5dMKqcBsW4Uji00,18735
308
+ flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=mR-ijliBxxrKFyIw5Vpc95QvapD7W8eY9pb-7VDj3gU,18519
310
309
  flwr/server/superlink/simulation/__init__.py,sha256=Ry8DrNaZCMcQXvUc4FoCN2m3dvUQgWjasfp015o3Ec4,718
311
310
  flwr/server/superlink/simulation/simulationio_grpc.py,sha256=VqWKxjpd4bCgPFKsgtIZPk9YcG0kc1EEmr5k20EKty4,2205
312
311
  flwr/server/superlink/simulation/simulationio_servicer.py,sha256=m1T1zvEn81jlfx9hVTqmeWxAu6APCS2YW8l5O0OQvhU,7724
313
- flwr/server/superlink/utils.py,sha256=kN7Wg7bK0wwK6B3JSXNCrUCVt8LTogKf3lKXAFREZSM,3892
312
+ flwr/server/superlink/utils.py,sha256=e_-BZmW19xRuClGwBxK1GNSM_WCDGM4A8TW6fHoLPF0,3532
314
313
  flwr/server/typing.py,sha256=LvO6gq7H6TAWhA9JFx0WyqHxU7FycyvhSsLjBLPgpts,1011
315
314
  flwr/server/utils/__init__.py,sha256=U4gM84-uUFddarODDQkO6SjNUuGhFcsHJZMjSEbezkU,884
316
315
  flwr/server/utils/tensorboard.py,sha256=3z3MeF0cu_U6ghNgRd0UQ5bunyDQKxCLpIpEdGMoCJ0,5466
@@ -336,11 +335,13 @@ flwr/supercore/ffs/__init__.py,sha256=U3KXwG_SplEvchat27K0LYPoPHzh-cwwT_NHsGlYMt
336
335
  flwr/supercore/ffs/disk_ffs.py,sha256=c5VywSaRnq3XM_zuJptNtsF2HFwsRK0pvBd5-5CNONs,3272
337
336
  flwr/supercore/ffs/ffs.py,sha256=6w7wy71i7tbuJwqEgdeCa49JejXMEof3jujURN_R7Rg,2395
338
337
  flwr/supercore/ffs/ffs_factory.py,sha256=pK-g3LMelvWTV6N9Cd-j-_-FdcGbRFTKNsWaqmlBDSk,1490
338
+ flwr/supercore/grpc_health/__init__.py,sha256=bK1jWNje-uwxf4_c0vfFsZdVrLzAHQ463OsOcVWERPU,814
339
+ flwr/supercore/grpc_health/simple_health_servicer.py,sha256=IUWS0NpgLAwxApvd4TpU8eZibpABbPX9w-SbMXDypdE,1521
339
340
  flwr/supercore/license_plugin/__init__.py,sha256=d8OgHTn2BwjoNSPy8jQQxTC_iT3-ENLwKM8yhHKvCRM,820
340
341
  flwr/supercore/license_plugin/license_plugin.py,sha256=BFhlCH5v9KKuY7crVCsi8fuYe98SJfnGxRS0CVc_Y5I,948
341
342
  flwr/supercore/object_store/__init__.py,sha256=cdfPAmjINY6iOp8oI_LdcVh2simg469Mkdl4LLV4kHI,911
342
- flwr/supercore/object_store/in_memory_object_store.py,sha256=oflJcOuVNgx9A-B2da4VHDb1qj_Jub9wKFOrUBgtz_U,9630
343
- flwr/supercore/object_store/object_store.py,sha256=VlZz-yzoWZtITbnYD8vwLZbFosv7vgr1XVNzByObeY0,5853
343
+ flwr/supercore/object_store/in_memory_object_store.py,sha256=CGY43syxDGrUPcdOzRH3hNrfeqmoTOY_wjo3qaAHuNk,9612
344
+ flwr/supercore/object_store/object_store.py,sha256=wC6Pxq89a7FwmIMJE3ZLPPy2i7Gdss7-8RUapECCAPY,5099
344
345
  flwr/supercore/object_store/object_store_factory.py,sha256=QVwE2ywi7vsj2iKfvWWnNw3N_I7Rz91NUt2RpcbJ7iM,1527
345
346
  flwr/supercore/utils.py,sha256=ebuHMbeA8eXisX0oMPqBK3hk7uVnIE_yiqWVz8YbkpQ,1324
346
347
  flwr/superexec/__init__.py,sha256=YFqER0IJc1XEWfsX6AxZ9LSRq0sawPYrNYki-brvTIc,715
@@ -368,7 +369,7 @@ flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca
368
369
  flwr/supernode/servicer/clientappio/__init__.py,sha256=7Oy62Y_oijqF7Dxi6tpcUQyOpLc_QpIRZ83NvwmB0Yg,813
369
370
  flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=U-uAJ7Yd_BzEqhbpCSgEG9pxX5Zf4RuPVYKimYDvMbU,7176
370
371
  flwr/supernode/start_client_internal.py,sha256=_ZqSfL_j4qn6Cg-P6sv3k_n1ZG62J_teokBxnWrXrPE,18772
371
- flwr_nightly-1.20.0.dev20250714.dist-info/METADATA,sha256=-5TYbMnUQ41aFZf_OizdSM0Rzf84wudcSfT9qkfpTEo,15910
372
- flwr_nightly-1.20.0.dev20250714.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
373
- flwr_nightly-1.20.0.dev20250714.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
374
- flwr_nightly-1.20.0.dev20250714.dist-info/RECORD,,
372
+ flwr_nightly-1.20.0.dev20250716.dist-info/METADATA,sha256=bp6v4He7vTM-vNpn-EKkSH-QXj2VZN62mGjFq5yWl7g,15966
373
+ flwr_nightly-1.20.0.dev20250716.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
374
+ flwr_nightly-1.20.0.dev20250716.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
375
+ flwr_nightly-1.20.0.dev20250716.dist-info/RECORD,,
@@ -1,99 +0,0 @@
1
- # Copyright 2025 Flower Labs GmbH. All Rights Reserved.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- # ==============================================================================
15
- """InflatableObject REST utils."""
16
-
17
-
18
- from typing import Callable
19
-
20
- from flwr.proto.message_pb2 import ( # pylint: disable=E0611
21
- PullObjectRequest,
22
- PullObjectResponse,
23
- PushObjectRequest,
24
- PushObjectResponse,
25
- )
26
- from flwr.proto.node_pb2 import Node # pylint: disable=E0611
27
-
28
- from .inflatable_utils import ObjectIdNotPreregisteredError, ObjectUnavailableError
29
-
30
-
31
- def make_pull_object_fn_rest(
32
- pull_object_rest: Callable[[PullObjectRequest], PullObjectResponse],
33
- node: Node,
34
- run_id: int,
35
- ) -> Callable[[str], bytes]:
36
- """Create a pull object function that uses REST to pull objects.
37
-
38
- Parameters
39
- ----------
40
- pull_object_rest : Callable[[PullObjectRequest], PullObjectResponse]
41
- A function that makes a POST request against the `/push-object` REST endpoint
42
- node : Node
43
- The node making the request.
44
- run_id : int
45
- The run ID for the current operation.
46
-
47
- Returns
48
- -------
49
- Callable[[str], bytes]
50
- A function that takes an object ID and returns the object content as bytes.
51
- The function raises `ObjectIdNotPreregisteredError` if the object ID is not
52
- pre-registered, or `ObjectUnavailableError` if the object is not yet available.
53
- """
54
-
55
- def pull_object_fn(object_id: str) -> bytes:
56
- request = PullObjectRequest(node=node, run_id=run_id, object_id=object_id)
57
- response: PullObjectResponse = pull_object_rest(request)
58
- if not response.object_found:
59
- raise ObjectIdNotPreregisteredError(object_id)
60
- if not response.object_available:
61
- raise ObjectUnavailableError(object_id)
62
- return response.object_content
63
-
64
- return pull_object_fn
65
-
66
-
67
- def make_push_object_fn_rest(
68
- push_object_rest: Callable[[PushObjectRequest], PushObjectResponse],
69
- node: Node,
70
- run_id: int,
71
- ) -> Callable[[str, bytes], None]:
72
- """Create a push object function that uses REST to push objects.
73
-
74
- Parameters
75
- ----------
76
- push_object_rest : Callable[[PushObjectRequest], PushObjectResponse]
77
- A function that makes a POST request against the `/pull-object` REST endpoint
78
- node : Node
79
- The node making the request.
80
- run_id : int
81
- The run ID for the current operation.
82
-
83
- Returns
84
- -------
85
- Callable[[str, bytes], None]
86
- A function that takes an object ID and its content as bytes, and pushes it
87
- to the servicer. The function raises `ObjectIdNotPreregisteredError` if
88
- the object ID is not pre-registered.
89
- """
90
-
91
- def push_object_fn(object_id: str, object_content: bytes) -> None:
92
- request = PushObjectRequest(
93
- node=node, run_id=run_id, object_id=object_id, object_content=object_content
94
- )
95
- response: PushObjectResponse = push_object_rest(request)
96
- if not response.stored:
97
- raise ObjectIdNotPreregisteredError(object_id)
98
-
99
- return push_object_fn