flwr-nightly 1.11.0.dev20240827__py3-none-any.whl → 1.11.0.dev20240829__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/new.py +19 -0
  2. flwr/cli/new/templates/app/LICENSE.tpl +202 -0
  3. flwr/cli/new/templates/app/README.baseline.md.tpl +127 -0
  4. flwr/cli/new/templates/app/code/__init__.baseline.py.tpl +1 -0
  5. flwr/cli/new/templates/app/code/client.baseline.py.tpl +58 -0
  6. flwr/cli/new/templates/app/code/dataset.baseline.py.tpl +36 -0
  7. flwr/cli/new/templates/app/code/model.baseline.py.tpl +80 -0
  8. flwr/cli/new/templates/app/code/server.baseline.py.tpl +46 -0
  9. flwr/cli/new/templates/app/code/strategy.baseline.py.tpl +1 -0
  10. flwr/cli/new/templates/app/code/utils.baseline.py.tpl +1 -0
  11. flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +138 -0
  12. flwr/client/__init__.py +0 -4
  13. flwr/client/grpc_rere_client/client_interceptor.py +13 -4
  14. flwr/client/supernode/app.py +3 -1
  15. flwr/common/config.py +14 -11
  16. flwr/common/telemetry.py +36 -30
  17. flwr/server/__init__.py +0 -4
  18. flwr/server/compat/app.py +0 -5
  19. flwr/server/driver/grpc_driver.py +1 -3
  20. flwr/simulation/run_simulation.py +23 -6
  21. flwr/superexec/__init__.py +0 -6
  22. {flwr_nightly-1.11.0.dev20240827.dist-info → flwr_nightly-1.11.0.dev20240829.dist-info}/METADATA +1 -1
  23. {flwr_nightly-1.11.0.dev20240827.dist-info → flwr_nightly-1.11.0.dev20240829.dist-info}/RECORD +26 -16
  24. flwr_nightly-1.11.0.dev20240829.dist-info/entry_points.txt +10 -0
  25. flwr_nightly-1.11.0.dev20240827.dist-info/entry_points.txt +0 -10
  26. {flwr_nightly-1.11.0.dev20240827.dist-info → flwr_nightly-1.11.0.dev20240829.dist-info}/LICENSE +0 -0
  27. {flwr_nightly-1.11.0.dev20240827.dist-info → flwr_nightly-1.11.0.dev20240829.dist-info}/WHEEL +0 -0
