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 +3 -1
- flwr/client/app.py +58 -28
- flwr/client/clientapp/app.py +108 -53
- flwr/client/clientapp/clientappio_servicer.py +27 -21
- flwr/client/supernode/app.py +20 -6
- flwr/proto/clientappio_pb2.py +10 -10
- flwr/proto/clientappio_pb2.pyi +7 -2
- flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +3 -1
- flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +8 -2
- {flwr_nightly-1.11.0.dev20240817.dist-info → flwr_nightly-1.11.0.dev20240819.dist-info}/METADATA +2 -2
- {flwr_nightly-1.11.0.dev20240817.dist-info → flwr_nightly-1.11.0.dev20240819.dist-info}/RECORD +14 -14
- {flwr_nightly-1.11.0.dev20240817.dist-info → flwr_nightly-1.11.0.dev20240819.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.11.0.dev20240817.dist-info → flwr_nightly-1.11.0.dev20240819.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.11.0.dev20240817.dist-info → flwr_nightly-1.11.0.dev20240819.dist-info}/entry_points.txt +0 -0
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()
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
260
|
-
|
|
261
|
-
`
|
|
262
|
-
`
|
|
263
|
-
gRPC at the 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
|
|
296
|
+
if isolation:
|
|
292
297
|
if supernode_address is None:
|
|
293
|
-
raise ValueError(
|
|
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
|
-
|
|
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
|
|
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=
|
|
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=
|
|
492
|
+
token_returned=start_subprocess,
|
|
470
493
|
)
|
|
471
494
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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:
|
flwr/client/clientapp/app.py
CHANGED
|
@@ -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
|
|
78
|
+
"with token %s",
|
|
72
79
|
args.supernode,
|
|
73
80
|
args.token,
|
|
74
81
|
)
|
|
75
|
-
run_clientapp(supernode=args.supernode, 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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
140
|
-
|
|
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
|
-
|
|
153
|
-
|
|
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(
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
res: PushClientAppOutputsResponse = stub.PushClientAppOutputs(
|
|
226
|
+
PushClientAppOutputsRequest(
|
|
227
|
+
token=token, message=proto_message, context=proto_context
|
|
228
|
+
)
|
|
176
229
|
)
|
|
177
|
-
|
|
178
|
-
|
|
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
|
|
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
|
|
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[
|
|
72
|
-
self.clientapp_output: Optional[
|
|
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
|
|
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(
|
|
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
|
-
# -
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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 =
|
|
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:
|
|
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 :
|
|
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
|
-
"
|
|
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
|
|
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("
|
|
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:
|
|
238
|
+
output: ClientAppOutputs = self.clientapp_output
|
|
233
239
|
self.clientapp_input = None
|
|
234
240
|
self.clientapp_output = None
|
|
235
241
|
self.token_returned = False
|
flwr/client/supernode/app.py
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
"--
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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",
|
flwr/proto/clientappio_pb2.py
CHANGED
|
@@ -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\"\
|
|
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=
|
|
28
|
-
_globals['_CLIENTAPPOUTPUTCODE']._serialized_end=
|
|
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=
|
|
39
|
-
_globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_start=
|
|
40
|
-
_globals['_PUSHCLIENTAPPOUTPUTSREQUEST']._serialized_end=
|
|
41
|
-
_globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_start=
|
|
42
|
-
_globals['_PUSHCLIENTAPPOUTPUTSRESPONSE']._serialized_end=
|
|
43
|
-
_globals['_CLIENTAPPIO']._serialized_start=
|
|
44
|
-
_globals['_CLIENTAPPIO']._serialized_end=
|
|
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)
|
flwr/proto/clientappio_pb2.pyi
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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(
|
{flwr_nightly-1.11.0.dev20240817.dist-info → flwr_nightly-1.11.0.dev20240819.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: flwr-nightly
|
|
3
|
-
Version: 1.11.0.
|
|
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
|
{flwr_nightly-1.11.0.dev20240817.dist-info → flwr_nightly-1.11.0.dev20240819.dist-info}/RECORD
RENAMED
|
@@ -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=
|
|
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=
|
|
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=
|
|
61
|
-
flwr/client/clientapp/clientappio_servicer.py,sha256=
|
|
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=
|
|
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=
|
|
131
|
-
flwr/proto/clientappio_pb2.pyi,sha256=
|
|
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=
|
|
249
|
-
flwr/server/superlink/fleet/grpc_rere/server_interceptor.py,sha256=
|
|
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.
|
|
290
|
-
flwr_nightly-1.11.0.
|
|
291
|
-
flwr_nightly-1.11.0.
|
|
292
|
-
flwr_nightly-1.11.0.
|
|
293
|
-
flwr_nightly-1.11.0.
|
|
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,,
|
{flwr_nightly-1.11.0.dev20240817.dist-info → flwr_nightly-1.11.0.dev20240819.dist-info}/LICENSE
RENAMED
|
File without changes
|
{flwr_nightly-1.11.0.dev20240817.dist-info → flwr_nightly-1.11.0.dev20240819.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|