flwr-nightly 1.20.0.dev20250618__py3-none-any.whl → 1.20.0.dev20250619__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
flwr/cli/build.py CHANGED
@@ -25,7 +25,12 @@ import pathspec
25
25
  import tomli_w
26
26
  import typer
27
27
 
28
- from flwr.common.constant import FAB_ALLOWED_EXTENSIONS, FAB_DATE, FAB_HASH_TRUNCATION
28
+ from flwr.common.constant import (
29
+ FAB_ALLOWED_EXTENSIONS,
30
+ FAB_DATE,
31
+ FAB_HASH_TRUNCATION,
32
+ FAB_MAX_SIZE,
33
+ )
29
34
 
30
35
  from .config_utils import load as load_toml
31
36
  from .config_utils import load_and_validate
@@ -57,7 +62,7 @@ def build(
57
62
  Optional[Path],
58
63
  typer.Option(help="Path of the Flower App to bundle into a FAB"),
59
64
  ] = None,
60
- ) -> tuple[str, str]:
65
+ ) -> None:
61
66
  """Build a Flower App into a Flower App Bundle (FAB).
62
67
 
63
68
  You can run ``flwr build`` without any arguments to bundle the app located in the
@@ -119,8 +124,6 @@ def build(
119
124
  f"🎊 Successfully built {fab_filename}", fg=typer.colors.GREEN, bold=True
120
125
  )
121
126
 
122
- return fab_filename, fab_hash
123
-
124
127
 
125
128
  def build_fab(app: Path) -> tuple[bytes, str, dict[str, Any]]:
126
129
  """Build a FAB in memory and return the bytes, hash, and config.
@@ -193,6 +196,13 @@ def build_fab(app: Path) -> tuple[bytes, str, dict[str, Any]]:
193
196
  write_to_zip(fab_file, ".info/CONTENT", list_file_content)
194
197
 
195
198
  fab_bytes = fab_buffer.getvalue()
199
+ if len(fab_bytes) > FAB_MAX_SIZE:
200
+ raise ValueError(
201
+ f"FAB size exceeds maximum allowed size of {FAB_MAX_SIZE:,} bytes."
202
+ "To reduce the package size, consider ignoring unnecessary files "
203
+ "via your `.gitignore` file or excluding them from the build."
204
+ )
205
+
196
206
  fab_hash = hashlib.sha256(fab_bytes).hexdigest()
197
207
 
198
208
  return fab_bytes, fab_hash, config
@@ -17,7 +17,6 @@
17
17
 
18
18
  from collections.abc import Iterator, Sequence
19
19
  from contextlib import contextmanager
20
- from copy import copy
21
20
  from logging import DEBUG, ERROR
22
21
  from pathlib import Path
23
22
  from typing import Callable, Optional, Union, cast
@@ -25,8 +24,6 @@ from typing import Callable, Optional, Union, cast
25
24
  import grpc
26
25
  from cryptography.hazmat.primitives.asymmetric import ec
27
26
 
28
- from flwr.app.metadata import Metadata
29
- from flwr.client.message_handler.message_handler import validate_out_message
30
27
  from flwr.common import GRPC_MAX_MESSAGE_LENGTH
31
28
  from flwr.common.constant import HEARTBEAT_CALL_TIMEOUT, HEARTBEAT_DEFAULT_INTERVAL
32
29
  from flwr.common.grpc import create_channel, on_channel_state_change
@@ -163,7 +160,6 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
163
160
  if adapter_cls is None:
164
161
  adapter_cls = FleetStub
165
162
  stub = adapter_cls(channel)
166
- metadata: Optional[Metadata] = None
167
163
  node: Optional[Node] = None
168
164
 
169
165
  def _should_giveup_fn(e: Exception) -> bool:
@@ -300,10 +296,6 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
300
296
  # Inject
301
297
  in_message.metadata.__dict__["_message_id"] = msg_id
302
298
 
303
- # Remember `metadata` of the in message
304
- nonlocal metadata
305
- metadata = copy(in_message.metadata) if in_message else None
306
-
307
299
  # Return the message if available
308
300
  return in_message
309
301
 
@@ -314,19 +306,6 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
314
306
  log(ERROR, "Node instance missing")
315
307
  return
316
308
 
317
- # Get the metadata of the incoming message
318
- nonlocal metadata
319
- if metadata is None:
320
- log(ERROR, "No current message")
321
- return
322
-
323
- # Set message_id
324
- message.metadata.__dict__["_message_id"] = message.object_id
325
- # Validate out message
326
- if not validate_out_message(message, metadata):
327
- log(ERROR, "Invalid out message")
328
- return
329
-
330
309
  with no_object_id_recompute():
331
310
  # Get all nested objects
332
311
  all_objects = get_all_nested_objects(message)
@@ -358,9 +337,6 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
358
337
  )
359
338
  log(DEBUG, "Pushed %s objects to servicer.", len(objs_to_push))
360
339
 
361
- # Cleanup
362
- metadata = None
363
-
364
340
  def get_run(run_id: int) -> Run:
365
341
  # Call FleetAPI
366
342
  get_run_request = GetRunRequest(node=node, run_id=run_id)
@@ -16,7 +16,6 @@
16
16
 
17
17
  from collections.abc import Iterator
18
18
  from contextlib import contextmanager
19
- from copy import copy
20
19
  from logging import DEBUG, ERROR, INFO, WARN
21
20
  from typing import Callable, Optional, TypeVar, Union, cast
22
21
 
@@ -24,8 +23,6 @@ from cryptography.hazmat.primitives.asymmetric import ec
24
23
  from google.protobuf.message import Message as GrpcMessage
25
24
  from requests.exceptions import ConnectionError as RequestsConnectionError
26
25
 
27
- from flwr.app.metadata import Metadata
28
- from flwr.client.message_handler.message_handler import validate_out_message
29
26
  from flwr.common import GRPC_MAX_MESSAGE_LENGTH
30
27
  from flwr.common.constant import HEARTBEAT_DEFAULT_INTERVAL
31
28
  from flwr.common.exit import ExitCode, flwr_exit
@@ -178,7 +175,6 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
178
175
  log(ERROR, "Client authentication is not supported for this transport type.")
179
176
 
180
177
  # Shared variables for inner functions
181
- metadata: Optional[Metadata] = None
182
178
  node: Optional[Node] = None
183
179
 
184
180
  ###########################################################################
@@ -367,10 +363,6 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
367
363
  # Inject
368
364
  in_message.metadata.__dict__["_message_id"] = msg_id
369
365
 
370
- # Remember `metadata` of the in message
371
- nonlocal metadata
372
- metadata = copy(in_message.metadata) if in_message else None
373
-
374
366
  return in_message
375
367
 
376
368
  def send(message: Message) -> None:
@@ -380,19 +372,6 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
380
372
  log(ERROR, "Node instance missing")
381
373
  return
382
374
 
383
- # Get incoming message
384
- nonlocal metadata
385
- if metadata is None:
386
- log(ERROR, "No current message")
387
- return
388
-
389
- # Set message_id
390
- message.metadata.__dict__["_message_id"] = message.object_id
391
- # Validate out message
392
- if not validate_out_message(message, metadata):
393
- log(ERROR, "Invalid out message")
394
- return
395
-
396
375
  with no_object_id_recompute():
