flwr-nightly 1.19.0.dev20250605__py3-none-any.whl → 1.19.0.dev20250606__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,6 +31,8 @@ from flwr.common.constant import HEARTBEAT_CALL_TIMEOUT, HEARTBEAT_DEFAULT_INTER
31
31
  from flwr.common.grpc import create_channel, on_channel_state_change
32
32
  from flwr.common.heartbeat import HeartbeatSender
33
33
  from flwr.common.inflatable_grpc_utils import (
34
+ make_pull_object_fn_grpc,
35
+ make_push_object_fn_grpc,
34
36
  pull_object_from_servicer,
35
37
  push_object_to_servicer,
36
38
  )
@@ -269,9 +271,11 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
269
271
  Message,
270
272
  pull_object_from_servicer(
271
273
  object_id=message_proto.metadata.message_id,
272
- stub=stub,
273
- node=node,
274
- run_id=message_proto.metadata.run_id,
274
+ pull_object_fn=make_pull_object_fn_grpc(
275
+ pull_object_grpc=stub.PullObject,
276
+ node=node,
277
+ run_id=message_proto.metadata.run_id,
278
+ ),
275
279
  ),
276
280
  )
277
281
 
@@ -322,9 +326,11 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
322
326
  objs_to_push = set(response.objects_to_push[message.object_id].object_ids)
323
327
  push_object_to_servicer(
324
328
  message,
325
- stub,
326
- node,
327
- run_id=message.metadata.run_id,
329
+ push_object_fn=make_push_object_fn_grpc(
330
+ push_object_grpc=stub.PushObject,
331
+ node=node,
332
+ run_id=message.metadata.run_id,
333
+ ),
328
334
  object_ids_to_push=objs_to_push,
329
335
  )
330
336
  log(DEBUG, "Pushed %s objects to servicer.", len(objs_to_push))
@@ -16,10 +16,8 @@
16
16
 
17
17
 
18
18
  from time import sleep
19
- from typing import Optional, Union
19
+ from typing import Callable, Optional
20
20
 
