flwr-nightly 1.19.0.dev20250602__py3-none-any.whl → 1.19.0.dev20250603__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.
@@ -33,7 +33,7 @@ from flwr.common.grpc import create_channel, on_channel_state_change
33
33
  from flwr.common.heartbeat import HeartbeatSender
34
34
  from flwr.common.logger import log
35
35
  from flwr.common.message import Message
36
- from flwr.common.retry_invoker import RetryInvoker
36
+ from flwr.common.retry_invoker import RetryInvoker, _wrap_stub
37
37
  from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
38
38
  generate_key_pairs,
39
39
  )
@@ -159,6 +159,8 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
159
159
  # If the status code is PERMISSION_DENIED, additionally raise RunNotRunningException
160
160
  retry_invoker.should_giveup = _should_giveup_fn
161
161
 
162
+ # Wrap stub
163
+ _wrap_stub(stub, retry_invoker)
162
164
  ###########################################################################
163
165
  # send_node_heartbeat/create_node/delete_node/receive/send/get_run functions
164
166
  ###########################################################################
@@ -203,10 +205,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
203
205
  create_node_request = CreateNodeRequest(
204
206
  heartbeat_interval=HEARTBEAT_DEFAULT_INTERVAL
205
207
  )
206
- create_node_response = retry_invoker.invoke(
207
- stub.CreateNode,
208
- request=create_node_request,
209
- )
208
+ create_node_response = stub.CreateNode(request=create_node_request)
210
209
 
211
210
  # Remember the node and start the heartbeat sender
212
211
  nonlocal node
@@ -227,7 +226,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
227
226
 
228
227
  # Call FleetAPI
229
228
  delete_node_request = DeleteNodeRequest(node=node)
230
- retry_invoker.invoke(stub.DeleteNode, request=delete_node_request)
229
+ stub.DeleteNode(request=delete_node_request)
231
230
 
232
231
  # Cleanup
233
232
  node = None
@@ -241,9 +240,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
241
240
 
242
241
  # Request instructions (message) from server
243
242
  request = PullMessagesRequest(node=node)
244
- response: PullMessagesResponse = retry_invoker.invoke(
245
- stub.PullMessages, request=request
246
- )
243
+ response: PullMessagesResponse = stub.PullMessages(request=request)
247
244
 
248
245
  # Get the current Messages
