flwr 1.12.0__py3-none-any.whl → 1.13.1__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.
Files changed (110) hide show
  1. flwr/cli/app.py +2 -0
  2. flwr/cli/build.py +2 -2
  3. flwr/cli/config_utils.py +97 -0
  4. flwr/cli/install.py +0 -16
  5. flwr/cli/log.py +63 -97
  6. flwr/cli/ls.py +228 -0
  7. flwr/cli/new/new.py +23 -13
  8. flwr/cli/new/templates/app/README.md.tpl +11 -0
  9. flwr/cli/new/templates/app/code/flwr_tune/dataset.py.tpl +1 -1
  10. flwr/cli/new/templates/app/pyproject.baseline.toml.tpl +1 -1
  11. flwr/cli/new/templates/app/pyproject.flowertune.toml.tpl +2 -1
  12. flwr/cli/new/templates/app/pyproject.huggingface.toml.tpl +1 -1
  13. flwr/cli/new/templates/app/pyproject.jax.toml.tpl +1 -1
  14. flwr/cli/new/templates/app/pyproject.mlx.toml.tpl +1 -1
  15. flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +1 -1
  16. flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +1 -1
  17. flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +1 -1
  18. flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +2 -2
  19. flwr/cli/run/run.py +37 -89
  20. flwr/client/app.py +73 -34
  21. flwr/client/clientapp/app.py +58 -37
  22. flwr/client/grpc_rere_client/connection.py +7 -12
  23. flwr/client/nodestate/__init__.py +25 -0
  24. flwr/client/nodestate/in_memory_nodestate.py +38 -0
  25. flwr/client/nodestate/nodestate.py +30 -0
  26. flwr/client/nodestate/nodestate_factory.py +37 -0
  27. flwr/client/rest_client/connection.py +4 -14
  28. flwr/client/{node_state.py → run_info_store.py} +4 -3
  29. flwr/client/supernode/app.py +34 -58
  30. flwr/common/args.py +152 -0
  31. flwr/common/config.py +10 -0
  32. flwr/common/constant.py +59 -7
  33. flwr/common/context.py +9 -4
  34. flwr/common/date.py +21 -3
  35. flwr/common/grpc.py +4 -1
  36. flwr/common/logger.py +108 -1
  37. flwr/common/object_ref.py +47 -16
  38. flwr/common/serde.py +34 -0
  39. flwr/common/telemetry.py +0 -6
  40. flwr/common/typing.py +32 -2
  41. flwr/proto/exec_pb2.py +23 -17
  42. flwr/proto/exec_pb2.pyi +58 -22
  43. flwr/proto/exec_pb2_grpc.py +34 -0
  44. flwr/proto/exec_pb2_grpc.pyi +13 -0
  45. flwr/proto/log_pb2.py +29 -0
  46. flwr/proto/log_pb2.pyi +39 -0
  47. flwr/proto/log_pb2_grpc.py +4 -0
  48. flwr/proto/log_pb2_grpc.pyi +4 -0
  49. flwr/proto/message_pb2.py +8 -8
  50. flwr/proto/message_pb2.pyi +4 -1
  51. flwr/proto/run_pb2.py +32 -27
  52. flwr/proto/run_pb2.pyi +44 -1
  53. flwr/proto/serverappio_pb2.py +52 -0
  54. flwr/proto/{driver_pb2.pyi → serverappio_pb2.pyi} +54 -0
  55. flwr/proto/serverappio_pb2_grpc.py +376 -0
  56. flwr/proto/serverappio_pb2_grpc.pyi +147 -0
  57. flwr/proto/simulationio_pb2.py +38 -0
  58. flwr/proto/simulationio_pb2.pyi +65 -0
  59. flwr/proto/simulationio_pb2_grpc.py +205 -0
  60. flwr/proto/simulationio_pb2_grpc.pyi +81 -0
  61. flwr/server/app.py +297 -162
  62. flwr/server/driver/driver.py +15 -1
  63. flwr/server/driver/grpc_driver.py +89 -50
  64. flwr/server/driver/inmemory_driver.py +6 -16
  65. flwr/server/run_serverapp.py +11 -235
  66. flwr/server/{superlink/state → serverapp}/__init__.py +3 -9
  67. flwr/server/serverapp/app.py +234 -0
  68. flwr/server/strategy/aggregate.py +4 -4
  69. flwr/server/strategy/fedadam.py +11 -1
  70. flwr/server/superlink/driver/__init__.py +1 -1
  71. flwr/server/superlink/driver/{driver_grpc.py → serverappio_grpc.py} +19 -16
  72. flwr/server/superlink/driver/{driver_servicer.py → serverappio_servicer.py} +125 -39
  73. flwr/server/superlink/fleet/grpc_adapter/grpc_adapter_servicer.py +4 -2
  74. flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +2 -2
  75. flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +4 -2
  76. flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +2 -2
  77. flwr/server/superlink/fleet/message_handler/message_handler.py +7 -7
  78. flwr/server/superlink/fleet/rest_rere/rest_api.py +10 -9
  79. flwr/server/superlink/fleet/vce/vce_api.py +23 -23
  80. flwr/server/superlink/linkstate/__init__.py +28 -0
  81. flwr/server/superlink/{state/in_memory_state.py → linkstate/in_memory_linkstate.py} +237 -64
  82. flwr/server/superlink/{state/state.py → linkstate/linkstate.py} +166 -22
  83. flwr/server/superlink/{state/state_factory.py → linkstate/linkstate_factory.py} +9 -9
  84. flwr/server/superlink/{state/sqlite_state.py → linkstate/sqlite_linkstate.py} +383 -174
  85. flwr/server/superlink/linkstate/utils.py +389 -0
  86. flwr/server/superlink/simulation/__init__.py +15 -0
  87. flwr/server/superlink/simulation/simulationio_grpc.py +65 -0
  88. flwr/server/superlink/simulation/simulationio_servicer.py +153 -0
  89. flwr/simulation/__init__.py +5 -1
  90. flwr/simulation/app.py +236 -347
  91. flwr/simulation/legacy_app.py +402 -0
  92. flwr/simulation/ray_transport/ray_client_proxy.py +2 -2
  93. flwr/simulation/run_simulation.py +56 -141
  94. flwr/simulation/simulationio_connection.py +86 -0
  95. flwr/superexec/app.py +6 -134
  96. flwr/superexec/deployment.py +70 -69
  97. flwr/superexec/exec_grpc.py +15 -8
  98. flwr/superexec/exec_servicer.py +65 -65
  99. flwr/superexec/executor.py +26 -7
  100. flwr/superexec/simulation.py +62 -150
  101. {flwr-1.12.0.dist-info → flwr-1.13.1.dist-info}/METADATA +9 -7
  102. {flwr-1.12.0.dist-info → flwr-1.13.1.dist-info}/RECORD +105 -85
  103. {flwr-1.12.0.dist-info → flwr-1.13.1.dist-info}/entry_points.txt +2 -0
  104. flwr/client/node_state_tests.py +0 -66
  105. flwr/proto/driver_pb2.py +0 -42
  106. flwr/proto/driver_pb2_grpc.py +0 -239
  107. flwr/proto/driver_pb2_grpc.pyi +0 -94
  108. flwr/server/superlink/state/utils.py +0 -148
  109. {flwr-1.12.0.dist-info → flwr-1.13.1.dist-info}/LICENSE +0 -0
  110. {flwr-1.12.0.dist-info → flwr-1.13.1.dist-info}/WHEEL +0 -0