21
- from flwr.client.grpc_rere_client.grpc_adapter import GrpcAdapter
22
- from flwr.proto.fleet_pb2_grpc import FleetStub # pylint: disable=E0611
23
21
  from flwr.proto.message_pb2 import ( # pylint: disable=E0611
24
22
  PullObjectRequest,
25
23
  PullObjectResponse,
@@ -27,7 +25,6 @@ from flwr.proto.message_pb2 import ( # pylint: disable=E0611
27
25
  PushObjectResponse,
28
26
  )
29
27
  from flwr.proto.node_pb2 import Node # pylint: disable=E0611
30
- from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub # pylint: disable=E0611
31
28
 
32
29
  from .inflatable import (
33
30
  InflatableObject,
@@ -48,11 +45,24 @@ inflatable_class_registry: dict[str, type[InflatableObject]] = {
48
45
  }
49
46
 
50
47
 
48
+ class ObjectUnavailableError(Exception):
49
+ """Exception raised when an object has been pre-registered but is not yet
50
+ available."""
51
+
52
+ def __init__(self, object_id: str):
53
+ super().__init__(f"Object with ID '{object_id}' is not yet available.")
54
+
55
+
56
+ class ObjectIdNotPreregisteredError(Exception):
57
+ """Exception raised when an object ID is not pre-registered."""
58
+
59
+ def __init__(self, object_id: str):
60
+ super().__init__(f"Object with ID '{object_id}' could not be found.")
61
+
62
+
51
63
  def push_object_to_servicer(
52
64
  obj: InflatableObject,
53
- stub: Union[FleetStub, ServerAppIoStub, GrpcAdapter],
54
- node: Node,
55
- run_id: int,
65
+ push_object_fn: Callable[[str, bytes], None],
56
66
  object_ids_to_push: Optional[set[str]] = None,
57
67
  ) -> set[str]:
58
68
  """Recursively deflate an object and push it to the servicer.
@@ -60,13 +70,30 @@ def push_object_to_servicer(
60
70
  Objects with the same ID are not pushed twice. If `object_ids_to_push` is set,
61
71
  only objects with those IDs are pushed. It returns the set of pushed object
62
72
  IDs.
73
+
74
+ Parameters
75
+ ----------
76
+ obj : InflatableObject
77
+ The object to push.
78
+ push_object_fn : Callable[[str, bytes], None]
79
+ A function that takes an object ID and its content as bytes, and pushes
80
+ it to the servicer. This function should raise `ObjectIdNotPreregisteredError`
81
+ if the object ID is not pre-registered.
82
+ object_ids_to_push : Optional[set[str]] (default: None)
83
+ A set of object IDs to push. If object ID of the given object is not in this
84
+ set, the object will not be pushed.
85
+
86
+ Returns
87
+ -------
88
+ set[str]
89
+ A set of object IDs that were pushed to the servicer.
63
90
  """
64
91
  pushed_object_ids: set[str] = set()
65
92
  # Push children if it has any
66
93
  if children := obj.children:
67
94
  for child in children.values():
68
95
  pushed_object_ids |= push_object_to_servicer(
69
- child, stub, node, run_id, object_ids_to_push
96
+ child, push_object_fn, object_ids_to_push
70
97
  )
71
98
 
72
99
  # Deflate object and push
@@ -74,14 +101,8 @@ def push_object_to_servicer(
74
101
  object_id = get_object_id(object_content)
75
102
  # Push always if no object set is specified, or if the object is in the set
76
103
  if object_ids_to_push is None or object_id in object_ids_to_push:
77
- _: PushObjectResponse = stub.PushObject(
78
- PushObjectRequest(
79
- node=node,
80
- run_id=run_id,
81
- object_id=object_id,
82
- object_content=object_content,
83
- )
84
- )
104
+ # The function may raise an error if the object ID is not pre-registered
105
+ push_object_fn(object_id, object_content)
85
106
  pushed_object_ids.add(object_id)
86
107
 
87
108
  return pushed_object_ids
@@ -89,20 +110,33 @@ def push_object_to_servicer(
89
110
 
90
111
  def pull_object_from_servicer(
91
112
  object_id: str,
92
- stub: Union[FleetStub, ServerAppIoStub, GrpcAdapter],
93
- node: Node,
94
- run_id: int,
113
+ pull_object_fn: Callable[[str], bytes],
95
114
  ) -> InflatableObject:
96
- """Recursively inflate an object by pulling it from the servicer."""
115
+ """Recursively inflate an object by pulling it from the servicer.
116
+
117
+ Parameters
118
+ ----------
119
+ object_id : str
120
+ The ID of the object to pull.
121
+ pull_object_fn : Callable[[str], bytes]
122
+ A function that takes an object ID and returns the object content as bytes.
123
+ The function should raise `ObjectUnavailableError` if the object is not yet
124
+ available, or `ObjectIdNotPreregisteredError` if the object ID is not
125
+ pre-registered.
126
+
127
+ Returns
128
+ -------
129
+ InflatableObject
130
+ The pulled object.
131
+ """
97
132
  # Pull object
98
- object_available = False
99
- while not object_available:
100
- object_proto: PullObjectResponse = stub.PullObject(
101
- PullObjectRequest(node=node, run_id=run_id, object_id=object_id)
102
- )
103
- object_available = object_proto.object_available
104
- object_content = object_proto.object_content
105
- sleep(0.1)
133
+ while True:
134
+ try:
135
+ # The function may raise an error if the object ID is not pre-registered
136
+ object_content: bytes = pull_object_fn(object_id)
137
+ break # Exit loop if object is successfully pulled
138
+ except ObjectUnavailableError:
139
+ sleep(0.1) # Retry after a short delay
106
140
 
107
141
  # Extract object class and object_ids of children
108
142
  obj_type, children_obj_ids, _ = get_object_head_values_from_object_content(
@@ -115,8 +149,79 @@ def pull_object_from_servicer(
115
149
  children: dict[str, InflatableObject] = {}
116
150
  for child_object_id in children_obj_ids:
117
151
  children[child_object_id] = pull_object_from_servicer(
118
- child_object_id, stub, node, run_id
152
+ child_object_id, pull_object_fn
119
153
  )
120
154
 
121
155
  # Inflate object passing its children
122
156
  return cls_type.inflate(object_content, children=children)
157
+
158
+
159
+ def make_pull_object_fn_grpc(
160
+ pull_object_grpc: Callable[[PullObjectRequest], PullObjectResponse],
161
+ node: Node,
162
+ run_id: int,
163
+ ) -> Callable[[str], bytes]:
164
+ """Create a pull object function that uses gRPC to pull objects.
165
+
166
+ Parameters
167
+ ----------
168
+ pull_object_grpc : Callable[[PullObjectRequest], PullObjectResponse]
169
+ The gRPC function to pull objects, e.g., `FleetStub.PullObject`.
170
+ node : Node
171
+ The node making the request.
172
+ run_id : int
173
+ The run ID for the current operation.
174
+
175
+ Returns
176
+ -------
177
+ Callable[[str], bytes]
178
+ A function that takes an object ID and returns the object content as bytes.
179
+ The function raises `ObjectIdNotPreregisteredError` if the object ID is not
180
+ pre-registered, or `ObjectUnavailableError` if the object is not yet available.
181
+ """
182
+
183
+ def pull_object_fn(object_id: str) -> bytes:
184
+ request = PullObjectRequest(node=node, run_id=run_id, object_id=object_id)
185
+ response: PullObjectResponse = pull_object_grpc(request)
186
+ if not response.object_found:
187
+ raise ObjectIdNotPreregisteredError(object_id)
188
+ if not response.object_available:
189
+ raise ObjectUnavailableError(object_id)
190
+ return response.object_content
191
+
192
+ return pull_object_fn
193
+
194
+
195
+ def make_push_object_fn_grpc(
196
+ push_object_grpc: Callable[[PushObjectRequest], PushObjectResponse],
197
+ node: Node,
198
+ run_id: int,
199
+ ) -> Callable[[str, bytes], None]:
200
+ """Create a push object function that uses gRPC to push objects.
201
+
202
+ Parameters
203
+ ----------
204
+ push_object_grpc : Callable[[PushObjectRequest], PushObjectResponse]
205
+ The gRPC function to push objects, e.g., `FleetStub.PushObject`.
206
+ node : Node
207
+ The node making the request.
208
+ run_id : int
209
+ The run ID for the current operation.
210
+
211
+ Returns
212
+ -------
213
+ Callable[[str, bytes], None]
214
+ A function that takes an object ID and its content as bytes, and pushes it
215
+ to the servicer. The function raises `ObjectIdNotPreregisteredError` if
216
+ the object ID is not pre-registered.
217
+ """
218
+
219
+ def push_object_fn(object_id: str, object_content: bytes) -> None:
220
+ request = PushObjectRequest(
221
+ node=node, run_id=run_id, object_id=object_id, object_content=object_content
222
+ )
223
+ response: PushObjectResponse = push_object_grpc(request)
224
+ if not response.stored:
225
+ raise ObjectIdNotPreregisteredError(object_id)
226
+
227
+ return push_object_fn
@@ -29,6 +29,8 @@ from flwr.common.constant import (
29
29
  )
30
30
  from flwr.common.grpc import create_channel, on_channel_state_change
31
31
  from flwr.common.inflatable_grpc_utils import (
32
+ make_pull_object_fn_grpc,
33
+ make_push_object_fn_grpc,
32
34
  pull_object_from_servicer,
33
35
  push_object_to_servicer,
34
36
  )
@@ -227,9 +229,11 @@ class GrpcGrid(Grid):
227
229
  # Push only object that are not in the store
228
230
  push_object_to_servicer(
229
231
  message,
230
- self._stub,
231
- node=self.node,
232
- run_id=run_id,
232
+ push_object_fn=make_push_object_fn_grpc(
233
+ push_object_grpc=self._stub.PushObject,
234
+ node=self.node,
235
+ run_id=run_id,
236
+ ),
233
237
  object_ids_to_push=obj_ids_to_push,
234
238
  )
235
239
  return msg_id
@@ -292,9 +296,11 @@ class GrpcGrid(Grid):
292
296
 
293
297
  message = pull_object_from_servicer(
294
298
  msg_proto.metadata.message_id,
295
- self._stub,
296
- node=self.node,
297
- run_id=run_id,
299
+ pull_object_fn=make_pull_object_fn_grpc(
300
+ pull_object_grpc=self._stub.PullObject,
301
+ node=self.node,
302
+ run_id=run_id,
303
+ ),
298
304
  )
299
305
  inflated_msgs.append(cast(Message, message))
300
306
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flwr-nightly
3
- Version: 1.19.0.dev20250605
3
+ Version: 1.19.0.dev20250606
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
@@ -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=XwhT-yrWLHHegXpiAu1YuICLQ1t-KkOh6pNYJ9R4FEE,13358
87
+ flwr/client/grpc_rere_client/connection.py,sha256=6LF9JuAhL4XDHVtPS6MzEYm-Nrer-5iM7fEjR5XaGzM,13658
88
88
  flwr/client/grpc_rere_client/grpc_adapter.py,sha256=JvMZ7vCFTaTEo6AzKYh3zDmeQAU7VSjdysbC6t3ufWg,6351
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
@@ -123,7 +123,7 @@ flwr/common/exit_handlers.py,sha256=IaqJ60fXZuu7McaRYnoYKtlbH9t4Yl9goNExKqtmQbs,
123
123
  flwr/common/grpc.py,sha256=manTaHaPiyYngUq1ErZvvV2B2GxlXUUUGRy3jc3TBIQ,9798
124
124
  flwr/common/heartbeat.py,sha256=SyEpNDnmJ0lni0cWO67rcoJVKasCLmkNHm3dKLeNrLU,5749
125
125
  flwr/common/inflatable.py,sha256=9yPsSFOfNM2OIb15JQ6-wY5kblwXiC5zNX-tsp2ZwW0,7017
126
- flwr/common/inflatable_grpc_utils.py,sha256=YGP8oJRfnkwvY6segWH1DUf_ljDIkku7-2zH66tv3HA,4337
126
+ flwr/common/inflatable_grpc_utils.py,sha256=3M3_334GM-BrjLysilPXEbkDAErh_dXVgkcmcFSQYWg,8017
127
127
  flwr/common/logger.py,sha256=JbRf6E2vQxXzpDBq1T8IDUJo_usu3gjWEBPQ6uKcmdg,13049
128
128
  flwr/common/message.py,sha256=ZdH35PznYhIzfNKPzHTL1YS5z-flTpHnjdNpQR6B8x0,19953
129
129
  flwr/common/object_ref.py,sha256=p3SfTeqo3Aj16SkB-vsnNn01zswOPdGNBitcbRnqmUk,9134
@@ -236,7 +236,7 @@ flwr/server/criterion.py,sha256=G4e-6B48Pc7d5rmGVUpIzNKb6UF88O3VmTRuUltgjzM,1061
236
236
  flwr/server/fleet_event_log_interceptor.py,sha256=AkL7Y5d3xm2vRhL3ahmEVVoOvAP7PA7dRgB-je4v-Ys,3774
237
237
  flwr/server/grid/__init__.py,sha256=aWZHezoR2UGMJISB_gPMCm2N_2GSbm97A3lAp7ruhRQ,888
238
238
  flwr/server/grid/grid.py,sha256=naGCYt5J6dnmUvrcGkdNyKPe3MBd-0awGm1ALmgahqY,6625
239
- flwr/server/grid/grpc_grid.py,sha256=ymLaqWYYkv0uWrYvxavMKEyB0TVRMSPi1tJhmvhe7_g,12392
239
+ flwr/server/grid/grpc_grid.py,sha256=o9oXBsAc9jp2RneY1AhOOyOO8B4sRJKP_l1UyC0j5_M,12692
240
240
  flwr/server/grid/inmemory_grid.py,sha256=RjejYT-d-hHuTs1KSs_5wvOdAWKLus8w5_UAcnGt4iw,6168
241
241
  flwr/server/history.py,sha256=cCkFhBN4GoHsYYNk5GG1Y089eKJh2DH_ZJbYPwLaGyk,5026
242
242
  flwr/server/run_serverapp.py,sha256=v0p6jXj2dFxlRUdoEeF1mnaFd9XRQi6dZCflPY6d3qI,2063
@@ -357,7 +357,7 @@ flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca
357
357
  flwr/supernode/servicer/clientappio/__init__.py,sha256=vJyOjO2FXZ2URbnthmdsgs6948wbYfdq1L1V8Um-Lr8,895
358
358
  flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=LmzkxtNQBn5vVrHc0Bhq2WqaK6-LM2v4kfLBN0PiNNM,8522
359
359
  flwr/supernode/start_client_internal.py,sha256=5CwTNV-XmIhwR1jv3G7aQAXGhf6OFWS6U-vmxY1iKGA,16984
360
- flwr_nightly-1.19.0.dev20250605.dist-info/METADATA,sha256=gsyzTuVl8GpQD7gk1RPBCbNvdugpyl08gCr1sC0kUHc,15910
361
- flwr_nightly-1.19.0.dev20250605.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
362
- flwr_nightly-1.19.0.dev20250605.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
363
- flwr_nightly-1.19.0.dev20250605.dist-info/RECORD,,
360
+ flwr_nightly-1.19.0.dev20250606.dist-info/METADATA,sha256=OBd3qXqNO4F-2bqFuBUM8HZ1hKilS8QDmf0fH12imYs,15910
361
+ flwr_nightly-1.19.0.dev20250606.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
362
+ flwr_nightly-1.19.0.dev20250606.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
363
+ flwr_nightly-1.19.0.dev20250606.dist-info/RECORD,,