@@ -0,0 +1,138 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "$package_name"
7
+ version = "1.0.0"
8
+ description = ""
9
+ license = "Apache-2.0"
10
+ dependencies = [
11
+ "flwr[simulation]>=1.11.0",
12
+ "flwr-datasets[vision]>=0.3.0",
13
+ "torch==2.2.1",
14
+ "torchvision==0.17.1",
15
+ ]
16
+
17
+ [tool.hatch.metadata]
18
+ allow-direct-references = true
19
+
20
+ [project.optional-dependencies]
21
+ dev = [
22
+ "isort==5.13.2",
23
+ "black==24.2.0",
24
+ "docformatter==1.7.5",
25
+ "mypy==1.8.0",
26
+ "pylint==3.2.6",
27
+ "flake8==5.0.4",
28
+ "pytest==6.2.4",
29
+ "pytest-watch==4.2.0",
30
+ "ruff==0.1.9",
31
+ "types-requests==2.31.0.20240125",
32
+ ]
33
+
34
+ [tool.isort]
35
+ profile = "black"
36
+ known_first_party = ["flwr"]
37
+
38
+ [tool.black]
39
+ line-length = 88
40
+ target-version = ["py38", "py39", "py310", "py311"]
41
+
42
+ [tool.pytest.ini_options]
43
+ minversion = "6.2"
44
+ addopts = "-qq"
45
+ testpaths = [
46
+ "flwr_baselines",
47
+ ]
48
+
49
+ [tool.mypy]
50
+ ignore_missing_imports = true
51
+ strict = false
52
+ plugins = "numpy.typing.mypy_plugin"
53
+
54
+ [tool.pylint."MESSAGES CONTROL"]
55
+ disable = "duplicate-code,too-few-public-methods,useless-import-alias"
56
+ good-names = "i,j,k,_,x,y,X,Y,K,N"
57
+ max-args = 10
58
+ max-attributes = 15
59
+ max-locals = 36
60
+ max-branches = 20
61
+ max-statements = 55
62
+
63
+ [tool.pylint.typecheck]
64
+ generated-members = "numpy.*, torch.*, tensorflow.*"
65
+
66
+ [[tool.mypy.overrides]]
67
+ module = [
68
+ "importlib.metadata.*",
69
+ "importlib_metadata.*",
70
+ ]
71
+ follow_imports = "skip"
72
+ follow_imports_for_stubs = true
73
+ disallow_untyped_calls = false
74
+
75
+ [[tool.mypy.overrides]]
76
+ module = "torch.*"
77
+ follow_imports = "skip"
78
+ follow_imports_for_stubs = true
79
+
80
+ [tool.docformatter]
81
+ wrap-summaries = 88
82
+ wrap-descriptions = 88
83
+
84
+ [tool.ruff]
85
+ target-version = "py38"
86
+ line-length = 88
87
+ select = ["D", "E", "F", "W", "B", "ISC", "C4"]
88
+ fixable = ["D", "E", "F", "W", "B", "ISC", "C4"]
89
+ ignore = ["B024", "B027"]
90
+ exclude = [
91
+ ".bzr",
92
+ ".direnv",
93
+ ".eggs",
94
+ ".git",
95
+ ".hg",
96
+ ".mypy_cache",
97
+ ".nox",
98
+ ".pants.d",
99
+ ".pytype",
100
+ ".ruff_cache",
101
+ ".svn",
102
+ ".tox",
103
+ ".venv",
104
+ "__pypackages__",
105
+ "_build",
106
+ "buck-out",
107
+ "build",
108
+ "dist",
109
+ "node_modules",
110
+ "venv",
111
+ "proto",
112
+ ]
113
+
114
+ [tool.ruff.pydocstyle]
115
+ convention = "numpy"
116
+
117
+ [tool.hatch.build.targets.wheel]
118
+ packages = ["."]
119
+
120
+ [tool.flwr.app]
121
+ publisher = "$username"
122
+
123
+ [tool.flwr.app.components]
124
+ serverapp = "$import_name.server_app:app"
125
+ clientapp = "$import_name.client_app:app"
126
+
127
+ [tool.flwr.app.config]
128
+ num-server-rounds = 3
129
+ fraction-fit = 0.5
130
+ local-epochs = 1
131
+
132
+ [tool.flwr.federations]
133
+ default = "local-simulation"
134
+
135
+ [tool.flwr.federations.local-simulation]
136
+ options.num-supernodes = 10
137
+ options.backend.client-resources.num-cpus = 2
138
+ options.backend.client-resources.num-gpus = 0.0
flwr/client/__init__.py CHANGED
@@ -20,8 +20,6 @@ from .app import start_numpy_client as start_numpy_client
20
20
  from .client import Client as Client
21
21
  from .client_app import ClientApp as ClientApp
22
22
  from .numpy_client import NumPyClient as NumPyClient
23
- from .supernode import run_client_app as run_client_app
24
- from .supernode import run_supernode as run_supernode
25
23
  from .typing import ClientFn as ClientFn
26
24
  from .typing import ClientFnExt as ClientFnExt
27
25
 
@@ -32,8 +30,6 @@ __all__ = [
32
30
  "ClientFnExt",
33
31
  "NumPyClient",
34
32
  "mod",
35
- "run_client_app",
36
- "run_supernode",
37
33
  "start_client",
38
34
  "start_numpy_client",
39
35
  ]
@@ -17,11 +17,13 @@
17
17
 
18
18
  import base64
19
19
  import collections
20
+ from logging import WARNING
20
21
  from typing import Any, Callable, Optional, Sequence, Tuple, Union
21
22
 
22
23
  import grpc
23
24
  from cryptography.hazmat.primitives.asymmetric import ec
24
25
 
26
+ from flwr.common.logger import log
25
27
  from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
26
28
  bytes_to_public_key,
27
29
  compute_hmac,