@@ -15,6 +15,7 @@
15
15
  """Flower ClientApp process."""
16
16
 
17
17
  import argparse
18
+ import sys
18
19
  import time
19
20
  from logging import DEBUG, ERROR, INFO
20
21
  from typing import Optional
@@ -24,7 +25,9 @@ import grpc
24
25
  from flwr.cli.install import install_from_fab
25
26
  from flwr.client.client_app import ClientApp, LoadClientAppError
26
27
  from flwr.common import Context, Message
27
- from flwr.common.constant import ErrorCode
28
+ from flwr.common.args import add_args_flwr_app_common
29
+ from flwr.common.config import get_flwr_dir
30
+ from flwr.common.constant import CLIENTAPPIO_API_DEFAULT_CLIENT_ADDRESS, ErrorCode
28
31
  from flwr.common.grpc import create_channel
29
32
  from flwr.common.logger import log
30
33
  from flwr.common.message import Error
@@ -54,32 +57,30 @@ from .utils import get_load_client_app_fn
54
57
 
55
58
  def flwr_clientapp() -> None:
56
59
  """Run process-isolated Flower ClientApp."""
57
- log(INFO, "Starting Flower ClientApp")
58
-
59
- parser = argparse.ArgumentParser(
60
- description="Run a Flower ClientApp",
61
- )
62
- parser.add_argument(
63
- "--supernode",
64
- type=str,
65
- help="Address of SuperNode ClientAppIo gRPC servicer",
66
- )
67
- parser.add_argument(
68
- "--token",
69
- type=int,
70
- required=False,
71
- help="Unique token generated by SuperNode for each ClientApp execution",
72
- )
73
- args = parser.parse_args()
60
+ args = _parse_args_run_flwr_clientapp().parse_args()
61
+ if not args.insecure:
62
+ log(
63
+ ERROR,
64
+ "flwr-clientapp does not support TLS yet. "
65
+ "Please use the '--insecure' flag.",
66
+ )
67
+ sys.exit(1)
74
68
 
