flwr-nightly 1.10.0.dev20240711__py3-none-any.whl → 1.10.0.dev20240713__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/new/templates/app/code/client.hf.py.tpl +6 -2
- flwr/cli/new/templates/app/code/client.jax.py.tpl +2 -1
- flwr/cli/new/templates/app/code/client.mlx.py.tpl +5 -2
- flwr/cli/new/templates/app/code/client.numpy.py.tpl +2 -1
- flwr/cli/new/templates/app/code/client.pytorch.py.tpl +5 -2
- flwr/cli/new/templates/app/code/client.sklearn.py.tpl +4 -2
- flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +5 -2
- flwr/cli/new/templates/app/code/task.hf.py.tpl +2 -2
- flwr/cli/new/templates/app/code/task.mlx.py.tpl +2 -2
- flwr/cli/new/templates/app/code/task.pytorch.py.tpl +1 -1
- flwr/client/app.py +39 -16
- flwr/client/client_app.py +28 -8
- flwr/client/grpc_adapter_client/connection.py +1 -1
- flwr/client/grpc_client/connection.py +1 -1
- flwr/client/grpc_rere_client/connection.py +3 -2
- flwr/client/message_handler/message_handler.py +1 -1
- flwr/client/node_state.py +10 -5
- flwr/client/node_state_tests.py +1 -1
- flwr/client/rest_client/connection.py +4 -3
- flwr/client/supernode/app.py +13 -7
- flwr/client/typing.py +2 -2
- flwr/common/config.py +3 -3
- flwr/common/constant.py +3 -0
- flwr/common/context.py +13 -9
- flwr/server/compat/legacy_context.py +1 -1
- flwr/server/run_serverapp.py +3 -1
- flwr/server/superlink/fleet/vce/backend/raybackend.py +2 -1
- flwr/server/superlink/fleet/vce/vce_api.py +16 -3
- flwr/simulation/app.py +4 -3
- flwr/simulation/ray_transport/ray_client_proxy.py +22 -9
- flwr/superexec/app.py +3 -3
- {flwr_nightly-1.10.0.dev20240711.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/METADATA +1 -1
- {flwr_nightly-1.10.0.dev20240711.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/RECORD +36 -36
- {flwr_nightly-1.10.0.dev20240711.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/LICENSE +0 -0
- {flwr_nightly-1.10.0.dev20240711.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/WHEEL +0 -0
- {flwr_nightly-1.10.0.dev20240711.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/entry_points.txt +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""$project_name: A Flower / HuggingFace Transformers app."""
|
|
2
2
|
|
|
3
3
|
from flwr.client import ClientApp, NumPyClient
|
|
4
|
+
from flwr.common import Context
|
|
4
5
|
from transformers import AutoModelForSequenceClassification
|
|
5
6
|
|
|
6
7
|
from $import_name.task import (
|
|
@@ -38,12 +39,15 @@ class FlowerClient(NumPyClient):
|
|
|
38
39
|
return float(loss), len(self.testloader), {"accuracy": accuracy}
|
|
39
40
|
|
|
40
41
|
|
|
41
|
-
def client_fn(
|
|
42
|
+
def client_fn(context: Context):
|
|
42
43
|
# Load model and data
|
|
43
44
|
net = AutoModelForSequenceClassification.from_pretrained(
|
|
44
45
|
CHECKPOINT, num_labels=2
|
|
45
46
|
).to(DEVICE)
|
|
46
|
-
|
|
47
|
+
|
|
48
|
+
partition_id = int(context.node_config['partition-id'])
|
|
49
|
+
num_partitions = int(context.node_config['num-partitions])
|
|
50
|
+
trainloader, valloader = load_data(partition_id, num_partitions)
|
|
47
51
|
|
|
48
52
|
# Return Client instance
|
|
49
53
|
return FlowerClient(net, trainloader, valloader).to_client()
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import jax
|
|
4
4
|
from flwr.client import NumPyClient, ClientApp
|
|
5
|
+
from flwr.common import Context
|
|
5
6
|
|
|
6
7
|
from $import_name.task import (
|
|
7
8
|
evaluation,
|
|
@@ -44,7 +45,7 @@ class FlowerClient(NumPyClient):
|
|
|
44
45
|
)
|
|
45
46
|
return float(loss), num_examples, {"loss": float(loss)}
|
|
46
47
|
|
|
47
|
-
def client_fn(
|
|
48
|
+
def client_fn(context: Context):
|
|
48
49
|
# Return Client instance
|
|
49
50
|
return FlowerClient().to_client()
|
|
50
51
|
|
|
@@ -4,6 +4,7 @@ import mlx.core as mx
|
|
|
4
4
|
import mlx.nn as nn
|
|
5
5
|
import mlx.optimizers as optim
|
|
6
6
|
from flwr.client import NumPyClient, ClientApp
|
|
7
|
+
from flwr.common import Context
|
|
7
8
|
|
|
8
9
|
from $import_name.task import (
|
|
9
10
|
batch_iterate,
|
|
@@ -57,8 +58,10 @@ class FlowerClient(NumPyClient):
|
|
|
57
58
|
return loss.item(), len(self.test_images), {"accuracy": accuracy.item()}
|
|
58
59
|
|
|
59
60
|
|
|
60
|
-
def client_fn(
|
|
61
|
-
|
|
61
|
+
def client_fn(context: Context):
|
|
62
|
+
partition_id = int(context.node_config["partition-id"])
|
|
63
|
+
num_partitions = int(context.node_config["num-partitions"])
|
|
64
|
+
data = load_data(partition_id, num_partitions)
|
|
62
65
|
|
|
63
66
|
# Return Client instance
|
|
64
67
|
return FlowerClient(data).to_client()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""$project_name: A Flower / NumPy app."""
|
|
2
2
|
|
|
3
3
|
from flwr.client import NumPyClient, ClientApp
|
|
4
|
+
from flwr.common import Context
|
|
4
5
|
import numpy as np
|
|
5
6
|
|
|
6
7
|
|
|
@@ -15,7 +16,7 @@ class FlowerClient(NumPyClient):
|
|
|
15
16
|
return float(0.0), 1, {"accuracy": float(1.0)}
|
|
16
17
|
|
|
17
18
|
|
|
18
|
-
def client_fn(
|
|
19
|
+
def client_fn(context: Context):
|
|
19
20
|
return FlowerClient().to_client()
|
|
20
21
|
|
|
21
22
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""$project_name: A Flower / PyTorch app."""
|
|
2
2
|
|
|
3
3
|
from flwr.client import NumPyClient, ClientApp
|
|
4
|
+
from flwr.common import Context
|
|
4
5
|
|
|
5
6
|
from $import_name.task import (
|
|
6
7
|
Net,
|
|
@@ -31,10 +32,12 @@ class FlowerClient(NumPyClient):
|
|
|
31
32
|
return loss, len(self.valloader.dataset), {"accuracy": accuracy}
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
def client_fn(
|
|
35
|
+
def client_fn(context: Context):
|
|
35
36
|
# Load model and data
|
|
36
37
|
net = Net().to(DEVICE)
|
|
37
|
-
|
|
38
|
+
partition_id = int(context.node_config["partition-id"])
|
|
39
|
+
num_partitions = int(context.node_config["num-partitions"])
|
|
40
|
+
trainloader, valloader = load_data(partition_id, num_partitions)
|
|
38
41
|
|
|
39
42
|
# Return Client instance
|
|
40
43
|
return FlowerClient(net, trainloader, valloader).to_client()
|
|
@@ -4,6 +4,7 @@ import warnings
|
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
from flwr.client import NumPyClient, ClientApp
|
|
7
|
+
from flwr.common import Context
|
|
7
8
|
from flwr_datasets import FederatedDataset
|
|
8
9
|
from sklearn.linear_model import LogisticRegression
|
|
9
10
|
from sklearn.metrics import log_loss
|
|
@@ -68,8 +69,9 @@ class FlowerClient(NumPyClient):
|
|
|
68
69
|
|
|
69
70
|
fds = FederatedDataset(dataset="mnist", partitioners={"train": 2})
|
|
70
71
|
|
|
71
|
-
def client_fn(
|
|
72
|
-
|
|
72
|
+
def client_fn(context: Context):
|
|
73
|
+
partition_id = int(context.node_config["partition-id"])
|
|
74
|
+
dataset = fds.load_partition(partition_id, "train").with_format("numpy")
|
|
73
75
|
|
|
74
76
|
X, y = dataset["image"].reshape((len(dataset), -1)), dataset["label"]
|
|
75
77
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""$project_name: A Flower / TensorFlow app."""
|
|
2
2
|
|
|
3
3
|
from flwr.client import NumPyClient, ClientApp
|
|
4
|
+
from flwr.common import Context
|
|
4
5
|
|
|
5
6
|
from $import_name.task import load_data, load_model
|
|
6
7
|
|
|
@@ -28,10 +29,12 @@ class FlowerClient(NumPyClient):
|
|
|
28
29
|
return loss, len(self.x_test), {"accuracy": accuracy}
|
|
29
30
|
|
|
30
31
|
|
|
31
|
-
def client_fn(
|
|
32
|
+
def client_fn(context: Context):
|
|
32
33
|
# Load model and data
|
|
33
34
|
net = load_model()
|
|
34
|
-
|
|
35
|
+
|
|
36
|
+
partition_id = int(context.node_config["partition-id"])
|
|
37
|
+
x_train, y_train, x_test, y_test = load_data(partition_id, 2)
|
|
35
38
|
|
|
36
39
|
# Return Client instance
|
|
37
40
|
return FlowerClient(net, x_train, y_train, x_test, y_test).to_client()
|
|
@@ -16,9 +16,9 @@ DEVICE = torch.device("cpu")
|
|
|
16
16
|
CHECKPOINT = "distilbert-base-uncased" # transformer model checkpoint
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def load_data(partition_id,
|
|
19
|
+
def load_data(partition_id: int, num_partitions: int):
|
|
20
20
|
"""Load IMDB data (training and eval)"""
|
|
21
|
-
fds = FederatedDataset(dataset="imdb", partitioners={"train":
|
|
21
|
+
fds = FederatedDataset(dataset="imdb", partitioners={"train": num_partitions})
|
|
22
22
|
partition = fds.load_partition(partition_id)
|
|
23
23
|
# Divide data: 80% train, 20% test
|
|
24
24
|
partition_train_test = partition.train_test_split(test_size=0.2, seed=42)
|
|
@@ -43,8 +43,8 @@ def batch_iterate(batch_size, X, y):
|
|
|
43
43
|
yield X[ids], y[ids]
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def load_data(partition_id,
|
|
47
|
-
fds = FederatedDataset(dataset="mnist", partitioners={"train":
|
|
46
|
+
def load_data(partition_id: int, num_partitions: int):
|
|
47
|
+
fds = FederatedDataset(dataset="mnist", partitioners={"train": num_partitions})
|
|
48
48
|
partition = fds.load_partition(partition_id)
|
|
49
49
|
partition_splits = partition.train_test_split(test_size=0.2, seed=42)
|
|
50
50
|
|
|
@@ -34,7 +34,7 @@ class Net(nn.Module):
|
|
|
34
34
|
return self.fc3(x)
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def load_data(partition_id, num_partitions):
|
|
37
|
+
def load_data(partition_id: int, num_partitions: int):
|
|
38
38
|
"""Load partition CIFAR10 data."""
|
|
39
39
|
fds = FederatedDataset(dataset="cifar10", partitioners={"train": num_partitions})
|
|
40
40
|
partition = fds.load_partition(partition_id)
|
flwr/client/app.py
CHANGED
|
@@ -18,7 +18,7 @@ import signal
|
|
|
18
18
|
import sys
|
|
19
19
|
import time
|
|
20
20
|
from dataclasses import dataclass
|
|
21
|
-
from logging import
|
|
21
|
+
from logging import ERROR, INFO, WARN
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
from typing import Callable, ContextManager, Dict, Optional, Tuple, Type, Union
|
|
24
24
|
|
|
@@ -28,7 +28,7 @@ from grpc import RpcError
|
|
|
28
28
|
from flwr.client.client import Client
|
|
29
29
|
from flwr.client.client_app import ClientApp, LoadClientAppError
|
|
30
30
|
from flwr.client.typing import ClientFnExt
|
|
31
|
-
from flwr.common import GRPC_MAX_MESSAGE_LENGTH, EventType, Message, event
|
|
31
|
+
from flwr.common import GRPC_MAX_MESSAGE_LENGTH, Context, EventType, Message, event
|
|
32
32
|
from flwr.common.address import parse_address
|
|
33
33
|
from flwr.common.constant import (
|
|
34
34
|
MISSING_EXTRA_REST,
|
|
@@ -138,8 +138,8 @@ def start_client(
|
|
|
138
138
|
|
|
139
139
|
Starting an SSL-enabled gRPC client using system certificates:
|
|
140
140
|
|
|
141
|
-
>>> def client_fn(
|
|
142
|
-
>>> return FlowerClient()
|
|
141
|
+
>>> def client_fn(context: Context):
|
|
142
|
+
>>> return FlowerClient().to_client()
|
|
143
143
|
>>>
|
|
144
144
|
>>> start_client(
|
|
145
145
|
>>> server_address=localhost:8080,
|
|
@@ -160,6 +160,7 @@ def start_client(
|
|
|
160
160
|
event(EventType.START_CLIENT_ENTER)
|
|
161
161
|
_start_client_internal(
|
|
162
162
|
server_address=server_address,
|
|
163
|
+
node_config={},
|
|
163
164
|
load_client_app_fn=None,
|
|
164
165
|
client_fn=client_fn,
|
|
165
166
|
client=client,
|
|
@@ -181,6 +182,7 @@ def start_client(
|
|
|
181
182
|
def _start_client_internal(
|
|
182
183
|
*,
|
|
183
184
|
server_address: str,
|
|
185
|
+
node_config: Dict[str, str],
|
|
184
186
|
load_client_app_fn: Optional[Callable[[str, str], ClientApp]] = None,
|
|
185
187
|
client_fn: Optional[ClientFnExt] = None,
|
|
186
188
|
client: Optional[Client] = None,
|
|
@@ -193,7 +195,6 @@ def _start_client_internal(
|
|
|
193
195
|
] = None,
|
|
194
196
|
max_retries: Optional[int] = None,
|
|
195
197
|
max_wait_time: Optional[float] = None,
|
|
196
|
-
partition_id: Optional[int] = None,
|
|
197
198
|
flwr_dir: Optional[Path] = None,
|
|
198
199
|
) -> None:
|
|
199
200
|
"""Start a Flower client node which connects to a Flower server.
|
|
@@ -204,6 +205,8 @@ def _start_client_internal(
|
|
|
204
205
|
The IPv4 or IPv6 address of the server. If the Flower
|
|
205
206
|
server runs on the same machine on port 8080, then `server_address`
|
|
206
207
|
would be `"[::]:8080"`.
|
|
208
|
+
node_config: Dict[str, str]
|
|
209
|
+
The configuration of the node.
|
|
207
210
|
load_client_app_fn : Optional[Callable[[], ClientApp]] (default: None)
|
|
208
211
|
A function that can be used to load a `ClientApp` instance.
|
|
209
212
|
client_fn : Optional[ClientFnExt]
|
|
@@ -238,9 +241,6 @@ def _start_client_internal(
|
|
|
238
241
|
The maximum duration before the client stops trying to
|
|
239
242
|
connect to the server in case of connection error.
|
|
240
243
|
If set to None, there is no limit to the total time.
|
|
241
|
-
partition_id: Optional[int] (default: None)
|
|
242
|
-
The data partition index associated with this node. Better suited for
|
|
243
|
-
prototyping purposes.
|
|
244
244
|
flwr_dir: Optional[Path] (default: None)
|
|
245
245
|
The fully resolved path containing installed Flower Apps.
|
|
246
246
|
"""
|
|
@@ -253,8 +253,7 @@ def _start_client_internal(
|
|
|
253
253
|
if client_fn is None:
|
|
254
254
|
# Wrap `Client` instance in `client_fn`
|
|
255
255
|
def single_client_factory(
|
|
256
|
-
|
|
257
|
-
partition_id: Optional[int], # pylint: disable=unused-argument
|
|
256
|
+
context: Context, # pylint: disable=unused-argument
|
|
258
257
|
) -> Client:
|
|
259
258
|
if client is None: # Added this to keep mypy happy
|
|
260
259
|
raise ValueError(
|
|
@@ -295,7 +294,7 @@ def _start_client_internal(
|
|
|
295
294
|
log(WARN, "Connection attempt failed, retrying...")
|
|
296
295
|
else:
|
|
297
296
|
log(
|
|
298
|
-
|
|
297
|
+
WARN,
|
|
299
298
|
"Connection attempt failed, retrying in %.2f seconds",
|
|
300
299
|
retry_state.actual_wait,
|
|
301
300
|
)
|
|
@@ -319,7 +318,9 @@ def _start_client_internal(
|
|
|
319
318
|
on_backoff=_on_backoff,
|
|
320
319
|
)
|
|
321
320
|
|
|
322
|
-
|
|
321
|
+
# NodeState gets initialized when the first connection is established
|
|
322
|
+
node_state: Optional[NodeState] = None
|
|
323
|
+
|
|
323
324
|
runs: Dict[int, Run] = {}
|
|
324
325
|
|
|
325
326
|
while not app_state_tracker.interrupt:
|
|
@@ -334,9 +335,31 @@ def _start_client_internal(
|
|
|
334
335
|
) as conn:
|
|
335
336
|
receive, send, create_node, delete_node, get_run = conn
|
|
336
337
|
|
|
337
|
-
# Register node
|
|
338
|
-
if
|
|
339
|
-
create_node
|
|
338
|
+
# Register node when connecting the first time
|
|
339
|
+
if node_state is None:
|
|
340
|
+
if create_node is None:
|
|
341
|
+
if transport not in ["grpc-bidi", None]:
|
|
342
|
+
raise NotImplementedError(
|
|
343
|
+
"All transports except `grpc-bidi` require "
|
|
344
|
+
"an implementation for `create_node()`.'"
|
|
345
|
+
)
|
|
346
|
+
# gRPC-bidi doesn't have the concept of node_id,
|
|
347
|
+
# so we set it to -1
|
|
348
|
+
node_state = NodeState(
|
|
349
|
+
node_id=-1,
|
|
350
|
+
node_config={},
|
|
351
|
+
)
|
|
352
|
+
else:
|
|
353
|
+
# Call create_node fn to register node
|
|
354
|
+
node_id: Optional[int] = ( # pylint: disable=assignment-from-none
|
|
355
|
+
create_node()
|
|
356
|
+
) # pylint: disable=not-callable
|
|
357
|
+
if node_id is None:
|
|
358
|
+
raise ValueError("Node registration failed")
|
|
359
|
+
node_state = NodeState(
|
|
360
|
+
node_id=node_id,
|
|
361
|
+
node_config=node_config,
|
|
362
|
+
)
|
|
340
363
|
|
|
341
364
|
app_state_tracker.register_signal_handler()
|
|
342
365
|
while not app_state_tracker.interrupt:
|
|
@@ -580,7 +603,7 @@ def _init_connection(transport: Optional[str], server_address: str) -> Tuple[
|
|
|
580
603
|
Tuple[
|
|
581
604
|
Callable[[], Optional[Message]],
|
|
582
605
|
Callable[[Message], None],
|
|
583
|
-
Optional[Callable[[],
|
|
606
|
+
Optional[Callable[[], Optional[int]]],
|
|
584
607
|
Optional[Callable[[], None]],
|
|
585
608
|
Optional[Callable[[int], Run]],
|
|
586
609
|
]
|
flwr/client/client_app.py
CHANGED
|
@@ -30,21 +30,41 @@ from flwr.common.logger import warn_deprecated_feature, warn_preview_feature
|
|
|
30
30
|
from .typing import ClientAppCallable
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
def _alert_erroneous_client_fn() -> None:
|
|
34
|
+
raise ValueError(
|
|
35
|
+
"A `ClientApp` cannot make use of a `client_fn` that does "
|
|
36
|
+
"not have a signature in the form: `def client_fn(context: "
|
|
37
|
+
"Context)`. You can import the `Context` like this: "
|
|
38
|
+
"`from flwr.common import Context`"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
33
42
|
def _inspect_maybe_adapt_client_fn_signature(client_fn: ClientFnExt) -> ClientFnExt:
|
|
34
43
|
client_fn_args = inspect.signature(client_fn).parameters
|
|
44
|
+
first_arg = list(client_fn_args.keys())[0]
|
|
45
|
+
|
|
46
|
+
if len(client_fn_args) != 1:
|
|
47
|
+
_alert_erroneous_client_fn()
|
|
48
|
+
|
|
49
|
+
first_arg_type = client_fn_args[first_arg].annotation
|
|
35
50
|
|
|
36
|
-
if
|
|
51
|
+
if first_arg_type is str or first_arg == "cid":
|
|
52
|
+
# Warn previous signature for `client_fn` seems to be used
|
|
37
53
|
warn_deprecated_feature(
|
|
38
|
-
"`client_fn` now expects a signature `def client_fn(
|
|
39
|
-
"
|
|
40
|
-
f"{dict(client_fn_args.items())}"
|
|
54
|
+
"`client_fn` now expects a signature `def client_fn(context: Context)`."
|
|
55
|
+
"The provided `client_fn` has signature: "
|
|
56
|
+
f"{dict(client_fn_args.items())}. You can import the `Context` like this:"
|
|
57
|
+
" `from flwr.common import Context`"
|
|
41
58
|
)
|
|
42
59
|
|
|
43
60
|
# Wrap depcreated client_fn inside a function with the expected signature
|
|
44
61
|
def adaptor_fn(
|
|
45
|
-
|
|
46
|
-
) -> Client:
|
|
47
|
-
|
|
62
|
+
context: Context,
|
|
63
|
+
) -> Client: # pylint: disable=unused-argument
|
|
64
|
+
# if patition-id is defined, pass it. Else pass node_id that should
|
|
65
|
+
# always be defined during Context init.
|
|
66
|
+
cid = context.node_config.get("partition-id", context.node_id)
|
|
67
|
+
return client_fn(str(cid)) # type: ignore
|
|
48
68
|
|
|
49
69
|
return adaptor_fn
|
|
50
70
|
|
|
@@ -71,7 +91,7 @@ class ClientApp:
|
|
|
71
91
|
>>> class FlowerClient(NumPyClient):
|
|
72
92
|
>>> # ...
|
|
73
93
|
>>>
|
|
74
|
-
>>> def client_fn(
|
|
94
|
+
>>> def client_fn(context: Context):
|
|
75
95
|
>>> return FlowerClient().to_client()
|
|
76
96
|
>>>
|
|
77
97
|
>>> app = ClientApp(client_fn)
|
|
@@ -44,7 +44,7 @@ def grpc_adapter( # pylint: disable=R0913
|
|
|
44
44
|
Tuple[
|
|
45
45
|
Callable[[], Optional[Message]],
|
|
46
46
|
Callable[[Message], None],
|
|
47
|
-
Optional[Callable[[],
|
|
47
|
+
Optional[Callable[[], Optional[int]]],
|
|
48
48
|
Optional[Callable[[], None]],
|
|
49
49
|
Optional[Callable[[int], Run]],
|
|
50
50
|
]
|
|
@@ -72,7 +72,7 @@ def grpc_connection( # pylint: disable=R0913, R0915
|
|
|
72
72
|
Tuple[
|
|
73
73
|
Callable[[], Optional[Message]],
|
|
74
74
|
Callable[[Message], None],
|
|
75
|
-
Optional[Callable[[],
|
|
75
|
+
Optional[Callable[[], Optional[int]]],
|
|
76
76
|
Optional[Callable[[], None]],
|
|
77
77
|
Optional[Callable[[int], Run]],
|
|
78
78
|
]
|
|
@@ -79,7 +79,7 @@ def grpc_request_response( # pylint: disable=R0913, R0914, R0915
|
|
|
79
79
|
Tuple[
|
|
80
80
|
Callable[[], Optional[Message]],
|
|
81
81
|
Callable[[Message], None],
|
|
82
|
-
Optional[Callable[[],
|
|
82
|
+
Optional[Callable[[], Optional[int]]],
|
|
83
83
|
Optional[Callable[[], None]],
|
|
84
84
|
Optional[Callable[[int], Run]],
|
|
85
85
|
]
|
|
@@ -176,7 +176,7 @@ def grpc_request_response( # pylint: disable=R0913, R0914, R0915
|
|
|
176
176
|
if not ping_stop_event.is_set():
|
|
177
177
|
ping_stop_event.wait(next_interval)
|
|
178
178
|
|
|
179
|
-
def create_node() ->
|
|
179
|
+
def create_node() -> Optional[int]:
|
|
180
180
|
"""Set create_node."""
|
|
181
181
|
# Call FleetAPI
|
|
182
182
|
create_node_request = CreateNodeRequest(ping_interval=PING_DEFAULT_INTERVAL)
|
|
@@ -189,6 +189,7 @@ def grpc_request_response( # pylint: disable=R0913, R0914, R0915
|
|
|
189
189
|
nonlocal node, ping_thread
|
|
190
190
|
node = cast(Node, create_node_response.node)
|
|
191
191
|
ping_thread = start_ping_loop(ping, ping_stop_event)
|
|
192
|
+
return node.node_id
|
|
192
193
|
|
|
193
194
|
def delete_node() -> None:
|
|
194
195
|
"""Set delete_node."""
|
|
@@ -92,7 +92,7 @@ def handle_legacy_message_from_msgtype(
|
|
|
92
92
|
client_fn: ClientFnExt, message: Message, context: Context
|
|
93
93
|
) -> Message:
|
|
94
94
|
"""Handle legacy message in the inner most mod."""
|
|
95
|
-
client = client_fn(
|
|
95
|
+
client = client_fn(context)
|
|
96
96
|
|
|
97
97
|
# Check if NumPyClient is returend
|
|
98
98
|
if isinstance(client, NumPyClient):
|
flwr/client/node_state.py
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
from dataclasses import dataclass
|
|
19
19
|
from pathlib import Path
|
|
20
|
-
from typing import
|
|
20
|
+
from typing import Dict, Optional
|
|
21
21
|
|
|
22
22
|
from flwr.common import Context, RecordSet
|
|
23
23
|
from flwr.common.config import get_fused_config
|
|
@@ -35,10 +35,14 @@ class RunInfo:
|
|
|
35
35
|
class NodeState:
|
|
36
36
|
"""State of a node where client nodes execute runs."""
|
|
37
37
|
|
|
38
|
-
def __init__(
|
|
39
|
-
self
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
node_id: int,
|
|
41
|
+
node_config: Dict[str, str],
|
|
42
|
+
) -> None:
|
|
43
|
+
self.node_id = node_id
|
|
44
|
+
self.node_config = node_config
|
|
40
45
|
self.run_infos: Dict[int, RunInfo] = {}
|
|
41
|
-
self._partition_id = partition_id
|
|
42
46
|
|
|
43
47
|
def register_context(
|
|
44
48
|
self,
|
|
@@ -52,9 +56,10 @@ class NodeState:
|
|
|
52
56
|
self.run_infos[run_id] = RunInfo(
|
|
53
57
|
initial_run_config=initial_run_config,
|
|
54
58
|
context=Context(
|
|
59
|
+
node_id=self.node_id,
|
|
60
|
+
node_config=self.node_config,
|
|
55
61
|
state=RecordSet(),
|
|
56
62
|
run_config=initial_run_config.copy(),
|
|
57
|
-
partition_id=self._partition_id,
|
|
58
63
|
),
|
|
59
64
|
)
|
|
60
65
|
|
flwr/client/node_state_tests.py
CHANGED
|
@@ -41,7 +41,7 @@ def test_multirun_in_node_state() -> None:
|
|
|
41
41
|
expected_values = {0: "1", 1: "1" * 3, 2: "1" * 2, 3: "1", 5: "1"}
|
|
42
42
|
|
|
43
43
|
# NodeState
|
|
44
|
-
node_state = NodeState(
|
|
44
|
+
node_state = NodeState(node_id=0, node_config={})
|
|
45
45
|
|
|
46
46
|
for task in tasks:
|
|
47
47
|
run_id = task.run_id
|
|
@@ -90,7 +90,7 @@ def http_request_response( # pylint: disable=,R0913, R0914, R0915
|
|
|
90
90
|
Tuple[
|
|
91
91
|
Callable[[], Optional[Message]],
|
|
92
92
|
Callable[[Message], None],
|
|
93
|
-
Optional[Callable[[],
|
|
93
|
+
Optional[Callable[[], Optional[int]]],
|
|
94
94
|
Optional[Callable[[], None]],
|
|
95
95
|
Optional[Callable[[int], Run]],
|
|
96
96
|
]
|
|
@@ -237,19 +237,20 @@ def http_request_response( # pylint: disable=,R0913, R0914, R0915
|
|
|
237
237
|
if not ping_stop_event.is_set():
|
|
238
238
|
ping_stop_event.wait(next_interval)
|
|
239
239
|
|
|
240
|
-
def create_node() ->
|
|
240
|
+
def create_node() -> Optional[int]:
|
|
241
241
|
"""Set create_node."""
|
|
242
242
|
req = CreateNodeRequest(ping_interval=PING_DEFAULT_INTERVAL)
|
|
243
243
|
|
|
244
244
|
# Send the request
|
|
245
245
|
res = _request(req, CreateNodeResponse, PATH_CREATE_NODE)
|
|
246
246
|
if res is None:
|
|
247
|
-
return
|
|
247
|
+
return None
|
|
248
248
|
|
|
249
249
|
# Remember the node and the ping-loop thread
|
|
250
250
|
nonlocal node, ping_thread
|
|
251
251
|
node = res.node
|
|
252
252
|
ping_thread = start_ping_loop(ping, ping_stop_event)
|
|
253
|
+
return node.node_id
|
|
253
254
|
|
|
254
255
|
def delete_node() -> None:
|
|
255
256
|
"""Set delete_node."""
|
flwr/client/supernode/app.py
CHANGED
|
@@ -29,7 +29,12 @@ from cryptography.hazmat.primitives.serialization import (
|
|
|
29
29
|
|
|
30
30
|
from flwr.client.client_app import ClientApp, LoadClientAppError
|
|
31
31
|
from flwr.common import EventType, event
|
|
32
|
-
from flwr.common.config import
|
|
32
|
+
from flwr.common.config import (
|
|
33
|
+
get_flwr_dir,
|
|
34
|
+
get_project_config,
|
|
35
|
+
get_project_dir,
|
|
36
|
+
parse_config_args,
|
|
37
|
+
)
|
|
33
38
|
from flwr.common.constant import (
|
|
34
39
|
TRANSPORT_TYPE_GRPC_ADAPTER,
|
|
35
40
|
TRANSPORT_TYPE_GRPC_RERE,
|
|
@@ -67,7 +72,7 @@ def run_supernode() -> None:
|
|
|
67
72
|
authentication_keys=authentication_keys,
|
|
68
73
|
max_retries=args.max_retries,
|
|
69
74
|
max_wait_time=args.max_wait_time,
|
|
70
|
-
|
|
75
|
+
node_config=parse_config_args(args.node_config),
|
|
71
76
|
flwr_dir=get_flwr_dir(args.flwr_dir),
|
|
72
77
|
)
|
|
73
78
|
|
|
@@ -93,6 +98,7 @@ def run_client_app() -> None:
|
|
|
93
98
|
|
|
94
99
|
_start_client_internal(
|
|
95
100
|
server_address=args.superlink,
|
|
101
|
+
node_config=parse_config_args(args.node_config),
|
|
96
102
|
load_client_app_fn=load_fn,
|
|
97
103
|
transport=args.transport,
|
|
98
104
|
root_certificates=root_certificates,
|
|
@@ -389,11 +395,11 @@ def _parse_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
389
395
|
help="The SuperNode's public key (as a path str) to enable authentication.",
|
|
390
396
|
)
|
|
391
397
|
parser.add_argument(
|
|
392
|
-
"--
|
|
393
|
-
type=
|
|
394
|
-
help="
|
|
395
|
-
"
|
|
396
|
-
"
|
|
398
|
+
"--node-config",
|
|
399
|
+
type=str,
|
|
400
|
+
help="A comma separated list of key/value pairs (separated by `=`) to "
|
|
401
|
+
"configure the SuperNode. "
|
|
402
|
+
"E.g. --node-config 'key1=\"value1\",partition-id=0,num-partitions=100'",
|
|
397
403
|
)
|
|
398
404
|
|
|
399
405
|
|
flwr/client/typing.py
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"""Custom types for Flower clients."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
from typing import Callable
|
|
18
|
+
from typing import Callable
|
|
19
19
|
|
|
20
20
|
from flwr.common import Context, Message
|
|
21
21
|
|
|
@@ -23,7 +23,7 @@ from .client import Client as Client
|
|
|
23
23
|
|
|
24
24
|
# Compatibility
|
|
25
25
|
ClientFn = Callable[[str], Client]
|
|
26
|
-
ClientFnExt = Callable[[
|
|
26
|
+
ClientFnExt = Callable[[Context], Client]
|
|
27
27
|
|
|
28
28
|
ClientAppCallable = Callable[[Message, Context], Message]
|
|
29
29
|
Mod = Callable[[Message, Context, ClientAppCallable], Message]
|
flwr/common/config.py
CHANGED
|
@@ -121,16 +121,16 @@ def flatten_dict(raw_dict: Dict[str, Any], parent_key: str = "") -> Dict[str, st
|
|
|
121
121
|
|
|
122
122
|
|
|
123
123
|
def parse_config_args(
|
|
124
|
-
|
|
124
|
+
config: Optional[str],
|
|
125
125
|
separator: str = ",",
|
|
126
126
|
) -> Dict[str, str]:
|
|
127
127
|
"""Parse separator separated list of key-value pairs separated by '='."""
|
|
128
128
|
overrides: Dict[str, str] = {}
|
|
129
129
|
|
|
130
|
-
if
|
|
130
|
+
if config is None:
|
|
131
131
|
return overrides
|
|
132
132
|
|
|
133
|
-
overrides_list =
|
|
133
|
+
overrides_list = config.split(separator)
|
|
134
134
|
if (
|
|
135
135
|
len(overrides_list) == 1
|
|
136
136
|
and "=" not in overrides_list
|
flwr/common/constant.py
CHANGED
|
@@ -57,6 +57,9 @@ APP_DIR = "apps"
|
|
|
57
57
|
FAB_CONFIG_FILE = "pyproject.toml"
|
|
58
58
|
FLWR_HOME = "FLWR_HOME"
|
|
59
59
|
|
|
60
|
+
# Constants entries in Node config for Simulation
|
|
61
|
+
PARTITION_ID_KEY = "partition-id"
|
|
62
|
+
NUM_PARTITIONS_KEY = "num-partitions"
|
|
60
63
|
|
|
61
64
|
GRPC_ADAPTER_METADATA_FLOWER_VERSION_KEY = "flower-version"
|
|
62
65
|
GRPC_ADAPTER_METADATA_SHOULD_EXIT_KEY = "should-exit"
|
flwr/common/context.py
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
from dataclasses import dataclass
|
|
19
|
-
from typing import Dict
|
|
19
|
+
from typing import Dict
|
|
20
20
|
|
|
21
21
|
from .record import RecordSet
|
|
22
22
|
|
|
@@ -27,6 +27,11 @@ class Context:
|
|
|
27
27
|
|
|
28
28
|
Parameters
|
|
29
29
|
----------
|
|
30
|
+
node_id : int
|
|
31
|
+
The ID that identifies the node.
|
|
32
|
+
node_config : Dict[str, str]
|
|
33
|
+
A config (key/value mapping) unique to the node and independent of the
|
|
34
|
+
`run_config`. This config persists across all runs this node participates in.
|
|
30
35
|
state : RecordSet
|
|
31
36
|
Holds records added by the entity in a given run and that will stay local.
|
|
32
37
|
This means that the data it holds will never leave the system it's running from.
|
|
@@ -38,22 +43,21 @@ class Context:
|
|
|
38
43
|
A config (key/value mapping) held by the entity in a given run and that will
|
|
39
44
|
stay local. It can be used at any point during the lifecycle of this entity
|
|
40
45
|
(e.g. across multiple rounds)
|
|
41
|
-
partition_id : Optional[int] (default: None)
|
|
42
|
-
An index that specifies the data partition that the ClientApp using this Context
|
|
43
|
-
object should make use of. Setting this attribute is better suited for
|
|
44
|
-
simulation or proto typing setups.
|
|
45
46
|
"""
|
|
46
47
|
|
|
48
|
+
node_id: int
|
|
49
|
+
node_config: Dict[str, str]
|
|
47
50
|
state: RecordSet
|
|
48
|
-
partition_id: Optional[int]
|
|
49
51
|
run_config: Dict[str, str]
|
|
50
52
|
|
|
51
|
-
def __init__(
|
|
53
|
+
def __init__( # pylint: disable=too-many-arguments
|
|
52
54
|
self,
|
|
55
|
+
node_id: int,
|
|
56
|
+
node_config: Dict[str, str],
|
|
53
57
|
state: RecordSet,
|
|
54
58
|
run_config: Dict[str, str],
|
|
55
|
-
partition_id: Optional[int] = None,
|
|
56
59
|
) -> None:
|
|
60
|
+
self.node_id = node_id
|
|
61
|
+
self.node_config = node_config
|
|
57
62
|
self.state = state
|
|
58
63
|
self.run_config = run_config
|
|
59
|
-
self.partition_id = partition_id
|
flwr/server/run_serverapp.py
CHANGED
|
@@ -78,7 +78,9 @@ def run(
|
|
|
78
78
|
server_app = _load()
|
|
79
79
|
|
|
80
80
|
# Initialize Context
|
|
81
|
-
context = Context(
|
|
81
|
+
context = Context(
|
|
82
|
+
node_id=0, node_config={}, state=RecordSet(), run_config=server_app_run_config
|
|
83
|
+
)
|
|
82
84
|
|
|
83
85
|
# Call ServerApp
|
|
84
86
|
server_app(driver=driver, context=context)
|
|
@@ -21,6 +21,7 @@ from typing import Callable, Dict, List, Tuple, Union
|
|
|
21
21
|
import ray
|
|
22
22
|
|
|
23
23
|
from flwr.client.client_app import ClientApp
|
|
24
|
+
from flwr.common.constant import PARTITION_ID_KEY
|
|
24
25
|
from flwr.common.context import Context
|
|
25
26
|
from flwr.common.logger import log
|
|
26
27
|
from flwr.common.message import Message
|
|
@@ -168,7 +169,7 @@ class RayBackend(Backend):
|
|
|
168
169
|
|
|
169
170
|
Return output message and updated context.
|
|
170
171
|
"""
|
|
171
|
-
partition_id = context.
|
|
172
|
+
partition_id = context.node_config[PARTITION_ID_KEY]
|
|
172
173
|
|
|
173
174
|
try:
|
|
174
175
|
# Submit a task to the pool
|
|
@@ -29,7 +29,12 @@ from typing import Callable, Dict, Optional
|
|
|
29
29
|
|
|
30
30
|
from flwr.client.client_app import ClientApp, ClientAppException, LoadClientAppError
|
|
31
31
|
from flwr.client.node_state import NodeState
|
|
32
|
-
from flwr.common.constant import
|
|
32
|
+
from flwr.common.constant import (
|
|
33
|
+
NUM_PARTITIONS_KEY,
|
|
34
|
+
PARTITION_ID_KEY,
|
|
35
|
+
PING_MAX_INTERVAL,
|
|
36
|
+
ErrorCode,
|
|
37
|
+
)
|
|
33
38
|
from flwr.common.logger import log
|
|
34
39
|
from flwr.common.message import Error
|
|
35
40
|
from flwr.common.object_ref import load_app
|
|
@@ -73,7 +78,7 @@ def worker(
|
|
|
73
78
|
task_ins: TaskIns = taskins_queue.get(timeout=1.0)
|
|
74
79
|
node_id = task_ins.task.consumer.node_id
|
|
75
80
|
|
|
76
|
-
# Register and retrieve
|
|
81
|
+
# Register and retrieve context
|
|
77
82
|
node_states[node_id].register_context(run_id=task_ins.run_id)
|
|
78
83
|
context = node_states[node_id].retrieve_context(run_id=task_ins.run_id)
|
|
79
84
|
|
|
@@ -283,8 +288,16 @@ def start_vce(
|
|
|
283
288
|
|
|
284
289
|
# Construct mapping of NodeStates
|
|
285
290
|
node_states: Dict[int, NodeState] = {}
|
|
291
|
+
# Number of unique partitions
|
|
292
|
+
num_partitions = len(set(nodes_mapping.values()))
|
|
286
293
|
for node_id, partition_id in nodes_mapping.items():
|
|
287
|
-
node_states[node_id] = NodeState(
|
|
294
|
+
node_states[node_id] = NodeState(
|
|
295
|
+
node_id=node_id,
|
|
296
|
+
node_config={
|
|
297
|
+
PARTITION_ID_KEY: str(partition_id),
|
|
298
|
+
NUM_PARTITIONS_KEY: str(num_partitions),
|
|
299
|
+
},
|
|
300
|
+
)
|
|
288
301
|
|
|
289
302
|
# Load backend config
|
|
290
303
|
log(DEBUG, "Supported backends: %s", list(supported_backends.keys()))
|
flwr/simulation/app.py
CHANGED
|
@@ -111,9 +111,9 @@ def start_simulation(
|
|
|
111
111
|
Parameters
|
|
112
112
|
----------
|
|
113
113
|
client_fn : ClientFnExt
|
|
114
|
-
A function creating Client instances. The function must have the signature
|
|
115
|
-
`client_fn(
|
|
116
|
-
a single client instance of type Client
|
|
114
|
+
A function creating `Client` instances. The function must have the signature
|
|
115
|
+
`client_fn(context: Context). It should return
|
|
116
|
+
a single client instance of type `Client`. Note that the created client
|
|
117
117
|
instances are ephemeral and will often be destroyed after a single method
|
|
118
118
|
invocation. Since client instances are not long-lived, they should not attempt
|
|
119
119
|
to carry state over method invocations. Any state required by the instance
|
|
@@ -327,6 +327,7 @@ def start_simulation(
|
|
|
327
327
|
client_fn=client_fn,
|
|
328
328
|
node_id=node_id,
|
|
329
329
|
partition_id=partition_id,
|
|
330
|
+
num_partitions=num_clients,
|
|
330
331
|
actor_pool=pool,
|
|
331
332
|
)
|
|
332
333
|
initialized_server.client_manager().register(client=client_proxy)
|
|
@@ -24,7 +24,12 @@ from flwr.client import ClientFnExt
|
|
|
24
24
|
from flwr.client.client_app import ClientApp
|
|
25
25
|
from flwr.client.node_state import NodeState
|
|
26
26
|
from flwr.common import DEFAULT_TTL, Message, Metadata, RecordSet
|
|
27
|
-
from flwr.common.constant import
|
|
27
|
+
from flwr.common.constant import (
|
|
28
|
+
NUM_PARTITIONS_KEY,
|
|
29
|
+
PARTITION_ID_KEY,
|
|
30
|
+
MessageType,
|
|
31
|
+
MessageTypeLegacy,
|
|
32
|
+
)
|
|
28
33
|
from flwr.common.logger import log
|
|
29
34
|
from flwr.common.recordset_compat import (
|
|
30
35
|
evaluateins_to_recordset,
|
|
@@ -43,11 +48,12 @@ from flwr.simulation.ray_transport.ray_actor import VirtualClientEngineActorPool
|
|
|
43
48
|
class RayActorClientProxy(ClientProxy):
|
|
44
49
|
"""Flower client proxy which delegates work using Ray."""
|
|
45
50
|
|
|
46
|
-
def __init__(
|
|
51
|
+
def __init__( # pylint: disable=too-many-arguments
|
|
47
52
|
self,
|
|
48
53
|
client_fn: ClientFnExt,
|
|
49
54
|
node_id: int,
|
|
50
55
|
partition_id: int,
|
|
56
|
+
num_partitions: int,
|
|
51
57
|
actor_pool: VirtualClientEngineActorPool,
|
|
52
58
|
):
|
|
53
59
|
super().__init__(cid=str(node_id))
|
|
@@ -59,7 +65,13 @@ class RayActorClientProxy(ClientProxy):
|
|
|
59
65
|
|
|
60
66
|
self.app_fn = _load_app
|
|
61
67
|
self.actor_pool = actor_pool
|
|
62
|
-
self.proxy_state = NodeState(
|
|
68
|
+
self.proxy_state = NodeState(
|
|
69
|
+
node_id=node_id,
|
|
70
|
+
node_config={
|
|
71
|
+
PARTITION_ID_KEY: str(partition_id),
|
|
72
|
+
NUM_PARTITIONS_KEY: str(num_partitions),
|
|
73
|
+
},
|
|
74
|
+
)
|
|
63
75
|
|
|
64
76
|
def _submit_job(self, message: Message, timeout: Optional[float]) -> Message:
|
|
65
77
|
"""Sumbit a message to the ActorPool."""
|
|
@@ -68,18 +80,19 @@ class RayActorClientProxy(ClientProxy):
|
|
|
68
80
|
# Register state
|
|
69
81
|
self.proxy_state.register_context(run_id=run_id)
|
|
70
82
|
|
|
71
|
-
# Retrieve
|
|
72
|
-
|
|
83
|
+
# Retrieve context
|
|
84
|
+
context = self.proxy_state.retrieve_context(run_id=run_id)
|
|
85
|
+
partition_id_str = context.node_config[PARTITION_ID_KEY]
|
|
73
86
|
|
|
74
87
|
try:
|
|
75
88
|
self.actor_pool.submit_client_job(
|
|
76
|
-
lambda a, a_fn, mssg, partition_id,
|
|
77
|
-
a_fn, mssg, partition_id,
|
|
89
|
+
lambda a, a_fn, mssg, partition_id, context: a.run.remote(
|
|
90
|
+
a_fn, mssg, partition_id, context
|
|
78
91
|
),
|
|
79
|
-
(self.app_fn, message,
|
|
92
|
+
(self.app_fn, message, partition_id_str, context),
|
|
80
93
|
)
|
|
81
94
|
out_mssg, updated_context = self.actor_pool.get_client_result(
|
|
82
|
-
|
|
95
|
+
partition_id_str, timeout
|
|
83
96
|
)
|
|
84
97
|
|
|
85
98
|
# Update state
|
flwr/superexec/app.py
CHANGED
|
@@ -127,11 +127,11 @@ def _try_obtain_certificates(
|
|
|
127
127
|
return None
|
|
128
128
|
# Check if certificates are provided
|
|
129
129
|
if args.ssl_certfile and args.ssl_keyfile and args.ssl_ca_certfile:
|
|
130
|
-
if not Path
|
|
130
|
+
if not Path(args.ssl_ca_certfile).is_file():
|
|
131
131
|
sys.exit("Path argument `--ssl-ca-certfile` does not point to a file.")
|
|
132
|
-
if not Path
|
|
132
|
+
if not Path(args.ssl_certfile).is_file():
|
|
133
133
|
sys.exit("Path argument `--ssl-certfile` does not point to a file.")
|
|
134
|
-
if not Path
|
|
134
|
+
if not Path(args.ssl_keyfile).is_file():
|
|
135
135
|
sys.exit("Path argument `--ssl-keyfile` does not point to a file.")
|
|
136
136
|
certificates = (
|
|
137
137
|
Path(args.ssl_ca_certfile).read_bytes(), # CA certificate
|
{flwr_nightly-1.10.0.dev20240711.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/RECORD
RENAMED
|
@@ -14,13 +14,13 @@ flwr/cli/new/templates/app/README.md.tpl,sha256=_qGtgpKYKoCJVjQnvlBMKvFs_1gzTcL9
|
|
|
14
14
|
flwr/cli/new/templates/app/__init__.py,sha256=DU7QMY7IhMQyuwm_tja66xU0KXTWQFqzfTqwg-_NJdE,729
|
|
15
15
|
flwr/cli/new/templates/app/code/__init__.py,sha256=EM6vfvgAILKPaPn7H1wMV1Wi01WyZCP_Eg6NxD6oWg8,736
|
|
16
16
|
flwr/cli/new/templates/app/code/__init__.py.tpl,sha256=olwrBeJemHNBWvjc6gJURloFRqW40dAy7FRQA5pDqHU,21
|
|
17
|
-
flwr/cli/new/templates/app/code/client.hf.py.tpl,sha256=
|
|
18
|
-
flwr/cli/new/templates/app/code/client.jax.py.tpl,sha256=
|
|
19
|
-
flwr/cli/new/templates/app/code/client.mlx.py.tpl,sha256=
|
|
20
|
-
flwr/cli/new/templates/app/code/client.numpy.py.tpl,sha256=
|
|
21
|
-
flwr/cli/new/templates/app/code/client.pytorch.py.tpl,sha256=
|
|
22
|
-
flwr/cli/new/templates/app/code/client.sklearn.py.tpl,sha256=
|
|
23
|
-
flwr/cli/new/templates/app/code/client.tensorflow.py.tpl,sha256=
|
|
17
|
+
flwr/cli/new/templates/app/code/client.hf.py.tpl,sha256=cqq2M-l8yrsw6kZZLIjum2g-0uKg4Pyh3YGhgpQKQrw,1636
|
|
18
|
+
flwr/cli/new/templates/app/code/client.jax.py.tpl,sha256=i_SZykD42vqEvv2ZyX655szuikXJXLc6uV1T-LWiYLU,1479
|
|
19
|
+
flwr/cli/new/templates/app/code/client.mlx.py.tpl,sha256=Ntpbz9fcw-87FPBZmhns1NbJJXOQxnssJ_lStAqGuaQ,2299
|
|
20
|
+
flwr/cli/new/templates/app/code/client.numpy.py.tpl,sha256=ov9mtWJGjaQ9ZVlQ5jsuCjHDeETf13GFla5jbP3KimE,561
|
|
21
|
+
flwr/cli/new/templates/app/code/client.pytorch.py.tpl,sha256=bmmplNEVk3uHERFGlDP6FmBJQ7IBFw-OQ8otueAmOX0,1358
|
|
22
|
+
flwr/cli/new/templates/app/code/client.sklearn.py.tpl,sha256=C2PfCn0w8MpXmY4tuIIJ7fF2Mv-YW37YmMf0knIEARo,2905
|
|
23
|
+
flwr/cli/new/templates/app/code/client.tensorflow.py.tpl,sha256=D8h_RSWk2GGazW2-fLle1dIz9ABWuC_1aczxNbKHfOA,1390
|
|
24
24
|
flwr/cli/new/templates/app/code/flwr_tune/__init__.py,sha256=JgNgBtKdm1jKM9625WxappCAVUGtYAmcjKSsXJ1u3ZQ,748
|
|
25
25
|
flwr/cli/new/templates/app/code/flwr_tune/app.py.tpl,sha256=KXqCaD2NSEaLHT08fgQTzWlrtOdfxRYs0fsLw9yecCY,2647
|
|
26
26
|
flwr/cli/new/templates/app/code/flwr_tune/client.py.tpl,sha256=MvQ5tt1r7CBUR8y-nBcZs4as2m1YimxegLYw_nHmXzc,4048
|
|
@@ -36,10 +36,10 @@ flwr/cli/new/templates/app/code/server.numpy.py.tpl,sha256=fRxrDXV7pB1aDhQUXMBmr
|
|
|
36
36
|
flwr/cli/new/templates/app/code/server.pytorch.py.tpl,sha256=ltdsnFSvFGPcycVmRL4ITlr-TV0CmmXcperZe7Vamow,593
|
|
37
37
|
flwr/cli/new/templates/app/code/server.sklearn.py.tpl,sha256=cLzOpQzGIUzEazuFsjBpXAQUNPy6in6zR33SCqhix6o,341
|
|
38
38
|
flwr/cli/new/templates/app/code/server.tensorflow.py.tpl,sha256=gsNrWCKTU77_65_gw9nlp1LSQojgP5QQIWILvqdjx2s,579
|
|
39
|
-
flwr/cli/new/templates/app/code/task.hf.py.tpl,sha256=
|
|
39
|
+
flwr/cli/new/templates/app/code/task.hf.py.tpl,sha256=B5CrA7L5PSOWnluYoAAL7LCeKvP8t-Rhwt6t2ZTYP3g,2873
|
|
40
40
|
flwr/cli/new/templates/app/code/task.jax.py.tpl,sha256=u4o3V019EH79szOw2xzVeC5r9xgQiayPi9ZTIopV2TA,1519
|
|
41
|
-
flwr/cli/new/templates/app/code/task.mlx.py.tpl,sha256=
|
|
42
|
-
flwr/cli/new/templates/app/code/task.pytorch.py.tpl,sha256=
|
|
41
|
+
flwr/cli/new/templates/app/code/task.mlx.py.tpl,sha256=nrfZ1aGOs_ayb70j7XdAmwFYa-rN10d9GIMIKLzctUE,2614
|
|
42
|
+
flwr/cli/new/templates/app/code/task.pytorch.py.tpl,sha256=TU4uNtJ9wtxeVvoHD3_K89EFWmrIvdECdASzRX-4Uvk,3694
|
|
43
43
|
flwr/cli/new/templates/app/code/task.tensorflow.py.tpl,sha256=cPOUUS07QbblT9PGFucwu9lY1clRA4-W4DQGA7cpcao,1044
|
|
44
44
|
flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl,sha256=5kAtRcTvn2-s2i2_WGoDNJQ__ALADQjabX7lQlCNOGA,899
|
|
45
45
|
flwr/cli/new/templates/app/pyproject.hf.toml.tpl,sha256=O3-dgH8_knk9uM49IzX06CYC2Ev5xdPuITB40Phvewc,759
|
|
@@ -53,21 +53,21 @@ flwr/cli/run/__init__.py,sha256=oCd6HmQDx-sqver1gecgx-uMA38BLTSiiKpl7RGNceg,789
|
|
|
53
53
|
flwr/cli/run/run.py,sha256=eFYZwHOw9pHo_jxtS-UQIf7LVIOiNwjnJdaykcZQz5Q,4969
|
|
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=5v5EsA1zbViJAp998dCVRXvsyigZ-x3JEIKQ_fLeA48,26102
|
|
57
57
|
flwr/client/client.py,sha256=Vp9UkOkoHdNfn6iMYZsj_5m_GICiFfUlKEVaLad-YhM,8183
|
|
58
|
-
flwr/client/client_app.py,sha256=
|
|
58
|
+
flwr/client/client_app.py,sha256=WcO4r6wrdfaus__3s22D2sYjfcptdgmVujUAYdNE6HU,10393
|
|
59
59
|
flwr/client/dpfedavg_numpy_client.py,sha256=ylZ-LpBIKmL1HCiS8kq4pkp2QGalc8rYEzDHdRG3VRQ,7435
|
|
60
60
|
flwr/client/grpc_adapter_client/__init__.py,sha256=QyNWIbsq9DpyMk7oemiO1P3TBFfkfkctnJ1JoAkTl3s,742
|
|
61
|
-
flwr/client/grpc_adapter_client/connection.py,sha256=
|
|
61
|
+
flwr/client/grpc_adapter_client/connection.py,sha256=fM6QTIrcDGIXux7nzxOY3qNUfBGxVl1W7861iGSy5wA,3873
|
|
62
62
|
flwr/client/grpc_client/__init__.py,sha256=LsnbqXiJhgQcB0XzAlUQgPx011Uf7Y7yabIC1HxivJ8,735
|
|
63
|
-
flwr/client/grpc_client/connection.py,sha256=
|
|
63
|
+
flwr/client/grpc_client/connection.py,sha256=7J3YlvvBrky3f8UJ99U9IsPECGtcY8rvXsyr_Ol8qyY,9311
|
|
64
64
|
flwr/client/grpc_rere_client/__init__.py,sha256=MK-oSoV3kwUEQnIwl0GN4OpiHR7eLOrMA8ikunET130,752
|
|
65
65
|
flwr/client/grpc_rere_client/client_interceptor.py,sha256=sYPEznuQPdy2BPDlvM9FK0ZRRucb4NfwUee1Z_mN82E,4954
|
|
66
|
-
flwr/client/grpc_rere_client/connection.py,sha256=
|
|
66
|
+
flwr/client/grpc_rere_client/connection.py,sha256=nC4Usb1qok2liVxwlbQokUNwRRRD10_GIscbspqqz_c,10338
|
|
67
67
|
flwr/client/grpc_rere_client/grpc_adapter.py,sha256=woljH8yr1pyLH4W4Azogyy7Nafn6y9DHBnDCIIVKwCw,4711
|
|
68
68
|
flwr/client/heartbeat.py,sha256=cx37mJBH8LyoIN4Lks85wtqT1mnU5GulQnr4pGCvAq0,2404
|
|
69
69
|
flwr/client/message_handler/__init__.py,sha256=QxxQuBNpFPTHx3KiUNvQSlqMKlEnbRR1kFfc1KVje08,719
|
|
70
|
-
flwr/client/message_handler/message_handler.py,sha256=
|
|
70
|
+
flwr/client/message_handler/message_handler.py,sha256=q1fiWQob4TCaSHxvIklEtqsz-TwupXNYK-yKV9LubWY,6531
|
|
71
71
|
flwr/client/message_handler/task_handler.py,sha256=ZDJBKmrn2grRMNl1rU1iGs7FiMHL5VmZiSp_6h9GHVU,1824
|
|
72
72
|
flwr/client/mod/__init__.py,sha256=37XeXZLFq_tzFVKVtC9JaigM2bSAU7BrGQvMPCE3Q28,1159
|
|
73
73
|
flwr/client/mod/centraldp_mods.py,sha256=UGwNuqpmOWfLdfJITFgdi1TG-nLjuSb-cbEyoyfDgxQ,5415
|
|
@@ -77,19 +77,19 @@ flwr/client/mod/secure_aggregation/__init__.py,sha256=A7DzZ3uvXTUkuHBzrxJMWQQD4R
|
|
|
77
77
|
flwr/client/mod/secure_aggregation/secagg_mod.py,sha256=wI9tuIEvMUETz-wVIEbPYvh-1nK9CEylBLGoVpNhL94,1095
|
|
78
78
|
flwr/client/mod/secure_aggregation/secaggplus_mod.py,sha256=fZTfIELkYS64lpgxQKL66s-QHjCn-159qfLoNoIMJjc,19699
|
|
79
79
|
flwr/client/mod/utils.py,sha256=UAJXiB0wwVyLkCkpW_i5BXikdBR65p8sNFr7VNHm2nk,1226
|
|
80
|
-
flwr/client/node_state.py,sha256=
|
|
81
|
-
flwr/client/node_state_tests.py,sha256
|
|
80
|
+
flwr/client/node_state.py,sha256=_qgoNJXay25maUmcBwUcSVYpKTiW0RaoiWDSL4oFvJE,2864
|
|
81
|
+
flwr/client/node_state_tests.py,sha256=-4fVsn7y-z9NYBuhq-cjepgxgVuPqqQgDOL4SofrdIo,2239
|
|
82
82
|
flwr/client/numpy_client.py,sha256=u76GWAdHmJM88Agm2EgLQSvO8Jnk225mJTk-_TmPjFE,10283
|
|
83
83
|
flwr/client/rest_client/__init__.py,sha256=5KGlp7pjc1dhNRkKlaNtUfQmg8wrRFh9lS3P3uRS-7Q,735
|
|
84
|
-
flwr/client/rest_client/connection.py,sha256=
|
|
84
|
+
flwr/client/rest_client/connection.py,sha256=aY_UzrNyE8g-xPAK_POZZZ93mERHTe-pOhNP-uZ8GyU,12147
|
|
85
85
|
flwr/client/supernode/__init__.py,sha256=SUhWOzcgXRNXk1V9UgB5-FaWukqqrOEajVUHEcPkwyQ,865
|
|
86
|
-
flwr/client/supernode/app.py,sha256=
|
|
87
|
-
flwr/client/typing.py,sha256=
|
|
86
|
+
flwr/client/supernode/app.py,sha256=cg8momLzMnFrDBNJsSRDYrn8zHuJ-4UC3wIHf51aBXQ,15385
|
|
87
|
+
flwr/client/typing.py,sha256=dxoTBnTMfqXr5J7G3y-uNjqxYCddvxhu89spfj4Lm2U,1048
|
|
88
88
|
flwr/common/__init__.py,sha256=4cBLNNnNTwHDnL_HCxhU5ILCSZ6fYh3A_aMBtlvHTVw,3721
|
|
89
89
|
flwr/common/address.py,sha256=wRu1Luezx1PWadwV9OA_KNko01oVvbRnPqfzaDn8QOk,1882
|
|
90
|
-
flwr/common/config.py,sha256=
|
|
91
|
-
flwr/common/constant.py,sha256=
|
|
92
|
-
flwr/common/context.py,sha256=
|
|
90
|
+
flwr/common/config.py,sha256=7OF4R43st8teFXBWmV92noGEYVe00wT29QMs6od8mlI,4994
|
|
91
|
+
flwr/common/constant.py,sha256=1XxuRezsr9fl3xvQNPR2kyFkwNeG_f5vZayv0PFh0kY,3012
|
|
92
|
+
flwr/common/context.py,sha256=CQt4uzCDvCIr2WdkrWq0obAz92k2_ucXGrWtBZCxP_M,2256
|
|
93
93
|
flwr/common/date.py,sha256=OcQuwpb2HxcblTqYm6H223ufop5UZw5N_fzalbpOVzY,891
|
|
94
94
|
flwr/common/differential_privacy.py,sha256=WZWrL7C9XaB9l9NDkLDI5PvM7jwcoTTFu08ZVG8-M5Q,6113
|
|
95
95
|
flwr/common/differential_privacy_constants.py,sha256=c7b7tqgvT7yMK0XN9ndiTBs4mQf6d3qk6K7KBZGlV4Q,1074
|
|
@@ -180,14 +180,14 @@ flwr/server/compat/__init__.py,sha256=VxnJtJyOjNFQXMNi9hIuzNlZM5n0Hj1p3aq_Pm2udw
|
|
|
180
180
|
flwr/server/compat/app.py,sha256=u0elxfiLjGouCMQIy5KnCpeCHdc3s0qvojUm8unInIs,3421
|
|
181
181
|
flwr/server/compat/app_utils.py,sha256=B9pec7LnYACzowXKZTZNu3SNS-fSaHfefwvRyAQa4Nc,3456
|
|
182
182
|
flwr/server/compat/driver_client_proxy.py,sha256=BxTDo7i89VAG2tuF4x7zogSVn2bXPMr0H2H0lERzW9c,5444
|
|
183
|
-
flwr/server/compat/legacy_context.py,sha256
|
|
183
|
+
flwr/server/compat/legacy_context.py,sha256=-c2J_tPDFahDILl80XFrgkdRLfpHWDu5W3DQP3nKdls,1814
|
|
184
184
|
flwr/server/criterion.py,sha256=ypbAexbztzGUxNen9RCHF91QeqiEQix4t4Ih3E-42MM,1061
|
|
185
185
|
flwr/server/driver/__init__.py,sha256=bikRv6CjTwSvYh7tf10gziU5o2YotOWhhftz2tr3KDc,886
|
|
186
186
|
flwr/server/driver/driver.py,sha256=NT_yaeit7_kZEIsCEqOWPID1GrVD3ywH4xZ2wtIh5lM,5217
|
|
187
187
|
flwr/server/driver/grpc_driver.py,sha256=4Azmzq4RWzcLbOqBBEF-I78krWVWZ6bT0U42S25zMvY,9659
|
|
188
188
|
flwr/server/driver/inmemory_driver.py,sha256=RcK94_NtjGZ4aZDIscnU7A3Uv1u8jGx29-xcbjQvZTM,6444
|
|
189
189
|
flwr/server/history.py,sha256=bBOHKyX1eQONIsUx4EUU-UnAk1i0EbEl8ioyMq_UWQ8,5063
|
|
190
|
-
flwr/server/run_serverapp.py,sha256=
|
|
190
|
+
flwr/server/run_serverapp.py,sha256=iq62xuSPYndmsYiJRpRkT9cTfQpZ0FgsWLncktUvh98,9486
|
|
191
191
|
flwr/server/server.py,sha256=wsXsxMZ9SQ0B42nBnUlcV83NJPycgrgg5bFwcQ4BYBE,17821
|
|
192
192
|
flwr/server/server_app.py,sha256=1hul76ospG8L_KooK_ewn1sWPNTNYLTtZMeGNOBNruA,6267
|
|
193
193
|
flwr/server/server_config.py,sha256=CZaHVAsMvGLjpWVcLPkiYxgJN4xfIyAiUrCI3fETKY4,1349
|
|
@@ -238,8 +238,8 @@ flwr/server/superlink/fleet/rest_rere/rest_api.py,sha256=yoSU-6nCJF9ASHGNpSY69nZ
|
|
|
238
238
|
flwr/server/superlink/fleet/vce/__init__.py,sha256=36MHKiefnJeyjwMQzVUK4m06Ojon3WDcwZGQsAcyVhQ,783
|
|
239
239
|
flwr/server/superlink/fleet/vce/backend/__init__.py,sha256=oBIzmnrSSRvH_H0vRGEGWhWzQQwqe3zn6e13RsNwlIY,1466
|
|
240
240
|
flwr/server/superlink/fleet/vce/backend/backend.py,sha256=iG3KSIY7DzNfcxmuLfTs7VdQJnqPCvvn5DFkTWKG5lI,2227
|
|
241
|
-
flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=
|
|
242
|
-
flwr/server/superlink/fleet/vce/vce_api.py,sha256=
|
|
241
|
+
flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=SnjZ1WOcrfMZNgiDdTHcFeXJqrY7UHx8kvO62mqU9S4,7489
|
|
242
|
+
flwr/server/superlink/fleet/vce/vce_api.py,sha256=jSMmo3AXN_6XlYyzasu5yZ2jir8_Avj2zD9qtMzun6Q,12055
|
|
243
243
|
flwr/server/superlink/state/__init__.py,sha256=Gj2OTFLXvA-mAjBvwuKDM3rDrVaQPcIoybSa2uskMTE,1003
|
|
244
244
|
flwr/server/superlink/state/in_memory_state.py,sha256=fb-f4RGiqXON0DC7aSEMNuNIjH406BhBYrNNX5Kza2g,13061
|
|
245
245
|
flwr/server/superlink/state/sqlite_state.py,sha256=dO374mTkvhWQSiwbqwUXVnAYHev-j2mHaX9v8wFmmMA,29044
|
|
@@ -257,20 +257,20 @@ flwr/server/workflow/secure_aggregation/__init__.py,sha256=3XlgDOjD_hcukTGl6Bc1B
|
|
|
257
257
|
flwr/server/workflow/secure_aggregation/secagg_workflow.py,sha256=wpAkYPId0nfK6SgpUAtsCni4_MQLd-uqJ81tUKu3xlI,5838
|
|
258
258
|
flwr/server/workflow/secure_aggregation/secaggplus_workflow.py,sha256=BRqhlnVe8CYNoUvb_KCfRXay02NTT6a-pCrMaOqAxGc,29038
|
|
259
259
|
flwr/simulation/__init__.py,sha256=9x8OCkK3jpFAPJB1aeEMOddz6V58bExQPtwE8Z3q-RY,1359
|
|
260
|
-
flwr/simulation/app.py,sha256=
|
|
260
|
+
flwr/simulation/app.py,sha256=te3dQB3eodPwzsv1y4daPyaskIAaOtgoHaQLobrqoqY,15163
|
|
261
261
|
flwr/simulation/ray_transport/__init__.py,sha256=wzcEEwUUlulnXsg6raCA1nGpP3LlAQDtJ8zNkCXcVbA,734
|
|
262
262
|
flwr/simulation/ray_transport/ray_actor.py,sha256=3j0HgzjrlYjnzdTRy8aA4Nf6VoUvxi1hGRQkGSU5z6c,19020
|
|
263
|
-
flwr/simulation/ray_transport/ray_client_proxy.py,sha256=
|
|
263
|
+
flwr/simulation/ray_transport/ray_client_proxy.py,sha256=4KWWGSnfEBe3aGc0Ln5_1yRcZ52wKmOA7gXJKkMglvM,7302
|
|
264
264
|
flwr/simulation/ray_transport/utils.py,sha256=TYdtfg1P9VfTdLMOJlifInGpxWHYs9UfUqIv2wfkRLA,2392
|
|
265
265
|
flwr/simulation/run_simulation.py,sha256=qGP8sHKAzJT9nGeqMw36iCsVXm4ZFMBisCORuTswr-g,17277
|
|
266
266
|
flwr/superexec/__init__.py,sha256=9h94ogLxi6eJ3bUuJYq3E3pApThSabTPiSmPAGlTkHE,800
|
|
267
|
-
flwr/superexec/app.py,sha256=
|
|
267
|
+
flwr/superexec/app.py,sha256=1ZGSErFo3AQeIQOARKM1DN99fCuH451PeM1bDasBjRQ,6157
|
|
268
268
|
flwr/superexec/deployment.py,sha256=xv5iQWuaMeeL0XE5KMLWq3gRU4lvsGu1-_oPIXi5x9E,3955
|
|
269
269
|
flwr/superexec/exec_grpc.py,sha256=u-rztpOleqSGqgvNE-ZLw1HchNsBHU1-eB3m52GZ0pQ,1852
|
|
270
270
|
flwr/superexec/exec_servicer.py,sha256=4R1f_9v0vly_bXpIYaXAeV1tO5LAy1AYygGGGNZmlQk,2194
|
|
271
271
|
flwr/superexec/executor.py,sha256=TMQMMf-vv0htlv6v-eEBI67J1WL3Yz7dp_Fm1lgMEyU,1718
|
|
272
|
-
flwr_nightly-1.10.0.
|
|
273
|
-
flwr_nightly-1.10.0.
|
|
274
|
-
flwr_nightly-1.10.0.
|
|
275
|
-
flwr_nightly-1.10.0.
|
|
276
|
-
flwr_nightly-1.10.0.
|
|
272
|
+
flwr_nightly-1.10.0.dev20240713.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
273
|
+
flwr_nightly-1.10.0.dev20240713.dist-info/METADATA,sha256=jmUv-NLDPXbUdEGIEy5HZ94y-UfQzpFziq6s4bj7PEE,15632
|
|
274
|
+
flwr_nightly-1.10.0.dev20240713.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
|
275
|
+
flwr_nightly-1.10.0.dev20240713.dist-info/entry_points.txt,sha256=7qBQcA-bDGDxnJmLd9FYqglFQubjCNqyg9M8a-lukps,336
|
|
276
|
+
flwr_nightly-1.10.0.dev20240713.dist-info/RECORD,,
|
{flwr_nightly-1.10.0.dev20240711.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/LICENSE
RENAMED
|
File without changes
|
{flwr_nightly-1.10.0.dev20240711.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|