flwr-nightly 1.10.0.dev20240715__py3-none-any.whl → 1.10.0.dev20240716__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 (32) hide show
  1. flwr/cli/build.py +16 -2
  2. flwr/cli/config_utils.py +23 -15
  3. flwr/cli/install.py +1 -1
  4. flwr/cli/new/templates/app/code/server.hf.py.tpl +4 -1
  5. flwr/cli/new/templates/app/code/server.jax.py.tpl +4 -1
  6. flwr/cli/new/templates/app/code/server.mlx.py.tpl +4 -1
  7. flwr/cli/new/templates/app/code/server.numpy.py.tpl +4 -1
  8. flwr/cli/new/templates/app/code/server.pytorch.py.tpl +4 -1
  9. flwr/cli/new/templates/app/code/server.sklearn.py.tpl +4 -1
  10. flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +4 -1
  11. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +6 -3
  12. flwr/cli/new/templates/app/pyproject.hf.toml.tpl +6 -3
  13. flwr/cli/new/templates/app/pyproject.jax.toml.tpl +6 -3
  14. flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +6 -3
  15. flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +6 -3
  16. flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +6 -3
  17. flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +6 -3
  18. flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +6 -3
  19. flwr/cli/run/run.py +22 -10
  20. flwr/client/app.py +3 -3
  21. flwr/client/node_state.py +17 -3
  22. flwr/client/supernode/app.py +2 -2
  23. flwr/common/config.py +13 -4
  24. flwr/server/run_serverapp.py +1 -1
  25. flwr/server/superlink/fleet/vce/vce_api.py +10 -3
  26. flwr/simulation/run_simulation.py +148 -14
  27. flwr/superexec/simulation.py +1 -1
  28. {flwr_nightly-1.10.0.dev20240715.dist-info → flwr_nightly-1.10.0.dev20240716.dist-info}/METADATA +2 -1
  29. {flwr_nightly-1.10.0.dev20240715.dist-info → flwr_nightly-1.10.0.dev20240716.dist-info}/RECORD +32 -32
  30. {flwr_nightly-1.10.0.dev20240715.dist-info → flwr_nightly-1.10.0.dev20240716.dist-info}/LICENSE +0 -0
  31. {flwr_nightly-1.10.0.dev20240715.dist-info → flwr_nightly-1.10.0.dev20240716.dist-info}/WHEEL +0 -0
  32. {flwr_nightly-1.10.0.dev20240715.dist-info → flwr_nightly-1.10.0.dev20240716.dist-info}/entry_points.txt +0 -0
flwr/cli/build.py CHANGED
@@ -20,6 +20,7 @@ from pathlib import Path
20
20
  from typing import Optional
21
21
 
22
22
  import pathspec
23
+ import tomli_w
23
24
  import typer
24
25
  from typing_extensions import Annotated
25
26
 