397
376
  # Get all nested objects
398
377
  all_objects = get_all_nested_objects(message)
@@ -450,9 +429,6 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
450
429
  )
451
430
  log(ERROR, str(e))
452
431
 
453
- # Cleanup
454
- metadata = None
455
-
456
432
  def get_run(run_id: int) -> Run:
457
433
  # Construct the request
458
434
  req = GetRunRequest(node=node, run_id=run_id)
flwr/common/constant.py CHANGED
@@ -74,6 +74,7 @@ FAB_ALLOWED_EXTENSIONS = {".py", ".toml", ".md"}
74
74
  FAB_CONFIG_FILE = "pyproject.toml"
75
75
  FAB_DATE = (2024, 10, 1, 0, 0, 0)
76
76
  FAB_HASH_TRUNCATION = 8
77
+ FAB_MAX_SIZE = 10 * 1024 * 1024 # 10 MB
77
78
  FLWR_DIR = ".flwr" # The default Flower directory: ~/.flwr/
78
79
  FLWR_HOME = "FLWR_HOME" # If set, override the default Flower directory
79
80
 
@@ -17,15 +17,15 @@ from flwr.proto import run_pb2 as flwr_dot_proto_dot_run__pb2
17
17
  from flwr.proto import message_pb2 as flwr_dot_proto_dot_message__pb2
18
18
 
19
19
 
20
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1c\x66lwr/proto/clientappio.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x18\x66lwr/proto/message.proto\"%\n#GetRunIdsWithPendingMessagesRequest\"7\n$GetRunIdsWithPendingMessagesResponse\x12\x0f\n\x07run_ids\x18\x01 \x03(\x04\"%\n\x13RequestTokenRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\"%\n\x14RequestTokenResponse\x12\r\n\x05token\x18\x01 \x01(\t\"W\n\x15\x43lientAppOutputStatus\x12-\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x1f.flwr.proto.ClientAppOutputCode\x12\x0f\n\x07message\x18\x02 \x01(\t\"\x11\n\x0fGetTokenRequest\"!\n\x10GetTokenResponse\x12\r\n\x05token\x18\x01 \x01(\x04\"+\n\x1aPullClientAppInputsRequest\x12\r\n\x05token\x18\x01 \x01(\t\"\xa5\x01\n\x1bPullClientAppInputsResponse\x12$\n\x07message\x18\x01 \x01(\x0b\x32\x13.flwr.proto.Message\x12$\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x13.flwr.proto.Context\x12\x1c\n\x03run\x18\x03 \x01(\x0b\x32\x0f.flwr.proto.Run\x12\x1c\n\x03\x66\x61\x62\x18\x04 \x01(\x0b\x32\x0f.flwr.proto.Fab\"x\n\x1bPushClientAppOutputsRequest\x12\r\n\x05token\x18\x01 \x01(\t\x12$\n\x07message\x18\x02 \x01(\x0b\x32\x13.flwr.proto.Message\x12$\n\x07\x63ontext\x18\x03 \x01(\x0b\x32\x13.flwr.proto.Context\"Q\n\x1cPushClientAppOutputsResponse\x12\x31\n\x06status\x18\x01 \x01(\x0b\x32!.flwr.proto.ClientAppOutputStatus*L\n\x13\x43lientAppOutputCode\x12\x0b\n\x07SUCCESS\x10\x00\x12\x15\n\x11\x44\x45\x41\x44LINE_EXCEEDED\x10\x01\x12\x11\n\rUNKNOWN_ERROR\x10\x02\x32\x88\x04\n\x0b\x43lientAppIo\x12\x83\x01\n\x1cGetRunIdsWithPendingMessages\x12/.flwr.proto.GetRunIdsWithPendingMessagesRequest\x1a\x30.flwr.proto.GetRunIdsWithPendingMessagesResponse\"\x00\x12S\n\x0cRequestToken\x12\x1f.flwr.proto.RequestTokenRequest\x1a .flwr.proto.RequestTokenResponse\"\x00\x12G\n\x08GetToken\x12\x1b.flwr.proto.GetTokenRequest\x1a\x1c.flwr.proto.GetTokenResponse\"\x00\x12h\n\x13PullClientAppInputs\x12&.flwr.proto.PullClientAppInputsRequest\x1a\'.flwr.proto.PullClientAppInputsResponse\"\x00\x12k\n\x14PushClientAppOutputs\x12\'.flwr.proto.PushClientAppOutputsRequest\x1a(.flwr.proto.PushClientAppOutputsResponse\"\x00\x62\x06proto3')
20
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1c\x66lwr/proto/clientappio.proto\x12\nflwr.proto\x1a\x14\x66lwr/proto/fab.proto\x1a\x14\x66lwr/proto/run.proto\x1a\x18\x66lwr/proto/message.proto\"%\n#GetRunIdsWithPendingMessagesRequest\"7\n$GetRunIdsWithPendingMessagesResponse\x12\x0f\n\x07run_ids\x18\x01 \x03(\x04\"%\n\x13RequestTokenRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\x04\"%\n\x14RequestTokenResponse\x12\r\n\x05token\x18\x01 \x01(\t\"W\n\x15\x43lientAppOutputStatus\x12-\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x1f.flwr.proto.ClientAppOutputCode\x12\x0f\n\x07message\x18\x02 \x01(\t\"+\n\x1aPullClientAppInputsRequest\x12\r\n\x05token\x18\x01 \x01(\t\"\xa5\x01\n\x1bPullClientAppInputsResponse\x12$\n\x07message\x18\x01 \x01(\x0b\x32\x13.flwr.proto.Message\x12$\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x13.flwr.proto.Context\x12\x1c\n\x03run\x18\x03 \x01(\x0b\x32\x0f.flwr.proto.Run\x12\x1c\n\x03\x66\x61\x62\x18\x04 \x01(\x0b\x32\x0f.flwr.proto.Fab\"x\n\x1bPushClientAppOutputsRequest\x12\r\n\x05token\x18\x01 \x01(\t\x12$\n\x07message\x18\x02 \x01(\x0b\x32\x13.flwr.proto.Message\x12$\n\x07\x63ontext\x18\x03 \x01(\x0b\x32\x13.flwr.proto.Context\"Q\n\x1cPushClientAppOutputsResponse\x12\x31\n\x06status\x18\x01 \x01(\x0b\x32!.flwr.proto.ClientAppOutputStatus*L\n\x13\x43lientAppOutputCode\x12\x0b\n\x07SUCCESS\x10\x00\x12\x15\n\x11\x44\x45\x41\x44LINE_EXCEEDED\x10\x01\x12\x11\n\rUNKNOWN_ERROR\x10\x02\x32\xbf\x03\n\x0b\x43lientAppIo\x12\x83\x01\n\x1cGetRunIdsWithPendingMessages\x12/.flwr.proto.GetRunIdsWithPendingMessagesRequest\x1a\x30.flwr.proto.GetRunIdsWithPendingMessagesResponse\"\x00\x12S\n\x0cRequestToken\x12\x1f.flwr.proto.RequestTokenRequest\x1a .flwr.proto.RequestTokenResponse\"\x00\x12h\n\x13PullClientAppInputs\x12&.flwr.proto.PullClientAppInputsRequest\x1a\'.flwr.proto.PullClientAppInputsResponse\"\x00\x12k\n\x14PushClientAppOutputs\x12\'.flwr.proto.PushClientAppOutputsRequest\x1a(.flwr.proto.PushClientAppOutputsResponse\"\x00\x62\x06proto3')
21
21
 
