flwr-nightly 1.13.0.dev20241106__py3-none-any.whl → 1.13.0.dev20241117__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 (58) hide show
  1. flwr/cli/app.py +2 -0
  2. flwr/cli/build.py +37 -0
  3. flwr/cli/install.py +5 -3
  4. flwr/cli/ls.py +228 -0
  5. flwr/cli/run/run.py +16 -5
  6. flwr/client/app.py +68 -19
  7. flwr/client/clientapp/app.py +51 -35
  8. flwr/client/grpc_rere_client/connection.py +2 -12
  9. flwr/client/nodestate/__init__.py +25 -0
  10. flwr/client/nodestate/in_memory_nodestate.py +38 -0
  11. flwr/client/nodestate/nodestate.py +30 -0
  12. flwr/client/nodestate/nodestate_factory.py +37 -0
  13. flwr/client/rest_client/connection.py +4 -14
  14. flwr/client/supernode/app.py +57 -53
  15. flwr/common/args.py +148 -0
  16. flwr/common/config.py +10 -0
  17. flwr/common/constant.py +21 -7
  18. flwr/common/date.py +18 -0
  19. flwr/common/logger.py +6 -2
  20. flwr/common/object_ref.py +47 -16
  21. flwr/common/serde.py +10 -0
  22. flwr/common/typing.py +32 -11
  23. flwr/proto/exec_pb2.py +23 -17
  24. flwr/proto/exec_pb2.pyi +50 -20
  25. flwr/proto/exec_pb2_grpc.py +34 -0
  26. flwr/proto/exec_pb2_grpc.pyi +13 -0
  27. flwr/proto/run_pb2.py +32 -27
  28. flwr/proto/run_pb2.pyi +44 -1
  29. flwr/proto/simulationio_pb2.py +2 -2
  30. flwr/proto/simulationio_pb2_grpc.py +34 -0
  31. flwr/proto/simulationio_pb2_grpc.pyi +13 -0
  32. flwr/server/app.py +83 -87
  33. flwr/server/driver/driver.py +1 -1
  34. flwr/server/driver/grpc_driver.py +6 -20
  35. flwr/server/driver/inmemory_driver.py +1 -3
  36. flwr/server/run_serverapp.py +8 -238
  37. flwr/server/serverapp/app.py +44 -89
  38. flwr/server/strategy/aggregate.py +4 -4
  39. flwr/server/superlink/fleet/rest_rere/rest_api.py +10 -9
  40. flwr/server/superlink/linkstate/in_memory_linkstate.py +76 -62
  41. flwr/server/superlink/linkstate/linkstate.py +24 -9
  42. flwr/server/superlink/linkstate/sqlite_linkstate.py +87 -128
  43. flwr/server/superlink/linkstate/utils.py +191 -32
  44. flwr/server/superlink/simulation/simulationio_servicer.py +22 -1
  45. flwr/simulation/__init__.py +3 -1
  46. flwr/simulation/app.py +245 -352
  47. flwr/simulation/legacy_app.py +402 -0
  48. flwr/simulation/run_simulation.py +8 -19
  49. flwr/simulation/simulationio_connection.py +2 -2
  50. flwr/superexec/deployment.py +13 -7
  51. flwr/superexec/exec_servicer.py +32 -3
  52. flwr/superexec/executor.py +4 -3
  53. flwr/superexec/simulation.py +52 -145
  54. {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241117.dist-info}/METADATA +10 -7
  55. {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241117.dist-info}/RECORD +58 -51
  56. {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241117.dist-info}/entry_points.txt +1 -0
  57. {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241117.dist-info}/LICENSE +0 -0
  58. {flwr_nightly-1.13.0.dev20241106.dist-info → flwr_nightly-1.13.0.dev20241117.dist-info}/WHEEL +0 -0
@@ -15,33 +15,15 @@
15
15
  """Run ServerApp."""
16
16
 
17
17
 
18
- import argparse
19
18
  import sys
