flwr-nightly 1.11.0.dev20240818__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
@@ -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,9 +293,12 @@ 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
  )
@@ -390,6 +398,7 @@ def start_client_internal(
390
398
  )
391
399
 
392
400
  app_state_tracker.register_signal_handler()
401
+ # pylint: disable=too-many-nested-blocks
393
402
  while not app_state_tracker.interrupt:
394
403
  try:
395
404
  # Receive
@@ -431,7 +440,9 @@ def start_client_internal(
431
440
  run: Run = runs[run_id]
432
441
  if get_fab is not None and run.fab_hash:
433
442
  fab = get_fab(run.fab_hash)
434
- 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)
435
446
  fab_id, fab_version = get_fab_metadata(fab.content)
436
447
  else:
437
448
  fab = None
@@ -455,39 +466,51 @@ def start_client_internal(
455
466
 
456
467
  # Handle app loading and task message
457
468
  try:
458
- if isolate:
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
+
459
477
  # Generate SuperNode token
460
478
  token: int = generate_rand_int_from_bytes(RUN_ID_NUM_BYTES)
461
479
 
480
+ # Mode 1: SuperNode starts ClientApp as subprocess
481
+ start_subprocess = isolation == ISOLATION_MODE_SUBPROCESS
482
+
462
483
  # Share Message and Context with servicer
463
484
  clientappio_servicer.set_inputs(
464
- clientapp_input=ClientAppIoInputs(
485
+ clientapp_input=ClientAppInputs(
465
486
  message=message,
466
487
  context=context,
467
488
  run=run,
489
+ fab=fab,
468
490
  token=token,
469
491
  ),
470
- token_returned=True,
471
- )
472
-
473
- # Run `ClientApp` in subprocess
474
- command = [
475
- "flwr-clientapp",
476
- "--supernode",
477
- supernode_address,
478
- "--token",
479
- str(token),
480
- ]
481
- subprocess.run(
482
- command,
483
- stdout=None,
484
- stderr=None,
485
- check=True,
492
+ token_returned=start_subprocess,
486
493
  )
487
494
 
488
- # Wait for output to become available
489
- while not clientappio_servicer.has_outputs():
490
- time.sleep(0.1)
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)
491
514
 
492
515
  outputs = clientappio_servicer.get_outputs()
493
516
  reply_message, context = outputs.message, outputs.context
@@ -544,6 +567,7 @@ def start_client_internal(
544
567
  except StopIteration:
545
568
  sleep_duration = 0
546
569
  break
570
+ # pylint: enable=too-many-nested-blocks
547
571
 
548
572
  # Unregister node
549
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 (
@@ -68,10 +71,11 @@ def flwr_clientapp() -> None:
68
71
  help="Unique token generated by SuperNode for each ClientApp execution",
69
72
  )
70
73
  args = parser.parse_args()
74
+
71
75
  log(
72
76
  DEBUG,
73
77
  "Staring isolated `ClientApp` connected to SuperNode ClientAppIo at %s "
74
- "with the token %s",
78
+ "with token %s",
75
79
  args.supernode,
76
80
  args.token,
77
81
  )
@@ -105,46 +109,67 @@ def run_clientapp( # pylint: disable=R0914
105
109
  try:
106
110
  stub = ClientAppIoStub(channel)
107
111
 
108
- # If token is not set, loop until token is received from SuperNode
109
- while token is None:
110
- token = get_token(stub)
111
-
112
- # Pull Message, Context, and Run from SuperNode
113
- message, context, run = pull_message(stub=stub, token=token)
114
-
115
- load_client_app_fn = get_load_client_app_fn(
116
- default_app_ref="",
117
- app_path=None,
118
- multi_app=True,
119
- flwr_dir=None,
120
- )
121
-
122
- try:
123
- # Load ClientApp
124
- client_app: ClientApp = load_client_app_fn(run.fab_id, run.fab_version)
125
-
126
- # Execute ClientApp
127
- reply_message = client_app(message=message, context=context)
128
- except Exception as ex: # pylint: disable=broad-exception-caught
129
- # Don't update/change NodeState
130
-
131
- e_code = ErrorCode.CLIENT_APP_RAISED_EXCEPTION
132
- # Ex fmt: "<class 'ZeroDivisionError'>:<'division by zero'>"
133
- reason = str(type(ex)) + ":<'" + str(ex) + "'>"
134
- exc_entity = "ClientApp"
135
- if isinstance(ex, LoadClientAppError):
136
- reason = "An exception was raised when attempting to load `ClientApp`"
137
- e_code = ErrorCode.LOAD_CLIENT_APP_EXCEPTION
138
-
139
- 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
+ )
140
133
 
141
- # Create error message
142
- reply_message = message.create_error_reply(
143
- 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
144
163
  )
145
164
 
146
- # Push Message and Context to SuperNode
147
- _ = 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
148
173
 
149
174
  except KeyboardInterrupt:
150
175
  log(INFO, "Closing connection")
@@ -157,30 +182,52 @@ def run_clientapp( # pylint: disable=R0914
157
182
  def get_token(stub: grpc.Channel) -> Optional[int]:
158
183
  """Get a token from SuperNode."""
159
184
  log(DEBUG, "Flower ClientApp process requests token")
160
- res: GetTokenResponse = stub.GetToken(GetTokenRequest())
161
- return res.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
162
195
 
163
196
 
164
- 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]]:
165
200
  """Pull message from SuperNode to ClientApp."""
166
- res: PullClientAppInputsResponse = stub.PullClientAppInputs(
167
- PullClientAppInputsRequest(token=token)
168
- )
169
- message = message_from_proto(res.message)
170
- context = context_from_proto(res.context)
171
- run = run_from_proto(res.run)
172
- 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
173
214
 
174
215
 
175
216
  def push_message(
176
217
  stub: grpc.Channel, token: int, message: Message, context: Context
177
218
  ) -> PushClientAppOutputsResponse:
178
219
  """Push message to SuperNode from ClientApp."""
220
+ log(INFO, "Pushing ClientAppOutputs for token %s", token)
179
221
  proto_message = message_to_proto(message)
180
222
  proto_context = context_to_proto(context)
181
- res: PushClientAppOutputsResponse = stub.PushClientAppOutputs(
182
- PushClientAppOutputsRequest(
183
- 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
+ )
184
229
  )
185
- )
186
- 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,13 +199,13 @@ 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.
@@ -215,9 +218,10 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
215
218
  or self.token_returned