22
22
  _globals = globals()
23
23
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
24
24
  _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flwr.proto.clientappio_pb2', _globals)
25
25
  if _descriptor._USE_C_DESCRIPTORS == False:
26
26
  DESCRIPTOR._options = None
27
- _globals['_CLIENTAPPOUTPUTCODE']._serialized_start=849
28
- _globals['_CLIENTAPPOUTPUTCODE']._serialized_end=925
27
+ _globals['_CLIENTAPPOUTPUTCODE']._serialized_start=795
28
+ _globals['_CLIENTAPPOUTPUTCODE']._serialized_end=871
29
29
  _globals['_GETRUNIDSWITHPENDINGMESSAGESREQUEST']._serialized_start=114
30
30
  _globals['_GETRUNIDSWITHPENDINGMESSAGESREQUEST']._serialized_end=151
31
31
  _globals['_GETRUNIDSWITHPENDINGMESSAGESRESPONSE']._serialized_start=153
@@ -36,18 +36,14 @@ if _descriptor._USE_C_DESCRIPTORS == False:
36
36
  _globals['_REQUESTTOKENRESPONSE']._serialized_end=286
37
37
  _globals['_CLIENTAPPOUTPUTSTATUS']._serialized_start=288
38
38
  _globals['_CLIENTAPPOUTPUTSTATUS']._serialized_end=375
39
- _globals['_GETTOKENREQUEST']._serialized_start=377
40
- _globals['_GETTOKENREQUEST']._serialized_end=394
41
- _globals['_GETTOKENRESPONSE']._serialized_start=396
42
- _globals['_GETTOKENRESPONSE']._serialized_end=429
43
- _globals['_PULLCLIENTAPPINPUTSREQUEST']._serialized_start=431
44
- _globals['_PULLCLIENTAPPINPUTSREQUEST']._serialized_end=474
45
- _globals['_PULLCLIENTAPPINPUTSRESPONSE']._serialized_start=477
46
- _globals['_PULLCLIENTAPPINPUTSRESPONSE']._serialized_end=642
47
- _globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_start=644
48
- _globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_end=764
49
- _globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_start=766
50
- _globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_end=847
51
- _globals['_CLIENTAPPIO']._serialized_start=928
52
- _globals['_CLIENTAPPIO']._serialized_end=1448
39
+ _globals['_PULLCLIENTAPPINPUTSREQUEST']._serialized_start=377
40
+ _globals['_PULLCLIENTAPPINPUTSREQUEST']._serialized_end=420
41
+ _globals['_PULLCLIENTAPPINPUTSRESPONSE']._serialized_start=423
42
+ _globals['_PULLCLIENTAPPINPUTSRESPONSE']._serialized_end=588
43
+ _globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_start=590
44
+ _globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_end=710
45
+ _globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_start=712
46
+ _globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_end=793
47
+ _globals['_CLIENTAPPIO']._serialized_start=874
48
+ _globals['_CLIENTAPPIO']._serialized_end=1321
53
49
  # @@protoc_insertion_point(module_scope)
@@ -88,23 +88,6 @@ class ClientAppOutputStatus(google.protobuf.message.Message):
88
88
  def ClearField(self, field_name: typing_extensions.Literal["code",b"code","message",b"message"]) -> None: ...
89
89
  global___ClientAppOutputStatus = ClientAppOutputStatus
90
90
 
91
- class GetTokenRequest(google.protobuf.message.Message):
92
- DESCRIPTOR: google.protobuf.descriptor.Descriptor
93
- def __init__(self,
94
- ) -> None: ...
95
- global___GetTokenRequest = GetTokenRequest
96
-
97
- class GetTokenResponse(google.protobuf.message.Message):
98
- DESCRIPTOR: google.protobuf.descriptor.Descriptor
99
- TOKEN_FIELD_NUMBER: builtins.int
100
- token: builtins.int
101
- def __init__(self,
102
- *,
103
- token: builtins.int = ...,
104
- ) -> None: ...
105
- def ClearField(self, field_name: typing_extensions.Literal["token",b"token"]) -> None: ...
106
- global___GetTokenResponse = GetTokenResponse
107
-
108
91
  class PullClientAppInputsRequest(google.protobuf.message.Message):
109
92
  DESCRIPTOR: google.protobuf.descriptor.Descriptor
110
93
  TOKEN_FIELD_NUMBER: builtins.int
@@ -24,11 +24,6 @@ class ClientAppIoStub(object):
24
24
  request_serializer=flwr_dot_proto_dot_clientappio__pb2.RequestTokenRequest.SerializeToString,
25
25
  response_deserializer=flwr_dot_proto_dot_clientappio__pb2.RequestTokenResponse.FromString,
26
26
  )
27
- self.GetToken = channel.unary_unary(
28
- '/flwr.proto.ClientAppIo/GetToken',
29
- request_serializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenRequest.SerializeToString,
30
- response_deserializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenResponse.FromString,
31
- )
32
27
  self.PullClientAppInputs = channel.unary_unary(
33
28
  '/flwr.proto.ClientAppIo/PullClientAppInputs',
34
29
  request_serializer=flwr_dot_proto_dot_clientappio__pb2.PullClientAppInputsRequest.SerializeToString,
@@ -58,13 +53,6 @@ class ClientAppIoServicer(object):
58
53
  context.set_details('Method not implemented!')
59
54
  raise NotImplementedError('Method not implemented!')
60
55
 
61
- def GetToken(self, request, context):
62
- """Get token
63
- """
64
- context.set_code(grpc.StatusCode.UNIMPLEMENTED)
65
- context.set_details('Method not implemented!')
66
- raise NotImplementedError('Method not implemented!')
67
-
68
56
  def PullClientAppInputs(self, request, context):
69
57
  """Pull client app inputs
70
58
  """
@@ -92,11 +80,6 @@ def add_ClientAppIoServicer_to_server(servicer, server):
92
80
  request_deserializer=flwr_dot_proto_dot_clientappio__pb2.RequestTokenRequest.FromString,
93
81
  response_serializer=flwr_dot_proto_dot_clientappio__pb2.RequestTokenResponse.SerializeToString,
94
82
  ),