69
+ log(INFO, "Starting Flower ClientApp")
75
70
  log(
76
71
  DEBUG,
77
- "Staring isolated `ClientApp` connected to SuperNode ClientAppIo at %s "
72
+ "Starting isolated `ClientApp` connected to SuperNode's ClientAppIo API at %s "
78
73
  "with token %s",
79
- args.supernode,
74
+ args.clientappio_api_address,
80
75
  args.token,
81
76
  )
82
- run_clientapp(supernode=args.supernode, token=args.token)
77
+ run_clientapp(
78
+ clientappio_api_address=args.clientappio_api_address,
79
+ run_once=(args.token is not None),
80
+ token=args.token,
81
+ flwr_dir=args.flwr_dir,
82
+ certificates=None,
83
+ )
83
84
 
84
85
 
85
86
  def on_channel_state_change(channel_connectivity: str) -> None:
@@ -88,28 +89,26 @@ def on_channel_state_change(channel_connectivity: str) -> None:
88
89
 
89
90
 
90
91
  def run_clientapp( # pylint: disable=R0914
91
- supernode: str,
92
+ clientappio_api_address: str,
93
+ run_once: bool,
92
94
  token: Optional[int] = None,
95
+ flwr_dir: Optional[str] = None,
96
+ certificates: Optional[bytes] = None,
93
97
  ) -> None:
94
- """Run Flower ClientApp process.
95
-
96
- Parameters
97
- ----------
98
- supernode : str
99
- Address of SuperNode
100
- token : Optional[int] (default: None)
101
- Unique SuperNode token for ClientApp-SuperNode authentication
102
- """
98
+ """Run Flower ClientApp process."""
103
99
  channel = create_channel(
104
- server_address=supernode,
105
- insecure=True,
100
+ server_address=clientappio_api_address,
101
+ insecure=(certificates is None),
102
+ root_certificates=certificates,
106
103
  )
107
104
  channel.subscribe(on_channel_state_change)
108
105
 
106
+ # Resolve directory where FABs are installed
107
+ flwr_dir_ = get_flwr_dir(flwr_dir)
108
+
109
109
  try:
110
110
  stub = ClientAppIoStub(channel)
111
111
 
112
- only_once = token is not None
113
112
  while True:
114
113
  # If token is not set, loop until token is received from SuperNode
115
114
  while token is None:
