flwr-nightly 1.11.0.dev20240817__py3-none-any.whl → 1.11.0.dev20240819__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.

Potentially problematic release.


This version of flwr-nightly might be problematic. Click here for more details.

flwr/cli/install.py CHANGED
@@ -173,7 +173,9 @@ def validate_and_install(
173
173
  / project_name
174
174
  / version
175
175
  )
176
- if install_dir.exists() and not skip_prompt:
176
+ if install_dir.exists():
177
+ if skip_prompt:
178
+ return install_dir
177
179
  if not typer.confirm(
178
180
  typer.style(
179
181
  f"\n💬 {project_name} version {version} is already installed, "
flwr/client/app.py CHANGED
@@ -21,7 +21,7 @@ import time
21
21
  from dataclasses import dataclass
22
22
  from logging import ERROR, INFO, WARN
23
23
  from pathlib import Path
24
- from typing import Callable, ContextManager, Dict, Optional, Tuple, Type, Union
24
+ from typing import Callable, ContextManager, Dict, Optional, Tuple, Type, Union, cast
25
25
 
26
26
  import grpc
27
27
  from cryptography.hazmat.primitives.asymmetric import ec
@@ -52,7 +52,7 @@ from flwr.proto.clientappio_pb2_grpc import add_ClientAppIoServicer_to_server
52
52
  from flwr.server.superlink.fleet.grpc_bidi.grpc_server import generic_create_grpc_server
53
53
  from flwr.server.superlink.state.utils import generate_rand_int_from_bytes
54
54
 
55
- from .clientapp.clientappio_servicer import ClientAppIoInputs, ClientAppIoServicer
55
+ from .clientapp.clientappio_servicer import ClientAppInputs, ClientAppIoServicer
56
56
  from .grpc_adapter_client.connection import grpc_adapter
57
57
  from .grpc_client.connection import grpc_connection
58
58
  from .grpc_rere_client.connection import grpc_request_response
@@ -62,6 +62,9 @@ from .numpy_client import NumPyClient
62
62
 
63
63
  ADDRESS_CLIENTAPPIO_API_GRPC_RERE = "0.0.0.0:9094"
64
64
 
65
+ ISOLATION_MODE_SUBPROCESS = "subprocess"
66
+ ISOLATION_MODE_PROCESS = "process"
67
+
65
68
 
66
69
  def _check_actionable_client(
67
70
  client: Optional[Client], client_fn: Optional[ClientFnExt]
@@ -207,7 +210,7 @@ def start_client_internal(
207
210
  max_retries: Optional[int] = None,
208
211
  max_wait_time: Optional[float] = None,
209
212
  flwr_path: Optional[Path] = None,
210
- isolate: Optional[bool] = False,
213
+ isolation: Optional[str] = None,
211
214
  supernode_address: Optional[str] = ADDRESS_CLIENTAPPIO_API_GRPC_RERE,
212
215
  ) -> None:
213
216
  """Start a Flower client node which connects to a Flower server.
@@ -256,11 +259,13 @@ def start_client_internal(
256
259
  If set to None, there is no limit to the total time.
257
260
  flwr_path: Optional[Path] (default: None)
258
261
  The fully resolved path containing installed Flower Apps.
259
- isolate : Optional[bool] (default: False)
260
- Whether to run `ClientApp` in a separate process. By default, this value is
261
- `False`, and the `ClientApp` runs in the same process as the SuperNode. If
262
- `True`, the `ClientApp` runs in an isolated process and communicates using
263
- gRPC at the address `supernode_address`.
262
+ isolation : Optional[str] (default: None)
263
+ Isolation mode for `ClientApp`. Possible values are `subprocess` and
264
+ `process`. Defaults to `None`, which runs the `ClientApp` in the same process
265
+ as the SuperNode. If `subprocess`, the `ClientApp` runs in a subprocess started
266
+ by the SueprNode and communicates using gRPC at the address
267
+ `supernode_address`. If `process`, the `ClientApp` runs in a separate isolated
268
+ process and communicates using gRPC at the address `supernode_address`.
264
269
  supernode_address : Optional[str] (default: `ADDRESS_CLIENTAPPIO_API_GRPC_RERE`)
265
270
  The SuperNode gRPC server address.
266
271
  """
@@ -288,12 +293,16 @@ def start_client_internal(
288
293
 
289
294
  load_client_app_fn = _load_client_app
290
295
 
291
- if isolate:
296
+ if isolation:
292
297
  if supernode_address is None:
293
- raise ValueError("`supernode_address` required when `isolate` is set")
298
+ raise ValueError(
299
+ f"`supernode_address` required when `isolation` is "
300
+ f"{ISOLATION_MODE_SUBPROCESS} or {ISOLATION_MODE_PROCESS}",
301
+ )
294
302
  _clientappio_grpc_server, clientappio_servicer = run_clientappio_api_grpc(
295
303
  address=supernode_address
296
304
  )
305
+ supernode_address = cast(str, supernode_address)
297
306
 
298
307
  # At this point, only `load_client_app_fn` should be used
299
308
  # Both `client` and `client_fn` must not be used directly
@@ -389,6 +398,7 @@ def start_client_internal(
389
398
  )
390
399
 
391
400
  app_state_tracker.register_signal_handler()
401
+ # pylint: disable=too-many-nested-blocks
392
402
  while not app_state_tracker.interrupt:
393
403
  try:
394
404
  # Receive
@@ -430,7 +440,9 @@ def start_client_internal(
430
440
  run: Run = runs[run_id]
431
441
  if get_fab is not None and run.fab_hash:
432
442
  fab = get_fab(run.fab_hash)
433
- install_from_fab(fab.content, flwr_path, True)
443
+ if not isolation:
444
+ # If `ClientApp` runs in the same process, install the FAB
445
+ install_from_fab(fab.content, flwr_path, True)
434
446
  fab_id, fab_version = get_fab_metadata(fab.content)
435
447
  else:
436
448
  fab = None
@@ -454,35 +466,52 @@ def start_client_internal(
454
466
 
455
467
  # Handle app loading and task message
456
468
  try:
457
- if isolate and supernode_address is not None:
469
+ if isolation:
470
+ # Two isolation modes:
471
+ # 1. `subprocess`: SuperNode is starting the ClientApp
472
+ # process as a subprocess.
473
+ # 2. `process`: ClientApp process gets started separately
474
+ # (via `flwr-clientapp`), for example, in a separate
475
+ # Docker container.
476
+
458
477
  # Generate SuperNode token
459
478
  token: int = generate_rand_int_from_bytes(RUN_ID_NUM_BYTES)
460
479
 
480
+ # Mode 1: SuperNode starts ClientApp as subprocess
481
+ start_subprocess = isolation == ISOLATION_MODE_SUBPROCESS
482
+
461
483
  # Share Message and Context with servicer
462
484
  clientappio_servicer.set_inputs(
463
- clientapp_input=ClientAppIoInputs(
485
+ clientapp_input=ClientAppInputs(
464
486
  message=message,
465
487
  context=context,
466
488
  run=run,
489
+ fab=fab,
467
490
  token=token,
468
491
  ),
469
- token_returned=True,
492
+ token_returned=start_subprocess,
470
493
  )
471
494
 
472
- # Run `ClientApp` in subprocess
473
- command = [
474
- "flwr-clientapp",
475
- "--supernode",
476
- supernode_address,
477
- "--token",
478
- str(token),
479
- ]
480
- subprocess.run(
481
- command,
482
- stdout=None,
483
- stderr=None,
484
- check=True,
485
- )
495
+ if start_subprocess:
496
+ # Start ClientApp subprocess
497
+ command = [
498
+ "flwr-clientapp",
499
+ "--supernode",
500
+ supernode_address,
501
+ "--token",
502
+ str(token),
503
+ ]
504
+ subprocess.run(
505
+ command,
506
+ stdout=None,
507
+ stderr=None,
508
+ check=True,
509
+ )
510
+ else:
511
+ # Wait for output to become available
512
+ while not clientappio_servicer.has_outputs():
513
+ time.sleep(0.1)
514
+
486
515
  outputs = clientappio_servicer.get_outputs()
487
516
  reply_message, context = outputs.message, outputs.context
488
517
  else:
@@ -538,6 +567,7 @@ def start_client_internal(
538
567
  except StopIteration:
539
568
  sleep_duration = 0
540
569
  break
570
+ # pylint: enable=too-many-nested-blocks
541
571
 
542
572
  # Unregister node
543
573
  if delete_node is not None and app_state_tracker.is_connected:
@@ -15,11 +15,13 @@
15
15
  """Flower ClientApp process."""
16
16
 
17
17
  import argparse
18
+ import time
18
19
  from logging import DEBUG, ERROR, INFO
19
20
  from typing import Optional, Tuple
20
21
 
21
22
  import grpc
22
23
 
24
+ from flwr.cli.install import install_from_fab
23
25
  from flwr.client.client_app import ClientApp, LoadClientAppError
24
26
  from flwr.common import Context, Message
25
27
  from flwr.common.constant import ErrorCode
@@ -29,11 +31,12 @@ from flwr.common.message import Error
29
31
  from flwr.common.serde import (
30
32
  context_from_proto,
31
33
  context_to_proto,
34
+ fab_from_proto,
32
35
  message_from_proto,
33
36
  message_to_proto,
34
37
  run_from_proto,
35
38
  )
36
- from flwr.common.typing import Run
39
+ from flwr.common.typing import Fab, Run
37
40
 
38
41
  # pylint: disable=E0611
39
42
  from flwr.proto.clientappio_pb2 import (
@@ -58,21 +61,25 @@ def flwr_clientapp() -> None:
58
61
  )
59
62
  parser.add_argument(
60
63
  "--supernode",
64
+ type=str,
61
65
  help="Address of SuperNode ClientAppIo gRPC servicer",
62
66
  )
63
67
  parser.add_argument(
64
68
  "--token",
69
+ type=int,
70
+ required=False,
65
71
  help="Unique token generated by SuperNode for each ClientApp execution",
66
72
  )
67
73
  args = parser.parse_args()
74
+
68
75
  log(
69
76
  DEBUG,
70
77
  "Staring isolated `ClientApp` connected to SuperNode ClientAppIo at %s "
71
- "with the token %s",
78
+ "with token %s",
72
79
  args.supernode,
73
80
  args.token,
74
81
  )
75
- run_clientapp(supernode=args.supernode, token=int(args.token))
82
+ run_clientapp(supernode=args.supernode, token=args.token)
76
83
 
77
84
 
78
85
  def on_channel_state_change(channel_connectivity: str) -> None:
@@ -82,7 +89,7 @@ def on_channel_state_change(channel_connectivity: str) -> None:
82
89
 
83
90
  def run_clientapp( # pylint: disable=R0914
84
91
  supernode: str,
85
- token: int,
92
+ token: Optional[int] = None,
86
93
  ) -> None:
87
94
  """Run Flower ClientApp process.
88
95
 
@@ -90,7 +97,7 @@ def run_clientapp( # pylint: disable=R0914
90
97
  ----------
91
98
  supernode : str
92
99
  Address of SuperNode
93
- token : int
100
+ token : Optional[int] (default: None)
94
101
  Unique SuperNode token for ClientApp-SuperNode authentication
95
102
  """
96
103
  channel = create_channel(
@@ -102,42 +109,67 @@ def run_clientapp( # pylint: disable=R0914
102
109
  try:
103
110
  stub = ClientAppIoStub(channel)
104
111
 
105
- # Pull Message, Context, and Run from SuperNode
106
- message, context, run = pull_message(stub=stub, token=token)
107
-
108
- load_client_app_fn = get_load_client_app_fn(
109
- default_app_ref="",
110
- app_path=None,
111
- multi_app=True,
112
- flwr_dir=None,
113
- )
114
-
115
- try:
116
- # Load ClientApp
117
- client_app: ClientApp = load_client_app_fn(run.fab_id, run.fab_version)
118
-
119
- # Execute ClientApp
120
- reply_message = client_app(message=message, context=context)
121
- except Exception as ex: # pylint: disable=broad-exception-caught
122
- # Don't update/change NodeState
123
-
124
- e_code = ErrorCode.CLIENT_APP_RAISED_EXCEPTION
125
- # Ex fmt: "<class 'ZeroDivisionError'>:<'division by zero'>"
126
- reason = str(type(ex)) + ":<'" + str(ex) + "'>"
127
- exc_entity = "ClientApp"
128
- if isinstance(ex, LoadClientAppError):
129
- reason = "An exception was raised when attempting to load `ClientApp`"
130
- e_code = ErrorCode.LOAD_CLIENT_APP_EXCEPTION
131
-
132
- log(ERROR, "%s raised an exception", exc_entity, exc_info=ex)
112
+ only_once = token is not None
113
+ while True:
114
+ # If token is not set, loop until token is received from SuperNode
115
+ while token is None:
116
+ token = get_token(stub)
117
+ time.sleep(1)
118
+
119
+ # Pull Message, Context, Run and (optional) FAB from SuperNode
120
+ message, context, run, fab = pull_message(stub=stub, token=token)
121
+
122
+ # Install FAB, if provided
123
+ if fab:
124
+ log(DEBUG, "Flower ClientApp starts FAB installation.")
125
+ install_from_fab(fab.content, flwr_dir=None, skip_prompt=True)
126
+
127
+ load_client_app_fn = get_load_client_app_fn(
128
+ default_app_ref="",
129
+ app_path=None,
130
+ multi_app=True,
131
+ flwr_dir=None,
132
+ )
133
133
 
134
- # Create error message
135
- reply_message = message.create_error_reply(
136
- error=Error(code=e_code, reason=reason)
134
+ try:
135
+ # Load ClientApp
136
+ client_app: ClientApp = load_client_app_fn(run.fab_id, run.fab_version)
137
+
138
+ # Execute ClientApp
139
+ reply_message = client_app(message=message, context=context)
140
+ except Exception as ex: # pylint: disable=broad-exception-caught
141
+ # Don't update/change NodeState
142
+
143
+ e_code = ErrorCode.CLIENT_APP_RAISED_EXCEPTION
144
+ # Ex fmt: "<class 'ZeroDivisionError'>:<'division by zero'>"
145
+ reason = str(type(ex)) + ":<'" + str(ex) + "'>"
146
+ exc_entity = "ClientApp"
147
+ if isinstance(ex, LoadClientAppError):
148
+ reason = (
149
+ "An exception was raised when attempting to load `ClientApp`"
150
+ )
151
+ e_code = ErrorCode.LOAD_CLIENT_APP_EXCEPTION
152
+
153
+ log(ERROR, "%s raised an exception", exc_entity, exc_info=ex)
154
+
155
+ # Create error message
156
+ reply_message = message.create_error_reply(
157
+ error=Error(code=e_code, reason=reason)
158
+ )
159
+
160
+ # Push Message and Context to SuperNode
161
+ _ = push_message(
162
+ stub=stub, token=token, message=reply_message, context=context
137
163
  )
138
164
 
139
- # Push Message and Context to SuperNode
140
- _ = push_message(stub=stub, token=token, message=reply_message, context=context)
165
+ # Reset token to `None` to prevent flwr-clientapp from trying to pull the
166
+ # same inputs again
167
+ token = None
168
+
169
+ # Stop the loop if `flwr-clientapp` is expected to process only a single
170
+ # message
171
+ if only_once:
172
+ break
141
173
 
142
174
  except KeyboardInterrupt:
143
175
  log(INFO, "Closing connection")
@@ -149,30 +181,53 @@ def run_clientapp( # pylint: disable=R0914
149
181
 
150
182
  def get_token(stub: grpc.Channel) -> Optional[int]:
151
183
  """Get a token from SuperNode."""
152
- res: GetTokenResponse = stub.GetToken(GetTokenRequest())
153
- return res.token
184
+ log(DEBUG, "Flower ClientApp process requests token")
185
+ try:
186
+ res: GetTokenResponse = stub.GetToken(GetTokenRequest())
187
+ log(DEBUG, "[GetToken] Received token: %s", res.token)
188
+ return res.token
189
+ except grpc.RpcError as e:
190
+ if e.code() == grpc.StatusCode.FAILED_PRECONDITION: # pylint: disable=no-member
191
+ log(DEBUG, "[GetToken] No token available yet")
192
+ else:
193
+ log(ERROR, "[GetToken] gRPC error occurred: %s", str(e))
194
+ return None
154
195
 
155
196
 
156
- def pull_message(stub: grpc.Channel, token: int) -> Tuple[Message, Context, Run]:
197
+ def pull_message(
198
+ stub: grpc.Channel, token: int
199
+ ) -> Tuple[Message, Context, Run, Optional[Fab]]:
157
200
  """Pull message from SuperNode to ClientApp."""
158
- res: PullClientAppInputsResponse = stub.PullClientAppInputs(
159
- PullClientAppInputsRequest(token=token)
160
- )
161
- message = message_from_proto(res.message)
162
- context = context_from_proto(res.context)
163
- run = run_from_proto(res.run)
164
- return message, context, run
201
+ log(INFO, "Pulling ClientAppInputs for token %s", token)
202
+ try:
203
+ res: PullClientAppInputsResponse = stub.PullClientAppInputs(
204
+ PullClientAppInputsRequest(token=token)
205
+ )
206
+ message = message_from_proto(res.message)
207
+ context = context_from_proto(res.context)
208
+ run = run_from_proto(res.run)
209
+ fab = fab_from_proto(res.fab) if res.fab else None
210
+ return message, context, run, fab
211
+ except grpc.RpcError as e:
212
+ log(ERROR, "[PullClientAppInputs] gRPC error occurred: %s", str(e))
213
+ raise e
165
214
 
166
215
 
167
216
  def push_message(
168
217
  stub: grpc.Channel, token: int, message: Message, context: Context
169
218
  ) -> PushClientAppOutputsResponse:
170
219
  """Push message to SuperNode from ClientApp."""
220
+ log(INFO, "Pushing ClientAppOutputs for token %s", token)
171
221
  proto_message = message_to_proto(message)
172
222
  proto_context = context_to_proto(context)
173
- res: PushClientAppOutputsResponse = stub.PushClientAppOutputs(
174
- PushClientAppOutputsRequest(
175
- token=token, message=proto_message, context=proto_context
223
+
224
+ try:
225
+ res: PushClientAppOutputsResponse = stub.PushClientAppOutputs(
226
+ PushClientAppOutputsRequest(
227
+ token=token, message=proto_message, context=proto_context
228
+ )
176
229
  )
177
- )
178
- return res
230
+ return res
231
+ except grpc.RpcError as e:
232
+ log(ERROR, "[PushClientAppOutputs] gRPC error occurred: %s", str(e))
233
+ raise e
@@ -27,11 +27,12 @@ from flwr.common.serde import (
27
27
  clientappstatus_to_proto,
28
28
  context_from_proto,
29
29
  context_to_proto,
30
+ fab_to_proto,
30
31
  message_from_proto,
31
32
  message_to_proto,
32
33
  run_to_proto,
33
34
  )
34
- from flwr.common.typing import Run
35
+ from flwr.common.typing import Fab, Run
35
36
 
36
37
  # pylint: disable=E0611
37
38
  from flwr.proto import clientappio_pb2_grpc
@@ -46,17 +47,18 @@ from flwr.proto.clientappio_pb2 import ( # pylint: disable=E0401
46
47
 
47
48
 
48
49
  @dataclass
49
- class ClientAppIoInputs:
50
+ class ClientAppInputs:
50
51
  """Specify the inputs to the ClientApp."""
51
52
 
52
53
  message: Message
53
54
  context: Context
54
55
  run: Run
56
+ fab: Optional[Fab]
55
57
  token: int
56
58
 
57
59
 
58
60
  @dataclass
59
- class ClientAppIoOutputs:
61
+ class ClientAppOutputs:
60
62
  """Specify the outputs from the ClientApp."""
61
63
 
62
64
  message: Message
@@ -68,8 +70,8 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
68
70
  """ClientAppIo API servicer."""
69
71
 
70
72
  def __init__(self) -> None:
71
- self.clientapp_input: Optional[ClientAppIoInputs] = None
72
- self.clientapp_output: Optional[ClientAppIoOutputs] = None
73
+ self.clientapp_input: Optional[ClientAppInputs] = None
74
+ self.clientapp_output: Optional[ClientAppOutputs] = None
73
75
  self.token_returned: bool = False
74
76
  self.inputs_returned: bool = False
75
77
 
@@ -79,13 +81,13 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
79
81
  """Get token."""
80
82
  log(DEBUG, "ClientAppIo.GetToken")
81
83
 
82
- # Fail if no ClientAppIoInputs are available
84
+ # Fail if no ClientAppInputs are available
83
85
  if self.clientapp_input is None:
84
86
  context.abort(
85
87
  grpc.StatusCode.FAILED_PRECONDITION,
86
88
  "No inputs available.",
87
89
  )
88
- clientapp_input = cast(ClientAppIoInputs, self.clientapp_input)
90
+ clientapp_input = cast(ClientAppInputs, self.clientapp_input)
89
91
 
90
92
  # Fail if token was already returned in a previous call
91
93
  if self.token_returned:
@@ -95,7 +97,7 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
95
97
  )
96
98
 
97
99
  # If
98
- # - ClientAppIoInputs is set, and
100
+ # - ClientAppInputs is set, and
99
101
  # - token hasn't been returned before,
100
102
  # return token
101
103
  self.token_returned = True
@@ -107,13 +109,13 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
107
109
  """Pull Message, Context, and Run."""
108
110
  log(DEBUG, "ClientAppIo.PullClientAppInputs")
109
111
 
110
- # Fail if no ClientAppIoInputs are available
112
+ # Fail if no ClientAppInputs are available
111
113
  if self.clientapp_input is None:
112
114
  context.abort(
113
115
  grpc.StatusCode.FAILED_PRECONDITION,
114
116
  "No inputs available.",
115
117
  )
116
- clientapp_input = cast(ClientAppIoInputs, self.clientapp_input)
118
+ clientapp_input = cast(ClientAppInputs, self.clientapp_input)
117
119
 
118
120
  # Fail if token wasn't returned in a previous call
119
121
  if not self.token_returned:
@@ -136,6 +138,7 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
136
138
  message=message_to_proto(clientapp_input.message),
137
139
  context=context_to_proto(clientapp_input.context),
138
140
  run=run_to_proto(clientapp_input.run),
141
+ fab=fab_to_proto(clientapp_input.fab) if clientapp_input.fab else None,
139
142
  )
140
143
 
141
144
  def PushClientAppOutputs(
@@ -144,13 +147,13 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
144
147
  """Push Message and Context."""
145
148
  log(DEBUG, "ClientAppIo.PushClientAppOutputs")
146
149
 
147
- # Fail if no ClientAppIoInputs are available
150
+ # Fail if no ClientAppInputs are available
148
151
  if not self.clientapp_input:
149
152
  context.abort(
150
153
  grpc.StatusCode.FAILED_PRECONDITION,
151
154
  "No inputs available.",
152
155
  )
153
- clientapp_input = cast(ClientAppIoInputs, self.clientapp_input)
156
+ clientapp_input = cast(ClientAppInputs, self.clientapp_input)
154
157
 
155
158
  # Fail if token wasn't returned in a previous call
156
159
  if not self.token_returned:
@@ -178,7 +181,7 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
178
181
  # Preconditions met
179
182
  try:
180
183
  # Update Message and Context
181
- self.clientapp_output = ClientAppIoOutputs(
184
+ self.clientapp_output = ClientAppOutputs(
182
185
  message=message_from_proto(request.message),
183
186
  context=context_from_proto(request.context),
184
187
  )
@@ -196,40 +199,43 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
196
199
  return PushClientAppOutputsResponse(status=proto_status)
197
200
 
198
201
  def set_inputs(
199
- self, clientapp_input: ClientAppIoInputs, token_returned: bool
202
+ self, clientapp_input: ClientAppInputs, token_returned: bool
200
203
  ) -> None:
201
204
  """Set ClientApp inputs.
202
205
 
203
206
  Parameters
204
207
  ----------
205
- clientapp_input : ClientAppIoInputs
208
+ clientapp_input : ClientAppInputs
206
209
  The inputs to the ClientApp.
207
210
  token_returned : bool
208
211
  A boolean indicating if the token has been returned.
209
212
  Set to `True` when passing the token to `flwr-clientap`
210
213
  and `False` otherwise.
211
214
  """
212
- log(DEBUG, "ClientAppIo.SetInputs")
213
215
  if (
214
216
  self.clientapp_input is not None
215
217
  or self.clientapp_output is not None
216
218
  or self.token_returned
217
219
  ):
218
220
  raise ValueError(
219
- "ClientAppIoInputs and ClientAppIoOutputs must not be set before "
221
+ "ClientAppInputs and ClientAppOutputs must not be set before "
220
222
  "calling `set_inputs`."
221
223
  )
224
+ log(DEBUG, "ClientAppInputs set (token: %s)", clientapp_input.token)
222
225
  self.clientapp_input = clientapp_input
223
226
  self.token_returned = token_returned
224
227
 
225
- def get_outputs(self) -> ClientAppIoOutputs:
228
+ def has_outputs(self) -> bool:
229
+ """Check if ClientAppOutputs are available."""
230
+ return self.clientapp_output is not None
231
+
232
+ def get_outputs(self) -> ClientAppOutputs:
226
233
  """Get ClientApp outputs."""
227
- log(DEBUG, "ClientAppIo.GetOutputs")
228
234
  if self.clientapp_output is None:
229
- raise ValueError("ClientAppIoOutputs not set before calling `get_outputs`.")
235
+ raise ValueError("ClientAppOutputs not set before calling `get_outputs`.")
230
236
 
231
237
  # Set outputs to a local variable and clear state
232
- output: ClientAppIoOutputs = self.clientapp_output
238
+ output: ClientAppOutputs = self.clientapp_output
233
239
  self.clientapp_input = None
234
240
  self.clientapp_output = None
235
241
  self.token_returned = False
@@ -37,7 +37,11 @@ from flwr.common.constant import (
37
37
  from flwr.common.exit_handlers import register_exit_handlers
38
38
  from flwr.common.logger import log, warn_deprecated_feature
39
39
 
40
- from ..app import start_client_internal
40
+ from ..app import (
41
+ ISOLATION_MODE_PROCESS,
42
+ ISOLATION_MODE_SUBPROCESS,
43
+ start_client_internal,
44
+ )
41
45
  from ..clientapp.utils import get_load_client_app_fn
42
46
 
43
47
  ADDRESS_FLEET_API_GRPC_RERE = "0.0.0.0:9092"
@@ -62,6 +66,8 @@ def run_supernode() -> None:
62
66
  )
63
67
  authentication_keys = _try_setup_client_authentication(args)
64
68
 
69
+ log(DEBUG, "Isolation mode: %s", args.isolation)
70
+
65
71
  start_client_internal(
66
72
  server_address=args.superlink,
67
73
  load_client_app_fn=load_fn,
@@ -72,7 +78,7 @@ def run_supernode() -> None:
72
78
  max_retries=args.max_retries,
73
79
  max_wait_time=args.max_wait_time,
74
80
  node_config=parse_config_args([args.node_config]),
75
- isolate=args.isolate,
81
+ isolation=args.isolation,
76
82
  supernode_address=args.supernode_address,
77
83
  )
78
84
 
@@ -199,10 +205,18 @@ def _parse_args_run_supernode() -> argparse.ArgumentParser:
199
205
  """,
200
206
  )
201
207
  parser.add_argument(
202
- "--isolate",
203
- action="store_true",
204
- help="Run `ClientApp` in an isolated subprocess. By default, `ClientApp` "
205
- "runs in the same process that executes the SuperNode.",
208
+ "--isolation",
209
+ default=None,
210
+ required=False,
211
+ choices=[
212
+ ISOLATION_MODE_SUBPROCESS,
213
+ ISOLATION_MODE_PROCESS,
214
+ ],
215
+ help="Isolation mode when running `ClientApp` (optional, possible values: "
216
+ "`subprocess`, `process`). By default, `ClientApp` runs in the same process "
217
+ "that executes the SuperNode. Use `subprocess` to configure SuperNode to run "
218
+ "`ClientApp` in a subprocess. Use `process` to indicate that a separate "
219
+ "independent process gets created outside of SuperNode.",
206
220
  )
207
221
  parser.add_argument(
208
222
  "--supernode-address",
@@ -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\"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(\x12\"+\n\x1aPullClientAppInputsRequest\x12\r\n\x05token\x18\x01 \x01(\x12\"\x87\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\"x\n\x1bPushClientAppOutputsRequest\x12\r\n\x05token\x18\x01 \x01(\x12\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\xad\x02\n\x0b\x43lientAppIo\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\"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(\x12\"+\n\x1aPullClientAppInputsRequest\x12\r\n\x05token\x18\x01 \x01(\x12\"\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(\x12\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\xad\x02\n\x0b\x43lientAppIo\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')
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=645
28
- _globals['_CLIENTAPPOUTPUTCODE']._serialized_end=721
27
+ _globals['_CLIENTAPPOUTPUTCODE']._serialized_start=675
28
+ _globals['_CLIENTAPPOUTPUTCODE']._serialized_end=751
29
29
  _globals['_CLIENTAPPOUTPUTSTATUS']._serialized_start=114
30
30
  _globals['_CLIENTAPPOUTPUTSTATUS']._serialized_end=201
31
31
  _globals['_GETTOKENREQUEST']._serialized_start=203
@@ -35,11 +35,11 @@ if _descriptor._USE_C_DESCRIPTORS == False:
35
35
  _globals['_PULLCLIENTAPPINPUTSREQUEST']._serialized_start=257
36
36
  _globals['_PULLCLIENTAPPINPUTSREQUEST']._serialized_end=300
37
37
  _globals['_PULLCLIENTAPPINPUTSRESPONSE']._serialized_start=303
38
- _globals['_PULLCLIENTAPPINPUTSRESPONSE']._serialized_end=438
39
- _globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_start=440
40
- _globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_end=560
41
- _globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_start=562
42
- _globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_end=643
43
- _globals['_CLIENTAPPIO']._serialized_start=724
44
- _globals['_CLIENTAPPIO']._serialized_end=1025
38
+ _globals['_PULLCLIENTAPPINPUTSRESPONSE']._serialized_end=468
39
+ _globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_start=470
40
+ _globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_end=590
41
+ _globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_start=592
42
+ _globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_end=673
43
+ _globals['_CLIENTAPPIO']._serialized_start=754
44
+ _globals['_CLIENTAPPIO']._serialized_end=1055
45
45
  # @@protoc_insertion_point(module_scope)
@@ -3,6 +3,7 @@
3
3
  isort:skip_file
4
4
  """
5
5
  import builtins
6
+ import flwr.proto.fab_pb2
6
7
  import flwr.proto.message_pb2
7
8
  import flwr.proto.run_pb2
8
9
  import google.protobuf.descriptor
@@ -77,20 +78,24 @@ class PullClientAppInputsResponse(google.protobuf.message.Message):
77
78
  MESSAGE_FIELD_NUMBER: builtins.int
78
79
  CONTEXT_FIELD_NUMBER: builtins.int
79
80
  RUN_FIELD_NUMBER: builtins.int
81
+ FAB_FIELD_NUMBER: builtins.int
80
82
  @property
81
83
  def message(self) -> flwr.proto.message_pb2.Message: ...
82
84
  @property
83
85
  def context(self) -> flwr.proto.message_pb2.Context: ...
84
86
  @property
85
87
  def run(self) -> flwr.proto.run_pb2.Run: ...
88
+ @property
89
+ def fab(self) -> flwr.proto.fab_pb2.Fab: ...
86
90
  def __init__(self,
87
91
  *,
88
92
  message: typing.Optional[flwr.proto.message_pb2.Message] = ...,
89
93
  context: typing.Optional[flwr.proto.message_pb2.Context] = ...,
90
94
  run: typing.Optional[flwr.proto.run_pb2.Run] = ...,
95
+ fab: typing.Optional[flwr.proto.fab_pb2.Fab] = ...,
91
96
  ) -> None: ...
92
- def HasField(self, field_name: typing_extensions.Literal["context",b"context","message",b"message","run",b"run"]) -> builtins.bool: ...
93
- def ClearField(self, field_name: typing_extensions.Literal["context",b"context","message",b"message","run",b"run"]) -> None: ...
97
+ def HasField(self, field_name: typing_extensions.Literal["context",b"context","fab",b"fab","message",b"message","run",b"run"]) -> builtins.bool: ...
98
+ def ClearField(self, field_name: typing_extensions.Literal["context",b"context","fab",b"fab","message",b"message","run",b"run"]) -> None: ...
94
99
  global___PullClientAppInputsResponse = PullClientAppInputsResponse
95
100
 
96
101
  class PushClientAppOutputsRequest(google.protobuf.message.Message):
@@ -52,10 +52,12 @@ class FleetServicer(fleet_pb2_grpc.FleetServicer):
52
52
  ) -> CreateNodeResponse:
53
53
  """."""
54
54
  log(INFO, "FleetServicer.CreateNode")
55
- return message_handler.create_node(
55
+ response = message_handler.create_node(
56
56
  request=request,
57
57
  state=self.state_factory.state(),
58
58
  )
59
+ log(INFO, "FleetServicer: Created node_id=%s", response.node.node_id)
60
+ return response
59
61
 
60
62
  def DeleteNode(
61
63
  self, request: DeleteNodeRequest, context: grpc.ServicerContext
@@ -16,7 +16,7 @@
16
16
 
17
17
 
18
18
  import base64
19
- from logging import WARNING
19
+ from logging import INFO, WARNING
20
20
  from typing import Any, Callable, Optional, Sequence, Tuple, Union
21
21
 
22
22
  import grpc
@@ -128,9 +128,15 @@ class AuthenticateServerInterceptor(grpc.ServerInterceptor): # type: ignore
128
128
  context.abort(grpc.StatusCode.UNAUTHENTICATED, "Access denied")
129
129
 
130
130
  if isinstance(request, CreateNodeRequest):
131
- return self._create_authenticated_node(
131
+ response = self._create_authenticated_node(
132
132
  client_public_key_bytes, request, context
133
133
  )
134
+ log(
135
+ INFO,
136
+ "AuthenticateServerInterceptor: Created node_id=%s",
137
+ response.node.node_id,
138
+ )
139
+ return response
134
140
 
135
141
  # Verify hmac value
136
142
  hmac_value = base64.urlsafe_b64decode(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.11.0.dev20240817
3
+ Version: 1.11.0.dev20240819
4
4
  Summary: Flower: A Friendly Federated Learning Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -212,7 +212,7 @@ Other [examples](https://github.com/adap/flower/tree/main/examples):
212
212
  Flower is built by a wonderful community of researchers and engineers. [Join Slack](https://flower.ai/join-slack) to meet them, [contributions](#contributing-to-flower) are welcome.
213
213
 
214
214
  <a href="https://github.com/adap/flower/graphs/contributors">
215
- <img src="https://contrib.rocks/image?repo=adap/flower" />
215
+ <img src="https://contrib.rocks/image?repo=adap/flower&columns=10" />
216
216
  </a>
217
217
 
218
218
  ## Citation
@@ -4,7 +4,7 @@ flwr/cli/app.py,sha256=FBcSrE35ll88VE11ib67qgsJe2GYDN25UswV9-cYcX8,1267
4
4
  flwr/cli/build.py,sha256=gIR-nTgmLJY5ZtJFLN5ebFBCN3_hoqaioFT77AHojNU,5159
5
5
  flwr/cli/config_utils.py,sha256=mDGXbcIxG14UpkUplILBYUkSk5M1LeTzZYDGNx-pFpU,7540
6
6
  flwr/cli/example.py,sha256=1bGDYll3BXQY2kRqSN-oICqS5n1b9m0g0RvXTopXHl4,2215
7
- flwr/cli/install.py,sha256=AI6Zv2dQVDHpLDX1Z_vX5XHVxmZo1OU3ndCSrD2stzQ,7059
7
+ flwr/cli/install.py,sha256=tUncrbZYRbC9QEcWSeTER16plPEoU-ERP0-nMgWiSPo,7094
8
8
  flwr/cli/new/__init__.py,sha256=cQzK1WH4JP2awef1t2UQ2xjl1agVEz9rwutV18SWV1k,789
9
9
  flwr/cli/new/new.py,sha256=VNb31-NLedm-_OK_D0aed0QxHO-tVlXjnf9UWVhC_Jk,9612
10
10
  flwr/cli/new/templates/__init__.py,sha256=4luU8RL-CK8JJCstQ_ON809W9bNTkY1l9zSaPKBkgwY,725
@@ -53,12 +53,12 @@ flwr/cli/run/__init__.py,sha256=oCd6HmQDx-sqver1gecgx-uMA38BLTSiiKpl7RGNceg,789
53
53
  flwr/cli/run/run.py,sha256=Ero4hxwZqx5ztFWvaJqslYCUBgp-AmImkomRosdGXyc,7661
54
54
  flwr/cli/utils.py,sha256=l65Ul0YsSBPuypk0uorAtEDmLEYiUrzpCXi6zCg9mJ4,4506
55
55
  flwr/client/__init__.py,sha256=wzJZsYJIHf_8-PMzvfbinyzzjgh1UP1vLrAw2_yEbKI,1345
56
- flwr/client/app.py,sha256=dtdgmm4xVFhkQvymf2vAjbawE9hIFkflzLBxWcYOJjA,30268
56
+ flwr/client/app.py,sha256=_nRrzltWI3_aAMaU3UbloPUkm08hgwr2LB7cGv4C-m4,31875
57
57
  flwr/client/client.py,sha256=Vp9UkOkoHdNfn6iMYZsj_5m_GICiFfUlKEVaLad-YhM,8183
58
58
  flwr/client/client_app.py,sha256=WcO4r6wrdfaus__3s22D2sYjfcptdgmVujUAYdNE6HU,10393
59
59
  flwr/client/clientapp/__init__.py,sha256=kZqChGnTChQ1WGSUkIlW2S5bc0d0mzDubCAmZUGRpEY,800
60
- flwr/client/clientapp/app.py,sha256=SVzkUAzaHWSH1Sbe2GzLMF-OnrbZ-iKg-QphuEHl8QE,5706
61
- flwr/client/clientapp/clientappio_servicer.py,sha256=lIH92rHuRQZUaEf9u8fNuiLIQIVYdAp4C1wPok62adQ,8302
60
+ flwr/client/clientapp/app.py,sha256=4QtblvJsZ0-V-QBbzyNqWV13ugrgJmkZnsHpBCuqgi8,7797
61
+ flwr/client/clientapp/clientappio_servicer.py,sha256=5L6bjw_j3Mnx9kRFwYwxDNABKurBO5q1jZOWE_X11wQ,8522
62
62
  flwr/client/clientapp/utils.py,sha256=2fYKY1LfZPalG5Cm5FbSuNMIDtouQg17GbrzPINyM_A,3990
63
63
  flwr/client/dpfedavg_numpy_client.py,sha256=ylZ-LpBIKmL1HCiS8kq4pkp2QGalc8rYEzDHdRG3VRQ,7435
64
64
  flwr/client/grpc_adapter_client/__init__.py,sha256=QyNWIbsq9DpyMk7oemiO1P3TBFfkfkctnJ1JoAkTl3s,742
@@ -87,7 +87,7 @@ flwr/client/numpy_client.py,sha256=u76GWAdHmJM88Agm2EgLQSvO8Jnk225mJTk-_TmPjFE,1
87
87
  flwr/client/rest_client/__init__.py,sha256=5KGlp7pjc1dhNRkKlaNtUfQmg8wrRFh9lS3P3uRS-7Q,735
88
88
  flwr/client/rest_client/connection.py,sha256=SglZC4jpqc_0-VBo9cBHa1_2RO9TfPUULQ49DnYeFS0,12767
89
89
  flwr/client/supernode/__init__.py,sha256=SUhWOzcgXRNXk1V9UgB5-FaWukqqrOEajVUHEcPkwyQ,865
90
- flwr/client/supernode/app.py,sha256=CrZG1AM19dgubuGOP0rWYnLwpCkt9F30v137BETSP30,12595
90
+ flwr/client/supernode/app.py,sha256=_hIbD2pyXQmtRw7D_qKOnkD-Zi5SiLcOLzIuEDlrlNA,13101
91
91
  flwr/client/typing.py,sha256=dxoTBnTMfqXr5J7G3y-uNjqxYCddvxhu89spfj4Lm2U,1048
92
92
  flwr/common/__init__.py,sha256=4cBLNNnNTwHDnL_HCxhU5ILCSZ6fYh3A_aMBtlvHTVw,3721
93
93
  flwr/common/address.py,sha256=wRu1Luezx1PWadwV9OA_KNko01oVvbRnPqfzaDn8QOk,1882
@@ -127,8 +127,8 @@ flwr/common/telemetry.py,sha256=nSjJHDitPhzB2qUl6LeSMT9Zld5lIk9uW98RpxQwiZw,8366
127
127
  flwr/common/typing.py,sha256=rGabiSkjFvGIHwmhDqtuu-LBvz7LVSj1vyMlNtA7VA0,5004
128
128
  flwr/common/version.py,sha256=W1ntylR04xkCP6zeSet6sRtBn7P1cje2lOqBJgYBjJY,1349
129
129
  flwr/proto/__init__.py,sha256=hbY7JYakwZwCkYgCNlmHdc8rtvfoJbAZLalMdc--CGc,683
130
- flwr/proto/clientappio_pb2.py,sha256=oGaTBdHuO4pL5oj2zIXG6kOdOdzZ8qaoP6I_oMOEnAY,3636
131
- flwr/proto/clientappio_pb2.pyi,sha256=7QUU3731Cin-fS-MYwfyU3GDndV_gMwnwOiU0jezHpY,5460
130
+ flwr/proto/clientappio_pb2.py,sha256=3qT-IbcGPFGh9WKpa9ZRKCYzUtwrDf-ziEY9uBhd_gU,3703
131
+ flwr/proto/clientappio_pb2.pyi,sha256=iL6pOPmnot5wP3aXGiDfiUpp-eJIkysyju0ebPehS8Y,5670
132
132
  flwr/proto/clientappio_pb2_grpc.py,sha256=G35GhZ3iEOL8N6tu7Kn_ip4QUx4O2HveXngHAuU2YEM,6112
133
133
  flwr/proto/clientappio_pb2_grpc.pyi,sha256=cybktpMPaIMwrItd8hQaQDnRv4zNu_wgRddSqR9REyI,1822
134
134
  flwr/proto/common_pb2.py,sha256=uzSmq0FJdC-MriN9UGPFs7QVIFTKJmX5lyLnzcyZ5WE,2405
@@ -245,8 +245,8 @@ flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py,sha256=hh7ykcLMA_ymmD72eWFM
245
245
  flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py,sha256=h3EhqgelegVC4EjOXH5birmAnMoCBJcP7jpHYCnHZPk,4887
246
246
  flwr/server/superlink/fleet/grpc_bidi/grpc_server.py,sha256=ROH-dr7TQZ9nVXjkKOzMhxidJguX2li8--nDnXRi-dU,12095
247
247
  flwr/server/superlink/fleet/grpc_rere/__init__.py,sha256=j2hyC342am-_Hgp1g80Y3fGDzfTI6n8QOOn2PyWf4eg,758
248
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=nqLILs_LV8T-x0BCLmgHy56ml7abjmHyRgc7xTnVbnw,3941
249
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=v54f7yEX0Xwqh9KRDPzKgJdSBsosus4RzUyzTl-_u5Q,7738
248
+ flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py,sha256=9vZPmdNuRcXsCJQUv9hrzQvdvUJO4-gvxxCHJJTFvGE,4047
249
+ flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=DsHj6XaE0pBSWLYFsUYE44NPqx6IWWTJ9sqbh3GpmvY,7961
250
250
  flwr/server/superlink/fleet/message_handler/__init__.py,sha256=h8oLD7uo5lKICPy0rRdKRjTYe62u8PKkT_fA4xF5JPA,731
251
251
  flwr/server/superlink/fleet/message_handler/message_handler.py,sha256=9qDDPwj3txHPo2dNaWQiO3UpGno5Zm9IMhJXnAPZbqg,4439
252
252
  flwr/server/superlink/fleet/rest_rere/__init__.py,sha256=5jbYbAn75sGv-gBwOPDySE0kz96F6dTYLeMrGqNi4lM,735
@@ -286,8 +286,8 @@ flwr/superexec/exec_grpc.py,sha256=PhqGoZEpTMxSQmUSV8Wgtzb1Za_pHJ-adZqo5RYnDyE,1
286
286
  flwr/superexec/exec_servicer.py,sha256=jl0aKVjm0PLQABcTL5c3jdSIzb0Z6hpVOtrAn4Ob7ts,2323
287
287
  flwr/superexec/executor.py,sha256=k_adivto6R2U82DADOHNvdtobehBYreRek1gOEBIQnQ,2318
288
288
  flwr/superexec/simulation.py,sha256=lfdClQYSAIMHe43aJ0Pk-kBw_xoV09LsIMfHo2eo-Ck,6775
289
- flwr_nightly-1.11.0.dev20240817.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
290
- flwr_nightly-1.11.0.dev20240817.dist-info/METADATA,sha256=AVTluXtc1QOLgptn-tnp6VC_4E4-pjGvwHOiVLNjVA4,15690
291
- flwr_nightly-1.11.0.dev20240817.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
292
- flwr_nightly-1.11.0.dev20240817.dist-info/entry_points.txt,sha256=3cDQVJEBRCSLzJrVYAgjXpoCjuQ74I3A9NZ61DOHdVo,388
293
- flwr_nightly-1.11.0.dev20240817.dist-info/RECORD,,
289
+ flwr_nightly-1.11.0.dev20240819.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
290
+ flwr_nightly-1.11.0.dev20240819.dist-info/METADATA,sha256=1TgmV-BxAz7GtNVJuJ9Ov1zrQl6dQwiZvsanz-EbQLM,15701
291
+ flwr_nightly-1.11.0.dev20240819.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
292
+ flwr_nightly-1.11.0.dev20240819.dist-info/entry_points.txt,sha256=3cDQVJEBRCSLzJrVYAgjXpoCjuQ74I3A9NZ61DOHdVo,388
293
+ flwr_nightly-1.11.0.dev20240819.dist-info/RECORD,,