@@ -85,7 +86,7 @@ def build(
85
86
 
86
87
  # Set the name of the zip file
87
88
  fab_filename = (
88
- f"{conf['tool']['flwr']['publisher']}"
89
+ f"{conf['tool']['flwr']['app']['publisher']}"
89
90
  f".{directory.name}"
90
91
  f".{conf['project']['version'].replace('.', '-')}.fab"
91
92
  )
@@ -93,15 +94,28 @@ def build(
93
94
 
94
95
  allowed_extensions = {".py", ".toml", ".md"}
95
96
 
97
+ # Remove the 'federations' field from 'tool.flwr' if it exists
98
+ if (
99
+ "tool" in conf
100
+ and "flwr" in conf["tool"]
101
+ and "federations" in conf["tool"]["flwr"]
102
+ ):
103
+ del conf["tool"]["flwr"]["federations"]
104
+
105
+ toml_contents = tomli_w.dumps(conf)
106
+
96
107
  with zipfile.ZipFile(fab_filename, "w", zipfile.ZIP_DEFLATED) as fab_file:
108
+ fab_file.writestr("pyproject.toml", toml_contents)
109
+
110
+ # Continue with adding other files
97
111
  for root, _, files in os.walk(directory, topdown=True):
98
- # Filter directories and files based on .gitignore
99
112
  files = [
100
113
  f
101
114
  for f in files
102
115
  if not ignore_spec.match_file(Path(root) / f)
103
116
  and f != fab_filename
104
117
  and Path(f).suffix in allowed_extensions
118
+ and f != "pyproject.toml" # Exclude the original pyproject.toml
105
119
  ]
106
120
 
107
121
  for file in files:
flwr/cli/config_utils.py CHANGED
@@ -60,7 +60,7 @@ def get_fab_metadata(fab_file: Union[Path, bytes]) -> Tuple[str, str]:
60
60
 
61
61
  return (
62
62
  conf["project"]["version"],
63
- f"{conf['tool']['flwr']['publisher']}/{conf['project']['name']}",
63
+ f"{conf['tool']['flwr']['app']['publisher']}/{conf['project']['name']}",
64
64
  )
65
65
 
66
66
 
@@ -136,20 +136,28 @@ def validate_fields(config: Dict[str, Any]) -> Tuple[bool, List[str], List[str]]
136
136
  if "authors" not in config["project"]:
137
137
  warnings.append('Recommended property "authors" missing in [project]')
138
138
 
139
- if "tool" not in config or "flwr" not in config["tool"]:
140
- errors.append("Missing [tool.flwr] section")
139
+ if (
140
+ "tool" not in config
141
+ or "flwr" not in config["tool"]
142
+ or "app" not in config["tool"]["flwr"]
143
+ ):
144
+ errors.append("Missing [tool.flwr.app] section")
141
145
  else:
142
- if "publisher" not in config["tool"]["flwr"]:
143
- errors.append('Property "publisher" missing in [tool.flwr]')
144
- if "config" in config["tool"]["flwr"]:
145
- _validate_run_config(config["tool"]["flwr"]["config"], errors)
146
- if "components" not in config["tool"]["flwr"]:
147
- errors.append("Missing [tool.flwr.components] section")
146
+ if "publisher" not in config["tool"]["flwr"]["app"]:
147
+ errors.append('Property "publisher" missing in [tool.flwr.app]')
148
+ if "config" in config["tool"]["flwr"]["app"]:
149
+ _validate_run_config(config["tool"]["flwr"]["app"]["config"], errors)
150
+ if "components" not in config["tool"]["flwr"]["app"]:
151
+ errors.append("Missing [tool.flwr.app.components] section")
148
152
  else:
149
- if "serverapp" not in config["tool"]["flwr"]["components"]:
150
- errors.append('Property "serverapp" missing in [tool.flwr.components]')
151
- if "clientapp" not in config["tool"]["flwr"]["components"]:
152
- errors.append('Property "clientapp" missing in [tool.flwr.components]')
153
+ if "serverapp" not in config["tool"]["flwr"]["app"]["components"]:
154
+ errors.append(
155
+ 'Property "serverapp" missing in [tool.flwr.app.components]'
156
+ )
157
+ if "clientapp" not in config["tool"]["flwr"]["app"]["components"]:
158
+ errors.append(
159
+ 'Property "clientapp" missing in [tool.flwr.app.components]'
160
+ )
153
161
 
154
162
  return len(errors) == 0, errors, warnings
155
163
 
@@ -165,14 +173,14 @@ def validate(
165
173
 
166
174
  # Validate serverapp
167
175
  is_valid, reason = object_ref.validate(
168
- config["tool"]["flwr"]["components"]["serverapp"], check_module
176
+ config["tool"]["flwr"]["app"]["components"]["serverapp"], check_module
169
177
  )
170
178
  if not is_valid and isinstance(reason, str):
171
179
  return False, [reason], []
172
180
 
173
181
  # Validate clientapp
174
182
  is_valid, reason = object_ref.validate(
175
- config["tool"]["flwr"]["components"]["clientapp"], check_module
183
+ config["tool"]["flwr"]["app"]["components"]["clientapp"], check_module
176
184
  )
177
185
 
178
186
  if not is_valid and isinstance(reason, str):
flwr/cli/install.py CHANGED
@@ -149,7 +149,7 @@ def validate_and_install(
149
149
  )
150
150
  raise typer.Exit(code=1)
151
151
 
152
- publisher = config["tool"]["flwr"]["publisher"]
152
+ publisher = config["tool"]["flwr"]["app"]["publisher"]
153
153
  project_name = config["project"]["name"]
154
154
  version = config["project"]["version"]
155
155
 
@@ -6,12 +6,15 @@ from flwr.server import ServerApp, ServerAppComponents, ServerConfig
6
6
 
7
7
 
8
8
  def server_fn(context: Context):
9
+ # Read from config
10
+ num_rounds = int(context.run_config["num-server-rounds"])
11
+
9
12
  # Define strategy
10
13
  strategy = FedAvg(
11
14
  fraction_fit=1.0,
12
15
  fraction_evaluate=1.0,
13
16
  )
14
- config = ServerConfig(num_rounds=3)
17
+ config = ServerConfig(num_rounds=num_rounds)
15
18
 
16
19
  return ServerAppComponents(strategy=strategy, config=config)
17
20
 
@@ -6,9 +6,12 @@ from flwr.server import ServerApp, ServerAppComponents, ServerConfig
6
6
 
7
7
 
8
8
  def server_fn(context: Context):
9
+ # Read from config
10
+ num_rounds = int(context.run_config["num-server-rounds"])
11
+
9
12
  # Define strategy
10
13
  strategy = FedAvg()
11
- config = ServerConfig(num_rounds=3)
14
+ config = ServerConfig(num_rounds=num_rounds)
12
15
 
13
16
  return ServerAppComponents(strategy=strategy, config=config)
14
17
 
@@ -6,9 +6,12 @@ from flwr.server.strategy import FedAvg
6
6
 
7
7
 
8
8
  def server_fn(context: Context):
9
+ # Read from config
10
+ num_rounds = int(context.run_config["num-server-rounds"])
11
+
9
12
  # Define strategy
10
13
  strategy = FedAvg()
11
- config = ServerConfig(num_rounds=3)
14
+ config = ServerConfig(num_rounds=num_rounds)
12
15
 
13
16
  return ServerAppComponents(strategy=strategy, config=config)
14
17
 
@@ -6,9 +6,12 @@ from flwr.server.strategy import FedAvg
6
6
 
7
7
 
8
8
  def server_fn(context: Context):
9
+ # Read from config
10
+ num_rounds = int(context.run_config["num-server-rounds"])
11
+
9
12
  # Define strategy
10
13
  strategy = FedAvg()
11
- config = ServerConfig(num_rounds=3)
14
+ config = ServerConfig(num_rounds=num_rounds)
12
15
 
13
16
  return ServerAppComponents(strategy=strategy, config=config)
14
17
 
@@ -12,6 +12,9 @@ ndarrays = get_weights(Net())
12
12
  parameters = ndarrays_to_parameters(ndarrays)
13
13
 
14
14
  def server_fn(context: Context):
15
+ # Read from config
16
+ num_rounds = int(context.run_config["num-server-rounds"])
17
+
15
18
  # Define strategy
16
19
  strategy = FedAvg(
17
20
  fraction_fit=1.0,
@@ -19,7 +22,7 @@ def server_fn(context: Context):
19
22
  min_available_clients=2,
20
23
  initial_parameters=parameters,
21
24
  )
22
- config = ServerConfig(num_rounds=3)
25
+ config = ServerConfig(num_rounds=num_rounds)
23
26
 
24
27
  return ServerAppComponents(strategy=strategy, config=config)
25
28
 
@@ -6,13 +6,16 @@ from flwr.server.strategy import FedAvg
6
6
 
7
7
 
8
8
  def server_fn(context: Context):
9
+ # Read from config
10
+ num_rounds = int(context.run_config["num-server-rounds"])
11
+
9
12
  # Define strategy
10
13
  strategy = FedAvg(
11
14
  fraction_fit=1.0,
12
15
  fraction_evaluate=1.0,
13
16
  min_available_clients=2,
14
17
  )
15
- config = ServerConfig(num_rounds=3)
18
+ config = ServerConfig(num_rounds=num_rounds)
16
19
 
17
20
  return ServerAppComponents(strategy=strategy, config=config)
18
21
 
@@ -12,6 +12,9 @@ config = ServerConfig(num_rounds=3)
12
12
  parameters = ndarrays_to_parameters(load_model().get_weights())
13
13
 
14
14
  def server_fn(context: Context):
15
+ # Read from config
16
+ num_rounds = int(context.run_config["num-server-rounds"])
17
+
15
18
  # Define strategy
16
19
  strategy = strategy = FedAvg(
17
20
  fraction_fit=1.0,
@@ -19,7 +22,7 @@ def server_fn(context: Context):
19
22
  min_available_clients=2,
20
23
  initial_parameters=parameters,
21
24
  )
22
- config = ServerConfig(num_rounds=3)
25
+ config = ServerConfig(num_rounds=num_rounds)
23
26
 
24
27
  return ServerAppComponents(strategy=strategy, config=config)
25
28
 
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
  name = "$package_name"
7
7
  version = "1.0.0"
8
8
  description = ""
9
- license = { text = "Apache License (2.0)" }
9
+ license = "Apache-2.0"
10
10
  dependencies = [
11
11
  "flwr[simulation]>=1.9.0,<2.0",
12
12
  "flwr-datasets>=0.1.0,<1.0.0",
@@ -22,13 +22,16 @@ dependencies = [
22
22
  [tool.hatch.build.targets.wheel]
23
23
  packages = ["."]
24
24
 
25
- [tool.flwr]
25
+ [tool.flwr.app]
26
26
  publisher = "$username"
27
27
 
28
- [tool.flwr.components]
28
+ [tool.flwr.app.components]
29
29
  serverapp = "$import_name.app:server"
30
30
  clientapp = "$import_name.app:client"
31
31
 
32
+ [tool.flwr.app.config]
33
+ num-server-rounds = "3"
34
+
32
35
  [tool.flwr.federations]
33
36
  default = "localhost"
34
37
 
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
  name = "$package_name"
7
7
  version = "1.0.0"
8
8
  description = ""
9
- license = { text = "Apache License (2.0)" }
9
+ license = "Apache-2.0"
10
10
  dependencies = [
11
11
  "flwr[simulation]>=1.9.0,<2.0",
12
12
  "flwr-datasets>=0.0.2,<1.0.0",
@@ -20,13 +20,16 @@ dependencies = [
20
20
  [tool.hatch.build.targets.wheel]
21
21
  packages = ["."]
22
22
 
23
- [tool.flwr]
23
+ [tool.flwr.app]
24
24
  publisher = "$username"
25
25
 
26
- [tool.flwr.components]
26
+ [tool.flwr.app.components]
27
27
  serverapp = "$import_name.server:app"
28
28
  clientapp = "$import_name.client:app"
29
29
 
30
+ [tool.flwr.app.config]
31
+ num-server-rounds = "3"
32
+
30
33
  [tool.flwr.federations]
31
34
  default = "localhost"
32
35
 
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
  name = "$package_name"
7
7
  version = "1.0.0"
8
8
  description = ""
9
- license = {text = "Apache License (2.0)"}
9
+ license = "Apache-2.0"
10
10
  dependencies = [
11
11
  "flwr[simulation]>=1.9.0,<2.0",
12
12
  "jax==0.4.26",
@@ -17,13 +17,16 @@ dependencies = [
17
17
  [tool.hatch.build.targets.wheel]
18
18
  packages = ["."]
19
19
 
20
- [tool.flwr]
20
+ [tool.flwr.app]
21
21
  publisher = "$username"
22
22
 
23
- [tool.flwr.components]
23
+ [tool.flwr.app.components]
24
24
  serverapp = "$import_name.server:app"
25
25
  clientapp = "$import_name.client:app"
26
26
 
27
+ [tool.flwr.app.config]
28
+ num-server-rounds = "3"
29
+
27
30
  [tool.flwr.federations]
28
31
  default = "localhost"
29
32
 
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
  name = "$package_name"
7
7
  version = "1.0.0"
8
8
  description = ""
9
- license = { text = "Apache License (2.0)" }
9
+ license = "Apache-2.0"
10
10
  dependencies = [
11
11
  "flwr[simulation]>=1.9.0,<2.0",
12
12
  "flwr-datasets[vision]>=0.0.2,<1.0.0",
@@ -17,13 +17,16 @@ dependencies = [
17
17
  [tool.hatch.build.targets.wheel]
18
18
  packages = ["."]
19
19
 
20
- [tool.flwr]
20
+ [tool.flwr.app]
21
21
  publisher = "$username"
22
22
 
23
- [tool.flwr.components]
23
+ [tool.flwr.app.components]
24
24
  serverapp = "$import_name.server:app"
25
25
  clientapp = "$import_name.client:app"
26
26
 
27
+ [tool.flwr.app.config]
28
+ num-server-rounds = "3"
29
+
27
30
  [tool.flwr.federations]
28
31
  default = "localhost"
29
32
 
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
  name = "$package_name"
7
7
  version = "1.0.0"
8
8
  description = ""
9
- license = { text = "Apache License (2.0)" }
9
+ license = "Apache-2.0"
10
10
  dependencies = [
11
11
  "flwr[simulation]>=1.9.0,<2.0",
12
12
  "numpy>=1.21.0",
@@ -15,13 +15,16 @@ dependencies = [
15
15
  [tool.hatch.build.targets.wheel]
16
16
  packages = ["."]
17
17
 
18
- [tool.flwr]
18
+ [tool.flwr.app]
19
19
  publisher = "$username"
20
20
 
21
- [tool.flwr.components]
21
+ [tool.flwr.app.components]
22
22
  serverapp = "$import_name.server:app"
23
23
  clientapp = "$import_name.client:app"
24
24
 
25
+ [tool.flwr.app.config]
26
+ num-server-rounds = "3"
27
+
25
28
  [tool.flwr.federations]
26
29
  default = "localhost"
27
30
 
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
  name = "$package_name"
7
7
  version = "1.0.0"
8
8
  description = ""
9
- license = { text = "Apache License (2.0)" }
9
+ license = "Apache-2.0"
10
10
  dependencies = [
11
11
  "flwr[simulation]>=1.9.0,<2.0",
12
12
  "flwr-datasets[vision]>=0.0.2,<1.0.0",
@@ -17,13 +17,16 @@ dependencies = [
17
17
  [tool.hatch.build.targets.wheel]
18
18
  packages = ["."]
19
19
 
20
- [tool.flwr]
20
+ [tool.flwr.app]
21
21
  publisher = "$username"
22
22
 
23
- [tool.flwr.components]
23
+ [tool.flwr.app.components]
24
24
  serverapp = "$import_name.server:app"
25
25
  clientapp = "$import_name.client:app"
26
26
 
27
+ [tool.flwr.app.config]
28
+ num-server-rounds = "3"
29
+
27
30
  [tool.flwr.federations]
28
31
  default = "localhost"
29
32
 
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
  name = "$package_name"
7
7
  version = "1.0.0"
8
8
  description = ""
9
- license = { text = "Apache License (2.0)" }
9
+ license = "Apache-2.0"
10
10
  dependencies = [
11
11
  "flwr[simulation]>=1.9.0,<2.0",
12
12
  "flwr-datasets[vision]>=0.0.2,<1.0.0",
@@ -16,13 +16,16 @@ dependencies = [
16
16
  [tool.hatch.build.targets.wheel]
17
17
  packages = ["."]
18
18
 
19
- [tool.flwr]
19
+ [tool.flwr.app]
20
20
  publisher = "$username"
21
21
 
22
- [tool.flwr.components]
22
+ [tool.flwr.app.components]
23
23
  serverapp = "$import_name.server:app"
24
24
  clientapp = "$import_name.client:app"
25
25
 
26
+ [tool.flwr.app.config]
27
+ num-server-rounds = "3"
28
+
26
29
  [tool.flwr.federations]
27
30
  default = "localhost"
28
31
 
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
  name = "$package_name"
7
7
  version = "1.0.0"
8
8
  description = ""
9
- license = { text = "Apache License (2.0)" }
9
+ license = "Apache-2.0"
10
10
  dependencies = [
11
11
  "flwr[simulation]>=1.9.0,<2.0",
12
12
  "flwr-datasets[vision]>=0.0.2,<1.0.0",
@@ -16,13 +16,16 @@ dependencies = [
16
16
  [tool.hatch.build.targets.wheel]
17
17
  packages = ["."]
18
18
 
19
- [tool.flwr]
19
+ [tool.flwr.app]
20
20
  publisher = "$username"
21
21
 
22
- [tool.flwr.components]
22
+ [tool.flwr.app.components]
23
23
  serverapp = "$import_name.server:app"
24
24
  clientapp = "$import_name.client:app"
25
25
 
26
+ [tool.flwr.app.config]
27
+ num-server-rounds = "3"
28
+
26
29
  [tool.flwr.federations]
27
30
  default = "localhost"
28
31
 
flwr/cli/run/run.py CHANGED
@@ -14,6 +14,7 @@
14
14
  # ==============================================================================
15
15
  """Flower command line interface `run` command."""
16
16
 
17
+ import subprocess
17
18
  import sys
18
19
  from logging import DEBUG
19
20
  from pathlib import Path
@@ -29,7 +30,6 @@ from flwr.common.grpc import GRPC_MAX_MESSAGE_LENGTH, create_channel
29
30
  from flwr.common.logger import log
30
31
  from flwr.proto.exec_pb2 import StartRunRequest # pylint: disable=E0611
31
32
  from flwr.proto.exec_pb2_grpc import ExecStub
32
- from flwr.simulation.run_simulation import _run_simulation
33
33
 
34
34
 
35
35
  # pylint: disable-next=too-many-locals
@@ -107,7 +107,7 @@ def run(
107
107
  if "address" in federation:
108
108
  _run_with_superexec(federation, directory, config_overrides)
109
109
  else:
110
- _run_without_superexec(config, federation, federation_name)
110
+ _run_without_superexec(directory, federation, federation_name, config_overrides)
111
111
 
112
112
 
113
113
  def _run_with_superexec(
@@ -169,11 +169,11 @@ def _run_with_superexec(
169
169
 
170
170
 
171
171
  def _run_without_superexec(
172
- config: Dict[str, Any], federation: Dict[str, Any], federation_name: str
172
+ app_path: Optional[Path],
173
+ federation: Dict[str, Any],
174
+ federation_name: str,
175
+ config_overrides: Optional[str],
173
176
  ) -> None:
174
- server_app_ref = config["tool"]["flwr"]["components"]["serverapp"]
175
- client_app_ref = config["tool"]["flwr"]["components"]["clientapp"]
176
-
177
177
  try:
178
178
  num_supernodes = federation["options"]["num-supernodes"]
179
179
  except KeyError as err:
@@ -188,8 +188,20 @@ def _run_without_superexec(
188
188
  )
189
189
  raise typer.Exit(code=1) from err
190
190
 
191
- _run_simulation(
192
- server_app_attr=server_app_ref,
193
- client_app_attr=client_app_ref,
194
- num_supernodes=num_supernodes,
191
+ command = [
192
+ "flower-simulation",
193
+ "--app",
194
+ f"{app_path}",
195
+ "--num-supernodes",
196
+ f"{num_supernodes}",
197
+ ]
198
+
199
+ if config_overrides:
200
+ command.extend(["--run-config", f"{config_overrides}"])
201
+
202
+ # Run the simulation
203
+ subprocess.run(
204
+ command,
205
+ check=True,
206
+ text=True,
195
207
  )
flwr/client/app.py CHANGED
@@ -195,7 +195,7 @@ def _start_client_internal(
195
195
  ] = None,
196
196
  max_retries: Optional[int] = None,
197
197
  max_wait_time: Optional[float] = None,
198
- flwr_dir: Optional[Path] = None,
198
+ flwr_path: Optional[Path] = None,
199
199
  ) -> None:
200
200
  """Start a Flower client node which connects to a Flower server.
201
201
 
@@ -241,7 +241,7 @@ def _start_client_internal(
241
241
  The maximum duration before the client stops trying to
242
242
  connect to the server in case of connection error.
243
243
  If set to None, there is no limit to the total time.
244
- flwr_dir: Optional[Path] (default: None)
244
+ flwr_path: Optional[Path] (default: None)
245
245
  The fully resolved path containing installed Flower Apps.
246
246
  """
247
247
  if insecure is None:
@@ -402,7 +402,7 @@ def _start_client_internal(
402
402
 
403
403
  # Register context for this run
404
404
  node_state.register_context(
405
- run_id=run_id, run=runs[run_id], flwr_dir=flwr_dir
405
+ run_id=run_id, run=runs[run_id], flwr_path=flwr_path
406
406
  )
407
407
 
408
408
  # Retrieve context for this run
flwr/client/node_state.py CHANGED
@@ -20,7 +20,7 @@ from pathlib import Path
20
20
  from typing import Dict, Optional
21
21
 
22
22
  from flwr.common import Context, RecordSet
23
- from flwr.common.config import get_fused_config
23
+ from flwr.common.config import get_fused_config, get_fused_config_from_dir
24
24
  from flwr.common.typing import Run
25
25
 
26
26
 
@@ -48,11 +48,25 @@ class NodeState:
48
48
  self,
49
49
  run_id: int,
50
50
  run: Optional[Run] = None,
51
- flwr_dir: Optional[Path] = None,
51
+ flwr_path: Optional[Path] = None,
52
+ app_dir: Optional[str] = None,
52
53
  ) -> None:
53
54
  """Register new run context for this node."""
54
55
  if run_id not in self.run_infos:
55
- initial_run_config = get_fused_config(run, flwr_dir) if run else {}
56
+ initial_run_config = {}
57
+ if app_dir:
58
+ # Load from app directory
59
+ app_path = Path(app_dir)
60
+ if app_path.is_dir():
61
+ override_config = run.override_config if run else {}
62
+ initial_run_config = get_fused_config_from_dir(
63
+ app_path, override_config
64
+ )
65
+ else:
66
+ raise ValueError("The specified `app_dir` must be a directory.")
67
+ else:
68
+ # Load from .fab
69
+ initial_run_config = get_fused_config(run, flwr_path) if run else {}
56
70
  self.run_infos[run_id] = RunInfo(
57
71
  initial_run_config=initial_run_config,
58
72
  context=Context(
@@ -78,7 +78,7 @@ def run_supernode() -> None:
78
78
  max_retries=args.max_retries,
79
79
  max_wait_time=args.max_wait_time,
80
80
  node_config=parse_config_args(args.node_config),
81
- flwr_dir=get_flwr_dir(args.flwr_dir),
81
+ flwr_path=get_flwr_dir(args.flwr_dir),
82
82
  )
83
83
 
84
84
  # Graceful shutdown
@@ -248,7 +248,7 @@ def _get_load_client_app_fn(
248
248
  dir_path = Path(project_dir).absolute()
249
249
 
250
250
  # Set app reference
251
- client_app_ref = config["tool"]["flwr"]["components"]["clientapp"]
251
+ client_app_ref = config["tool"]["flwr"]["app"]["components"]["clientapp"]
252
252
 
253
253
  # Set sys.path
254
254
  nonlocal inserted_path
flwr/common/config.py CHANGED
@@ -86,6 +86,18 @@ def _fuse_dicts(
86
86
  return fused_dict
87
87
 
88
88
 
89
+ def get_fused_config_from_dir(
90
+ project_dir: Path, override_config: Dict[str, str]
91
+ ) -> Dict[str, str]:
92
+ """Merge the overrides from a given dict with the config from a Flower App."""
93
+ default_config = get_project_config(project_dir)["tool"]["flwr"]["app"].get(
94
+ "config", {}
95
+ )
96
+ flat_default_config = flatten_dict(default_config)
97
+
98
+ return _fuse_dicts(flat_default_config, override_config)
99
+
100
+
89
101
  def get_fused_config(run: Run, flwr_dir: Optional[Path]) -> Dict[str, str]:
90
102
  """Merge the overrides from a `Run` with the config from a FAB.
91
103
 
@@ -97,10 +109,7 @@ def get_fused_config(run: Run, flwr_dir: Optional[Path]) -> Dict[str, str]:
97
109
 
98
110
  project_dir = get_project_dir(run.fab_id, run.fab_version, flwr_dir)
99
111
 
100
- default_config = get_project_config(project_dir)["tool"]["flwr"].get("config", {})
101
- flat_default_config = flatten_dict(default_config)
102
-
103
- return _fuse_dicts(flat_default_config, run.override_config)
112
+ return get_fused_config_from_dir(project_dir, run.override_config)
104
113
 
105
114
 
106
115
  def flatten_dict(raw_dict: Dict[str, Any], parent_key: str = "") -> Dict[str, str]:
@@ -186,7 +186,7 @@ def run_server_app() -> None: # pylint: disable=too-many-branches
186
186
  run_ = driver.run
187
187
  server_app_dir = str(get_project_dir(run_.fab_id, run_.fab_version, flwr_dir))
188
188
  config = get_project_config(server_app_dir)
189
- server_app_attr = config["tool"]["flwr"]["components"]["serverapp"]
189
+ server_app_attr = config["tool"]["flwr"]["app"]["components"]["serverapp"]
190
190
  server_app_run_config = get_fused_config(run_, flwr_dir)
191
191
  else:
192
192
  # User provided `server-app`, but not `--run-id`
@@ -61,7 +61,9 @@ def _register_nodes(
61
61
 
62
62
 
63
63
  def _register_node_states(
64
- nodes_mapping: NodeToPartitionMapping, run: Run
64
+ nodes_mapping: NodeToPartitionMapping,
65
+ run: Run,
66
+ app_dir: Optional[str] = None,
65
67
  ) -> Dict[int, NodeState]:
66
68
  """Create NodeState objects and pre-register the context for the run."""
67
69
  node_states: Dict[int, NodeState] = {}
@@ -76,7 +78,9 @@ def _register_node_states(
76
78
  )
77
79
 
78
80
  # Pre-register Context objects
79
- node_states[node_id].register_context(run_id=run.run_id, run=run)
81
+ node_states[node_id].register_context(
82
+ run_id=run.run_id, run=run, app_dir=app_dir
83
+ )
80
84
 
81
85
  return node_states
82
86
 
@@ -256,6 +260,7 @@ def start_vce(
256
260
  backend_name: str,
257
261
  backend_config_json_stream: str,
258
262
  app_dir: str,
263
+ is_app: bool,
259
264
  f_stop: threading.Event,
260
265
  run: Run,
261
266
  flwr_dir: Optional[str] = None,
@@ -309,7 +314,9 @@ def start_vce(
309
314
  )
310
315
 
311
316
  # Construct mapping of NodeStates
312
- node_states = _register_node_states(nodes_mapping=nodes_mapping, run=run)
317
+ node_states = _register_node_states(
318
+ nodes_mapping=nodes_mapping, run=run, app_dir=app_dir if is_app else None
319
+ )
313
320
 
314
321
  # Load backend config
315
322
  log(DEBUG, "Supported backends: %s", list(supported_backends.keys()))
@@ -18,14 +18,19 @@ import argparse
18
18
  import asyncio
19
19
  import json
20
20
  import logging
21
+ import sys
21
22
  import threading
22
23
  import traceback
24
+ from argparse import Namespace
23
25
  from logging import DEBUG, ERROR, INFO, WARNING
26
+ from pathlib import Path
24
27
  from time import sleep
25
- from typing import Dict, Optional
28
+ from typing import Dict, List, Optional
26
29
 
30
+ from flwr.cli.config_utils import load_and_validate
27
31
  from flwr.client import ClientApp
28
32
  from flwr.common import EventType, event, log
33
+ from flwr.common.config import get_fused_config_from_dir, parse_config_args
29
34
  from flwr.common.constant import RUN_ID_NUM_BYTES
30
35
  from flwr.common.logger import set_logger_propagation, update_console_handler
31
36
  from flwr.common.typing import Run
@@ -41,28 +46,129 @@ from flwr.simulation.ray_transport.utils import (
41
46
  )
42
47
 
43
48
 
49
+ def _check_args_do_not_interfere(args: Namespace) -> bool:
50
+ """Ensure decoupling of flags for different ways to start the simulation."""
51
+ mode_one_args = ["app", "run_config"]
52
+ mode_two_args = ["client_app", "server_app"]
53
+
54
+ def _resolve_message(conflict_keys: List[str]) -> str:
55
+ return ",".join([f"`--{key}`".replace("_", "-") for key in conflict_keys])
56
+
57
+ # When passing `--app`, `--app-dir` is ignored
58
+ if args.app and args.app_dir:
59
+ log(ERROR, "Either `--app` or `--app-dir` can be set, but not both.")
60
+ return False
61
+
62
+ if any(getattr(args, key) for key in mode_one_args):
63
+ if any(getattr(args, key) for key in mode_two_args):
64
+ log(
65
+ ERROR,
66
+ "Passing any of {%s} alongside with any of {%s}",
67
+ _resolve_message(mode_one_args),
68
+ _resolve_message(mode_two_args),
69
+ )
70
+ return False
71
+
72
+ if not args.app:
73
+ log(ERROR, "You need to pass --app")
74
+ return False
75
+
76
+ return True
77
+
78
+ # Ensure all args are set (required for the non-FAB mode of execution)
79
+ if not all(getattr(args, key) for key in mode_two_args):
80
+ log(
81
+ ERROR,
82
+ "Passing all of %s keys are required.",
83
+ _resolve_message(mode_two_args),
84
+ )
85
+ return False
86
+
87
+ return True
88
+
89
+
44
90
  # Entry point from CLI
91
+ # pylint: disable=too-many-locals
45
92
  def run_simulation_from_cli() -> None:
46
93
  """Run Simulation Engine from the CLI."""
47
94
  args = _parse_args_run_simulation().parse_args()
48
95
 
96
+ # We are supporting two modes for the CLI entrypoint:
97
+ # 1) Running an app dir containing a `pyproject.toml`
98
+ # 2) Running any ClientApp and SeverApp w/o pyproject.toml being present
99
+ # For 2), some CLI args are compulsory, but they are not required for 1)
100
+ # We first do these checks
101
+ args_check_pass = _check_args_do_not_interfere(args)
102
+ if not args_check_pass:
103
+ sys.exit("Simulation Engine cannot start.")
104
+
105
+ run_id = (
106
+ generate_rand_int_from_bytes(RUN_ID_NUM_BYTES)
107
+ if args.run_id is None
108
+ else args.run_id
109
+ )
110
+ if args.app:
111
+ # Mode 1
112
+ app_path = Path(args.app)
113
+ if not app_path.is_dir():
114
+ log(ERROR, "--app is not a directory")
115
+ sys.exit("Simulation Engine cannot start.")
116
+
117
+ # Load pyproject.toml
118
+ config, errors, warnings = load_and_validate(
119
+ app_path / "pyproject.toml", check_module=False
120
+ )
121
+ if errors:
122
+ raise ValueError(errors)
123
+
124
+ if warnings:
125
+ log(WARNING, warnings)
126
+
127
+ if config is None:
128
+ raise ValueError("Config extracted from FAB's pyproject.toml is not valid")
129
+
130
+ # Get ClientApp and SeverApp components
131
+ app_components = config["tool"]["flwr"]["app"]["components"]
132
+ client_app_attr = app_components["clientapp"]
133
+ server_app_attr = app_components["serverapp"]
134
+
135
+ override_config = parse_config_args(args.run_config)
136
+ fused_config = get_fused_config_from_dir(app_path, override_config)
137
+ app_dir = args.app
138
+ is_app = True
139
+
140
+ else:
141
+ # Mode 2
142
+ client_app_attr = args.client_app
143
+ server_app_attr = args.server_app
144
+ override_config = {}
145
+ fused_config = None
146
+ app_dir = args.app_dir
147
+ is_app = False
148
+
149
+ # Create run
150
+ run = Run(
151
+ run_id=run_id,
152
+ fab_id="",
153
+ fab_version="",
154
+ override_config=override_config,
155
+ )
156
+
49
157
  # Load JSON config
50
158
  backend_config_dict = json.loads(args.backend_config)
51
159
 
52
160
  _run_simulation(
53
- server_app_attr=args.server_app,
54
- client_app_attr=args.client_app,
161
+ server_app_attr=server_app_attr,
162
+ client_app_attr=client_app_attr,
55
163
  num_supernodes=args.num_supernodes,
56
164
  backend_name=args.backend,
57
165
  backend_config=backend_config_dict,
58
- app_dir=args.app_dir,
59
- run=(
60
- Run(run_id=args.run_id, fab_id="", fab_version="", override_config={})
61
- if args.run_id
62
- else None
63
- ),
166
+ app_dir=app_dir,
167
+ run=run,
64
168
  enable_tf_gpu_growth=args.enable_tf_gpu_growth,
65
169
  verbose_logging=args.verbose,
170
+ server_app_run_config=fused_config,
171
+ is_app=is_app,
66
172
  )
67
173
 
68
174
 
@@ -205,6 +311,7 @@ def _main_loop(
205
311
  backend_name: str,
206
312
  backend_config_stream: str,
207
313
  app_dir: str,
314
+ is_app: bool,
208
315
  enable_tf_gpu_growth: bool,
209
316
  run: Run,
210
317
  flwr_dir: Optional[str] = None,
@@ -212,6 +319,7 @@ def _main_loop(
212
319
  client_app_attr: Optional[str] = None,
213
320
  server_app: Optional[ServerApp] = None,
214
321
  server_app_attr: Optional[str] = None,
322
+ server_app_run_config: Optional[Dict[str, str]] = None,
215
323
  ) -> None:
216
324
  """Launch SuperLink with Simulation Engine, then ServerApp on a separate thread."""
217
325
  # Initialize StateFactory
@@ -225,7 +333,9 @@ def _main_loop(
225
333
  # Register run
226
334
  log(DEBUG, "Pre-registering run with id %s", run.run_id)
227
335
  state_factory.state().run_ids[run.run_id] = run # type: ignore
228
- server_app_run_config: Dict[str, str] = {}
336
+
337
+ if server_app_run_config is None:
338
+ server_app_run_config = {}
229
339
 
230
340
  # Initialize Driver
231
341
  driver = InMemoryDriver(run_id=run.run_id, state_factory=state_factory)
@@ -251,6 +361,7 @@ def _main_loop(
251
361
  backend_name=backend_name,
252
362
  backend_config_json_stream=backend_config_stream,
253
363
  app_dir=app_dir,
364
+ is_app=is_app,
254
365
  state_factory=state_factory,
255
366
  f_stop=f_stop,
256
367
  run=run,
@@ -284,11 +395,13 @@ def _run_simulation(
284
395
  backend_config: Optional[BackendConfig] = None,
285
396
  client_app_attr: Optional[str] = None,
286
397
  server_app_attr: Optional[str] = None,
398
+ server_app_run_config: Optional[Dict[str, str]] = None,
287
399
  app_dir: str = "",
288
400
  flwr_dir: Optional[str] = None,
289
401
  run: Optional[Run] = None,
290
402
  enable_tf_gpu_growth: bool = False,
291
403
  verbose_logging: bool = False,
404
+ is_app: bool = False,
292
405
  ) -> None:
293
406
  r"""Launch the Simulation Engine.
294
407
 
@@ -317,14 +430,18 @@ def _run_simulation(
317
430
  parameters. Values supported in <value> are those included by
318
431
  `flwr.common.typing.ConfigsRecordValues`.
319
432
 
320
- client_app_attr : str
433
+ client_app_attr : Optional[str]
321
434
  A path to a `ClientApp` module to be loaded: For example: `client:app` or
322
435
  `project.package.module:wrapper.app`."
323
436
 
324
- server_app_attr : str
437
+ server_app_attr : Optional[str]
325
438
  A path to a `ServerApp` module to be loaded: For example: `server:app` or
326
439
  `project.package.module:wrapper.app`."
327
440
 
441
+ server_app_run_config : Optional[Dict[str, str]]
442
+ Config dictionary that parameterizes the run config. It will be made accesible
443
+ to the ServerApp.
444
+
328
445
  app_dir : str
329
446
  Add specified directory to the PYTHONPATH and load `ClientApp` from there.
330
447
  (Default: current working directory.)
@@ -346,6 +463,11 @@ def _run_simulation(
346
463
  verbose_logging : bool (default: False)
347
464
  When disabled, only INFO, WARNING and ERROR log messages will be shown. If
348
465
  enabled, DEBUG-level logs will be displayed.
466
+
467
+ is_app : bool (default: False)
468
+ A flag that indicates whether the simulation is running an app or not. This is
469
+ needed in order to attempt loading an app's pyproject.toml when nodes register
470
+ a context object.
349
471
  """
350
472
  if backend_config is None:
351
473
  backend_config = {}
@@ -381,6 +503,7 @@ def _run_simulation(
381
503
  backend_name,
382
504
  backend_config_stream,
383
505
  app_dir,
506
+ is_app,
384
507
  enable_tf_gpu_growth,
385
508
  run,
386
509
  flwr_dir,
@@ -388,6 +511,7 @@ def _run_simulation(
388
511
  client_app_attr,
389
512
  server_app,
390
513
  server_app_attr,
514
+ server_app_run_config,
391
515
  )
392
516
  # Detect if there is an Asyncio event loop already running.
393
517
  # If yes, disable logger propagation. In environmnets
@@ -419,12 +543,10 @@ def _parse_args_run_simulation() -> argparse.ArgumentParser:
419
543
  )
420
544
  parser.add_argument(
421
545
  "--server-app",
422
- required=True,
423
546
  help="For example: `server:app` or `project.package.module:wrapper.app`",
424
547
  )
425
548
  parser.add_argument(
426
549
  "--client-app",
427
- required=True,
428
550
  help="For example: `client:app` or `project.package.module:wrapper.app`",
429
551
  )
430
552
  parser.add_argument(
@@ -433,6 +555,18 @@ def _parse_args_run_simulation() -> argparse.ArgumentParser:
433
555
  required=True,
434
556
  help="Number of simulated SuperNodes.",
435
557
  )
558
+ parser.add_argument(
559
+ "--app",
560
+ type=str,
561
+ default=None,
562
+ help="Path to a directory containing a FAB-like structure with a "
563
+ "pyproject.toml.",
564
+ )
565
+ parser.add_argument(
566
+ "--run-config",
567
+ default=None,
568
+ help="Override configuration key-value pairs.",
569
+ )
436
570
  parser.add_argument(
437
571
  "--backend",
438
572
  default="ray",
@@ -112,7 +112,7 @@ class SimulationEngine(Executor):
112
112
  )
113
113
 
114
114
  # Get ClientApp and SeverApp components
115
- flower_components = config["tool"]["flwr"]["components"]
115
+ flower_components = config["tool"]["flwr"]["app"]["components"]
116
116
  clientapp = flower_components["clientapp"]
117
117
  serverapp = flower_components["serverapp"]
118
118
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.10.0.dev20240715
3
+ Version: 1.10.0.dev20240716
4
4
  Summary: Flower: A Friendly Federated Learning Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0
@@ -43,6 +43,7 @@ Requires-Dist: ray (==2.10.0) ; (python_version >= "3.8" and python_version < "3
43
43
  Requires-Dist: requests (>=2.31.0,<3.0.0) ; extra == "rest"
44
44
  Requires-Dist: starlette (>=0.31.0,<0.32.0) ; extra == "rest"
45
45
  Requires-Dist: tomli (>=2.0.1,<3.0.0)
46
+ Requires-Dist: tomli-w (>=1.0.0,<2.0.0)
46
47
  Requires-Dist: typer[all] (>=0.9.0,<0.10.0)
47
48
  Requires-Dist: uvicorn[standard] (>=0.23.0,<0.24.0) ; extra == "rest"
48
49
  Project-URL: Documentation, https://flower.ai
@@ -1,10 +1,10 @@
1
1
  flwr/__init__.py,sha256=VmBWedrCxqmt4QvUHBLqyVEH6p7zaFMD_oCHerXHSVw,937
2
2
  flwr/cli/__init__.py,sha256=cZJVgozlkC6Ni2Hd_FAIrqefrkCGOV18fikToq-6iLw,720
3
3
  flwr/cli/app.py,sha256=FBcSrE35ll88VE11ib67qgsJe2GYDN25UswV9-cYcX8,1267
4
- flwr/cli/build.py,sha256=otFX_fKyMKFDQun9ku7VLK5S5vfmrCFmxxkvgKTa9QQ,4743
5
- flwr/cli/config_utils.py,sha256=bLkKx4irCvjMX2NU81Oax6OWJUPkjQqHefK_HqD9NgA,6587
4
+ flwr/cli/build.py,sha256=5igi2013fLH-TlR6MNpbxNEMaVqdBbts-E-WdY3JPsE,5167
5
+ flwr/cli/config_utils.py,sha256=6g5gxdEKSYVomwG9w8Pfa-RzMWdbV6XchdUpJ5rzDhg,6817
6
6
  flwr/cli/example.py,sha256=1bGDYll3BXQY2kRqSN-oICqS5n1b9m0g0RvXTopXHl4,2215
7
- flwr/cli/install.py,sha256=ve2Bimhxq-p7dXsWkzoGuto3uVcA356DeKCMlgHIL9k,6585
7
+ flwr/cli/install.py,sha256=DY2hWgpSDvGd8-HRVTMXg9dTKo-5COTkAnlE2BE6b60,6592
8
8
  flwr/cli/new/__init__.py,sha256=cQzK1WH4JP2awef1t2UQ2xjl1agVEz9rwutV18SWV1k,789
9
9
  flwr/cli/new/new.py,sha256=vSLxyWOtD33U8mTGeqOhw5OjeDpFStekAVLUH9GJq6k,9432
10
10
  flwr/cli/new/templates/__init__.py,sha256=4luU8RL-CK8JJCstQ_ON809W9bNTkY1l9zSaPKBkgwY,725
@@ -29,31 +29,31 @@ 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=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
32
+ flwr/cli/new/templates/app/code/server.hf.py.tpl,sha256=oYJpB0Y_F6nSgelf7NQ1BWZxxW5E6rBrQVmIQNQUPfc,605
33
+ flwr/cli/new/templates/app/code/server.jax.py.tpl,sha256=z9q6AHu_1vMRBVMlnDshPScV6GPTBdwuV49L5ekDVAI,522
34
+ flwr/cli/new/templates/app/code/server.mlx.py.tpl,sha256=2C4KeLiJMr2fQaXHXdpTf6fpHpeMRv4JWpxQJy_VI20,522
35
+ flwr/cli/new/templates/app/code/server.numpy.py.tpl,sha256=MYXAJDIDw5mRLSG-B3trJZoC3krPPWpvinYHeiUbAmA,524
36
+ flwr/cli/new/templates/app/code/server.pytorch.py.tpl,sha256=lBNcTJL01x90bjQ2ITv_pMFzzSSd1Pboy-72h7ejRk4,839
37
+ flwr/cli/new/templates/app/code/server.sklearn.py.tpl,sha256=1Zg0SNqLEGryCjhCs9hUNGIVWUQgmxVz4ImE8utH_Ck,626
38
+ flwr/cli/new/templates/app/code/server.tensorflow.py.tpl,sha256=IRhPa0JzlmAs8j55h2mp2VeT6tNXoRkmpNL7kBlaK5c,857
39
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
41
  flwr/cli/new/templates/app/code/task.mlx.py.tpl,sha256=nrfZ1aGOs_ayb70j7XdAmwFYa-rN10d9GIMIKLzctUE,2614
42
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
- flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl,sha256=7BojTJ1ePuRTANNcNBqLY7jgehvbRRawXJFiQhExYWk,742
45
- flwr/cli/new/templates/app/pyproject.hf.toml.tpl,sha256=NSXJ9qxjjuumg84bX8y7spoKaVHm9DUjofYBGbCBPDc,714
46
- flwr/cli/new/templates/app/pyproject.jax.toml.tpl,sha256=iIdKwB_FEA2oVtL8uSOj43uredcbRpEzy-rnEzCv-UM,606
47
- flwr/cli/new/templates/app/pyproject.mlx.toml.tpl,sha256=rq1mERo0-PFJHbIX7tv0B_uzhvnbrqXKkC7j93aGvjE,623
48
- flwr/cli/new/templates/app/pyproject.numpy.toml.tpl,sha256=C6XuAL9eJzp0SiDGOEQJQvW4qyrzEmiJRCwOKxq8xq4,561
49
- flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl,sha256=ApZ8sHILExQE20pVjA03_dI_wO-oHtg_C8qXVHzFU3g,630
50
- flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl,sha256=5-dv9fD-omZA9Y4qXX1_Hcaei_Lh5-p4jdTKvWafU7M,610
51
- flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=md9I4C86ZRF7p50hZhF5bw0Aax7vu_bvEldoaAkU5Uk,609
44
+ flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl,sha256=XBcU_XPYt7GecNjeBmD915fZGsF189QMb_IzFl4ATTA,777
45
+ flwr/cli/new/templates/app/pyproject.hf.toml.tpl,sha256=s0Dbgf4Dey7pJRPh6mVg2u1Kpk7Mif1yPyE7hm9-huI,749
46
+ flwr/cli/new/templates/app/pyproject.jax.toml.tpl,sha256=F9xgMke-YE2ufCad_LjdCp6ARkg8wjkPjfxd49bXR3c,643
47
+ flwr/cli/new/templates/app/pyproject.mlx.toml.tpl,sha256=0iXZzEByEjcJE2t2Bj2xflHzqsNoUzb9gFEwC5oUheg,658
48
+ flwr/cli/new/templates/app/pyproject.numpy.toml.tpl,sha256=_jJPAcAe_tdxea4ckMhCf6cWYM9d_-iuZiQqQ-XZq2o,596
49
+ flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl,sha256=9hCWjxh-EKkhXxv05HiIfqvKAxCUiVF1hpzPd7YCncA,665
50
+ flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl,sha256=NO2gKJWauwX95Ov3rl71TMAAKu7RPwOrAIQGnn7lwnY,645
51
+ flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl,sha256=vQAKtZnPy-PrB7ct9zuPgddiwsuRe-ifHqlTb0r_Jas,644
52
52
  flwr/cli/run/__init__.py,sha256=oCd6HmQDx-sqver1gecgx-uMA38BLTSiiKpl7RGNceg,789
53
- flwr/cli/run/run.py,sha256=PW_b1EprTB5NZyx0hAWWPFtpGR9tM7WJ9tlmDahU8J4,6818
53
+ flwr/cli/run/run.py,sha256=CIyv2q76SH6238eF_xRwqQua5fZCy_QXRYV0uImvTUM,6903
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=5v5EsA1zbViJAp998dCVRXvsyigZ-x3JEIKQ_fLeA48,26102
56
+ flwr/client/app.py,sha256=jobLLjUGV3pkSYpd2wGyzG8e1KZPk2_O47IjTsXnk6Y,26106
57
57
  flwr/client/client.py,sha256=Vp9UkOkoHdNfn6iMYZsj_5m_GICiFfUlKEVaLad-YhM,8183
58
58
  flwr/client/client_app.py,sha256=WcO4r6wrdfaus__3s22D2sYjfcptdgmVujUAYdNE6HU,10393
59
59
  flwr/client/dpfedavg_numpy_client.py,sha256=ylZ-LpBIKmL1HCiS8kq4pkp2QGalc8rYEzDHdRG3VRQ,7435
@@ -77,17 +77,17 @@ 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=_qgoNJXay25maUmcBwUcSVYpKTiW0RaoiWDSL4oFvJE,2864
80
+ flwr/client/node_state.py,sha256=4WUQv0_bcKKEs5Vk4j7YsHMpoxV8oAUAhBIY4gW--sM,3488
81
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
- flwr/client/supernode/app.py,sha256=LMJiuodmTUOAQ9MEbl4V2HjwBVJquJ9lZI38RGBh15Q,15598
86
+ flwr/client/supernode/app.py,sha256=R4lGlRhs4gMwWjdy_RXnAgxstvXj-SQoJhO7Zz8it1U,15606
87
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=W8EEfey1IHytkdXII3fTExc3uFxNm_Ysf35inG3cTkg,5000
90
+ flwr/common/config.py,sha256=SBQjCzJKyDyjn97GCmKW7u1iTgFKZAuRWQ4tAE9fWGA,5280
91
91
  flwr/common/constant.py,sha256=1XxuRezsr9fl3xvQNPR2kyFkwNeG_f5vZayv0PFh0kY,3012
92
92
  flwr/common/context.py,sha256=CQt4uzCDvCIr2WdkrWq0obAz92k2_ucXGrWtBZCxP_M,2256
93
93
  flwr/common/date.py,sha256=OcQuwpb2HxcblTqYm6H223ufop5UZw5N_fzalbpOVzY,891
@@ -187,7 +187,7 @@ flwr/server/driver/driver.py,sha256=NT_yaeit7_kZEIsCEqOWPID1GrVD3ywH4xZ2wtIh5lM,
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=PkQy67LRxKr1dqH--VUOLtrgLw8JVFVNNr0hFqiINh0,9492
190
+ flwr/server/run_serverapp.py,sha256=5_Upd-Qp9b_oM49v6RwJxR8ivcTb3Hh_pfhyO0EWAB0,9499
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
@@ -239,7 +239,7 @@ flwr/server/superlink/fleet/vce/__init__.py,sha256=36MHKiefnJeyjwMQzVUK4m06Ojon3
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
241
  flwr/server/superlink/fleet/vce/backend/raybackend.py,sha256=SnjZ1WOcrfMZNgiDdTHcFeXJqrY7UHx8kvO62mqU9S4,7489
242
- flwr/server/superlink/fleet/vce/vce_api.py,sha256=GVPxAgFR-K-hfWOphsZo-PFGmkLze4eytrLaE6TV6l8,12632
242
+ flwr/server/superlink/fleet/vce/vce_api.py,sha256=B_xnbaPKWuuovaNnkH21PYNrDKc0gtaWMQu_5kjYW5w,12780
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
@@ -262,16 +262,16 @@ flwr/simulation/ray_transport/__init__.py,sha256=wzcEEwUUlulnXsg6raCA1nGpP3LlAQD
262
262
  flwr/simulation/ray_transport/ray_actor.py,sha256=3j0HgzjrlYjnzdTRy8aA4Nf6VoUvxi1hGRQkGSU5z6c,19020
263
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
- flwr/simulation/run_simulation.py,sha256=wjN1spmdEmNZn06LDiuih1k3HHFKkHCKPbq-DieKw3A,17742
265
+ flwr/simulation/run_simulation.py,sha256=8qWEdgxeMtU8N3ZU1eeX6Upi8edOz88CeY7xpo0ZuMs,22173
266
266
  flwr/superexec/__init__.py,sha256=9h94ogLxi6eJ3bUuJYq3E3pApThSabTPiSmPAGlTkHE,800
267
267
  flwr/superexec/app.py,sha256=Zh9I64XfCoghWoT1k2DKDrcVCXIGOpw03v0WKCOg-mg,6402
268
268
  flwr/superexec/deployment.py,sha256=o_FYkB_vamBPjeVpPbqvzr4kBYID26sXVDrLO3Ac4R0,6130
269
269
  flwr/superexec/exec_grpc.py,sha256=vYbZyV89MuvYDH1XzVYHkKmGfOcU6FWh8rTcIJk2TIQ,1910
270
270
  flwr/superexec/exec_servicer.py,sha256=4R1f_9v0vly_bXpIYaXAeV1tO5LAy1AYygGGGNZmlQk,2194
271
271
  flwr/superexec/executor.py,sha256=5ua0AU2cfisyD79dosP-POF3w0FRH2I5Wko_PPKLWqU,2153
272
- flwr/superexec/simulation.py,sha256=flYwBU9lL3WV2jfGgp6bCjRNRlxmZ-ajkEHXab6HSug,5104
273
- flwr_nightly-1.10.0.dev20240715.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
274
- flwr_nightly-1.10.0.dev20240715.dist-info/METADATA,sha256=23pOsDu0OCNNq2lJKcXgdhg__CcotuXHOKOYTO9js04,15632
275
- flwr_nightly-1.10.0.dev20240715.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
276
- flwr_nightly-1.10.0.dev20240715.dist-info/entry_points.txt,sha256=7qBQcA-bDGDxnJmLd9FYqglFQubjCNqyg9M8a-lukps,336
277
- flwr_nightly-1.10.0.dev20240715.dist-info/RECORD,,
272
+ flwr/superexec/simulation.py,sha256=_FPxJ36yQNkJlC4jSdvXVinShmRBWS6gi3cZLP3mabQ,5111
273
+ flwr_nightly-1.10.0.dev20240716.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
274
+ flwr_nightly-1.10.0.dev20240716.dist-info/METADATA,sha256=xoYwajHb-KK8B3YvHaDIGAFOLD1VZRtodHu9ruPAt0w,15672
275
+ flwr_nightly-1.10.0.dev20240716.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
276
+ flwr_nightly-1.10.0.dev20240716.dist-info/entry_points.txt,sha256=7qBQcA-bDGDxnJmLd9FYqglFQubjCNqyg9M8a-lukps,336
277
+ flwr_nightly-1.10.0.dev20240716.dist-info/RECORD,,