20
- from logging import DEBUG, INFO, WARN
21
- from pathlib import Path
19
+ from logging import DEBUG, ERROR
22
20
  from typing import Optional
23
21
 
24
- from flwr.cli.config_utils import get_fab_metadata
25
- from flwr.cli.install import install_from_fab
26
- from flwr.common import Context, EventType, RecordSet, event
27
- from flwr.common.config import (
28
- get_flwr_dir,
29
- get_fused_config_from_dir,
30
- get_metadata_from_config,
31
- get_project_config,
32
- get_project_dir,
33
- )
34
- from flwr.common.constant import SERVERAPPIO_API_DEFAULT_ADDRESS
35
- from flwr.common.logger import log, update_console_handler, warn_deprecated_feature
22
+ from flwr.common import Context
23
+ from flwr.common.logger import log, warn_unsupported_feature
36
24
  from flwr.common.object_ref import load_app
37
- from flwr.proto.fab_pb2 import GetFabRequest, GetFabResponse # pylint: disable=E0611
38
- from flwr.proto.run_pb2 import ( # pylint: disable=E0611
39
- CreateRunRequest,
40
- CreateRunResponse,
41
- )
42
25
 
43
26
  from .driver import Driver
44
- from .driver.grpc_driver import GrpcDriver
45
27
  from .server_app import LoadServerAppError, ServerApp
46
28
 
47
29
 