249
246
  message_proto = (
@@ -289,7 +286,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
289
286
  # Serialize Message
290
287
  message_proto = message_to_proto(message=message)
291
288
  request = PushMessagesRequest(node=node, messages_list=[message_proto])
292
- _ = retry_invoker.invoke(stub.PushMessages, request)
289
+ _ = stub.PushMessages(request)
293
290
 
294
291
  # Cleanup
295
292
  metadata = None
@@ -297,10 +294,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
297
294
  def get_run(run_id: int) -> Run:
298
295
  # Call FleetAPI
299
296
  get_run_request = GetRunRequest(node=node, run_id=run_id)
300
- get_run_response: GetRunResponse = retry_invoker.invoke(
301
- stub.GetRun,
302
- request=get_run_request,
303
- )
297
+ get_run_response: GetRunResponse = stub.GetRun(request=get_run_request)
304
298
 
305
299
  # Return fab_id and fab_version
306
300
  return run_from_proto(get_run_response.run)
@@ -308,10 +302,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
308
302
  def get_fab(fab_hash: str, run_id: int) -> Fab:
309
303
  # Call FleetAPI
310
304
  get_fab_request = GetFabRequest(node=node, hash_str=fab_hash, run_id=run_id)
311
- get_fab_response: GetFabResponse = retry_invoker.invoke(
312
- stub.GetFab,
313
- request=get_fab_request,
314
- )
305
+ get_fab_response: GetFabResponse = stub.GetFab(request=get_fab_request)
315
306
 
316
307
  return Fab(get_fab_response.fab.hash_str, get_fab_response.fab.content)
317
308
 
flwr/common/inflatable.py CHANGED
@@ -18,9 +18,11 @@
18
18
  from __future__ import annotations
19
19
 
20
20
  import hashlib
21
+ from logging import ERROR
21
22
  from typing import TypeVar, cast
22
23
 
23
24
  from .constant import HEAD_BODY_DIVIDER, HEAD_VALUE_DIVIDER
25
+ from .logger import log
24
26
 
25
27
 
26
28
  class InflatableObject:
@@ -163,8 +165,12 @@ def get_object_body_len_from_object_content(object_content: bytes) -> int:
163
165
 
164
166
  def check_body_len_consistency(object_content: bytes) -> bool:
165
167
  """Check that the object body is of length as specified in the head."""
166
- body_len = get_object_body_len_from_object_content(object_content)
167
- return body_len == len(_get_object_body(object_content))
168
+ try:
169
+ body_len = get_object_body_len_from_object_content(object_content)
170
+ return body_len == len(_get_object_body(object_content))
171
+ except ValueError:
172
+ log(ERROR, "Object content does match the expected format.")
173
+ return False
168
174
 
169
175
 
170
176
  def get_object_head_values_from_object_content(
@@ -17,6 +17,7 @@
17
17
 
18
18
  from typing import Optional, Union
19
19
 
20
+ from flwr.client.grpc_rere_client.grpc_adapter import GrpcAdapter
20
21
  from flwr.proto.fleet_pb2_grpc import FleetStub # pylint: disable=E0611
21
22
  from flwr.proto.message_pb2 import ( # pylint: disable=E0611
22
23
  PullObjectRequest,
@@ -48,7 +49,7 @@ inflatable_class_registry: dict[str, type[InflatableObject]] = {
48
49
 
49
50
  def push_object_to_servicer(
50
51
  obj: InflatableObject,
51
- stub: Union[FleetStub, ServerAppIoStub],
52
+ stub: Union[FleetStub, ServerAppIoStub, GrpcAdapter],
52
53
  node: Node,
53
54
  run_id: int,
54
55
  object_ids_to_push: Optional[set[str]] = None,
@@ -87,7 +88,7 @@ def push_object_to_servicer(
87
88
 
88
89
  def pull_object_from_servicer(
89
90
  object_id: str,
90
- stub: Union[FleetStub, ServerAppIoStub],
91
+ stub: Union[FleetStub, ServerAppIoStub, GrpcAdapter],
91
92
  node: Node,
92
93
  run_id: int,
93
94
  ) -> InflatableObject:
@@ -180,7 +180,7 @@ class MetricRecord(TypedDict[str, MetricRecordValues], InflatableObject):
180
180
  MetricRecord
181
181
  The inflated MetricRecord.
182
182
  """
183
- if children is not None:
183
+ if children:
184
184
  raise ValueError("`MetricRecord` objects do not have children.")
185
185
 
186
186
  obj_body = get_object_body(object_content, cls)
@@ -25,10 +25,12 @@ from typing import Any, Callable, Optional, Union, cast
25
25
 
26
26
  import grpc
27
27
 
28
+ from flwr.client.grpc_rere_client.grpc_adapter import GrpcAdapter
28
29
  from flwr.common.constant import MAX_RETRY_DELAY
29
30
  from flwr.common.logger import log
30
31
  from flwr.common.typing import RunNotRunningException
31
32
  from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
33
+ from flwr.proto.fleet_pb2_grpc import FleetStub
32
34
  from flwr.proto.serverappio_pb2_grpc import ServerAppIoStub
33
35
  from flwr.proto.simulationio_pb2_grpc import SimulationIoStub
34
36
 
@@ -366,7 +368,9 @@ def _make_simple_grpc_retry_invoker() -> RetryInvoker:
366
368
 
367
369
 
368
370
  def _wrap_stub(
369
- stub: Union[ServerAppIoStub, ClientAppIoStub, SimulationIoStub],
371
+ stub: Union[
372
+ ServerAppIoStub, ClientAppIoStub, SimulationIoStub, FleetStub, GrpcAdapter
373
+ ],
370
374
  retry_invoker: RetryInvoker,
371
375
  ) -> None:
372
376
  """Wrap a gRPC stub with a retry invoker."""
flwr/proto/message_pb2.py CHANGED
@@ -18,7 +18,7 @@ from flwr.proto import transport_pb2 as flwr_dot_proto_dot_transport__pb2
18
18
  from flwr.proto import node_pb2 as flwr_dot_proto_dot_node__pb2
19
19
 
20
20
 
21
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x66lwr/proto/message.proto\x12\nflwr.proto\x1a\x16\x66lwr/proto/error.proto\x1a\x1b\x66lwr/proto/recorddict.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x15\x66lwr/proto/node.proto\"|\n\x07Message\x12&\n\x08metadata\x18\x01 \x01(\x0b\x32\x14.flwr.proto.Metadata\x12\'\n\x07\x63ontent\x18\x02 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12 \n\x05\x65rror\x18\x03 \x01(\x0b\x32\x11.flwr.proto.Error\"\xd0\x02\n\x07\x43ontext\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x0f\n\x07node_id\x18\x02 \x01(\x04\x12\x38\n\x0bnode_config\x18\x03 \x03(\x0b\x32#.flwr.proto.Context.NodeConfigEntry\x12%\n\x05state\x18\x04 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12\x36\n\nrun_config\x18\x05 \x03(\x0b\x32\".flwr.proto.Context.RunConfigEntry\x1a\x45\n\x0fNodeConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\x1a\x44\n\x0eRunConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"\xbe\x01\n\x08Metadata\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x12\n\nmessage_id\x18\x02 \x01(\t\x12\x13\n\x0bsrc_node_id\x18\x03 \x01(\x04\x12\x13\n\x0b\x64st_node_id\x18\x04 \x01(\x04\x12\x1b\n\x13reply_to_message_id\x18\x05 \x01(\t\x12\x10\n\x08group_id\x18\x06 \x01(\t\x12\x0b\n\x03ttl\x18\x07 \x01(\x01\x12\x14\n\x0cmessage_type\x18\x08 \x01(\t\x12\x12\n\ncreated_at\x18\t \x01(\x01\"\x1f\n\tObjectIDs\x12\x12\n\nobject_ids\x18\x01 \x03(\t\"n\n\x11PushObjectRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x0e\n\x06run_id\x18\x02 \x01(\x04\x12\x11\n\tobject_id\x18\x03 \x01(\t\x12\x16\n\x0eobject_content\x18\x04 \x01(\x0c\"$\n\x12PushObjectResponse\x12\x0e\n\x06stored\x18\x01 \x01(\x08\"V\n\x11PullObjectRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x0e\n\x06run_id\x18\x02 \x01(\x04\x12\x11\n\tobject_id\x18\x03 \x01(\t\",\n\x12PullObjectResponse\x12\x16\n\x0eobject_content\x18\x01 \x01(\x0c\x62\x06proto3')
21
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x66lwr/proto/message.proto\x12\nflwr.proto\x1a\x16\x66lwr/proto/error.proto\x1a\x1b\x66lwr/proto/recorddict.proto\x1a\x1a\x66lwr/proto/transport.proto\x1a\x15\x66lwr/proto/node.proto\"|\n\x07Message\x12&\n\x08metadata\x18\x01 \x01(\x0b\x32\x14.flwr.proto.Metadata\x12\'\n\x07\x63ontent\x18\x02 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12 \n\x05\x65rror\x18\x03 \x01(\x0b\x32\x11.flwr.proto.Error\"\xd0\x02\n\x07\x43ontext\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x0f\n\x07node_id\x18\x02 \x01(\x04\x12\x38\n\x0bnode_config\x18\x03 \x03(\x0b\x32#.flwr.proto.Context.NodeConfigEntry\x12%\n\x05state\x18\x04 \x01(\x0b\x32\x16.flwr.proto.RecordDict\x12\x36\n\nrun_config\x18\x05 \x03(\x0b\x32\".flwr.proto.Context.RunConfigEntry\x1a\x45\n\x0fNodeConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\x1a\x44\n\x0eRunConfigEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.flwr.proto.Scalar:\x02\x38\x01\"\xbe\x01\n\x08Metadata\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\x12\x12\n\nmessage_id\x18\x02 \x01(\t\x12\x13\n\x0bsrc_node_id\x18\x03 \x01(\x04\x12\x13\n\x0b\x64st_node_id\x18\x04 \x01(\x04\x12\x1b\n\x13reply_to_message_id\x18\x05 \x01(\t\x12\x10\n\x08group_id\x18\x06 \x01(\t\x12\x0b\n\x03ttl\x18\x07 \x01(\x01\x12\x14\n\x0cmessage_type\x18\x08 \x01(\t\x12\x12\n\ncreated_at\x18\t \x01(\x01\"\x1f\n\tObjectIDs\x12\x12\n\nobject_ids\x18\x01 \x03(\t\"n\n\x11PushObjectRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x0e\n\x06run_id\x18\x02 \x01(\x04\x12\x11\n\tobject_id\x18\x03 \x01(\t\x12\x16\n\x0eobject_content\x18\x04 \x01(\x0c\"$\n\x12PushObjectResponse\x12\x0e\n\x06stored\x18\x01 \x01(\x08\"V\n\x11PullObjectRequest\x12\x1e\n\x04node\x18\x01 \x01(\x0b\x32\x10.flwr.proto.Node\x12\x0e\n\x06run_id\x18\x02 \x01(\x04\x12\x11\n\tobject_id\x18\x03 \x01(\t\"\\\n\x12PullObjectResponse\x12\x14\n\x0cobject_found\x18\x01 \x01(\x08\x12\x18\n\x10object_available\x18\x02 \x01(\x08\x12\x16\n\x0eobject_content\x18\x03 \x01(\x0c\x62\x06proto3')
22
22
 
23
23
  _globals = globals()
24
24
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -48,5 +48,5 @@ if _descriptor._USE_C_DESCRIPTORS == False:
48
48
  _globals['_PULLOBJECTREQUEST']._serialized_start=985
49
49
  _globals['_PULLOBJECTREQUEST']._serialized_end=1071
50
50
  _globals['_PULLOBJECTRESPONSE']._serialized_start=1073
51
- _globals['_PULLOBJECTRESPONSE']._serialized_end=1117
51
+ _globals['_PULLOBJECTRESPONSE']._serialized_end=1165
52
52
  # @@protoc_insertion_point(module_scope)
@@ -196,11 +196,17 @@ global___PullObjectRequest = PullObjectRequest
196
196
 
197
197
  class PullObjectResponse(google.protobuf.message.Message):
198
198
  DESCRIPTOR: google.protobuf.descriptor.Descriptor
199
+ OBJECT_FOUND_FIELD_NUMBER: builtins.int
200
+ OBJECT_AVAILABLE_FIELD_NUMBER: builtins.int
199
201
  OBJECT_CONTENT_FIELD_NUMBER: builtins.int
202
+ object_found: builtins.bool
203
+ object_available: builtins.bool
200
204
  object_content: builtins.bytes
201
205
  def __init__(self,
202
206
  *,
207
+ object_found: builtins.bool = ...,
208
+ object_available: builtins.bool = ...,
203
209
  object_content: builtins.bytes = ...,
204
210
  ) -> None: ...
205
- def ClearField(self, field_name: typing_extensions.Literal["object_content",b"object_content"]) -> None: ...
211
+ def ClearField(self, field_name: typing_extensions.Literal["object_available",b"object_available","object_content",b"object_content","object_found",b"object_found"]) -> None: ...
206
212
  global___PullObjectResponse = PullObjectResponse
@@ -15,11 +15,12 @@
15
15
  """Fleet API gRPC request-response servicer."""
16
16
 
17
17
 
18
- from logging import DEBUG, INFO
18
+ from logging import DEBUG, ERROR, INFO
19
19
 
20
20
  import grpc
21
21
  from google.protobuf.json_format import MessageToDict
22
22
 
23
+ from flwr.common.constant import Status
23
24
  from flwr.common.inflatable import check_body_len_consistency
24
25
  from flwr.common.logger import log
25
26
  from flwr.common.typing import InvalidRunStatusException
@@ -49,8 +50,9 @@ from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=
49
50
  from flwr.server.superlink.ffs.ffs_factory import FfsFactory
50
51
  from flwr.server.superlink.fleet.message_handler import message_handler
51
52
  from flwr.server.superlink.linkstate import LinkStateFactory
52
- from flwr.server.superlink.utils import abort_grpc_context
53
+ from flwr.server.superlink.utils import abort_grpc_context, check_abort
53
54
  from flwr.supercore.object_store import ObjectStoreFactory
55
+ from flwr.supercore.object_store.object_store import NoObjectInStoreError
54
56
 
55
57
 
56
58
  class FleetServicer(fleet_pb2_grpc.FleetServicer):
@@ -183,11 +185,39 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
183
185
  request.object_id,
184
186
  )
185
187
 
188
+ state = self.state_factory.state()
189
+
190
+ # Abort if the run is not running
191
+ abort_msg = check_abort(
192
+ request.run_id,
193
+ [Status.PENDING, Status.STARTING, Status.FINISHED],
194
+ state,
195
+ )
196
+ if abort_msg:
197
+ abort_grpc_context(abort_msg, context)
198
+
199
+ if request.node.node_id not in state.get_nodes(run_id=request.run_id):
200
+ # Cancel insertion in ObjectStore
201
+ context.abort(grpc.StatusCode.FAILED_PRECONDITION, "Unexpected node ID.")
202
+
186
203
  if not check_body_len_consistency(request.object_content):
187
204
  # Cancel insertion in ObjectStore
188
- context.abort(grpc.StatusCode.PERMISSION_DENIED, "Unexpected object length")
205
+ context.abort(
206
+ grpc.StatusCode.FAILED_PRECONDITION, "Unexpected object length"
207
+ )
208
+
209
+ # Init store
210
+ store = self.objectstore_factory.store()
211
+
212
+ # Insert in store
213
+ stored = False
214
+ try:
215
+ store.put(request.object_id, request.object_content)
216
+ stored = True
217
+ except (NoObjectInStoreError, ValueError) as e:
218
+ log(ERROR, str(e))
189
219
 
190
- return PushObjectResponse()
220
+ return PushObjectResponse(stored=stored)
191
221
 
192
222
  def PullObject(
193
223
  self, request: PullObjectRequest, context: grpc.ServicerContext
@@ -199,4 +229,31 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
199
229
  request.object_id,
200
230
  )
201
231
 
202
- return PullObjectResponse()
232
+ state = self.state_factory.state()
233
+
234
+ # Abort if the run is not running
235
+ abort_msg = check_abort(
236
+ request.run_id,
237
+ [Status.PENDING, Status.STARTING, Status.FINISHED],
238
+ state,
239
+ )
240
+ if abort_msg:
241
+ abort_grpc_context(abort_msg, context)
242
+
243
+ if request.node.node_id not in state.get_nodes(run_id=request.run_id):
244
+ # Cancel insertion in ObjectStore
245
+ context.abort(grpc.StatusCode.FAILED_PRECONDITION, "Unexpected node ID.")
246
+
247
+ # Init store
248
+ store = self.objectstore_factory.store()
249
+
250
+ # Fetch from store
251
+ content = store.get(request.object_id)
252
+ if content is not None:
253
+ object_available = content != b""
254
+ return PullObjectResponse(
255
+ object_found=True,
256
+ object_available=object_available,
257
+ object_content=content,
258
+ )
259
+ return PullObjectResponse(object_found=False, object_available=False)
@@ -409,11 +409,39 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
409
409
  """Push an object to the ObjectStore."""
410
410
  log(DEBUG, "ServerAppIoServicer.PushObject")
411
411
 
412
+ # Init state
413
+ state: LinkState = self.state_factory.state()
414
+
415
+ # Abort if the run is not running
416
+ abort_if(
417
+ request.run_id,
418
+ [Status.PENDING, Status.STARTING, Status.FINISHED],
419
+ state,
420
+ context,
421
+ )
422
+
423
+ if request.node.node_id != SUPERLINK_NODE_ID:
424
+ # Cancel insertion in ObjectStore
425
+ context.abort(grpc.StatusCode.FAILED_PRECONDITION, "Unexpected node ID.")
426
+
412
427
  if not check_body_len_consistency(request.object_content):
413
428
  # Cancel insertion in ObjectStore
414
- context.abort(grpc.StatusCode.PERMISSION_DENIED, "Unexpected object length")
429
+ context.abort(
430
+ grpc.StatusCode.FAILED_PRECONDITION, "Unexpected object length."
431
+ )
432
+
433
+ # Init store
434
+ store = self.objectstore_factory.store()
435
+
436
+ # Insert in store
437
+ stored = False
438
+ try:
439
+ store.put(request.object_id, request.object_content)
440
+ stored = True
441
+ except (NoObjectInStoreError, ValueError) as e:
442
+ log(ERROR, str(e))
415
443
 
416
- return PushObjectResponse()
444
+ return PushObjectResponse(stored=stored)
417
445
 
418
446
  def PullObject(
419
447
  self, request: PullObjectRequest, context: grpc.ServicerContext
@@ -421,7 +449,34 @@ class ServerAppIoServicer(serverappio_pb2_grpc.ServerAppIoServicer):
421
449
  """Pull an object from the ObjectStore."""
422
450
  log(DEBUG, "ServerAppIoServicer.PullObject")
423
451
 
424
- return PullObjectResponse()
452
+ # Init state
453
+ state: LinkState = self.state_factory.state()
454
+
455
+ # Abort if the run is not running
456
+ abort_if(
457
+ request.run_id,
458
+ [Status.PENDING, Status.STARTING, Status.FINISHED],
459
+ state,
460
+ context,
461
+ )
462
+
463
+ if request.node.node_id != SUPERLINK_NODE_ID:
464
+ # Cancel insertion in ObjectStore
465
+ context.abort(grpc.StatusCode.FAILED_PRECONDITION, "Unexpected node ID.")
466
+
467
+ # Init store
468
+ store = self.objectstore_factory.store()
469
+
470
+ # Fetch from store
471
+ content = store.get(request.object_id)
472
+ if content is not None:
473
+ object_available = content != b""
474
+ return PullObjectResponse(
475
+ object_found=True,
476
+ object_available=object_available,
477
+ object_content=content,
478
+ )
479
+ return PullObjectResponse(object_found=False, object_available=False)
425
480
 
426
481
 
427
482
  def _raise_if(validation_error: bool, request_name: str, detail: str) -> None:
@@ -42,8 +42,7 @@ from flwr.common.constant import (
42
42
  from flwr.common.exit import ExitCode, flwr_exit
43
43
  from flwr.common.exit_handlers import register_exit_handlers
44
44
  from flwr.common.logger import log
45
-
46
- from ..start_client_internal import start_client_internal
45
+ from flwr.supernode.start_client_internal import start_client_internal
47
46
 
48
47
 
49
48
  def flower_supernode() -> None:
@@ -17,7 +17,6 @@
17
17
 
18
18
  import multiprocessing
19
19
  import os
20
- import sys
21
20
  import threading
22
21
  import time
23
22
  from collections.abc import Iterator
@@ -57,8 +56,8 @@ from flwr.common.logger import log
57
56
  from flwr.common.retry_invoker import RetryInvoker, RetryState, exponential
58
57
  from flwr.common.typing import Fab, Run, RunNotRunningException, UserConfig
59
58
  from flwr.proto.clientappio_pb2_grpc import add_ClientAppIoServicer_to_server
60
- from flwr.supernode.cli.flwr_clientapp import flwr_clientapp
61
59
  from flwr.supernode.nodestate import NodeStateFactory
60
+ from flwr.supernode.runtime.run_clientapp import run_clientapp
62
61
  from flwr.supernode.servicer.clientappio import ClientAppInputs, ClientAppIoServicer
63
62
 
64
63
 
@@ -259,18 +258,14 @@ def start_client_internal(
259
258
  else clientappio_api_address
260
259
  )
261
260
  # Start ClientApp subprocess
262
- command = [
263
- "flwr-clientapp",
264
- "--clientappio-api-address",
265
- io_address,
266
- "--token",
267
- str(token),
268
- ]
269
- command.append("--insecure")
270
-
271
261
  proc = mp_spawn_context.Process(
272
262
  target=_run_flwr_clientapp,
273
- args=(command, os.getpid()),
263
+ kwargs={
264
+ "main_pid": os.getpid(),
265
+ "clientappio_api_address": io_address,
266
+ "run_once": True,
267
+ "token": token,
268
+ },
274
269
  daemon=True,
275
270
  )
276
271
  proc.start()
@@ -421,7 +416,14 @@ def _make_fleet_connection_retry_invoker(
421
416
  )
422
417
 
423
418
 
424
- def _run_flwr_clientapp(args: list[str], main_pid: int) -> None:
419
+ def _run_flwr_clientapp( # pylint: disable=R0917
420
+ main_pid: int,
421
+ clientappio_api_address: str,
422
+ run_once: bool,
423
+ token: Optional[int] = None,
424
+ flwr_dir: Optional[str] = None,
425
+ certificates: Optional[bytes] = None,
426
+ ) -> None:
425
427
  # Monitor the main process in case of SIGKILL
426
428
  def main_process_monitor() -> None:
427
429
  while True:
@@ -431,9 +433,14 @@ def _run_flwr_clientapp(args: list[str], main_pid: int) -> None:
431
433
 
432
434
  threading.Thread(target=main_process_monitor, daemon=True).start()
433
435
 
434
- # Run the command
435
- sys.argv = args
436
- flwr_clientapp()
436
+ # Run flwr-clientapp
437
+ run_clientapp(
438
+ clientappio_api_address=clientappio_api_address,
439
+ run_once=run_once,
440
+ token=token,
441
+ flwr_dir=flwr_dir,
442
+ certificates=certificates,
443
+ )
437
444
 
438
445
 
439
446
  def run_clientappio_api_grpc(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flwr-nightly
3
- Version: 1.19.0.dev20250602
3
+ Version: 1.19.0.dev20250603
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=slRDCax2CTwVURURUf8qV9Ph4eDuf67XVLB77PuV9fE,12118
87
+ flwr/client/grpc_rere_client/connection.py,sha256=QEUjpXdWGVn_kaFv6Hv2WmJRpcggjMzR7QFpiAa-r6M,11923
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
@@ -122,8 +122,8 @@ flwr/common/exit/exit_code.py,sha256=PNEnCrZfOILjfDAFu5m-2YWEJBrk97xglq4zCUlqV7E
122
122
  flwr/common/exit_handlers.py,sha256=IaqJ60fXZuu7McaRYnoYKtlbH9t4Yl9goNExKqtmQbs,4304
123
123
  flwr/common/grpc.py,sha256=manTaHaPiyYngUq1ErZvvV2B2GxlXUUUGRy3jc3TBIQ,9798
124
124
  flwr/common/heartbeat.py,sha256=SyEpNDnmJ0lni0cWO67rcoJVKasCLmkNHm3dKLeNrLU,5749
125
- flwr/common/inflatable.py,sha256=vBDlaJlgF6sryjglhFcr22zylROmPFwM7QLjVV7XbtU,6837
126
- flwr/common/inflatable_grpc_utils.py,sha256=e8uoQyuuhPlJiW359AuWrqcyRUtVRCP-v8M2hH-_U6U,4069
125
+ flwr/common/inflatable.py,sha256=9yPsSFOfNM2OIb15JQ6-wY5kblwXiC5zNX-tsp2ZwW0,7017
126
+ flwr/common/inflatable_grpc_utils.py,sha256=KSrV51jaKsaAA__dROtlTAUC5k_FYJDVcPA0uITWM0s,4161
127
127
  flwr/common/logger.py,sha256=JbRf6E2vQxXzpDBq1T8IDUJo_usu3gjWEBPQ6uKcmdg,13049
128
128
  flwr/common/message.py,sha256=HfSeqxwXgf90ilbMlM0vrF4cJWqJVx3jJ0gNmTfgdFw,19628
129
129
  flwr/common/object_ref.py,sha256=p3SfTeqo3Aj16SkB-vsnNn01zswOPdGNBitcbRnqmUk,9134
@@ -134,11 +134,11 @@ flwr/common/record/array.py,sha256=3K01tAf_jedub2r2-vkRshbsjBSiKErAO4KqDgdDaSo,1
134
134
  flwr/common/record/arrayrecord.py,sha256=CpoqYXM6Iv4XEc9SryCMYmw-bIvP8ut6xWJzRwYJzdU,18008
135
135
  flwr/common/record/configrecord.py,sha256=G7U0q39kB0Kyi0zMxFmPxcVemL9NgwVS1qjvI4BRQuU,9763
136
136
  flwr/common/record/conversion_utils.py,sha256=wbNCzy7oAqaA3-arhls_EqRZYXRC4YrWIoE-Gy82fJ0,1191
137
- flwr/common/record/metricrecord.py,sha256=XBPnIclQBRV_vHuvMk2sEdPjeyX5_Y00nuOHy8rASW8,8966
137
+ flwr/common/record/metricrecord.py,sha256=KOyJjJbvFV6IwBPbgm92FZ_0_hXpMHuwfCi1rh5Zddk,8954
138
138
  flwr/common/record/recorddict.py,sha256=p7hBimFpKM1XKUe6OAkR_7pYGzGL_EwUJUvJ8odZEcY,14986
139
139
  flwr/common/record/typeddict.py,sha256=dDKgUThs2BscYUNcgP82KP8-qfAYXYftDrf2LszAC_o,3599
140
140
  flwr/common/recorddict_compat.py,sha256=D5SqXWkqBddn5b6K_5UoH7aZ11UaN3lDTlzvHx3-rqk,14119
141
- flwr/common/retry_invoker.py,sha256=T6puUH3nCxdRzQHeanyr-0nTxhRiS1TH07rmef9vuLQ,14482
141
+ flwr/common/retry_invoker.py,sha256=s5IGgRovE19laMetHFePoqIdMBYfz_KdXs-KyfaCrXw,14634
142
142
  flwr/common/secure_aggregation/__init__.py,sha256=MgW6uHGhyFLBAYQqa1Vzs5n2Gc0d4yEw1_NmerFir70,731
143
143
  flwr/common/secure_aggregation/crypto/__init__.py,sha256=5E4q4-Fw0CNz4tLah_QHj7m_rDeM4ucHcFlPWB_Na3Q,738
144
144
  flwr/common/secure_aggregation/crypto/shamir.py,sha256=N8pPa5cEksowNoAqfFm5SP3IuxuVi9GGMa3JOtPniQY,3954
@@ -194,8 +194,8 @@ flwr/proto/log_pb2.py,sha256=iKaS3MVn1BS4xHu8uGPFCOi1KWtvVx-H9V4jCUIJghs,1393
194
194
  flwr/proto/log_pb2.pyi,sha256=ipuhgo40sAHTcRzCsGI1HwIstr5q0THPNk_cf62YyME,1448
195
195
  flwr/proto/log_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
196
196
  flwr/proto/log_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
197
- flwr/proto/message_pb2.py,sha256=0gwIorik6s5o7UF603mtRecDlQclPFwiDSlvkMxqzc0,4388
198
- flwr/proto/message_pb2.pyi,sha256=J1Y7Ok546KJXyvpShElhWLWNusfqww-K_7D6u0fFZbA,9072
197
+ flwr/proto/message_pb2.py,sha256=VoFv02FalR-xegoyqVMC1M_rD02sdWdoAAfFkw00k84,4481
198
+ flwr/proto/message_pb2.pyi,sha256=FmBgs2PsotAdv-OOCEHp4Dc3e6dSo6-CAB3-pgmva4g,9392
199
199
  flwr/proto/message_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
200
200
  flwr/proto/message_pb2_grpc.pyi,sha256=ff2TSiLVnG6IVQcTGzb2DIH3XRSoAvAo_RMcvbMFyc0,76
201
201
  flwr/proto/node_pb2.py,sha256=BzZfAWIX7lV62bZr9f7x16lUZcpg-EImxnwxQXgCbYg,1045
@@ -284,7 +284,7 @@ flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py,sha256=KouR9PUcrPmMtoLooF4O
284
284
  flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py,sha256=iSf0mbBAlig7G6subQwBSVjcUCgSihONKdZ1RmQPTOk,4887
285
285
  flwr/server/superlink/fleet/grpc_bidi/grpc_server.py,sha256=OsS-6GgCIzMMZDVu5Y-OKjynHVUrpdc_5OrtuB-IbU0,5174
286
286
  flwr/server/superlink/fleet/grpc_rere/__init__.py,sha256=ahDJJ1e-lDxBpeBMgPk7YZt2wB38_QltcpOC0gLbpFs,758
287
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=Y92dcvbaN4EHb4Rlut5O2saJsoAN_Tejs4iFtzCS0P0,7189
287
+ flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=SsMtj1EeOgumffWtYTQt-ii3JPldszXvP91C3axznq8,9176
288
288
  flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=DrHubsaLgJCwCeeJPYogQTiP0xYqjxwnT9rh7OP7BoU,6984
289
289
  flwr/server/superlink/fleet/message_handler/__init__.py,sha256=fHsRV0KvJ8HtgSA4_YBsEzuhJLjO8p6xx4aCY2oE1p4,731
290
290
  flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=P43PapLZJKbZ0Oo0kP_KcO5zSMvO53SakQgPMiR5d1M,6500
@@ -303,7 +303,7 @@ flwr/server/superlink/linkstate/sqlite_linkstate.py,sha256=sHJPK1w0tP0m2WCXH2F9l
303
303
  flwr/server/superlink/linkstate/utils.py,sha256=IeLh7iGRCHU5MEWOl7iriaSE4L__8GWOa2OleXadK5M,15444
304
304
  flwr/server/superlink/serverappio/__init__.py,sha256=Fy4zJuoccZe5mZSEIpOmQvU6YeXFBa1M4eZuXXmJcn8,717
305
305
  flwr/server/superlink/serverappio/serverappio_grpc.py,sha256=6-FUUt0GiLcBPljj8bBrUNeAITUoDQOLzaMihKo52hg,2326
306
- flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=JkCqxYNV2Oou6CLdXndRzPjk281cSE4EVDKcuVh7jHE,15556
306
+ flwr/server/superlink/serverappio/serverappio_servicer.py,sha256=qInBXn7xcnNUNIXj_BkjoWfZd96By55gbTsp4onwfDQ,17290
307
307
  flwr/server/superlink/simulation/__init__.py,sha256=Ry8DrNaZCMcQXvUc4FoCN2m3dvUQgWjasfp015o3Ec4,718
308
308
  flwr/server/superlink/simulation/simulationio_grpc.py,sha256=0l0F-UjYEk6W7HZmI28PbJQLFxSi_vBHRkdchgdaSMQ,2224
309
309
  flwr/server/superlink/simulation/simulationio_servicer.py,sha256=aJezU8RSJswcmWm7Eoy0BqsU13jrcfuFwX3ljm-cORM,7719
@@ -345,7 +345,7 @@ flwr/superexec/simulation.py,sha256=j6YwUvBN7EQ09ID7MYOCVZ70PGbuyBy8f9bXU0EszEM,
345
345
  flwr/superlink/__init__.py,sha256=GNSuJ4-N6Z8wun2iZNlXqENt5beUyzC0Gi_tN396bbM,707
346
346
  flwr/supernode/__init__.py,sha256=KgeCaVvXWrU3rptNR1y0oBp4YtXbAcrnCcJAiOoWkI4,707
347
347
  flwr/supernode/cli/__init__.py,sha256=JuEMr0-s9zv-PEWKuLB9tj1ocNfroSyNJ-oyv7ati9A,887
348
- flwr/supernode/cli/flower_supernode.py,sha256=pr16i1xWDzxxB5lcRTaSd4DVQvVOC3G0zwLliS9jSZ0,8766
348
+ flwr/supernode/cli/flower_supernode.py,sha256=ly2AQhbla2sufDaMsENaEALDEd0a4CS4D0eUrUOkHzY,8778
349
349
  flwr/supernode/cli/flwr_clientapp.py,sha256=ORsNxviXOKGzZdcp5DEiHIuj4RycgB2OaPDaTTJJWz4,2555
350
350
  flwr/supernode/nodestate/__init__.py,sha256=CyLLObbmmVgfRO88UCM0VMait1dL57mUauUDfuSHsbU,976
351
351
  flwr/supernode/nodestate/in_memory_nodestate.py,sha256=4ZiLA45fMi2bJgmfDNLtiv-gVNru95Bi48xBy7xtatA,5212
@@ -356,8 +356,8 @@ flwr/supernode/runtime/run_clientapp.py,sha256=sEmrN1F-tV2YAzw06Dk4RM696yyP4xqm2
356
356
  flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca8gxdEo,717
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
- flwr/supernode/start_client_internal.py,sha256=n8xmASWkJB1SngirdvpohjO2RCrGeasKwiLrOMjN4X8,17366
360
- flwr_nightly-1.19.0.dev20250602.dist-info/METADATA,sha256=csDAUbHgOviQ9Y9bb0VKlKRsI6i_wNi_SfUORnqWDr0,15910
361
- flwr_nightly-1.19.0.dev20250602.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
362
- flwr_nightly-1.19.0.dev20250602.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
363
- flwr_nightly-1.19.0.dev20250602.dist-info/RECORD,,
359
+ flwr/supernode/start_client_internal.py,sha256=fI44QAbNbrRomwHI83X1sqtPlDcV8oIAWuZ0DxMTCVY,17602
360
+ flwr_nightly-1.19.0.dev20250603.dist-info/METADATA,sha256=uMka7DkhCI_KfSOFFsib_P7qj7UO05ccr88R1qecUi4,15910
361
+ flwr_nightly-1.19.0.dev20250603.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
362
+ flwr_nightly-1.19.0.dev20250603.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
363
+ flwr_nightly-1.19.0.dev20250603.dist-info/RECORD,,