flwr-nightly 1.10.0.dev20240712__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.

Files changed (27) 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/task.hf.py.tpl +2 -2
  9. flwr/cli/new/templates/app/code/task.mlx.py.tpl +2 -2
  10. flwr/cli/new/templates/app/code/task.pytorch.py.tpl +1 -1
  11. flwr/client/app.py +4 -7
  12. flwr/client/client_app.py +28 -8
  13. flwr/client/message_handler/message_handler.py +1 -1
  14. flwr/client/node_state.py +3 -3
  15. flwr/client/node_state_tests.py +1 -1
  16. flwr/client/typing.py +2 -2
  17. flwr/common/constant.py +3 -0
  18. flwr/common/context.py +1 -8
  19. flwr/server/superlink/fleet/vce/backend/raybackend.py +2 -1
  20. flwr/server/superlink/fleet/vce/vce_api.py +14 -3
  21. flwr/simulation/app.py +4 -3
  22. flwr/simulation/ray_transport/ray_client_proxy.py +20 -9
  23. {flwr_nightly-1.10.0.dev20240712.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/METADATA +1 -1
  24. {flwr_nightly-1.10.0.dev20240712.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/RECORD +27 -27
  25. {flwr_nightly-1.10.0.dev20240712.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/LICENSE +0 -0
  26. {flwr_nightly-1.10.0.dev20240712.dist-info → flwr_nightly-1.10.0.dev20240713.dist-info}/WHEEL +0 -0
  27. {flwr_nightly-1.10.0.dev20240712.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(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()
@@ -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/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
@@ -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.dev20240713
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
@@ -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=Rw8cnds4Ym8o8TOq6kMkwlBJfIfvsfnb02jwyulOgF8,2857
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
@@ -53,9 +53,9 @@ 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=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,10 +257,10 @@ 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
@@ -269,8 +269,8 @@ flwr/superexec/deployment.py,sha256=xv5iQWuaMeeL0XE5KMLWq3gRU4lvsGu1-_oPIXi5x9E,
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.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,,
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,,