@@ -151,8 +153,15 @@ class AuthenticateClientInterceptor(grpc.UnaryUnaryClientInterceptor): # type:
151
153
  server_public_key_bytes = base64.urlsafe_b64decode(
152
154
  _get_value_from_tuples(_PUBLIC_KEY_HEADER, response.initial_metadata())
153
155
  )
154
- self.server_public_key = bytes_to_public_key(server_public_key_bytes)
155
- self.shared_secret = generate_shared_key(
156
- self.private_key, self.server_public_key
157
- )
156
+
157
+ if server_public_key_bytes != b"":
158
+ self.server_public_key = bytes_to_public_key(server_public_key_bytes)
159
+ else:
160
+ log(WARNING, "Can't get server public key, SuperLink may be offline")
161
+
162
+ if self.server_public_key is not None:
163
+ self.shared_secret = generate_shared_key(
164
+ self.private_key, self.server_public_key
165
+ )
166
+
158
167
  return response
@@ -77,7 +77,9 @@ def run_supernode() -> None:
77
77
  authentication_keys=authentication_keys,
78
78
  max_retries=args.max_retries,
79
79
  max_wait_time=args.max_wait_time,
80
- node_config=parse_config_args([args.node_config]),
80
+ node_config=parse_config_args(
81
+ [args.node_config] if args.node_config else args.node_config
82
+ ),
81
83
  isolation=args.isolation,
82
84
  supernode_address=args.supernode_address,
83
85
  )