@@ -122,13 +121,13 @@ def run_clientapp( # pylint: disable=R0914
122
121
  # Install FAB, if provided
123
122
  if fab:
124
123
  log(DEBUG, "Flower ClientApp starts FAB installation.")
125
- install_from_fab(fab.content, flwr_dir=None, skip_prompt=True)
124
+ install_from_fab(fab.content, flwr_dir=flwr_dir_, skip_prompt=True)
126
125
 
127
126
  load_client_app_fn = get_load_client_app_fn(
128
127
  default_app_ref="",
129
128
  app_path=None,
130
129
  multi_app=True,
131
- flwr_dir=None,
130
+ flwr_dir=str(flwr_dir_),
132
131
  )
133
132
 
134
133
  try:
@@ -170,7 +169,7 @@ def run_clientapp( # pylint: disable=R0914
170
169
 
171
170
  # Stop the loop if `flwr-clientapp` is expected to process only a single
172
171
  # message
173
- if only_once:
172
+ if run_once:
174
173
  break
175
174
 
176
175
  except KeyboardInterrupt:
@@ -233,3 +232,25 @@ def push_message(
233
232
  except grpc.RpcError as e:
234
233
  log(ERROR, "[PushClientAppOutputs] gRPC error occurred: %s", str(e))
235
234
  raise e
235
+
236
+
237
+ def _parse_args_run_flwr_clientapp() -> argparse.ArgumentParser:
238
+ """Parse flwr-clientapp command line arguments."""
239
+ parser = argparse.ArgumentParser(
240
+ description="Run a Flower ClientApp",
241
+ )
242
+ parser.add_argument(
243
+ "--clientappio-api-address",
244
+ default=CLIENTAPPIO_API_DEFAULT_CLIENT_ADDRESS,
245
+ type=str,
246
+ help="Address of SuperNode's ClientAppIo API (IPv4, IPv6, or a domain name)."
247
+ f"By default, it is set to {CLIENTAPPIO_API_DEFAULT_CLIENT_ADDRESS}.",
248
+ )
249
+ parser.add_argument(
250
+ "--token",
251
+ type=int,
252
+ required=False,
253
+ help="Unique token generated by SuperNode for each ClientApp execution",
254
+ )
255
+ add_args_flwr_app_common(parser=parser)
256
+ return parser
@@ -41,11 +41,7 @@ from flwr.common.grpc import create_channel
41
41
  from flwr.common.logger import log
42
42
  from flwr.common.message import Message, Metadata
43
43
  from flwr.common.retry_invoker import RetryInvoker
44
- from flwr.common.serde import (
45
- message_from_taskins,
46
- message_to_taskres,
47
- user_config_from_proto,
48
- )
44
+ from flwr.common.serde import message_from_taskins, message_to_taskres, run_from_proto
49
45
  from flwr.common.typing import Fab, Run
50
46
  from flwr.proto.fab_pb2 import GetFabRequest, GetFabResponse # pylint: disable=E0611
51
47
  from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
@@ -159,6 +155,11 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
159
155
  ping_thread: Optional[threading.Thread] = None
160
156
  ping_stop_event = threading.Event()
161
157
 
158
+ # Restrict retries to cases where the status code is UNAVAILABLE
159
+ retry_invoker.should_giveup = (
160
+ lambda e: e.code() != grpc.StatusCode.UNAVAILABLE # type: ignore
161
+ )
162
+
162
163
  ###########################################################################
163
164
  # ping/create_node/delete_node/receive/send/get_run functions
164
165
  ###########################################################################
@@ -287,13 +288,7 @@ def grpc_request_response( # pylint: disable=R0913,R0914,R0915,R0917
287
288
  )
288
289
 
289
290
  # Return fab_id and fab_version
290
- return Run(
291
- run_id,
292
- get_run_response.run.fab_id,
293
- get_run_response.run.fab_version,
294
- get_run_response.run.fab_hash,
295
- user_config_from_proto(get_run_response.run.override_config),
296
- )
291
+ return run_from_proto(get_run_response.run)
297
292
 
298
293
  def get_fab(fab_hash: str) -> Fab:
299
294
  # Call FleetAPI
@@ -0,0 +1,25 @@
1
+ # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """Flower NodeState."""
16
+
17
+ from .in_memory_nodestate import InMemoryNodeState as InMemoryNodeState
18
+ from .nodestate import NodeState as NodeState
19
+ from .nodestate_factory import NodeStateFactory as NodeStateFactory
20
+
21
+ __all__ = [
22
+ "InMemoryNodeState",
23
+ "NodeState",
24
+ "NodeStateFactory",
25
+ ]
@@ -0,0 +1,38 @@
1
+ # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """In-memory NodeState implementation."""
16
+
17
+
18
+ from typing import Optional
19
+
20
+ from flwr.client.nodestate.nodestate import NodeState
21
+
22
+
23
+ class InMemoryNodeState(NodeState):
24
+ """In-memory NodeState implementation."""
25
+
26
+ def __init__(self) -> None:
27
+ # Store node_id
28
+ self.node_id: Optional[int] = None
29
+
30
+ def set_node_id(self, node_id: Optional[int]) -> None:
31
+ """Set the node ID."""
32
+ self.node_id = node_id
33
+
34
+ def get_node_id(self) -> int:
35
+ """Get the node ID."""
36
+ if self.node_id is None:
37
+ raise ValueError("Node ID not set")
38
+ return self.node_id
@@ -0,0 +1,30 @@
1
+ # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """Abstract base class NodeState."""
16
+
17
+ import abc
18
+ from typing import Optional
19
+
20
+
21
+ class NodeState(abc.ABC):
22
+ """Abstract NodeState."""
23
+
24
+ @abc.abstractmethod
25
+ def set_node_id(self, node_id: Optional[int]) -> None:
26
+ """Set the node ID."""
27
+
28
+ @abc.abstractmethod
29
+ def get_node_id(self) -> int:
30
+ """Get the node ID."""
@@ -0,0 +1,37 @@
1
+ # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ==============================================================================
15
+ """Factory class that creates NodeState instances."""
16
+
17
+ import threading
18
+ from typing import Optional
19
+
20
+ from .in_memory_nodestate import InMemoryNodeState
21
+ from .nodestate import NodeState
22
+
23
+
24
+ class NodeStateFactory:
25
+ """Factory class that creates NodeState instances."""
26
+
27
+ def __init__(self) -> None:
28
+ self.state_instance: Optional[NodeState] = None
29
+ self.lock = threading.RLock()
30
+
31
+ def state(self) -> NodeState:
32
+ """Return a State instance and create it, if necessary."""
33
+ # Lock access to NodeStateFactory to prevent returning different instances
34
+ with self.lock:
35
+ if self.state_instance is None:
36
+ self.state_instance = InMemoryNodeState()
37
+ return self.state_instance
@@ -41,11 +41,7 @@ from flwr.common.constant import (
41
41
  from flwr.common.logger import log
42
42
  from flwr.common.message import Message, Metadata
43
43
  from flwr.common.retry_invoker import RetryInvoker
44
- from flwr.common.serde import (
45
- message_from_taskins,
46
- message_to_taskres,
47
- user_config_from_proto,
48
- )
44
+ from flwr.common.serde import message_from_taskins, message_to_taskres, run_from_proto
49
45
  from flwr.common.typing import Fab, Run
50
46
  from flwr.proto.fab_pb2 import GetFabRequest, GetFabResponse # pylint: disable=E0611
51
47
  from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
@@ -361,15 +357,9 @@ def http_request_response( # pylint: disable=R0913,R0914,R0915,R0917
361
357
  # Send the request
362
358
  res = _request(req, GetRunResponse, PATH_GET_RUN)
363
359
  if res is None:
364
- return Run(run_id, "", "", "", {})
365
-
366
- return Run(
367
- run_id,
368
- res.run.fab_id,
369
- res.run.fab_version,
370
- res.run.fab_hash,
371
- user_config_from_proto(res.run.override_config),
372
- )
360
+ return Run.create_empty(run_id)
361
+
362
+ return run_from_proto(res.run)
373
363
 
374
364
  def get_fab(fab_hash: str) -> Fab:
375
365
  # Construct the request
@@ -1,4 +1,4 @@
1
- # Copyright 2023 Flower Labs GmbH. All Rights Reserved.
1
+ # Copyright 2024 Flower Labs GmbH. All Rights Reserved.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,7 +12,7 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
  # ==============================================================================
15
- """Node state."""
15
+ """Deprecated Run Info Store."""
16
16
 
17
17
 
18
18
  from dataclasses import dataclass
@@ -36,7 +36,7 @@ class RunInfo:
36
36
  initial_run_config: UserConfig
37
37
 
38
38
 
39
- class NodeState:
39
+ class DeprecatedRunInfoStore:
40
40
  """State of a node where client nodes execute runs."""
41
41
 
42
42
  def __init__(
@@ -83,6 +83,7 @@ class NodeState:
83
83
  self.run_infos[run_id] = RunInfo(
84
84
  initial_run_config=initial_run_config,
85
85
  context=Context(
86
+ run_id=run_id,
86
87
  node_id=self.node_id,
87
88
  node_config=self.node_config,
88
89
  state=RecordSet(),
@@ -28,9 +28,13 @@ from cryptography.hazmat.primitives.serialization import (
28
28
  )
29
29
 
30
30
  from flwr.common import EventType, event
31
+ from flwr.common.args import try_obtain_root_certificates
31
32
  from flwr.common.config import parse_config_args
32
33
  from flwr.common.constant import (
34
+ CLIENTAPPIO_API_DEFAULT_SERVER_ADDRESS,
33
35
  FLEET_API_GRPC_RERE_DEFAULT_ADDRESS,
36
+ ISOLATION_MODE_PROCESS,
37
+ ISOLATION_MODE_SUBPROCESS,
34
38
  TRANSPORT_TYPE_GRPC_ADAPTER,
35
39
  TRANSPORT_TYPE_GRPC_RERE,
36
40
  TRANSPORT_TYPE_REST,
@@ -38,11 +42,7 @@ from flwr.common.constant import (
38
42
  from flwr.common.exit_handlers import register_exit_handlers
39
43
  from flwr.common.logger import log, warn_deprecated_feature
40
44
 
41
- from ..app import (
42
- ISOLATION_MODE_PROCESS,
43
- ISOLATION_MODE_SUBPROCESS,
44
- start_client_internal,
45
- )
45
+ from ..app import start_client_internal
46
46
  from ..clientapp.utils import get_load_client_app_fn
47
47
 
48
48
 
@@ -63,10 +63,21 @@ def run_supernode() -> None:
63
63
  "Ignoring `--flwr-dir`.",
64
64
  )
65
65
 
66
- root_certificates = _get_certificates(args)
66
+ # Exit if unsupported argument is passed by the user
67
+ if args.app is not None:
68
+ log(
69
+ ERROR,
70
+ "The `app` argument is deprecated. The SuperNode now automatically "
71
+ "uses the ClientApp delivered from the SuperLink. Providing the app "
72
+ "directory manually is no longer supported. Please remove the `app` "
73
+ "argument from your command.",
74
+ )
75
+ sys.exit(1)
76
+
77
+ root_certificates = try_obtain_root_certificates(args, args.superlink)
67
78
  load_fn = get_load_client_app_fn(
68
79
  default_app_ref="",
69
- app_path=args.app,
80
+ app_path=None,
70
81
  flwr_dir=args.flwr_dir,
71
82
  multi_app=True,
72
83
  )
@@ -88,7 +99,7 @@ def run_supernode() -> None:
88
99
  ),
89
100
  flwr_path=args.flwr_dir,
90
101
  isolation=args.isolation,
91
- supernode_address=args.supernode_address,
102
+ clientappio_api_address=args.clientappio_api_address,
92
103
  )
93
104
 
94
105
  # Graceful shutdown
@@ -128,41 +139,6 @@ def _warn_deprecated_server_arg(args: argparse.Namespace) -> None:
128
139
  args.superlink = args.server
129
140
 
130
141
 
131
- def _get_certificates(args: argparse.Namespace) -> Optional[bytes]:
132
- """Load certificates if specified in args."""
133
- # Obtain certificates
134
- if args.insecure:
135
- if args.root_certificates is not None:
136
- sys.exit(
137
- "Conflicting options: The '--insecure' flag disables HTTPS, "
138
- "but '--root-certificates' was also specified. Please remove "
139
- "the '--root-certificates' option when running in insecure mode, "
140
- "or omit '--insecure' to use HTTPS."
141
- )
142
- log(
143
- WARN,
144
- "Option `--insecure` was set. "
145
- "Starting insecure HTTP client connected to %s.",
146
- args.superlink,
147
- )
148
- root_certificates = None
149
- else:
150
- # Load the certificates if provided, or load the system certificates
151
- cert_path = args.root_certificates
152
- if cert_path is None:
153
- root_certificates = None
154
- else:
155
- root_certificates = Path(cert_path).read_bytes()
156
- log(
157
- DEBUG,
158
- "Starting secure HTTPS client connected to %s "
159
- "with the following certificates: %s.",
160
- args.superlink,
161
- cert_path,
162
- )
163
- return root_certificates
164
-
165
-
166
142
  def _parse_args_run_supernode() -> argparse.ArgumentParser:
167
143
  """Parse flower-supernode command line arguments."""
168
144
  parser = argparse.ArgumentParser(
@@ -173,12 +149,12 @@ def _parse_args_run_supernode() -> argparse.ArgumentParser:
173
149
  "app",
174
150
  nargs="?",
175
151
  default=None,
176
- help="Specify the path of the Flower App to load and run the `ClientApp`. "
177
- "The `pyproject.toml` file must be located in the root of this path. "
178
- "When this argument is provided, the SuperNode will exclusively respond to "
179
- "messages from the corresponding `ServerApp` by matching the FAB ID and FAB "
180
- "version. An error will be raised if a message is received from any other "
181
- "`ServerApp`.",
152
+ help=(
153
+ "(REMOVED) This argument is removed. The SuperNode now automatically "
154
+ "uses the ClientApp delivered from the SuperLink, so there is no need to "
155
+ "provide the app directory manually. This argument will be removed in a "
156
+ "future version."
157
+ ),
182
158
  )
183
159
  _parse_args_common(parser)
184
160
  parser.add_argument(
@@ -194,22 +170,22 @@ def _parse_args_run_supernode() -> argparse.ArgumentParser:
194
170
  )
195
171
  parser.add_argument(
196
172
  "--isolation",
197
- default=None,
173
+ default=ISOLATION_MODE_SUBPROCESS,
198
174
  required=False,
199
175
  choices=[
200
176
  ISOLATION_MODE_SUBPROCESS,
201
177
  ISOLATION_MODE_PROCESS,
202
178
  ],
203
- help="Isolation mode when running `ClientApp` (optional, possible values: "
204
- "`subprocess`, `process`). By default, `ClientApp` runs in the same process "
205
- "that executes the SuperNode. Use `subprocess` to configure SuperNode to run "
206
- "`ClientApp` in a subprocess. Use `process` to indicate that a separate "
207
- "independent process gets created outside of SuperNode.",
179
+ help="Isolation mode when running a `ClientApp` (`subprocess` by default, "
180
+ "possible values: `subprocess`, `process`). Use `subprocess` to configure "
181
+ "SuperNode to run a `ClientApp` in a subprocess. Use `process` to indicate "
182
+ "that a separate independent process gets created outside of SuperNode.",
208
183
  )
209
184
  parser.add_argument(
210
- "--supernode-address",
211
- default="0.0.0.0:9094",
212
- help="Set the SuperNode gRPC server address. Defaults to `0.0.0.0:9094`.",
185
+ "--clientappio-api-address",
186
+ default=CLIENTAPPIO_API_DEFAULT_SERVER_ADDRESS,
187
+ help="ClientAppIo API (gRPC) server address (IPv4, IPv6, or a domain name). "
188
+ f"By default, it is set to {CLIENTAPPIO_API_DEFAULT_SERVER_ADDRESS}.",
213
189
  )
214
190
 
215
191
  return parser