216
219
  ):
217
220
  raise ValueError(
218
- "ClientAppIoInputs and ClientAppIoOutputs must not be set before "
221
+ "ClientAppInputs and ClientAppOutputs must not be set before "
219
222
  "calling `set_inputs`."
220
223
  )
224
+ log(DEBUG, "ClientAppInputs set (token: %s)", clientapp_input.token)
221
225
  self.clientapp_input = clientapp_input
222
226
  self.token_returned = token_returned
223
227
 
@@ -225,13 +229,13 @@ class ClientAppIoServicer(clientappio_pb2_grpc.ClientAppIoServicer):
225
229
  """Check if ClientAppOutputs are available."""
226
230
  return self.clientapp_output is not None
227
231
 
228
- def get_outputs(self) -> ClientAppIoOutputs:
232
+ def get_outputs(self) -> ClientAppOutputs:
229
233
  """Get ClientApp outputs."""
230
234
  if self.clientapp_output is None:
231
- raise ValueError("ClientAppIoOutputs not set before calling `get_outputs`.")
235
+ raise ValueError("ClientAppOutputs not set before calling `get_outputs`.")
232
236
 
233
237
  # Set outputs to a local variable and clear state
234
- output: ClientAppIoOutputs = self.clientapp_output
238
+ output: ClientAppOutputs = self.clientapp_output
235
239
  self.clientapp_input = None
236
240
  self.clientapp_output = None
237
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.dev20240818
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=tB-bl3pcUhn-bUgGxRVUaZiS-AlZjf-zfxWdZA-r50Q,30483
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=Ae5dNoLbLsaKKRUZHRnZ7povobk6DdA0C7e06gPiJLc,6003
61
- flwr/client/clientapp/clientappio_servicer.py,sha256=ysCgLY4oV2FmyltPQH2ZobbQ5e_TYd9BAuR1MdQrtXA,8353
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.dev20240818.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
290
- flwr_nightly-1.11.0.dev20240818.dist-info/METADATA,sha256=9h_o6Y1-M5y5_TUc0stYWb0E1GPhBo0uN_yCLAMqgNs,15690
291
- flwr_nightly-1.11.0.dev20240818.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
292
- flwr_nightly-1.11.0.dev20240818.dist-info/entry_points.txt,sha256=3cDQVJEBRCSLzJrVYAgjXpoCjuQ74I3A9NZ61DOHdVo,388
293
- flwr_nightly-1.11.0.dev20240818.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,,