flwr-nightly 1.10.0.dev20240712__py3-none-any.whl → 1.10.0.dev20240714__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.

Files changed (39) hide show
  1. flwr/cli/new/templates/app/code/client.hf.py.tpl +6 -2
  2. flwr/cli/new/templates/app/code/client.jax.py.tpl +2 -1
  3. flwr/cli/new/templates/app/code/client.mlx.py.tpl +5 -2
  4. flwr/cli/new/templates/app/code/client.numpy.py.tpl +2 -1
  5. flwr/cli/new/templates/app/code/client.pytorch.py.tpl +5 -2
  6. flwr/cli/new/templates/app/code/client.sklearn.py.tpl +4 -2
  7. flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +5 -2
  8. flwr/cli/new/templates/app/code/server.hf.py.tpl +13 -11
  9. flwr/cli/new/templates/app/code/server.jax.py.tpl +12 -8
  10. flwr/cli/new/templates/app/code/server.mlx.py.tpl +8 -7
  11. flwr/cli/new/templates/app/code/server.numpy.py.tpl +12 -8
  12. flwr/cli/new/templates/app/code/server.pytorch.py.tpl +13 -14
  13. flwr/cli/new/templates/app/code/server.sklearn.py.tpl +13 -10
  14. flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +13 -13
  15. flwr/cli/new/templates/app/code/task.hf.py.tpl +2 -2
  16. flwr/cli/new/templates/app/code/task.mlx.py.tpl +2 -2
  17. flwr/cli/new/templates/app/code/task.pytorch.py.tpl +1 -1
  18. flwr/cli/run/run.py +1 -1
  19. flwr/client/app.py +4 -7
  20. flwr/client/client_app.py +28 -8
  21. flwr/client/message_handler/message_handler.py +1 -1
  22. flwr/client/node_state.py +3 -3
  23. flwr/client/node_state_tests.py +1 -1
  24. flwr/client/typing.py +2 -2
  25. flwr/common/constant.py +3 -0
  26. flwr/common/context.py +1 -8
  27. flwr/server/superlink/fleet/vce/backend/raybackend.py +2 -1
  28. flwr/server/superlink/fleet/vce/vce_api.py +14 -3
  29. flwr/simulation/app.py +4 -3
  30. flwr/simulation/ray_transport/ray_client_proxy.py +20 -9
  31. flwr/superexec/app.py +11 -5
  32. flwr/superexec/deployment.py +85 -21
  33. flwr/superexec/exec_grpc.py +5 -2
  34. flwr/superexec/executor.py +18 -1
  35. {flwr_nightly-1.10.0.dev20240712.dist-info → flwr_nightly-1.10.0.dev20240714.dist-info}/METADATA +1 -1
  36. {flwr_nightly-1.10.0.dev20240712.dist-info → flwr_nightly-1.10.0.dev20240714.dist-info}/RECORD +39 -39
  37. {flwr_nightly-1.10.0.dev20240712.dist-info → flwr_nightly-1.10.0.dev20240714.dist-info}/LICENSE +0 -0
  38. {flwr_nightly-1.10.0.dev20240712.dist-info → flwr_nightly-1.10.0.dev20240714.dist-info}/WHEEL +0 -0
  39. {flwr_nightly-1.10.0.dev20240712.dist-info → flwr_nightly-1.10.0.dev20240714.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(cid):
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
- trainloader, valloader = load_data(int(cid), 2)
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(cid):
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(cid):
61
- data = load_data(int(cid), 2)
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(cid: str):
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(cid):
35
+ def client_fn(context: Context):
35
36
  # Load model and data
36
37
  net = Net().to(DEVICE)
37
- trainloader, valloader = load_data(int(cid), 2)
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(cid: str):
72
- dataset = fds.load_partition(int(cid), "train").with_format("numpy")
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(cid):
32
+ def client_fn(context: Context):
32
33
  # Load model and data
33
34
  net = load_model()
34
- x_train, y_train, x_test, y_test = load_data(int(cid), 2)
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()
@@ -1,17 +1,19 @@
1
1
  """$project_name: A Flower / HuggingFace Transformers app."""
2
2
 
3
+ from flwr.common import Context
3
4
  from flwr.server.strategy import FedAvg
4
- from flwr.server import ServerApp, ServerConfig
5
+ from flwr.server import ServerApp, ServerAppComponents, ServerConfig
5
6
 
6
7
 
7
- # Define strategy
8
- strategy = FedAvg(
9
- fraction_fit=1.0,
10
- fraction_evaluate=1.0,
11
- )
8
+ def server_fn(context: Context):
9
+ # Define strategy
10
+ strategy = FedAvg(
11
+ fraction_fit=1.0,
12
+ fraction_evaluate=1.0,
13
+ )
14
+ config = ServerConfig(num_rounds=3)
12
15
 
13
- # Start server
14
- app = ServerApp(
15
- config=ServerConfig(num_rounds=3),
16
- strategy=strategy,
17
- )
16
+ return ServerAppComponents(strategy=strategy, config=config)
17
+
18
+ # Create ServerApp
19
+ app = ServerApp(server_fn=server_fn)
@@ -1,12 +1,16 @@
1
1
  """$project_name: A Flower / JAX app."""
2
2
 
3
- import flwr as fl
3
+ from flwr.common import Context
4
+ from flwr.server.strategy import FedAvg
5
+ from flwr.server import ServerApp, ServerAppComponents, ServerConfig
4
6
 
5
- # Configure the strategy
6
- strategy = fl.server.strategy.FedAvg()
7
7
 
8
- # Flower ServerApp
9
- app = fl.server.ServerApp(
10
- config=fl.server.ServerConfig(num_rounds=3),
11
- strategy=strategy,
12
- )
8
+ def server_fn(context: Context):
9
+ # Define strategy
10
+ strategy = FedAvg()
11
+ config = ServerConfig(num_rounds=3)
12
+
13
+ return ServerAppComponents(strategy=strategy, config=config)
14
+
15
+ # Create ServerApp
16
+ app = ServerApp(server_fn=server_fn)
@@ -1,15 +1,16 @@
1
1
  """$project_name: A Flower / MLX app."""
2
2
 
3
- from flwr.server import ServerApp, ServerConfig
3
+ from flwr.common import Context
4
+ from flwr.server import ServerApp, ServerAppComponents, ServerConfig
4
5
  from flwr.server.strategy import FedAvg
5
6
 
6
7
 
7
- # Define strategy
8
- strategy = FedAvg()
8
+ def server_fn(context: Context):
9
+ # Define strategy
10
+ strategy = FedAvg()
11
+ config = ServerConfig(num_rounds=3)
9
12
 
13
+ return ServerAppComponents(strategy=strategy, config=config)
10
14
 
11
15
  # Create ServerApp
12
- app = ServerApp(
13
- config=ServerConfig(num_rounds=3),
14
- strategy=strategy,
15
- )
16
+ app = ServerApp(server_fn=server_fn)
@@ -1,12 +1,16 @@
1
1
  """$project_name: A Flower / NumPy app."""
2
2
 
3
- import flwr as fl
3
+ from flwr.common import Context
4
+ from flwr.server import ServerApp, ServerAppComponents, ServerConfig
5
+ from flwr.server.strategy import FedAvg
4
6
 
5
- # Configure the strategy
6
- strategy = fl.server.strategy.FedAvg()
7
7
 
8
- # Flower ServerApp
9
- app = fl.server.ServerApp(
10
- config=fl.server.ServerConfig(num_rounds=1),
11
- strategy=strategy,
12
- )
8
+ def server_fn(context: Context):
9
+ # Define strategy
10
+ strategy = FedAvg()
11
+ config = ServerConfig(num_rounds=3)
12
+
13
+ return ServerAppComponents(strategy=strategy, config=config)
14
+
15
+ # Create ServerApp
16
+ app = ServerApp(server_fn=server_fn)
@@ -1,7 +1,7 @@
1
1
  """$project_name: A Flower / PyTorch app."""
2
2
 
3
- from flwr.common import ndarrays_to_parameters
4
- from flwr.server import ServerApp, ServerConfig
3
+ from flwr.common import Context, ndarrays_to_parameters
4
+ from flwr.server import ServerApp, ServerAppComponents, ServerConfig
5
5
  from flwr.server.strategy import FedAvg
6
6
 
7
7
  from $import_name.task import Net, get_weights
@@ -11,18 +11,17 @@ from $import_name.task import Net, get_weights
11
11
  ndarrays = get_weights(Net())
12
12
  parameters = ndarrays_to_parameters(ndarrays)
13
13
 
14
+ def server_fn(context: Context):
15
+ # Define strategy
16
+ strategy = FedAvg(
17
+ fraction_fit=1.0,
18
+ fraction_evaluate=1.0,
19
+ min_available_clients=2,
20
+ initial_parameters=parameters,
21
+ )
22
+ config = ServerConfig(num_rounds=3)
14
23
 
15
- # Define strategy
16
- strategy = FedAvg(
17
- fraction_fit=1.0,
18
- fraction_evaluate=1.0,
19
- min_available_clients=2,
20
- initial_parameters=parameters,
21
- )
22
-
24
+ return ServerAppComponents(strategy=strategy, config=config)
23
25
 
24
26
  # Create ServerApp
25
- app = ServerApp(
26
- config=ServerConfig(num_rounds=3),
27
- strategy=strategy,
28
- )
27
+ app = ServerApp(server_fn=server_fn)
@@ -1,17 +1,20 @@
1
1
  """$project_name: A Flower / Scikit-Learn app."""
2
2
 
3
- from flwr.server import ServerApp, ServerConfig
3
+ from flwr.common import Context
4
+ from flwr.server import ServerApp, ServerAppComponents, ServerConfig
4
5
  from flwr.server.strategy import FedAvg
5
6
 
6
7
 
7
- strategy = FedAvg(
8
- fraction_fit=1.0,
9
- fraction_evaluate=1.0,
10
- min_available_clients=2,
11
- )
8
+ def server_fn(context: Context):
9
+ # Define strategy
10
+ strategy = FedAvg(
11
+ fraction_fit=1.0,
12
+ fraction_evaluate=1.0,
13
+ min_available_clients=2,
14
+ )
15
+ config = ServerConfig(num_rounds=3)
16
+
17
+ return ServerAppComponents(strategy=strategy, config=config)
12
18
 
13
19
  # Create ServerApp
14
- app = ServerApp(
15
- config=ServerConfig(num_rounds=3),
16
- strategy=strategy,
17
- )
20
+ app = ServerApp(server_fn=server_fn)
@@ -1,7 +1,7 @@
1
1
  """$project_name: A Flower / TensorFlow app."""
2
2
 
3
- from flwr.common import ndarrays_to_parameters
4
- from flwr.server import ServerApp, ServerConfig
3
+ from flwr.common import Context, ndarrays_to_parameters
4
+ from flwr.server import ServerApp, ServerAppComponents, ServerConfig
5
5
  from flwr.server.strategy import FedAvg
6
6
 
7
7
  from $import_name.task import load_model
@@ -11,17 +11,17 @@ config = ServerConfig(num_rounds=3)
11
11
 
12
12
  parameters = ndarrays_to_parameters(load_model().get_weights())
13
13
 
14
- # Define strategy
15
- strategy = FedAvg(
16
- fraction_fit=1.0,
17
- fraction_evaluate=1.0,
18
- min_available_clients=2,
19
- initial_parameters=parameters,
20
- )
14
+ def server_fn(context: Context):
15
+ # Define strategy
16
+ strategy = strategy = FedAvg(
17
+ fraction_fit=1.0,
18
+ fraction_evaluate=1.0,
19
+ min_available_clients=2,
20
+ initial_parameters=parameters,
21
+ )
22
+ config = ServerConfig(num_rounds=3)
21
23
 
24
+ return ServerAppComponents(strategy=strategy, config=config)
22
25
 
23
26
  # Create ServerApp
24
- app = ServerApp(
25
- config=config,
26
- strategy=strategy,
27
- )
27
+ app = ServerApp(server_fn=server_fn)
@@ -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, num_clients):
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": num_clients})
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, num_clients):
47
- fds = FederatedDataset(dataset="mnist", partitioners={"train": num_clients})
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/cli/run/run.py CHANGED
@@ -62,7 +62,7 @@ def run(
62
62
  config_overrides: Annotated[
63
63
  Optional[str],
64
64
  typer.Option(
65
- "--config",
65
+ "--run-config",
66
66
  "-c",
67
67
  help="Override configuration key-value pairs",
68
68
  ),
flwr/client/app.py CHANGED
@@ -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(node_id: int, partition_id: Optional[int]):
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,
@@ -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
- node_id: int, # pylint: disable=unused-argument
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(
@@ -349,7 +348,6 @@ def _start_client_internal(
349
348
  node_state = NodeState(
350
349
  node_id=-1,
351
350
  node_config={},
352
- partition_id=None,
353
351
  )
354
352
  else:
355
353
  # Call create_node fn to register node
@@ -361,7 +359,6 @@ def _start_client_internal(
361
359
  node_state = NodeState(
362
360
  node_id=node_id,
363
361
  node_config=node_config,
364
- partition_id=None,
365
362
  )
366
363
 
367
364
  app_state_tracker.register_signal_handler()
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 not all(key in client_fn_args for key in ["node_id", "partition_id"]):
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(node_id: int, "
39
- "partition_id: Optional[int])`.\nYou provided `client_fn` with signature: "
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
- node_id: int, partition_id: Optional[int] # pylint: disable=unused-argument
46
- ) -> Client:
47
- return client_fn(str(partition_id)) # type: ignore
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(node_id: int, partition_id: Optional[int]):
94
+ >>> def client_fn(context: Context):
75
95
  >>> return FlowerClient().to_client()
76
96
  >>>
77
97
  >>> app = ClientApp(client_fn)
@@ -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(message.metadata.dst_node_id, context.partition_id)
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
@@ -36,12 +36,13 @@ class NodeState:
36
36
  """State of a node where client nodes execute runs."""
37
37
 
38
38
  def __init__(
39
- self, node_id: int, node_config: Dict[str, str], partition_id: Optional[int]
39
+ self,
40
+ node_id: int,
41
+ node_config: Dict[str, str],
40
42
  ) -> None:
41
43
  self.node_id = node_id
42
44
  self.node_config = node_config
43
45
  self.run_infos: Dict[int, RunInfo] = {}
44
- self._partition_id = partition_id
45
46
 
46
47
  def register_context(
47
48
  self,
@@ -59,7 +60,6 @@ class NodeState:
59
60
  node_config=self.node_config,
60
61
  state=RecordSet(),
61
62
  run_config=initial_run_config.copy(),
62
- partition_id=self._partition_id,
63
63
  ),
64
64
  )
65
65
 
@@ -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(node_id=0, node_config={}, partition_id=None)
44
+ node_state = NodeState(node_id=0, node_config={})
45
45
 
46
46
  for task in tasks:
47
47
  run_id = task.run_id
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, Optional
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[[int, Optional[int]], Client]
26
+ ClientFnExt = Callable[[Context], Client]
27
27
 
28
28
  ClientAppCallable = Callable[[Message, Context], Message]
29
29
  Mod = Callable[[Message, Context, ClientAppCallable], Message]
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, Optional
19
+ from typing import Dict
20
20
 
21
21
  from .record import RecordSet
22
22
 
@@ -43,17 +43,12 @@ class Context:
43
43
  A config (key/value mapping) held by the entity in a given run and that will
44
44
  stay local. It can be used at any point during the lifecycle of this entity
45
45
  (e.g. across multiple rounds)
46
- partition_id : Optional[int] (default: None)
47
- An index that specifies the data partition that the ClientApp using this Context
48
- object should make use of. Setting this attribute is better suited for
49
- simulation or proto typing setups.
50
46
  """
51
47
 
52
48
  node_id: int
53
49
  node_config: Dict[str, str]
54
50
  state: RecordSet
55
51
  run_config: Dict[str, str]
56
- partition_id: Optional[int]
57
52
 
58
53
  def __init__( # pylint: disable=too-many-arguments
59
54
  self,
@@ -61,10 +56,8 @@ class Context:
61
56
  node_config: Dict[str, str],
62
57
  state: RecordSet,
63
58
  run_config: Dict[str, str],
64
- partition_id: Optional[int] = None,
65
59
  ) -> None:
66
60
  self.node_id = node_id
67
61
  self.node_config = node_config
68
62
  self.state = state
69
63
  self.run_config = run_config
70
- self.partition_id = partition_id
@@ -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.partition_id
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 PING_MAX_INTERVAL, ErrorCode
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 runstate
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,9 +288,15 @@ 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
294
  node_states[node_id] = NodeState(
288
- node_id=node_id, node_config={}, partition_id=partition_id
295
+ node_id=node_id,
296
+ node_config={
297
+ PARTITION_ID_KEY: str(partition_id),
298
+ NUM_PARTITIONS_KEY: str(num_partitions),
299
+ },
289
300
  )
290
301
 
291
302
  # Load backend config
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(node_id: int, partition_id: Optional[int]). It should return
116
- a single client instance of type Client. Note that the created 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 MessageType, MessageTypeLegacy
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))
@@ -60,7 +66,11 @@ class RayActorClientProxy(ClientProxy):
60
66
  self.app_fn = _load_app
61
67
  self.actor_pool = actor_pool
62
68
  self.proxy_state = NodeState(
63
- node_id=node_id, node_config={}, partition_id=self.partition_id
69
+ node_id=node_id,
70
+ node_config={
71
+ PARTITION_ID_KEY: str(partition_id),
72
+ NUM_PARTITIONS_KEY: str(num_partitions),
73
+ },
64
74
  )
65
75
 
66
76
  def _submit_job(self, message: Message, timeout: Optional[float]) -> Message:
@@ -70,18 +80,19 @@ class RayActorClientProxy(ClientProxy):
70
80
  # Register state
71
81
  self.proxy_state.register_context(run_id=run_id)
72
82
 
73
- # Retrieve state
74
- state = self.proxy_state.retrieve_context(run_id=run_id)
83
+ # Retrieve context
84
+ context = self.proxy_state.retrieve_context(run_id=run_id)
85
+ partition_id_str = context.node_config[PARTITION_ID_KEY]
75
86
 
76
87
  try:
77
88
  self.actor_pool.submit_client_job(
78
- lambda a, a_fn, mssg, partition_id, state: a.run.remote(
79
- a_fn, mssg, partition_id, state
89
+ lambda a, a_fn, mssg, partition_id, context: a.run.remote(
90
+ a_fn, mssg, partition_id, context
80
91
  ),
81
- (self.app_fn, message, str(self.partition_id), state),
92
+ (self.app_fn, message, partition_id_str, context),
82
93
  )
83
94
  out_mssg, updated_context = self.actor_pool.get_client_result(
84
- str(self.partition_id), timeout
95
+ partition_id_str, timeout
85
96
  )
86
97
 
87
98
  # Update state
flwr/superexec/app.py CHANGED
@@ -24,6 +24,7 @@ import grpc
24
24
 
25
25
  from flwr.common import EventType, event, log
26
26
  from flwr.common.address import parse_address
27
+ from flwr.common.config import parse_config_args
27
28
  from flwr.common.constant import SUPEREXEC_DEFAULT_ADDRESS
28
29
  from flwr.common.exit_handlers import register_exit_handlers
29
30
  from flwr.common.object_ref import load_app, validate
@@ -55,6 +56,7 @@ def run_superexec() -> None:
55
56
  address=address,
56
57
  executor=_load_executor(args),
57
58
  certificates=certificates,
59
+ config=parse_config_args(args.executor_config),
58
60
  )
59
61
 
60
62
  grpc_servers = [superexec_server]
@@ -74,21 +76,25 @@ def _parse_args_run_superexec() -> argparse.ArgumentParser:
74
76
  parser = argparse.ArgumentParser(
75
77
  description="Start a Flower SuperExec",
76
78
  )
77
- parser.add_argument(
78
- "executor",
79
- help="For example: `deployment:exec` or `project.package.module:wrapper.exec`.",
80
- default="flwr.superexec.deployment:executor",
81
- )
82
79
  parser.add_argument(
83
80
  "--address",
84
81
  help="SuperExec (gRPC) server address (IPv4, IPv6, or a domain name)",
85
82
  default=SUPEREXEC_DEFAULT_ADDRESS,
86
83
  )
84
+ parser.add_argument(
85
+ "--executor",
86
+ help="For example: `deployment:exec` or `project.package.module:wrapper.exec`.",
87
+ default="flwr.superexec.deployment:executor",
88
+ )
87
89
  parser.add_argument(
88
90
  "--executor-dir",
89
91
  help="The directory for the executor.",
90
92
  default=".",
91
93
  )
94
+ parser.add_argument(
95
+ "--executor-config",
96
+ help="Key-value pairs for the executor config, separated by commas.",
97
+ )
92
98
  parser.add_argument(
93
99
  "--insecure",
94
100
  action="store_true",
@@ -17,6 +17,7 @@
17
17
  import subprocess
18
18
  import sys
19
19
  from logging import ERROR, INFO
20
+ from pathlib import Path
20
21
  from typing import Dict, Optional
21
22
 
22
23
  from typing_extensions import override
@@ -33,25 +34,73 @@ from .executor import Executor, RunTracker
33
34
 
34
35
 
35
36
  class DeploymentEngine(Executor):
36
- """Deployment engine executor."""
37
+ """Deployment engine executor.
38
+
39
+ Parameters
40
+ ----------
41
+ superlink: str (default: "0.0.0.0:9091")
42
+ Address of the SuperLink to connect to.
43
+ root_certificates: Optional[str] (default: None)
44
+ Specifies the path to the PEM-encoded root certificate file for
45
+ establishing secure HTTPS connections.
46
+ flwr_dir: Optional[str] (default: None)
47
+ The path containing installed Flower Apps.
48
+ """
37
49
 
38
50
  def __init__(
39
51
  self,
40
- address: str = DEFAULT_SERVER_ADDRESS_DRIVER,
41
- root_certificates: Optional[bytes] = None,
52
+ superlink: str = DEFAULT_SERVER_ADDRESS_DRIVER,
53
+ root_certificates: Optional[str] = None,
54
+ flwr_dir: Optional[str] = None,
42
55
  ) -> None:
43
- self.address = address
44
- self.root_certificates = root_certificates
56
+ self.superlink = superlink
57
+ if root_certificates is None:
58
+ self.root_certificates = None
59
+ self.root_certificates_bytes = None
60
+ else:
61
+ self.root_certificates = root_certificates
62
+ self.root_certificates_bytes = Path(root_certificates).read_bytes()
63
+ self.flwr_dir = flwr_dir
45
64
  self.stub: Optional[DriverStub] = None
46
65
 
66
+ @override
67
+ def set_config(
68
+ self,
69
+ config: Dict[str, str],
70
+ ) -> None:
71
+ """Set executor config arguments.
72
+
73
+ Parameters
74
+ ----------
75
+ config : Dict[str, str]
76
+ A dictionary for configuration values.
77
+ Supported configuration key/value pairs:
78
+ - "superlink": str
79
+ The address of the SuperLink Driver API.
80
+ - "root-certificates": str
81
+ The path to the root certificates.
82
+ - "flwr-dir": str
83
+ The path to the Flower directory.
84
+ """
85
+ if not config:
86
+ return
87
+ if superlink_address := config.get("superlink"):
88
+ self.superlink = superlink_address
89
+ if root_certificates := config.get("root-certificates"):
90
+ self.root_certificates = root_certificates
91
+ self.root_certificates_bytes = Path(root_certificates).read_bytes()
92
+ if flwr_dir := config.get("flwr-dir"):
93
+ self.flwr_dir = flwr_dir
94
+
47
95
  def _connect(self) -> None:
48
- if self.stub is None:
49
- channel = create_channel(
50
- server_address=self.address,
51
- insecure=(self.root_certificates is None),
52
- root_certificates=self.root_certificates,
53
- )
54
- self.stub = DriverStub(channel)
96
+ if self.stub is not None:
97
+ return
98
+ channel = create_channel(
99
+ server_address=self.superlink,
100
+ insecure=(self.root_certificates_bytes is None),
101
+ root_certificates=self.root_certificates_bytes,
102
+ )
103
+ self.stub = DriverStub(channel)
55
104
 
56
105
  def _create_run(
57
106
  self,
@@ -74,7 +123,9 @@ class DeploymentEngine(Executor):
74
123
 
75
124
  @override
76
125
  def start_run(
77
- self, fab_file: bytes, override_config: Dict[str, str]
126
+ self,
127
+ fab_file: bytes,
128
+ override_config: Dict[str, str],
78
129
  ) -> Optional[RunTracker]:
79
130
  """Start run using the Flower Deployment Engine."""
80
131
  try:
@@ -84,7 +135,7 @@ class DeploymentEngine(Executor):
84
135
 
85
136
  # Install FAB Python package
86
137
  subprocess.check_call(
87
- [sys.executable, "-m", "pip", "install", str(fab_path)],
138
+ [sys.executable, "-m", "pip", "install", "--no-deps", str(fab_path)],
88
139
  stdout=subprocess.DEVNULL,
89
140
  stderr=subprocess.DEVNULL,
90
141
  )
@@ -93,14 +144,27 @@ class DeploymentEngine(Executor):
93
144
  run_id: int = self._create_run(fab_id, fab_version, override_config)
94
145
  log(INFO, "Created run %s", str(run_id))
95
146
 
96
- # Start ServerApp
147
+ command = [
148
+ "flower-server-app",
149
+ "--run-id",
150
+ str(run_id),
151
+ "--superlink",
152
+ str(self.superlink),
153
+ ]
154
+
155
+ if self.flwr_dir:
156
+ command.append("--flwr-dir")
157
+ command.append(self.flwr_dir)
158
+
159
+ if self.root_certificates is None:
160
+ command.append("--insecure")
161
+ else:
162
+ command.append("--root-certificates")
163
+ command.append(self.root_certificates)
164
+
165
+ # Execute the command
97
166
  proc = subprocess.Popen( # pylint: disable=consider-using-with
98
- [
99
- "flower-server-app",
100
- "--run-id",
101
- str(run_id),
102
- "--insecure",
103
- ],
167
+ command,
104
168
  stdout=subprocess.PIPE,
105
169
  stderr=subprocess.PIPE,
106
170
  text=True,
@@ -15,7 +15,7 @@
15
15
  """SuperExec gRPC API."""
16
16
 
17
17
  from logging import INFO
18
- from typing import Optional, Tuple
18
+ from typing import Dict, Optional, Tuple
19
19
 
20
20
  import grpc
21
21
 
@@ -32,8 +32,11 @@ def run_superexec_api_grpc(
32
32
  address: str,
33
33
  executor: Executor,
34
34
  certificates: Optional[Tuple[bytes, bytes, bytes]],
35
+ config: Dict[str, str],
35
36
  ) -> grpc.Server:
36
37
  """Run SuperExec API (gRPC, request-response)."""
38
+ executor.set_config(config)
39
+
37
40
  exec_servicer: grpc.Server = ExecServicer(
38
41
  executor=executor,
39
42
  )
@@ -45,7 +48,7 @@ def run_superexec_api_grpc(
45
48
  certificates=certificates,
46
49
  )
47
50
 
48
- log(INFO, "Flower ECE: Starting SuperExec API (gRPC-rere) on %s", address)
51
+ log(INFO, "Starting Flower SuperExec gRPC server on %s", address)
49
52
  superexec_grpc_server.start()
50
53
 
51
54
  return superexec_grpc_server
@@ -31,9 +31,24 @@ class RunTracker:
31
31
  class Executor(ABC):
32
32
  """Execute and monitor a Flower run."""
33
33
 
34
+ @abstractmethod
35
+ def set_config(
36
+ self,
37
+ config: Dict[str, str],
38
+ ) -> None:
39
+ """Register provided config as class attributes.
40
+
41
+ Parameters
42
+ ----------
43
+ config : Optional[Dict[str, str]]
44
+ A dictionary for configuration values.
45
+ """
46
+
34
47
  @abstractmethod
35
48
  def start_run(
36
- self, fab_file: bytes, override_config: Dict[str, str]
49
+ self,
50
+ fab_file: bytes,
51
+ override_config: Dict[str, str],
37
52
  ) -> Optional[RunTracker]:
38
53
  """Start a run using the given Flower FAB ID and version.
39
54
 
@@ -44,6 +59,8 @@ class Executor(ABC):
44
59
  ----------
45
60
  fab_file : bytes
46
61
  The Flower App Bundle file bytes.
62
+ override_config: Dict[str, str]
63
+ The config overrides dict sent by the user (using `flwr run`).
47
64
 
48
65
  Returns
49
66
  -------
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.10.0.dev20240712
3
+ Version: 1.10.0.dev20240714
4
4
  Summary: Flower: A Friendly Federated Learning Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -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=RaN89A8HgKp6kjhzH8tgtDSWW8BwwcvJdqRLcvG04zw,1450
18
- flwr/cli/new/templates/app/code/client.jax.py.tpl,sha256=MtxhwQzxAWNvlz8B-L-2a8LXcgaLPW8dp5K0vBZHR_o,1434
19
- flwr/cli/new/templates/app/code/client.mlx.py.tpl,sha256=53wJy6s3zk4CZwob_qPmMoOqJ-LZNKbdDe_hw5LwOXE,2113
20
- flwr/cli/new/templates/app/code/client.numpy.py.tpl,sha256=mTh7Y_jOJrPUvDYHVJy4wJCnjXZV_q-jlDkB07U5GSk,521
21
- flwr/cli/new/templates/app/code/client.pytorch.py.tpl,sha256=MgCtMSv1Th16Faod11HubVaARkLYt7vS9RYH962-2pk,1172
22
- flwr/cli/new/templates/app/code/client.sklearn.py.tpl,sha256=S71SZiHaRXtKqUk3m5Elc_c6HhKAIKLalrKOQ3p20No,2801
23
- flwr/cli/new/templates/app/code/client.tensorflow.py.tpl,sha256=dxrTO9JwYrDBjLsmCiRLetN9KxbnWRTeGA0BQbnOu_A,1280
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
@@ -29,17 +29,17 @@ flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl,sha256=kPG4AIXQfNNHZGYC
29
29
  flwr/cli/new/templates/app/code/flwr_tune/models.py.tpl,sha256=cEq9ZWM3zImJVceNtxHC_bYBLE8OChK0BdjpWs5Wz-0,1881
30
30
  flwr/cli/new/templates/app/code/flwr_tune/server.py.tpl,sha256=Z_JC7-YdjCnnUJPKILwT5Iqc70byJpthbye8RsQp9L0,1548
31
31
  flwr/cli/new/templates/app/code/flwr_tune/static_config.yaml.tpl,sha256=cBPpBVN_N7p4T2a3rqChlngmE0dB_jveOLHesNcEHvs,268
32
- flwr/cli/new/templates/app/code/server.hf.py.tpl,sha256=Mld452y3SUkejlFzac5hpCjT7_mbA0ZEEMJIUyHtSTI,338
33
- flwr/cli/new/templates/app/code/server.jax.py.tpl,sha256=YTi-wroUpjRDY_AZqnoN5X-n3U5V7laL6UJgqFLEbKE,246
34
- flwr/cli/new/templates/app/code/server.mlx.py.tpl,sha256=Cqk3PvM0e7hzohXPqD5hG_cthXoxCfc30bpEThqMy7M,272
35
- flwr/cli/new/templates/app/code/server.numpy.py.tpl,sha256=fRxrDXV7pB1aDhQUXMBmrCsC1zp0uKwsBxZBx1JzbHA,248
36
- flwr/cli/new/templates/app/code/server.pytorch.py.tpl,sha256=ltdsnFSvFGPcycVmRL4ITlr-TV0CmmXcperZe7Vamow,593
37
- flwr/cli/new/templates/app/code/server.sklearn.py.tpl,sha256=cLzOpQzGIUzEazuFsjBpXAQUNPy6in6zR33SCqhix6o,341
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=Rw8cnds4Ym8o8TOq6kMkwlBJfIfvsfnb02jwyulOgF8,2857
32
+ flwr/cli/new/templates/app/code/server.hf.py.tpl,sha256=BQmQy7UR8B1mNojUaTNVM4ci1pdKCk1Znw4bH_3nE1c,510
33
+ flwr/cli/new/templates/app/code/server.jax.py.tpl,sha256=stWCaIZCqdw-RnLtpa7hdz24JaiG65z2OSTB1yz6NdA,427
34
+ flwr/cli/new/templates/app/code/server.mlx.py.tpl,sha256=P1Odp3SYl0CQt5tX4fcrY4nxOBOejOMMerRvbrOq-KA,427
35
+ flwr/cli/new/templates/app/code/server.numpy.py.tpl,sha256=oZ_KBcvv0NRINjCKbwNCnSz7xcquDRQEgSh7yOEWZ5E,429
36
+ flwr/cli/new/templates/app/code/server.pytorch.py.tpl,sha256=wcekFyR4qMc3zfi39_AmSps8ahL_NpIzfvfI5iKj_vE,744
37
+ flwr/cli/new/templates/app/code/server.sklearn.py.tpl,sha256=SmlGeCnpPlfx0x0P3RgO2jPlablovp0ugMDcPDgXVmk,531
38
+ flwr/cli/new/templates/app/code/server.tensorflow.py.tpl,sha256=DHTIcUzA0XbtUVWvZ8LYABpzwdubsyxkNk42OiWG7vs,762
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=y7aVj3F_98-wBnDcbPsCNnFs9BOHTn0y6XIYkByzv7Y,2598
42
- flwr/cli/new/templates/app/code/task.pytorch.py.tpl,sha256=NvajdZN-eTyfdqKK0v2MrvWITXw9BjJ3Ri5c1haPJDs,3684
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
@@ -50,12 +50,12 @@ flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl,sha256=wxN6I8uvWZ4MErvTbQJ
50
50
  flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl,sha256=wFeJuhqnBPQtKCBvnE3ySBpxmbeNdxcsq2Eb_RmSDIg,655
51
51
  flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=zkxLTQRvujF76sIlzNNGPVU7Y9nVCwNBxAx82AOBaJY,654
52
52
  flwr/cli/run/__init__.py,sha256=oCd6HmQDx-sqver1gecgx-uMA38BLTSiiKpl7RGNceg,789
53
- flwr/cli/run/run.py,sha256=eFYZwHOw9pHo_jxtS-UQIf7LVIOiNwjnJdaykcZQz5Q,4969
53
+ flwr/cli/run/run.py,sha256=b_TcqJAGOiF0RDO5f25HCWYYdG54CxSjtsXwcRYN_J8,4973
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=60e0vEmMNRusDheu7laQRqe87FhFyVzxIZKAhLrRLAo,26268
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=cvY-km3JEOWKxUio4xvksNFBk2FQQXliUfQTlDty71w,9648
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
61
  flwr/client/grpc_adapter_client/connection.py,sha256=fM6QTIrcDGIXux7nzxOY3qNUfBGxVl1W7861iGSy5wA,3873
@@ -67,7 +67,7 @@ flwr/client/grpc_rere_client/connection.py,sha256=nC4Usb1qok2liVxwlbQokUNwRRRD10
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=rLuzcpRqSFofQ8QIB6OGnh9HC5uxUAnkQQIJaP0JHvM,6574
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=Yh-3-YQtnUfAjMxz356cUQp40UFfdM1yw-n_Ir50JBk,2971
81
- flwr/client/node_state_tests.py,sha256=DAZk3Ir3HSN24xx42l0u9n5Q7sTgw8Jps4QRhwGew3A,2258
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
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
86
  flwr/client/supernode/app.py,sha256=cg8momLzMnFrDBNJsSRDYrn8zHuJ-4UC3wIHf51aBXQ,15385
87
- flwr/client/typing.py,sha256=RJGVF64Z0nqW-qmdFuFaY4Jig3dMUFgNhFi-5dq-8-I,1069
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
90
  flwr/common/config.py,sha256=7OF4R43st8teFXBWmV92noGEYVe00wT29QMs6od8mlI,4994
91
- flwr/common/constant.py,sha256=qNmxEV3_pOO7MeTAA9qwIh4KoCPStcX3Gm8GRPIRx_4,2890
92
- flwr/common/context.py,sha256=iW-rDC0dTzwyvLSWdtaeHMZM7l5XAf6dg2TdVw0lg68,2643
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
@@ -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=pIJm6YXZw-Jv3okRgred1yjm7b3EWuj1BvtyBd3Fk08,7422
242
- flwr/server/superlink/fleet/vce/vce_api.py,sha256=253x7nGgAbLZzJmSKNxii_xZDrF_8fC0hpbj4bIQ7SY,11800
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=8NDXoQ8oC11khXIGnydrsUh5JfaH7c2Fwzix8vDFK1I,15144
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=lcrYLHeAud6AT0TgzKLK14yi3ijZpqMWS4oKj5M1A3A,7009
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=1ZGSErFo3AQeIQOARKM1DN99fCuH451PeM1bDasBjRQ,6157
268
- flwr/superexec/deployment.py,sha256=xv5iQWuaMeeL0XE5KMLWq3gRU4lvsGu1-_oPIXi5x9E,3955
269
- flwr/superexec/exec_grpc.py,sha256=u-rztpOleqSGqgvNE-ZLw1HchNsBHU1-eB3m52GZ0pQ,1852
267
+ flwr/superexec/app.py,sha256=Zh9I64XfCoghWoT1k2DKDrcVCXIGOpw03v0WKCOg-mg,6402
268
+ flwr/superexec/deployment.py,sha256=o_FYkB_vamBPjeVpPbqvzr4kBYID26sXVDrLO3Ac4R0,6130
269
+ flwr/superexec/exec_grpc.py,sha256=vYbZyV89MuvYDH1XzVYHkKmGfOcU6FWh8rTcIJk2TIQ,1910
270
270
  flwr/superexec/exec_servicer.py,sha256=4R1f_9v0vly_bXpIYaXAeV1tO5LAy1AYygGGGNZmlQk,2194
271
- flwr/superexec/executor.py,sha256=TMQMMf-vv0htlv6v-eEBI67J1WL3Yz7dp_Fm1lgMEyU,1718
272
- flwr_nightly-1.10.0.dev20240712.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
273
- flwr_nightly-1.10.0.dev20240712.dist-info/METADATA,sha256=ueea2HUP0m4iFuOa_T3u2lD-93HGTmfD-ulaZv7LKJg,15632
274
- flwr_nightly-1.10.0.dev20240712.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
275
- flwr_nightly-1.10.0.dev20240712.dist-info/entry_points.txt,sha256=7qBQcA-bDGDxnJmLd9FYqglFQubjCNqyg9M8a-lukps,336
276
- flwr_nightly-1.10.0.dev20240712.dist-info/RECORD,,
271
+ flwr/superexec/executor.py,sha256=5ua0AU2cfisyD79dosP-POF3w0FRH2I5Wko_PPKLWqU,2153
272
+ flwr_nightly-1.10.0.dev20240714.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
273
+ flwr_nightly-1.10.0.dev20240714.dist-info/METADATA,sha256=9aI10DHtz4gZbec9re5g_yizKlPUjDQptMpkYOShtHE,15632
274
+ flwr_nightly-1.10.0.dev20240714.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
275
+ flwr_nightly-1.10.0.dev20240714.dist-info/entry_points.txt,sha256=7qBQcA-bDGDxnJmLd9FYqglFQubjCNqyg9M8a-lukps,336
276
+ flwr_nightly-1.10.0.dev20240714.dist-info/RECORD,,