95
- 'GetToken': grpc.unary_unary_rpc_method_handler(
96
- servicer.GetToken,
97
- request_deserializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenRequest.FromString,
98
- response_serializer=flwr_dot_proto_dot_clientappio__pb2.GetTokenResponse.SerializeToString,
99
- ),
100
83
  'PullClientAppInputs': grpc.unary_unary_rpc_method_handler(
101
84
  servicer.PullClientAppInputs,
102
85
  request_deserializer=flwr_dot_proto_dot_clientappio__pb2.PullClientAppInputsRequest.FromString,
@@ -151,23 +134,6 @@ class ClientAppIo(object):
151
134
  options, channel_credentials,
152
135
  insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
153
136
 
154
- @staticmethod
155
- def GetToken(request,
156
- target,
157
- options=(),
158
- channel_credentials=None,
159
- call_credentials=None,
160
- insecure=False,
161
- compression=None,
162
- wait_for_ready=None,
163
- timeout=None,
164
- metadata=None):
165
- return grpc.experimental.unary_unary(request, target, '/flwr.proto.ClientAppIo/GetToken',
166
- flwr_dot_proto_dot_clientappio__pb2.GetTokenRequest.SerializeToString,
167
- flwr_dot_proto_dot_clientappio__pb2.GetTokenResponse.FromString,
168
- options, channel_credentials,
169
- insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
170
-
171
137
  @staticmethod
172
138
  def PullClientAppInputs(request,
173
139
  target,
@@ -18,11 +18,6 @@ class ClientAppIoStub:
18
18
  flwr.proto.clientappio_pb2.RequestTokenResponse]
19
19
  """Request token"""
20
20
 
21
- GetToken: grpc.UnaryUnaryMultiCallable[
22
- flwr.proto.clientappio_pb2.GetTokenRequest,
23
- flwr.proto.clientappio_pb2.GetTokenResponse]
24
- """Get token"""
25
-
26
21
  PullClientAppInputs: grpc.UnaryUnaryMultiCallable[
27
22
  flwr.proto.clientappio_pb2.PullClientAppInputsRequest,
28
23
  flwr.proto.clientappio_pb2.PullClientAppInputsResponse]
@@ -51,14 +46,6 @@ class ClientAppIoServicer(metaclass=abc.ABCMeta):
51
46
  """Request token"""
52
47
  pass
53
48
 
54
- @abc.abstractmethod
55
- def GetToken(self,
56
- request: flwr.proto.clientappio_pb2.GetTokenRequest,
57
- context: grpc.ServicerContext,
58
- ) -> flwr.proto.clientappio_pb2.GetTokenResponse:
59
- """Get token"""
60
- pass
61
-
62
49
  @abc.abstractmethod
63
50
  def PullClientAppInputs(self,
64
51
  request: flwr.proto.clientappio_pb2.PullClientAppInputsRequest,
@@ -0,0 +1,32 @@
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
+ """Utility functions for the infrastructure."""
16
+
17
+
18
+ def mask_string(value: str, head: int = 4, tail: int = 4) -> str:
19
+ """Mask a string by preserving only the head and tail characters.
20
+
21
+ Mask a string for safe display by preserving the head and tail characters,
22
+ and replacing the middle with '...'. Useful for logging tokens, secrets,
23
+ or IDs without exposing sensitive data.
24
+
25
+ Notes
26
+ -----
27
+ If the string is shorter than the combined length of `head` and `tail`,
28
+ the original string is returned unchanged.
29
+ """
30
+ if len(value) <= head + tail:
31
+ return value
32
+ return f"{value[:head]}...{value[-tail:]}"
@@ -25,6 +25,7 @@ import grpc
25
25
  from flwr.common import now
26
26
  from flwr.common.auth_plugin import ExecAuthPlugin
27
27
  from flwr.common.constant import (
28
+ FAB_MAX_SIZE,
28
29
  LOG_STREAM_INTERVAL,
29
30
  RUN_ID_NOT_FOUND_MESSAGE,
30
31
  Status,
@@ -84,6 +85,14 @@ class ExecServicer(exec_pb2_grpc.ExecServicer):
84
85
  """Create run ID."""
85
86
  log(INFO, "ExecServicer.StartRun")
86
87
 
88
+ if len(request.fab.content) > FAB_MAX_SIZE:
89
+ log(
90
+ ERROR,
91
+ "FAB size exceeds maximum allowed size of %d bytes.",
92
+ FAB_MAX_SIZE,
93
+ )
94
+ return StartRunResponse()
95
+
87
96
  flwr_aid = shared_account_info.get().flwr_aid if self.auth_plugin else None
88
97
  run_id = self.executor.start_run(
89
98
  request.fab.content,
@@ -40,7 +40,6 @@ from flwr.common.constant import (
40
40
  TRANSPORT_TYPE_REST,
41
41
  )
42
42
  from flwr.common.exit import ExitCode, flwr_exit
43
- from flwr.common.exit_handlers import register_exit_handlers
44
43
  from flwr.common.logger import log
45
44
  from flwr.supernode.start_client_internal import start_client_internal
46
45
 
@@ -66,12 +65,6 @@ def flower_supernode() -> None:
66
65
 
67
66
  log(DEBUG, "Isolation mode: %s", args.isolation)
68
67
 
69
- # Register handlers for graceful shutdown
70
- register_exit_handlers(
71
- event_type=EventType.RUN_SUPERNODE_LEAVE,
72
- exit_message="SuperNode terminated gracefully.",
73
- )
74
-
75
68
  start_client_internal(
76
69
  server_address=args.superlink,
77
70
  transport=args.transport,
@@ -22,6 +22,7 @@ from flwr.common.args import add_args_flwr_app_common
22
22
  from flwr.common.constant import CLIENTAPPIO_API_DEFAULT_CLIENT_ADDRESS
23
23
  from flwr.common.exit import ExitCode, flwr_exit
24
24
  from flwr.common.logger import log
25
+ from flwr.supercore.utils import mask_string
25
26
  from flwr.supernode.runtime.run_clientapp import run_clientapp
26
27
 
27
28
 
@@ -40,7 +41,7 @@ def flwr_clientapp() -> None:
40
41
  "`flwr-clientapp` will attempt to connect to SuperNode's "
41
42
  "ClientAppIo API at %s with token %s",
42
43
  args.clientappio_api_address,
43
- args.token,
44
+ mask_string(args.token) if args.token else "None",
44
45
  )
45
46
  run_clientapp(
46
47
  clientappio_api_address=args.clientappio_api_address,
@@ -56,6 +56,7 @@ from flwr.proto.clientappio_pb2 import (
56
56
  RequestTokenResponse,
57
57
  )
58
58
  from flwr.proto.clientappio_pb2_grpc import ClientAppIoStub
59
+ from flwr.supercore.utils import mask_string
59
60
 
60
61
 
61
62
  def run_clientapp( # pylint: disable=R0913, R0914, R0917
@@ -195,7 +196,8 @@ def pull_clientappinputs(
195
196
  stub: ClientAppIoStub, token: str
196
197
  ) -> tuple[Message, Context, Run, Optional[Fab]]:
197
198
  """Pull ClientAppInputs from SuperNode."""
198
- log(INFO, "[flwr-clientapp] Pull `ClientAppInputs` for token %s", token)
199
+ masked_token = mask_string(token)
200
+ log(INFO, "[flwr-clientapp] Pull `ClientAppInputs` for token %s", masked_token)
199
201
  try:
200
202
  res: PullClientAppInputsResponse = stub.PullClientAppInputs(
201
203
  PullClientAppInputsRequest(token=token)
@@ -214,7 +216,10 @@ def push_clientappoutputs(
214
216
  stub: ClientAppIoStub, token: str, message: Message, context: Context
215
217
  ) -> PushClientAppOutputsResponse:
216
218
  """Push ClientAppOutputs to SuperNode."""
217
- log(INFO, "[flwr-clientapp] Push `ClientAppOutputs` for token %s", token)
219
+ masked_token = mask_string(token)
220
+ log(INFO, "[flwr-clientapp] Push `ClientAppOutputs` for token %s", masked_token)
221
+ # Set message ID
222
+ message.metadata.__dict__["_message_id"] = message.object_id
218
223
  proto_message = message_to_proto(message)
219
224
  proto_context = context_to_proto(context)
220
225
 
@@ -15,10 +15,8 @@
15
15
  """ClientAppIo API Servicer."""
16
16
 
17
17
 
18
- from .clientappio_servicer import ClientAppInputs, ClientAppIoServicer, ClientAppOutputs
18
+ from .clientappio_servicer import ClientAppIoServicer
19
19
 
20
20
  __all__ = [
21
- "ClientAppInputs",
22
21
  "ClientAppIoServicer",
23
- "ClientAppOutputs",
24
22
  ]
@@ -15,16 +15,14 @@
15
15
  """ClientAppIo API servicer."""
16
16
 
17
17
 
18
- from dataclasses import dataclass
19
- from logging import DEBUG, ERROR
20
- from typing import Optional, cast
18
+ from logging import DEBUG
19
+ from typing import cast
21
20
 
22
21
  import grpc
23
22
 
24
- from flwr.common import Context, Message, typing
23
+ from flwr.common import Context
25
24
  from flwr.common.logger import log
26
25
  from flwr.common.serde import (
27
- clientappstatus_to_proto,
28
26
  context_from_proto,
29
27
  context_to_proto,
30
28
  fab_to_proto,
@@ -39,8 +37,6 @@ from flwr.proto import clientappio_pb2_grpc
39
37
  from flwr.proto.clientappio_pb2 import ( # pylint: disable=E0401
40
38
  GetRunIdsWithPendingMessagesRequest,
41
39
  GetRunIdsWithPendingMessagesResponse,
42
- GetTokenRequest,
43
- GetTokenResponse,
44
40
  PullClientAppInputsRequest,
45
41
  PullClientAppInputsResponse,
46
42
  PushClientAppOutputsRequest,
@@ -53,24 +49,6 @@ from flwr.supercore.object_store import ObjectStoreFactory
53
49
  from flwr.supernode.nodestate import NodeStateFactory
54
50
 
55
51
 
56
- @dataclass
57
- class ClientAppInputs:
58
- """Specify the inputs to the ClientApp."""
59
-
60
- message: Message
61
- context: Context
62
- run: Run
63
- fab: Optional[Fab]
64
-
65
-
66
- @dataclass
67
- class ClientAppOutputs:
68
- """Specify the outputs from the ClientApp."""
69
-
70
- message: Message
71
- context: Context
72
-
73
-
74
52
  # pylint: disable=C0103,W0613,W0201
75
53
  class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
76
54
  """ClientAppIo API servicer."""
@@ -85,10 +63,6 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
85
63
  self.ffs_factory = ffs_factory
86
64
  self.objectstore_factory = objectstore_factory
87
65
 
88
- self.clientapp_input: Optional[ClientAppInputs] = None
89
- self.clientapp_output: Optional[ClientAppOutputs] = None
90
- self.token_returned: bool = False
91
-
92
66
  def GetRunIdsWithPendingMessages(
93
67
  self,
94
68
  request: GetRunIdsWithPendingMessagesRequest,
@@ -126,33 +100,6 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
126
100
  # Return the token
127
101
  return RequestTokenResponse(token=token)
128
102
 
129
- def GetToken(
130
- self, request: GetTokenRequest, context: grpc.ServicerContext
131
- ) -> GetTokenResponse:
132
- """Get token."""
133
- log(DEBUG, "ClientAppIo.GetToken")
134
-
135
- # Fail if no ClientAppInputs are available
136
- if self.clientapp_input is None:
137
- context.abort(
138
- grpc.StatusCode.FAILED_PRECONDITION,
139
- "No inputs available.",
140
- )
141
-
142
- # Fail if token was already returned in a previous call
143
- if self.token_returned:
144
- context.abort(
145
- grpc.StatusCode.FAILED_PRECONDITION,
146
- "Token already returned. A token can be returned only once.",
147
- )
148
-
149
- # If
150
- # - ClientAppInputs is set, and
151
- # - token hasn't been returned before,
152
- # return token
153
- self.token_returned = True
154
- return GetTokenResponse(token=123) # To be deleted
155
-
156
103
  def PullClientAppInputs(
157
104
  self, request: PullClientAppInputsRequest, context: grpc.ServicerContext
158
105
  ) -> PullClientAppInputsResponse:
@@ -203,40 +150,12 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
203
150
  )
204
151
  raise RuntimeError("This line should never be reached.")
205
152
 
206
- # Delete the token
207
- state.delete_token(run_id)
208
-
209
- # Preconditions met
210
- try:
211
- # Update Message and Context
212
- self.clientapp_output = ClientAppOutputs(
213
- message=message_from_proto(request.message),
214
- context=context_from_proto(request.context),
215
- )
216
-
217
- # Set status
218
- code = typing.ClientAppOutputCode.SUCCESS
219
- status = typing.ClientAppOutputStatus(code=code, message="Success")
220
- except Exception as e: # pylint: disable=broad-exception-caught
221
- log(ERROR, "ClientApp failed to push message to SuperNode, %s", e)
222
- code = typing.ClientAppOutputCode.UNKNOWN_ERROR
223
- status = typing.ClientAppOutputStatus(code=code, message="Unkonwn error")
224
-
225
- # Return status to ClientApp process
226
- proto_status = clientappstatus_to_proto(status=status)
227
- return PushClientAppOutputsResponse(status=proto_status)
153
+ # Save the message and context to the state
154
+ state.store_message(message_from_proto(request.message))
155
+ state.store_context(context_from_proto(request.context))
228
156
 
229
- def has_outputs(self) -> bool:
230
- """Check if ClientAppOutputs are available."""
231
- return self.clientapp_output is not None
232
-
233
- def get_outputs(self) -> ClientAppOutputs:
234
- """Get ClientApp outputs."""
235
- if self.clientapp_output is None:
236
- raise ValueError("ClientAppOutputs not set before calling `get_outputs`.")
237
-
238
- # Set outputs to a local variable and clear state
239
- output: ClientAppOutputs = self.clientapp_output
240
- self.clientapp_output = None
157
+ # Remove the token to make the run eligible for processing
158
+ # A run associated with a token cannot be handled until its token is cleared
159
+ state.delete_token(run_id)
241
160
 
242
- return output
161
+ return PushClientAppOutputsResponse()
@@ -45,9 +45,11 @@ from flwr.common.constant import (
45
45
  TRANSPORT_TYPES,
46
46
  )
47
47
  from flwr.common.exit import ExitCode, flwr_exit
48
+ from flwr.common.exit_handlers import register_exit_handlers
48
49
  from flwr.common.grpc import generic_create_grpc_server
49
50
  from flwr.common.logger import log
50
51
  from flwr.common.retry_invoker import RetryInvoker, RetryState, exponential
52
+ from flwr.common.telemetry import EventType
51
53
  from flwr.common.typing import Fab, Run, RunNotRunningException, UserConfig
52
54
  from flwr.proto.clientappio_pb2_grpc import add_ClientAppIoServicer_to_server
53
55
  from flwr.supercore.ffs import Ffs, FfsFactory
@@ -136,7 +138,7 @@ def start_client_internal(
136
138
  object_store_factory = ObjectStoreFactory()
137
139
 
138
140
  # Launch ClientAppIo API server
139
- _clientappio_grpc_server, clientappio_servicer = run_clientappio_api_grpc(
141
+ clientappio_server = run_clientappio_api_grpc(
140
142
  address=clientappio_api_address,
141
143
  state_factory=state_factory,
142
144
  ffs_factory=ffs_factory,
@@ -144,6 +146,13 @@ def start_client_internal(
144
146
  certificates=None,
145
147
  )
146
148
 
149
+ # Register handlers for graceful shutdown
150
+ register_exit_handlers(
151
+ event_type=EventType.RUN_SUPERNODE_LEAVE,
152
+ exit_message="SuperNode terminated gracefully.",
153
+ grpc_servers=[clientappio_server],
154
+ )
155
+
147
156
  # Initialize NodeState, Ffs, and ObjectStore
148
157
  state = state_factory.state()
149
158
  ffs = ffs_factory.ffs()
@@ -180,72 +189,39 @@ def start_client_internal(
180
189
  get_fab=get_fab,
181
190
  )
182
191
 
183
- if run_id is None:
184
- time.sleep(3) # Wait for 3s before asking again
185
- continue
186
-
187
- try:
188
- # Two isolation modes:
189
- # 1. `subprocess`: SuperNode is starting the ClientApp
190
- # process as a subprocess.
191
- # 2. `process`: ClientApp process gets started separately
192
- # (via `flwr-clientapp`), for example, in a separate
193
- # Docker container.
194
-
195
- # Mode 1: SuperNode starts ClientApp as subprocess
196
- start_subprocess = isolation == ISOLATION_MODE_SUBPROCESS
197
-
198
- if start_subprocess:
199
- _octet, _colon, _port = clientappio_api_address.rpartition(":")
200
- io_address = (
201
- f"{CLIENT_OCTET}:{_port}"
202
- if _octet == SERVER_OCTET
203
- else clientappio_api_address
204
- )
205
- # Start ClientApp subprocess
206
- command = [
207
- "flwr-clientapp",
208
- "--clientappio-api-address",
209
- io_address,
210
- "--parent-pid",
211
- str(os.getpid()),
212
- "--insecure",
213
- "--run-once",
214
- ]
215
- subprocess.run(command, check=False)
216
- else:
217
- # Wait for output to become available
218
- while not clientappio_servicer.has_outputs():
219
- time.sleep(0.1)
220
-
221
- outputs = clientappio_servicer.get_outputs()
222
- reply_message, context = outputs.message, outputs.context
223
-
224
- # Update context in the state
225
- state.store_context(context)
226
-
227
- # Send
228
- send(reply_message)
229
-
230
- # Delete messages from the state
231
- state.delete_messages(
232
- message_ids=[
233
- reply_message.metadata.message_id,
234
- reply_message.metadata.reply_to_message_id,
235
- ]
192
+ # Two isolation modes:
193
+ # 1. `subprocess`: SuperNode is starting the ClientApp
194
+ # process as a subprocess.
195
+ # 2. `process`: ClientApp process gets started separately
196
+ # (via `flwr-clientapp`), for example, in a separate
197
+ # Docker container.
198
+
199
+ # Mode 1: SuperNode starts ClientApp as subprocess
200
+ start_subprocess = isolation == ISOLATION_MODE_SUBPROCESS
201
+
202
+ if start_subprocess and run_id is not None:
203
+ _octet, _colon, _port = clientappio_api_address.rpartition(":")
204
+ io_address = (
205
+ f"{CLIENT_OCTET}:{_port}"
206
+ if _octet == SERVER_OCTET
207
+ else clientappio_api_address
236
208
  )
209
+ # Start ClientApp subprocess
210
+ command = [
211
+ "flwr-clientapp",
212
+ "--clientappio-api-address",
213
+ io_address,
214
+ "--parent-pid",
215
+ str(os.getpid()),
216
+ "--insecure",
217
+ "--run-once",
218
+ ]
219
+ subprocess.run(command, check=False)
237
220
 
238
- log(INFO, "Sent reply")
221
+ _push_messages(state=state, send=send)
239
222
 
240
- except RunNotRunningException:
241
- log(INFO, "")
242
- log(
243
- INFO,
244
- "SuperNode aborted sending the reply message. "
245
- "Run ID %s is not in `RUNNING` status.",
246
- run_id,
247
- )
248
- log(INFO, "")
223
+ # Sleep for 3 seconds before the next iteration
224
+ time.sleep(3)
249
225
 
250
226
 
251
227
  def _pull_and_store_message( # pylint: disable=too-many-positional-arguments
@@ -333,6 +309,53 @@ def _pull_and_store_message( # pylint: disable=too-many-positional-arguments
333
309
  return run_id
334
310
 
335
311
 
312
+ def _push_messages(
313
+ state: NodeState,
314
+ send: Callable[[Message], None],
315
+ ) -> None:
316
+ """Push reply messages to the SuperLink."""
317
+ # Get messages to send
318
+ reply_messages = state.get_messages(is_reply=True)
319
+
320
+ for message in reply_messages:
321
+ # Log message sending
322
+ log(INFO, "")
323
+ if message.metadata.group_id:
324
+ log(
325
+ INFO,
326
+ "[RUN %s, ROUND %s]",
327
+ message.metadata.run_id,
328
+ message.metadata.group_id,
329
+ )
330
+ else:
331
+ log(INFO, "[RUN %s]", message.metadata.run_id)
332
+ log(
333
+ INFO,
334
+ "Sending: %s message",
335
+ message.metadata.message_type,
336
+ )
337
+
338
+ # Send the message
339
+ try:
340
+ send(message)
341
+ log(INFO, "Sent successfully")
342
+ except RunNotRunningException:
343
+ log(
344
+ INFO,
345
+ "Run ID %s is not in `RUNNING` status. Ignoring reply message %s.",
346
+ message.metadata.run_id,
347
+ message.metadata.message_id,
348
+ )
349
+ finally:
350
+ # Delete the message from the state
351
+ state.delete_messages(
352
+ message_ids=[
353
+ message.metadata.message_id,
354
+ message.metadata.reply_to_message_id,
355
+ ]
356
+ )
357
+
358
+
336
359
  @contextmanager
337
360
  def _init_connection( # pylint: disable=too-many-positional-arguments
338
361
  transport: str,
@@ -456,7 +479,7 @@ def run_clientappio_api_grpc(
456
479
  ffs_factory: FfsFactory,
457
480
  objectstore_factory: ObjectStoreFactory,
458
481
  certificates: Optional[tuple[bytes, bytes, bytes]],
459
- ) -> tuple[grpc.Server, ClientAppIoServicer]:
482
+ ) -> grpc.Server:
460
483
  """Run ClientAppIo API gRPC server."""
461
484
  clientappio_servicer: grpc.Server = ClientAppIoServicer(
462
485
  state_factory=state_factory,
@@ -475,4 +498,4 @@ def run_clientappio_api_grpc(
475
498
  )
476
499
  log(INFO, "Starting Flower ClientAppIo gRPC server on %s", address)
477
500
  clientappio_grpc_server.start()
478
- return clientappio_grpc_server, clientappio_servicer
501
+ return clientappio_grpc_server
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: flwr-nightly
3
- Version: 1.20.0.dev20250618
3
+ Version: 1.20.0.dev20250619
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
@@ -6,7 +6,7 @@ flwr/cli/__init__.py,sha256=EfMGmHoobET6P2blBt_eOByXL8299MgFfB7XNdaPQ6I,720
6
6
  flwr/cli/app.py,sha256=AKCP45Dkbpvdil_4Ir9S93L3HP3iUOnHmcZjscoM8uU,1856
7
7
  flwr/cli/auth_plugin/__init__.py,sha256=FyaoqPzcxlBTFfJ2sBRC5USwQLmAhFr5KuBwfMO4bmo,1052
8
8
  flwr/cli/auth_plugin/oidc_cli_plugin.py,sha256=gIhW6Jg9QAo-jL43LYPpw_kn7pdUZZae0s0H8dEgjLM,5384
9
- flwr/cli/build.py,sha256=bzvXbA0MdNMni3uu8KUl32y3VOTJpsUToxNQl_0qE6U,6967
9
+ flwr/cli/build.py,sha256=7OrcTqrjJd-iVq-MCtCIBCfvzi1JoqwUxeZDGKDKu6I,7265
10
10
  flwr/cli/cli_user_auth_interceptor.py,sha256=-JqDXpeZNQVwoSG7hMKsiS5qY5k5oklNSlQOVpM0-aY,3126
11
11
  flwr/cli/config_utils.py,sha256=IAVn2uWTXpN72YYt7raLtwp8ziwZugUKSURpc471VzU,9123
12
12
  flwr/cli/constant.py,sha256=g7Ad7o3DJDkJNrWS0T3SSJETWSTkkVJWGpLM8zlbpcY,1289
@@ -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=dyRBkTVUNhlMmLaoJUz9U4lWnAb7QjYRmGfOzaE0CbA,14402
87
+ flwr/client/grpc_rere_client/connection.py,sha256=5XNwDiac3YEXjyosSmiGz3lJyGNzA8I1I-ft4z08uIw,13619
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=yxWuuh9A7CVzHDoAcBOQOUmCoT0kXSTGZ8zyD8YZGuo,17033
101
+ flwr/client/rest_client/connection.py,sha256=hp-bVcqG0Ul4OmITxcqEHOsGtJuyNevndP-B8trwlns,16270
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
@@ -108,7 +108,7 @@ flwr/common/args.py,sha256=-aX_jVnSaDrJR2KZ8Wq0Y3dQHII4R4MJtJOIXzVUA0c,5417
108
108
  flwr/common/auth_plugin/__init__.py,sha256=3rzPkVLn9WyB5n7HLk1XGDw3SLCqRWAU1_CnglcWPfw,970
109
109
  flwr/common/auth_plugin/auth_plugin.py,sha256=kXx5o39vJchaPv28sK9qO6H_UXSWym6zRBbCa7sUwtQ,4825
110
110
  flwr/common/config.py,sha256=glcZDjco-amw1YfQcYTFJ4S1pt9APoexT-mf1QscuHs,13960
111
- flwr/common/constant.py,sha256=yCJk_m7sJiMz8fTmOMWLBzltGRVUjFmt9NoYJt3Fz-w,8150
111
+ flwr/common/constant.py,sha256=HO1y0YYHZUCIDt5QQnvCTSYVeKhkIJve0RbQ3nW7jHU,8191
112
112
  flwr/common/context.py,sha256=Be8obQR_OvEDy1OmshuUKxGRQ7Qx89mf5F4xlhkR10s,2407
113
113
  flwr/common/date.py,sha256=1ZT2cRSpC2DJqprOVTLXYCR_O2_OZR0zXO_brJ3LqWc,1554
114
114
  flwr/common/differential_privacy.py,sha256=FdlpdpPl_H_2HJa8CQM1iCUGBBQ5Dc8CzxmHERM-EoE,6148
@@ -164,10 +164,10 @@ flwr/compat/server/__init__.py,sha256=TGVSoOTuf5T5JHUVrK5wuorQF7L6Wvdem8B4uufvMJ
164
164
  flwr/compat/server/app.py,sha256=_lIe7Q4KUk-olq9PYBxIsO3UaOn6N92CWgWQ4hRcAZw,6490
165
165
  flwr/compat/simulation/__init__.py,sha256=MApGa-tysDDw34iSdxZ7TWOKtGJM-z3i8fIRJa0qbZ8,750
166
166
  flwr/proto/__init__.py,sha256=S3VbQzVwNC1P-3_9EdrXuwgptO-BVuuAe20Z_OUc1cQ,683
167
- flwr/proto/clientappio_pb2.py,sha256=sI2VLXYaUqEcPHvuh0iCnETAhfHqP2PcvQX6KY_gVMY,4730
168
- flwr/proto/clientappio_pb2.pyi,sha256=WFxzJ5jomhuFaQ5RRF1noKuOWAshaCcap4scEAuunVQ,7448
169
- flwr/proto/clientappio_pb2_grpc.py,sha256=zVJ0mTgwh5TXvIfBr1hf2l1JT0kg6MCIK9xwwUJbRjc,9634
170
- flwr/proto/clientappio_pb2_grpc.pyi,sha256=uvDYLp-Ljf3qk5MI_s05HjHneAi3qo9udVztzfLPXYs,2808
167
+ flwr/proto/clientappio_pb2.py,sha256=jkTJnHtHOylYTV0pxfFAaA0CtIPGrwGCcVgCg6i0LhU,4337
168
+ flwr/proto/clientappio_pb2.pyi,sha256=qrH9KeJ8YXRa9iQYlKV8-kwXrmxGr6AJp5f7Yx88CEg,6843
169
+ flwr/proto/clientappio_pb2_grpc.py,sha256=vstXed6-uSOqM0qbaZBwYIgHHs7GH6oKqOq0TniboOk,8035
170
+ flwr/proto/clientappio_pb2_grpc.pyi,sha256=828mbHoq0SxZ3NRmGqiZmpb4KtLPi71piQBMF_2EZxk,2399
171
171
  flwr/proto/error_pb2.py,sha256=PQVWrfjVPo88ql_KgV9nCxyQNCcV9PVfmcw7sOzTMro,1084
172
172
  flwr/proto/error_pb2.pyi,sha256=ZNH4HhJTU_KfMXlyCeg8FwU-fcUYxTqEmoJPtWtHikc,734
173
173
  flwr/proto/error_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
@@ -335,31 +335,32 @@ flwr/supercore/object_store/__init__.py,sha256=cdfPAmjINY6iOp8oI_LdcVh2simg469Mk
335
335
  flwr/supercore/object_store/in_memory_object_store.py,sha256=oflJcOuVNgx9A-B2da4VHDb1qj_Jub9wKFOrUBgtz_U,9630
336
336
  flwr/supercore/object_store/object_store.py,sha256=VlZz-yzoWZtITbnYD8vwLZbFosv7vgr1XVNzByObeY0,5853
337
337
  flwr/supercore/object_store/object_store_factory.py,sha256=QVwE2ywi7vsj2iKfvWWnNw3N_I7Rz91NUt2RpcbJ7iM,1527
338
+ flwr/supercore/utils.py,sha256=ebuHMbeA8eXisX0oMPqBK3hk7uVnIE_yiqWVz8YbkpQ,1324
338
339
  flwr/superexec/__init__.py,sha256=YFqER0IJc1XEWfsX6AxZ9LSRq0sawPYrNYki-brvTIc,715
339
340
  flwr/superexec/app.py,sha256=U2jjOHb2LGWoU7vrl9_czTzre9O2mPxu3CPGUZ86sK4,1465
340
341
  flwr/superexec/deployment.py,sha256=cFxhFom-0zv93HLNjNcUdBy3Sf6JwshRoXPQtcZunF0,6797
341
342
  flwr/superexec/exec_event_log_interceptor.py,sha256=7aBjZ4lkpOIyWut0s394OpMePr16g_Te594s-9aDM9Q,5774
342
343
  flwr/superexec/exec_grpc.py,sha256=lpc_rgRjtHHMzcdOzznl12D4vT22JqV5acdy45YDb0k,3498
343
- flwr/superexec/exec_servicer.py,sha256=U2-sOV0C87zvOaWZ0sQcCtnh8ENRWs6bgJhpH1srcEs,12235
344
+ flwr/superexec/exec_servicer.py,sha256=c0nwdFBiS6CbKrRA7ffOpsgASOLeaRV_ICwxDfxNGAg,12498
344
345
  flwr/superexec/exec_user_auth_interceptor.py,sha256=HpGHTcDKzB7XUiQHXgntNVFYL-VfP9Wj5tEVc04VOOw,5820
345
346
  flwr/superexec/executor.py,sha256=LaErHRJvNggjWV6FI6eajgKfnwOvSv2UqzFH253yDro,3265
346
347
  flwr/superexec/simulation.py,sha256=62rSLcS-1wnMsMsafSQuIDLs5ZS6Ail1spkZ-alNNTg,4156
347
348
  flwr/superlink/__init__.py,sha256=GNSuJ4-N6Z8wun2iZNlXqENt5beUyzC0Gi_tN396bbM,707
348
349
  flwr/supernode/__init__.py,sha256=KgeCaVvXWrU3rptNR1y0oBp4YtXbAcrnCcJAiOoWkI4,707
349
350
  flwr/supernode/cli/__init__.py,sha256=JuEMr0-s9zv-PEWKuLB9tj1ocNfroSyNJ-oyv7ati9A,887
350
- flwr/supernode/cli/flower_supernode.py,sha256=ly2AQhbla2sufDaMsENaEALDEd0a4CS4D0eUrUOkHzY,8778
351
- flwr/supernode/cli/flwr_clientapp.py,sha256=QeC9TeNq6vrFnYqDPCMym-AieZcp9VrasixkgUFvIAQ,3069
351
+ flwr/supernode/cli/flower_supernode.py,sha256=fAkk9zGhoP8Sv05EkdXRiCtirTAzWkSZBqRoaDdgflk,8529
352
+ flwr/supernode/cli/flwr_clientapp.py,sha256=zaro6BoUEmfKIPQYuyJ9oR4rrHSS3bufhEqxcTo5VZU,3153
352
353
  flwr/supernode/nodestate/__init__.py,sha256=CyLLObbmmVgfRO88UCM0VMait1dL57mUauUDfuSHsbU,976
353
354
  flwr/supernode/nodestate/in_memory_nodestate.py,sha256=LF3AbaW0bcZHY5yKWwUJSU2RZbMynt-YjFysGqvTOQY,7338
354
355
  flwr/supernode/nodestate/nodestate.py,sha256=kkGFxYnLIwT4-UmlPnf6HvAUpPey2urUNrweGybAIY4,6398
355
356
  flwr/supernode/nodestate/nodestate_factory.py,sha256=UYTDCcwK_baHUmkzkJDxL0UEqvtTfOMlQRrROMCd0Xo,1430
356
357
  flwr/supernode/runtime/__init__.py,sha256=JQdqd2EMTn-ORMeTvewYYh52ls0YKP68jrps1qioxu4,718
357
- flwr/supernode/runtime/run_clientapp.py,sha256=k6R5PKRTEJQ0gfCOhNb6K8HVMyIJyhm_TdtJE5Jy0hA,8027
358
+ flwr/supernode/runtime/run_clientapp.py,sha256=wDOs0SbTQJxcm4z63qK4mHomKXjyW-VMsUjD-mXD5X4,8248
358
359
  flwr/supernode/servicer/__init__.py,sha256=lucTzre5WPK7G1YLCfaqg3rbFWdNSb7ZTt-ca8gxdEo,717
359
- flwr/supernode/servicer/clientappio/__init__.py,sha256=vJyOjO2FXZ2URbnthmdsgs6948wbYfdq1L1V8Um-Lr8,895
360
- flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=QGJhRwgGYnxQjLJk8wA6-25AIw3NH0QRjBfgvmHErRU,8302
361
- flwr/supernode/start_client_internal.py,sha256=gpIv0vIfMVJzNt8qOf6PGHeqRWHMb_MkpArvYvj_45g,17831
362
- flwr_nightly-1.20.0.dev20250618.dist-info/METADATA,sha256=PTDjvTipZ8rFu-CkqCn3-W1UPs6ClM10p0wtQ1Hva4c,15910
363
- flwr_nightly-1.20.0.dev20250618.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
364
- flwr_nightly-1.20.0.dev20250618.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
365
- flwr_nightly-1.20.0.dev20250618.dist-info/RECORD,,
360
+ flwr/supernode/servicer/clientappio/__init__.py,sha256=7Oy62Y_oijqF7Dxi6tpcUQyOpLc_QpIRZ83NvwmB0Yg,813
361
+ flwr/supernode/servicer/clientappio/clientappio_servicer.py,sha256=d3GdIabycUoDBDL_eVlt513knGSjQW3-9lG6Cw4QEk4,5719
362
+ flwr/supernode/start_client_internal.py,sha256=DAXuReZ1FCXt9Y1KbM0p-dI50ROWPEJXzfKrl14OE6k,18233
363
+ flwr_nightly-1.20.0.dev20250619.dist-info/METADATA,sha256=jui4QpPMXqhY6NHr7ILSXqQLGJSa4QzLuSiS-mWM398,15910
364
+ flwr_nightly-1.20.0.dev20250619.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
365
+ flwr_nightly-1.20.0.dev20250619.dist-info/entry_points.txt,sha256=jNpDXGBGgs21RqUxelF_jwGaxtqFwm-MQyfz-ZqSjrA,367
366
+ flwr_nightly-1.20.0.dev20250619.dist-info/RECORD,,