@@ -87,221 +69,9 @@ def run(
87
69
  # pylint: disable-next=too-many-branches,too-many-statements,too-many-locals
88
70
  def run_server_app() -> None:
89
71
  """Run Flower server app."""
90
- event(EventType.RUN_SERVER_APP_ENTER)
91
-
92
- args = _parse_args_run_server_app().parse_args()
93
-
94
- # Check if the server app reference is passed.
95
- # Since Flower 1.11, passing a reference is not allowed.
96
- app_path: Optional[str] = args.app
97
- # If the provided app_path doesn't exist, and contains a ":",
98
- # it is likely to be a server app reference instead of a path.
99
- if app_path is not None and not Path(app_path).exists() and ":" in app_path:
100
- sys.exit(
101
- "It appears you've passed a reference like `server:app`.\n\n"
102
- "Note that since version `1.11.0`, `flower-server-app` no longer supports "
103
- "passing a reference to a `ServerApp` attribute. Instead, you need to pass "
104
- "the path to Flower app via the argument `--app`. This is the path to a "
105
- "directory containing a `pyproject.toml`. You can create a valid Flower "
106
- "app by executing `flwr new` and following the prompt."
107
- )
108
-
109
- if args.server != SERVERAPPIO_API_DEFAULT_ADDRESS:
110
- warn = "Passing flag --server is deprecated. Use --superlink instead."
111
- warn_deprecated_feature(warn)
112
-
113
- if args.superlink != SERVERAPPIO_API_DEFAULT_ADDRESS:
114
- # if `--superlink` also passed, then
115
- # warn user that this argument overrides what was passed with `--server`
116
- log(
117
- WARN,
118
- "Both `--server` and `--superlink` were passed. "
119
- "`--server` will be ignored. Connecting to the "
120
- "SuperLink ServerAppIo API at %s.",
121
- args.superlink,
122
- )
123
- else:
124
- args.superlink = args.server
125
-
126
- update_console_handler(
127
- level=DEBUG if args.verbose else INFO,
128
- timestamps=args.verbose,
129
- colored=True,
130
- )
131
-
132
- # Obtain certificates
133
- if args.insecure:
134
- if args.root_certificates is not None:
135
- sys.exit(
136
- "Conflicting options: The '--insecure' flag disables HTTPS, "
137
- "but '--root-certificates' was also specified. Please remove "
138
- "the '--root-certificates' option when running in insecure mode, "
139
- "or omit '--insecure' to use HTTPS."
140
- )
141
- log(
142
- WARN,
143
- "Option `--insecure` was set. "
144
- "Starting insecure HTTP client connected to %s.",
145
- args.superlink,
146
- )
147
- root_certificates = None
148
- else:
149
- # Load the certificates if provided, or load the system certificates
150
- cert_path = args.root_certificates
151
- if cert_path is None:
152
- root_certificates = None
153
- else:
154
- root_certificates = Path(cert_path).read_bytes()
155
- log(
156
- DEBUG,
157
- "Starting secure HTTPS client connected to %s "
158
- "with the following certificates: %s.",
159
- args.superlink,
160
- cert_path,
161
- )
162
-
163
- if not (app_path is None) ^ (args.run_id is None):
164
- raise sys.exit(
165
- "Please provide either a Flower App path or a Run ID, but not both. "
166
- "For more details, use: ``flower-server-app -h``"
167
- )
168
-
169
- # Initialize GrpcDriver
170
- if app_path is None:
171
- # User provided `--run-id`, but not `app_dir`
172
- driver = GrpcDriver(
173
- serverappio_service_address=args.superlink,
174
- root_certificates=root_certificates,
175
- )
176
- flwr_dir = get_flwr_dir(args.flwr_dir)
177
- driver.init_run(args.run_id)
178
- run_ = driver.run
179
- if not run_.fab_hash:
180
- raise ValueError("FAB hash not provided.")
181
- fab_req = GetFabRequest(hash_str=run_.fab_hash)
182
- # pylint: disable-next=W0212
183
- fab_res: GetFabResponse = driver._stub.GetFab(fab_req)
184
- if fab_res.fab.hash_str != run_.fab_hash:
185
- raise ValueError("FAB hashes don't match.")
186
- install_from_fab(fab_res.fab.content, flwr_dir, True)
187
- fab_id, fab_version = get_fab_metadata(fab_res.fab.content)
188
-
189
- app_path = str(get_project_dir(fab_id, fab_version, run_.fab_hash, flwr_dir))
190
- config = get_project_config(app_path)
191
- run_id = run_.run_id
192
- else:
193
- # User provided `app_dir`, but not `--run-id`
194
- # Create run if run_id is not provided
195
- driver = GrpcDriver(
196
- serverappio_service_address=args.superlink,
197
- root_certificates=root_certificates,
198
- )
199
- # Load config from the project directory
200
- config = get_project_config(app_path)
201
- fab_version, fab_id = get_metadata_from_config(config)
202
-
203
- # Create run
204
- req = CreateRunRequest(fab_id=fab_id, fab_version=fab_version)
205
- res: CreateRunResponse = driver._stub.CreateRun(req) # pylint: disable=W0212
206
- # Fetch full `Run` using `run_id`
207
- driver.init_run(res.run_id) # pylint: disable=W0212
208
- run_id = res.run_id
209
-
210
- # Obtain server app reference and the run config
211
- server_app_attr = config["tool"]["flwr"]["app"]["components"]["serverapp"]
212
- server_app_run_config = get_fused_config_from_dir(
213
- Path(app_path), driver.run.override_config
72
+ warn_unsupported_feature(
73
+ "The command `flower-server-app` is deprecated and no longer in use. "
74
+ "Use the `flwr-serverapp` exclusively instead."
214
75
  )
215
-
216
- log(DEBUG, "Flower will load ServerApp `%s` in %s", server_app_attr, app_path)
217
-
218
- log(
219
- DEBUG,
220
- "root_certificates: `%s`",
221
- root_certificates,
222
- )
223
-
224
- # Initialize Context
225
- context = Context(
226
- run_id=run_id,
227
- node_id=0,
228
- node_config={},
229
- state=RecordSet(),
230
- run_config=server_app_run_config,
231
- )
232
-
233
- # Run the ServerApp with the Driver
234
- run(
235
- driver=driver,
236
- context=context,
237
- server_app_dir=app_path,
238
- server_app_attr=server_app_attr,
239
- )
240
-
241
- # Clean up
242
- driver.close()
243
-
244
- event(EventType.RUN_SERVER_APP_LEAVE)
245
-
246
-
247
- def _parse_args_run_server_app() -> argparse.ArgumentParser:
248
- """Parse flower-server-app command line arguments."""
249
- parser = argparse.ArgumentParser(
250
- description="Start a Flower server app",
251
- )
252
-
253
- parser.add_argument(
254
- "app",
255
- nargs="?",
256
- default=None,
257
- help="Load and run the `ServerApp` from the specified Flower App path. "
258
- "The `pyproject.toml` file must be located in the root of this path.",
259
- )
260
- parser.add_argument(
261
- "--insecure",
262
- action="store_true",
263
- help="Run the `ServerApp` without HTTPS. By default, the app runs with "
264
- "HTTPS enabled. Use this flag only if you understand the risks.",
265
- )
266
- parser.add_argument(
267
- "--verbose",
268
- action="store_true",
269
- help="Set the logging to `DEBUG`.",
270
- )
271
- parser.add_argument(
272
- "--root-certificates",
273
- metavar="ROOT_CERT",
274
- type=str,
275
- help="Specifies the path to the PEM-encoded root certificate file for "
276
- "establishing secure HTTPS connections.",
277
- )
278
- parser.add_argument(
279
- "--server",
280
- default=SERVERAPPIO_API_DEFAULT_ADDRESS,
281
- help="Server address",
282
- )
283
- parser.add_argument(
284
- "--superlink",
285
- default=SERVERAPPIO_API_DEFAULT_ADDRESS,
286
- help="SuperLink ServerAppIo API (gRPC-rere) address "
287
- "(IPv4, IPv6, or a domain name)",
288
- )
289
- parser.add_argument(
290
- "--run-id",
291
- default=None,
292
- type=int,
293
- help="The identifier of the run.",
294
- )
295
- parser.add_argument(
296
- "--flwr-dir",
297
- default=None,
298
- help="""The path containing installed Flower Apps.
299
- By default, this value is equal to:
300
-
301
- - `$FLWR_HOME/` if `$FLWR_HOME` is defined
302
- - `$XDG_DATA_HOME/.flwr/` if `$XDG_DATA_HOME` is defined
303
- - `$HOME/.flwr/` in all other cases
304
- """,
305
- )
306
-
307
- return parser
76
+ log(ERROR, "`flower-server-app` used.")
77
+ sys.exit()
@@ -15,9 +15,7 @@
15
15
  """Flower ServerApp process."""
16
16
 
17
17
  import argparse
18
- import sys
19
- from logging import DEBUG, ERROR, INFO, WARN
20
- from os.path import isfile
18
+ from logging import DEBUG, ERROR, INFO
21
19
  from pathlib import Path
22
20
  from queue import Queue
23
21
  from time import sleep
@@ -25,13 +23,18 @@ from typing import Optional
25
23
 
26
24
  from flwr.cli.config_utils import get_fab_metadata
27
25
  from flwr.cli.install import install_from_fab
26
+ from flwr.common.args import add_args_flwr_app_common, try_obtain_root_certificates
28
27
  from flwr.common.config import (
29
28
  get_flwr_dir,
30
29
  get_fused_config_from_dir,
31
30
  get_project_config,
32
31
  get_project_dir,
33
32
  )
34
- from flwr.common.constant import Status, SubStatus
33
+ from flwr.common.constant import (
34
+ SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS,
35
+ Status,
36
+ SubStatus,
37
+ )
35
38
  from flwr.common.logger import (
36
39
  log,
37
40
  mirror_output_to_queue,
@@ -63,60 +66,21 @@ def flwr_serverapp() -> None:
63
66
  log_queue: Queue[Optional[str]] = Queue()
64
67
  mirror_output_to_queue(log_queue)
65
68
 
66
- parser = argparse.ArgumentParser(
67
- description="Run a Flower ServerApp",
68
- )
69
- parser.add_argument(
70
- "--superlink",
71
- type=str,
72
- help="Address of SuperLink's DriverAPI",
73
- )
74
- parser.add_argument(
75
- "--run-once",
76
- action="store_true",
77
- help="When set, this process will start a single ServerApp "
78
- "for a pending Run. If no pending run the process will exit. ",
79
- )
80
- parser.add_argument(
81
- "--flwr-dir",
82
- default=None,
83
- help="""The path containing installed Flower Apps.
84
- By default, this value is equal to:
85
-
86
- - `$FLWR_HOME/` if `$FLWR_HOME` is defined
87
- - `$XDG_DATA_HOME/.flwr/` if `$XDG_DATA_HOME` is defined
88
- - `$HOME/.flwr/` in all other cases
89
- """,
90
- )
91
- parser.add_argument(
92
- "--insecure",
93
- action="store_true",
94
- help="Run the server without HTTPS, regardless of whether certificate "
95
- "paths are provided. By default, the server runs with HTTPS enabled. "
96
- "Use this flag only if you understand the risks.",
97
- )
98
- parser.add_argument(
99
- "--root-certificates",
100
- metavar="ROOT_CERT",
101
- type=str,
102
- help="Specifies the path to the PEM-encoded root certificate file for "
103
- "establishing secure HTTPS connections.",
104
- )
105
- args = parser.parse_args()
69
+ args = _parse_args_run_flwr_serverapp().parse_args()
106
70
 
107
71
  log(INFO, "Starting Flower ServerApp")
108
- certificates = _try_obtain_certificates(args)
72
+ certificates = try_obtain_root_certificates(args, args.serverappio_api_address)
109
73
 
110
74
  log(
111
75
  DEBUG,
112
- "Staring isolated `ServerApp` connected to SuperLink DriverAPI at %s",
113
- args.superlink,
76
+ "Starting isolated `ServerApp` connected to SuperLink's ServerAppIo API at %s",
77
+ args.serverappio_api_address,
114
78
  )
115
79
  run_serverapp(
116
- superlink=args.superlink,
80
+ serverappio_api_address=args.serverappio_api_address,
117
81
  log_queue=log_queue,
118
82
  run_once=args.run_once,
119
- flwr_dir_=args.flwr_dir,
83
+ flwr_dir=args.flwr_dir,
120
84
  certificates=certificates,
121
85
  )
122
86
 
@@ -124,54 +88,21 @@ def flwr_serverapp() -> None:
124
88
  restore_output()
125
89
 
126
90
 
127
- def _try_obtain_certificates(
128
- args: argparse.Namespace,
129
- ) -> Optional[bytes]:
130
-
131
- if args.insecure:
132
- if args.root_certificates is not None:
133
- sys.exit(
134
- "Conflicting options: The '--insecure' flag disables HTTPS, "
135
- "but '--root-certificates' was also specified. Please remove "
136
- "the '--root-certificates' option when running in insecure mode, "
137
- "or omit '--insecure' to use HTTPS."
138
- )
139
- log(
140
- WARN,
141
- "Option `--insecure` was set. Starting insecure HTTP channel to %s.",
142
- args.superlink,
143
- )
144
- root_certificates = None
145
- else:
146
- # Load the certificates if provided, or load the system certificates
147
- if not isfile(args.root_certificates):
148
- sys.exit("Path argument `--root-certificates` does not point to a file.")
149
- root_certificates = Path(args.root_certificates).read_bytes()
150
- log(
151
- DEBUG,
152
- "Starting secure HTTPS channel to %s "
153
- "with the following certificates: %s.",
154
- args.superlink,
155
- args.root_certificates,
156
- )
157
- return root_certificates
158
-
159
-
160
91
  def run_serverapp( # pylint: disable=R0914, disable=W0212
161
- superlink: str,
92
+ serverappio_api_address: str,
162
93
  log_queue: Queue[Optional[str]],
163
94
  run_once: bool,
164
- flwr_dir_: Optional[str] = None,
95
+ flwr_dir: Optional[str] = None,
165
96
  certificates: Optional[bytes] = None,
166
97
  ) -> None:
167
98
  """Run Flower ServerApp process."""
168
99
  driver = GrpcDriver(
169
- serverappio_service_address=superlink,
100
+ serverappio_service_address=serverappio_api_address,
170
101
  root_certificates=certificates,
171
102
  )
172
103
 
173
104
  # Resolve directory where FABs are installed
174
- flwr_dir = get_flwr_dir(flwr_dir_)
105
+ flwr_dir_ = get_flwr_dir(flwr_dir)
175
106
  log_uploader = None
176
107
 
177
108
  while True:
@@ -189,7 +120,7 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212
189
120
  run = run_from_proto(res.run)
190
121
  fab = fab_from_proto(res.fab)
191
122
 
192
- driver.init_run(run.run_id)
123
+ driver.set_run(run.run_id)
193
124
 
194
125
  # Start log uploader for this run
195
126
  log_uploader = start_log_uploader(
@@ -200,11 +131,13 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212
200
131
  )
201
132
 
202
133
  log(DEBUG, "ServerApp process starts FAB installation.")
203
- install_from_fab(fab.content, flwr_dir=flwr_dir, skip_prompt=True)
134
+ install_from_fab(fab.content, flwr_dir=flwr_dir_, skip_prompt=True)
204
135
 
205
136
  fab_id, fab_version = get_fab_metadata(fab.content)
206
137
 
207
- app_path = str(get_project_dir(fab_id, fab_version, fab.hash_str, flwr_dir))
138
+ app_path = str(
139
+ get_project_dir(fab_id, fab_version, fab.hash_str, flwr_dir_)
140
+ )
208
141
  config = get_project_config(app_path)
209
142
 
210
143
  # Obtain server app reference and the run config
@@ -268,3 +201,25 @@ def run_serverapp( # pylint: disable=R0914, disable=W0212
268
201
  # Stop the loop if `flwr-serverapp` is expected to process a single run
269
202
  if run_once:
270
203
  break
204
+
205
+
206
+ def _parse_args_run_flwr_serverapp() -> argparse.ArgumentParser:
207
+ """Parse flwr-serverapp command line arguments."""
208
+ parser = argparse.ArgumentParser(
209
+ description="Run a Flower ServerApp",
210
+ )
211
+ parser.add_argument(
212
+ "--serverappio-api-address",
213
+ default=SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS,
214
+ type=str,
215
+ help="Address of SuperLink's ServerAppIo API (IPv4, IPv6, or a domain name)."
216
+ f"By default, it is set to {SERVERAPPIO_API_DEFAULT_CLIENT_ADDRESS}.",
217
+ )
218
+ parser.add_argument(
219
+ "--run-once",
220
+ action="store_true",
221
+ help="When set, this process will start a single ServerApp for a pending Run. "
222
+ "If there is no pending Run, the process will exit.",
223
+ )
224
+ add_args_flwr_app_common(parser=parser)
225
+ return parser
@@ -48,12 +48,12 @@ def aggregate_inplace(results: list[tuple[ClientProxy, FitRes]]) -> NDArrays:
48
48
  num_examples_total = sum(fit_res.num_examples for (_, fit_res) in results)
49
49
 
50
50
  # Compute scaling factors for each result
51
- scaling_factors = [
52
- fit_res.num_examples / num_examples_total for _, fit_res in results
53
- ]
51
+ scaling_factors = np.asarray(
52
+ [fit_res.num_examples / num_examples_total for _, fit_res in results]
53
+ )
54
54
 
55
55
  def _try_inplace(
56
- x: NDArray, y: Union[NDArray, float], np_binary_op: np.ufunc
56
+ x: NDArray, y: Union[NDArray, np.float64], np_binary_op: np.ufunc
57
57
  ) -> NDArray:
58
58
  return ( # type: ignore[no-any-return]
59
59
  np_binary_op(x, y, out=x)
@@ -19,7 +19,7 @@ from __future__ import annotations
19
19
 
20
20
  import sys
21
21
  from collections.abc import Awaitable
22
- from typing import Callable, TypeVar
22
+ from typing import Callable, TypeVar, cast
23
23
 
24
24
  from google.protobuf.message import Message as GrpcMessage
25
25
 
@@ -39,8 +39,9 @@ from flwr.proto.fleet_pb2 import ( # pylint: disable=E0611
39
39
  )
40
40
  from flwr.proto.run_pb2 import GetRunRequest, GetRunResponse # pylint: disable=E0611
41
41
  from flwr.server.superlink.ffs.ffs import Ffs
42
+ from flwr.server.superlink.ffs.ffs_factory import FfsFactory
42
43
  from flwr.server.superlink.fleet.message_handler import message_handler
43
- from flwr.server.superlink.linkstate import LinkState
44
+ from flwr.server.superlink.linkstate import LinkState, LinkStateFactory
44
45
 
45
46
  try:
46
47
  from starlette.applications import Starlette
@@ -90,7 +91,7 @@ def rest_request_response(
90
91
  async def create_node(request: CreateNodeRequest) -> CreateNodeResponse:
91
92
  """Create Node."""
92
93
  # Get state from app
93
- state: LinkState = app.state.STATE_FACTORY.state()
94
+ state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
94
95
 
95
96
  # Handle message
96
97
  return message_handler.create_node(request=request, state=state)
@@ -100,7 +101,7 @@ async def create_node(request: CreateNodeRequest) -> CreateNodeResponse:
100
101
  async def delete_node(request: DeleteNodeRequest) -> DeleteNodeResponse:
101
102
  """Delete Node Id."""
102
103
  # Get state from app
103
- state: LinkState = app.state.STATE_FACTORY.state()
104
+ state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
104
105
 
105
106
  # Handle message
106
107
  return message_handler.delete_node(request=request, state=state)
@@ -110,7 +111,7 @@ async def delete_node(request: DeleteNodeRequest) -> DeleteNodeResponse:
110
111
  async def pull_task_ins(request: PullTaskInsRequest) -> PullTaskInsResponse:
111
112
  """Pull TaskIns."""
112
113
  # Get state from app
113
- state: LinkState = app.state.STATE_FACTORY.state()
114
+ state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
114
115
 
115
116
  # Handle message
116
117
  return message_handler.pull_task_ins(request=request, state=state)
@@ -121,7 +122,7 @@ async def pull_task_ins(request: PullTaskInsRequest) -> PullTaskInsResponse:
121
122
  async def push_task_res(request: PushTaskResRequest) -> PushTaskResResponse:
122
123
  """Push TaskRes."""
123
124
  # Get state from app
124
- state: LinkState = app.state.STATE_FACTORY.state()
125
+ state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
125
126
 
126
127
  # Handle message
127
128
  return message_handler.push_task_res(request=request, state=state)
@@ -131,7 +132,7 @@ async def push_task_res(request: PushTaskResRequest) -> PushTaskResResponse:
131
132
  async def ping(request: PingRequest) -> PingResponse:
132
133
  """Ping."""
133
134
  # Get state from app
134
- state: LinkState = app.state.STATE_FACTORY.state()
135
+ state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
135
136
 
136
137
  # Handle message
137
138
  return message_handler.ping(request=request, state=state)
@@ -141,7 +142,7 @@ async def ping(request: PingRequest) -> PingResponse:
141
142
  async def get_run(request: GetRunRequest) -> GetRunResponse:
142
143
  """GetRun."""
143
144
  # Get state from app
144
- state: LinkState = app.state.STATE_FACTORY.state()
145
+ state: LinkState = cast(LinkStateFactory, app.state.STATE_FACTORY).state()
145
146
 
146
147
  # Handle message
147
148
  return message_handler.get_run(request=request, state=state)
@@ -151,7 +152,7 @@ async def get_run(request: GetRunRequest) -> GetRunResponse:
151
152
  async def get_fab(request: GetFabRequest) -> GetFabResponse:
152
153
  """GetRun."""
153
154
  # Get ffs from app
154
- ffs: Ffs = app.state.FFS_FACTORY.state()
155
+ ffs: Ffs = cast(FfsFactory, app.state.FFS_FACTORY).ffs()
155
156
 
156
157
  # Handle message
157
158
  return message_handler.get_fab(request=request, ffs=ffs)