flwr/common/config.py CHANGED
@@ -185,23 +185,26 @@ def parse_config_args(
185
185
  if config is None:
186
186
  return overrides
187
187
 
188
+ # Handle if .toml file is passed
189
+ if len(config) == 1 and config[0].endswith(".toml"):
190
+ with Path(config[0]).open("rb") as config_file:
191
+ overrides = flatten_dict(tomli.load(config_file))
192
+ return overrides
193
+
188
194
  # Regular expression to capture key-value pairs with possible quoted values
189
195
  pattern = re.compile(r"(\S+?)=(\'[^\']*\'|\"[^\"]*\"|\S+)")
190
196
 
191
197
  for config_line in config:
192
198
  if config_line:
193
- matches = pattern.findall(config_line)
199
+ # .toml files aren't allowed alongside other configs
200
+ if config_line.endswith(".toml"):
201
+ raise ValueError(
202
+ "TOML files cannot be passed alongside key-value pairs."
203
+ )
194
204
 
195
- if (
196
- len(matches) == 1
197
- and "=" not in matches[0][0]
198
- and matches[0][0].endswith(".toml")
199
- ):
200
- with Path(matches[0][0]).open("rb") as config_file:
201
- overrides = flatten_dict(tomli.load(config_file))
202
- else:
203
- toml_str = "\n".join(f"{k} = {v}" for k, v in matches)
204
- overrides.update(tomli.loads(toml_str))
205
+ matches = pattern.findall(config_line)
206
+ toml_str = "\n".join(f"{k} = {v}" for k, v in matches)
207
+ overrides.update(tomli.loads(toml_str))
205
208
 
206
209
  return overrides
207
210
 
flwr/common/telemetry.py CHANGED
@@ -132,53 +132,59 @@ class EventType(str, Enum):
132
132
  # Ping
133
133
  PING = auto()
134
134
 
135
- # Client: start_client
135
+ # --- LEGACY FUNCTIONS -------------------------------------------------------------
136
+
137
+ # Legacy: `start_client` function
136
138
  START_CLIENT_ENTER = auto()
137
139
  START_CLIENT_LEAVE = auto()
138
140
 
139
- # Server: start_server
141
+ # Legacy: `start_server` function
140
142
  START_SERVER_ENTER = auto()
141
143
  START_SERVER_LEAVE = auto()
142
144
 
143
- # Driver API
144
- RUN_DRIVER_API_ENTER = auto()
145
- RUN_DRIVER_API_LEAVE = auto()
145
+ # Legacy: `start_simulation` function
146
+ START_SIMULATION_ENTER = auto()
147
+ START_SIMULATION_LEAVE = auto()
146
148
 
147
- # Fleet API
148
- RUN_FLEET_API_ENTER = auto()
149
- RUN_FLEET_API_LEAVE = auto()
149
+ # --- `flwr` CLI -------------------------------------------------------------------
150
150
 
151
- # Driver API and Fleet API
152
- RUN_SUPERLINK_ENTER = auto()
153
- RUN_SUPERLINK_LEAVE = auto()
151
+ # Not yet implemented
154
152
 
155
- # Simulation
156
- START_SIMULATION_ENTER = auto()
157
- START_SIMULATION_LEAVE = auto()
153
+ # --- SuperExec --------------------------------------------------------------------
158
154
 
159
- # Driver: Driver
160
- DRIVER_CONNECT = auto()
161
- DRIVER_DISCONNECT = auto()
155
+ # SuperExec
156
+ RUN_SUPEREXEC_ENTER = auto()
157
+ RUN_SUPEREXEC_LEAVE = auto()
162
158
 
163
- # Driver: start_driver
164
- START_DRIVER_ENTER = auto()
165
- START_DRIVER_LEAVE = auto()
159
+ # --- Simulation Engine ------------------------------------------------------------
166
160
 
167
- # flower-client-app
168
- RUN_CLIENT_APP_ENTER = auto()
169
- RUN_CLIENT_APP_LEAVE = auto()
161
+ # CLI: flower-simulation
162
+ CLI_FLOWER_SIMULATION_ENTER = auto()
163
+ CLI_FLOWER_SIMULATION_LEAVE = auto()
170
164
 
171
- # flower-server-app
172
- RUN_SERVER_APP_ENTER = auto()
173
- RUN_SERVER_APP_LEAVE = auto()
165
+ # Python API: `run_simulation`
166
+ PYTHON_API_RUN_SIMULATION_ENTER = auto()
167
+ PYTHON_API_RUN_SIMULATION_LEAVE = auto()
174
168
 
175
- # SuperNode
169
+ # --- Deployment Engine ------------------------------------------------------------
170
+
171
+ # CLI: `flower-superlink`
172
+ RUN_SUPERLINK_ENTER = auto()
173
+ RUN_SUPERLINK_LEAVE = auto()
174
+
175
+ # CLI: `flower-supernode`
176
176
  RUN_SUPERNODE_ENTER = auto()
177
177
  RUN_SUPERNODE_LEAVE = auto()
178
178
 
179
- # SuperExec
180
- RUN_SUPEREXEC_ENTER = auto()
181
- RUN_SUPEREXEC_LEAVE = auto()
179
+ # CLI: `flower-server-app`
180
+ RUN_SERVER_APP_ENTER = auto()
181
+ RUN_SERVER_APP_LEAVE = auto()
182
+
183
+ # --- DEPRECATED -------------------------------------------------------------------
184
+
185
+ # [DEPRECATED] CLI: `flower-client-app`
186
+ RUN_CLIENT_APP_ENTER = auto()
187
+ RUN_CLIENT_APP_LEAVE = auto()
182
188
 
183
189
 
184
190
  # Use the ThreadPoolExecutor with max_workers=1 to have a queue
flwr/server/__init__.py CHANGED
@@ -17,14 +17,12 @@
17
17
 
18
18
  from . import strategy
19
19
  from . import workflow as workflow
20
- from .app import run_superlink as run_superlink
21
20
  from .app import start_server as start_server
22
21
  from .client_manager import ClientManager as ClientManager
23
22
  from .client_manager import SimpleClientManager as SimpleClientManager
24
23
  from .compat import LegacyContext as LegacyContext
25
24
  from .driver import Driver as Driver
26
25
  from .history import History as History
27
- from .run_serverapp import run_server_app as run_server_app
28
26
  from .server import Server as Server
29
27
  from .server_app import ServerApp as ServerApp
30
28
  from .server_config import ServerConfig as ServerConfig
@@ -40,8 +38,6 @@ __all__ = [
40
38
  "ServerAppComponents",
41
39
  "ServerConfig",
42
40
  "SimpleClientManager",
43
- "run_server_app",
44
- "run_superlink",
45
41
  "start_server",
46
42
  "strategy",
47
43
  "workflow",
flwr/server/compat/app.py CHANGED
@@ -18,7 +18,6 @@
18
18
  from logging import INFO
19
19
  from typing import Optional
20
20
 
21
- from flwr.common import EventType, event
22
21
  from flwr.common.logger import log
23
22
  from flwr.server.client_manager import ClientManager
24
23
  from flwr.server.history import History
@@ -65,8 +64,6 @@ def start_driver( # pylint: disable=too-many-arguments, too-many-locals
65
64
  hist : flwr.server.history.History
66
65
  Object containing training and evaluation metrics.
67
66
  """
68
- event(EventType.START_DRIVER_ENTER)
69
-
70
67
  # Initialize the Driver API server and config
71
68
  initialized_server, initialized_config = init_defaults(
72
69
  server=server,
@@ -96,6 +93,4 @@ def start_driver( # pylint: disable=too-many-arguments, too-many-locals
96
93
  f_stop.set()
97
94
  thread.join()
98
95
 
99
- event(EventType.START_SERVER_LEAVE)
100
-
101
96
  return hist
@@ -21,7 +21,7 @@ from typing import Iterable, List, Optional, cast
21
21
 
22
22
  import grpc
23
23
 
24
- from flwr.common import DEFAULT_TTL, EventType, Message, Metadata, RecordSet, event
24
+ from flwr.common import DEFAULT_TTL, Message, Metadata, RecordSet
25
25
  from flwr.common.grpc import create_channel
26
26
  from flwr.common.logger import log
27
27
  from flwr.common.serde import (
@@ -94,7 +94,6 @@ class GrpcDriver(Driver):
94
94
 
95
95
  This will not call GetRun.
96
96
  """
97
- event(EventType.DRIVER_CONNECT)
98
97
  if self._is_connected:
99
98
  log(WARNING, "Already connected")
100
99
  return
@@ -108,7 +107,6 @@ class GrpcDriver(Driver):
108
107
 
109
108
  def _disconnect(self) -> None:
110
109
  """Disconnect from the Driver API."""
111
- event(EventType.DRIVER_DISCONNECT)
112
110
  if not self._is_connected:
113
111
  log(DEBUG, "Already disconnected")
114
112
  return
@@ -109,6 +109,11 @@ def run_simulation_from_cli() -> None:
109
109
  """Run Simulation Engine from the CLI."""
110
110
  args = _parse_args_run_simulation().parse_args()
111
111
 
112
+ event(
113
+ EventType.CLI_FLOWER_SIMULATION_ENTER,
114
+ event_details={"backend": args.backend, "num-supernodes": args.num_supernodes},
115
+ )
116
+
112
117
  # Add warnings for deprecated server_app and client_app arguments
113
118
  if args.server_app:
114
119
  warn_deprecated_feature(
@@ -177,7 +182,9 @@ def run_simulation_from_cli() -> None:
177
182
  client_app_attr = app_components["clientapp"]
178
183
  server_app_attr = app_components["serverapp"]
179
184
 
180
- override_config = parse_config_args([args.run_config])
185
+ override_config = parse_config_args(
186
+ [args.run_config] if args.run_config else args.run_config
187
+ )
181
188
  fused_config = get_fused_config_from_dir(app_path, override_config)
182
189
  app_dir = args.app
183
190
  is_app = True
@@ -212,6 +219,7 @@ def run_simulation_from_cli() -> None:
212
219
  verbose_logging=args.verbose,
213
220
  server_app_run_config=fused_config,
214
221
  is_app=is_app,
222
+ exit_event=EventType.CLI_FLOWER_SIMULATION_LEAVE,
215
223
  )
216
224
 
217
225
 
@@ -265,6 +273,11 @@ def run_simulation(
265
273
  When disabled, only INFO, WARNING and ERROR log messages will be shown. If
266
274
  enabled, DEBUG-level logs will be displayed.
267
275
  """
276
+ event(
277
+ EventType.PYTHON_API_RUN_SIMULATION_ENTER,
278
+ event_details={"backend": backend_name, "num-supernodes": num_supernodes},
279
+ )
280
+
268
281
  if enable_tf_gpu_growth:
269
282
  warn_deprecated_feature_with_example(
270
283
  "Passing `enable_tf_gpu_growth=True` is deprecated.",
@@ -282,6 +295,7 @@ def run_simulation(
282
295
  backend_config=backend_config,
283
296
  enable_tf_gpu_growth=enable_tf_gpu_growth,
284
297
  verbose_logging=verbose_logging,
298
+ exit_event=EventType.PYTHON_API_RUN_SIMULATION_LEAVE,
285
299
  )
286
300
 
287
301
 
@@ -365,6 +379,7 @@ def _main_loop(
365
379
  is_app: bool,
366
380
  enable_tf_gpu_growth: bool,
367
381
  run: Run,
382
+ exit_event: EventType,
368
383
  flwr_dir: Optional[str] = None,
369
384
  client_app: Optional[ClientApp] = None,
370
385
  client_app_attr: Optional[str] = None,
@@ -372,7 +387,7 @@ def _main_loop(
372
387
  server_app_attr: Optional[str] = None,
373
388
  server_app_run_config: Optional[UserConfig] = None,
374
389
  ) -> None:
375
- """Launch SuperLink with Simulation Engine, then ServerApp on a separate thread."""
390
+ """Start ServerApp on a separate thread, then launch Simulation Engine."""
376
391
  # Initialize StateFactory
377
392
  state_factory = StateFactory(":flwr-in-memory-state:")
378
393
 
@@ -380,6 +395,7 @@ def _main_loop(
380
395
  # A Threading event to indicate if an exception was raised in the ServerApp thread
381
396
  server_app_thread_has_exception = threading.Event()
382
397
  serverapp_th = None
398
+ success = True
383
399
  try:
384
400
  # Register run
385
401
  log(DEBUG, "Pre-registering run with id %s", run.run_id)
@@ -403,8 +419,7 @@ def _main_loop(
403
419
  enable_tf_gpu_growth=enable_tf_gpu_growth,
404
420
  )
405
421
 
406
- # SuperLink with Simulation Engine
407
- event(EventType.RUN_SUPERLINK_ENTER)
422
+ # Start Simulation Engine
408
423
  vce.start_vce(
409
424
  num_supernodes=num_supernodes,
410
425
  client_app_attr=client_app_attr,
@@ -422,13 +437,13 @@ def _main_loop(
422
437
  except Exception as ex:
423
438
  log(ERROR, "An exception occurred !! %s", ex)
424
439
  log(ERROR, traceback.format_exc())
440
+ success = False
425
441
  raise RuntimeError("An error was encountered. Ending simulation.") from ex
426
442
 
427
443
  finally:
428
444
  # Trigger stop event
429
445
  f_stop.set()
430
-
431
- event(EventType.RUN_SUPERLINK_LEAVE)
446
+ event(exit_event, event_details={"success": success})
432
447
  if serverapp_th:
433
448
  serverapp_th.join()
434
449
  if server_app_thread_has_exception.is_set():
@@ -440,6 +455,7 @@ def _main_loop(
440
455
  # pylint: disable=too-many-arguments,too-many-locals
441
456
  def _run_simulation(
442
457
  num_supernodes: int,
458
+ exit_event: EventType,
443
459
  client_app: Optional[ClientApp] = None,
444
460
  server_app: Optional[ServerApp] = None,
445
461
  backend_name: str = "ray",
@@ -506,6 +522,7 @@ def _run_simulation(
506
522
  is_app,
507
523
  enable_tf_gpu_growth,
508
524
  run,
525
+ exit_event,
509
526
  flwr_dir,
510
527
  client_app,
511
528
  client_app_attr,
@@ -13,9 +13,3 @@
13
13
  # limitations under the License.
14
14
  # ==============================================================================
15
15
  """Flower SuperExec service."""
16
-
17
- from .app import run_superexec as run_superexec
18
-
19
- __all__ = [
20
- "run_superexec",
21
- ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: flwr-nightly
3
- Version: 1.11.0.dev20240827
3
+ Version: 1.11.0.dev20240829
4
4
  Summary: Flower: A Friendly Federated Learning Framework
5
5
  Home-page: https://flower.ai
6
6
  License: Apache-2.0