vantage6 5.0.0a33__py3-none-any.whl → 5.0.0a34__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 vantage6 might be problematic. Click here for more details.

@@ -1,25 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
- import enum
4
- import os
5
3
  import re
6
4
  import subprocess
7
5
  import time
8
6
  from os import PathLike
9
7
  from pathlib import Path
10
- from threading import Thread
11
8
 
12
9
  import docker
13
- from colorama import Fore, Style
14
10
  from docker.client import DockerClient
15
- from docker.models.containers import Container
16
- from sqlalchemy.engine.url import make_url
17
11
 
18
12
  from vantage6.common import error, info, warning
19
- from vantage6.common.context import AppContext
20
- from vantage6.common.docker.addons import check_docker_running, pull_image
13
+ from vantage6.common.docker.addons import pull_image
21
14
  from vantage6.common.globals import (
22
- APPNAME,
23
15
  DEFAULT_ALGO_STORE_IMAGE,
24
16
  DEFAULT_CHART_REPO,
25
17
  DEFAULT_DOCKER_REGISTRY,
@@ -29,83 +21,8 @@ from vantage6.common.globals import (
29
21
  InstanceType,
30
22
  )
31
23
 
32
- from vantage6.cli.common.utils import print_log_worker
33
- from vantage6.cli.context import AlgorithmStoreContext, ServerContext
34
- from vantage6.cli.globals import AlgoStoreGlobals, ServerGlobals
35
- from vantage6.cli.utils import (
36
- check_config_name_allowed,
37
- validate_input_cmd_args,
38
- )
39
-
40
-
41
- def check_for_start(ctx: AppContext, type_: InstanceType) -> DockerClient:
42
- """
43
- Check if all requirements are met to start the instance.
44
-
45
- Parameters
46
- ----------
47
- ctx : AppContext
48
- The context object
49
- type_ : InstanceType
50
- The type of instance to check for
51
-
52
- Returns
53
- -------
54
- DockerClient
55
- A Docker client instance
56
- """
57
- # will print an error if not
58
- check_docker_running()
59
-
60
- info("Finding Docker daemon.")
61
- docker_client = docker.from_env()
62
-
63
- # check if name is allowed for docker volume, else exit
64
- check_config_name_allowed(ctx.name)
65
-
66
- # check that this server is not already running
67
- running_servers = docker_client.containers.list(
68
- filters={"label": f"{APPNAME}-type={type_}"}
69
- )
70
- for server in running_servers:
71
- if server.name == f"{APPNAME}-{ctx.name}-{ctx.scope}-{type_}":
72
- error(f"Server {Fore.RED}{ctx.name}{Style.RESET_ALL} is already running")
73
- exit(1)
74
- return docker_client
75
-
76
-
77
- def get_image(
78
- image: str, ctx: AppContext, custom_image_key: str, default_image: str
79
- ) -> str:
80
- """
81
- Get the image name for the given instance type.
82
-
83
- Parameters
84
- ----------
85
- image : str | None
86
- The image name to use if specified
87
- ctx : AppContext
88
- The context object
89
- custom_image_key : str
90
- The key to look for in the config file
91
- default_image : str
92
- The default image name
93
-
94
- Returns
95
- -------
96
- str
97
- The image name to use
98
- """
99
- # Determine image-name. First we check if the option --image has been used.
100
- # Then we check if the image has been specified in the config file, and
101
- # finally we use the default settings from the package.
102
- if image is None:
103
- custom_images: dict = ctx.config.get("images")
104
- if custom_images:
105
- image = custom_images.get(custom_image_key)
106
- if not image:
107
- image = f"{DEFAULT_DOCKER_REGISTRY}/{default_image}"
108
- return image
24
+ from vantage6.cli.globals import ChartName
25
+ from vantage6.cli.utils import validate_input_cmd_args
109
26
 
110
27
 
111
28
  def pull_infra_image(
@@ -129,8 +46,8 @@ def pull_infra_image(
129
46
  try:
130
47
  pull_image(client, image, suppress_error=True)
131
48
  except docker.errors.APIError:
132
- if not is_default_infra_image(image, instance_type):
133
- if image_exists_locally(client, image):
49
+ if not _is_default_infra_image(image, instance_type):
50
+ if _image_exists_locally(client, image):
134
51
  warning("Failed to pull infrastructure image! Will use local image...")
135
52
  else:
136
53
  error("Failed to pull infrastructure image!")
@@ -141,7 +58,7 @@ def pull_infra_image(
141
58
  exit(1)
142
59
 
143
60
 
144
- def is_default_infra_image(image: str, instance_type: InstanceType) -> bool:
61
+ def _is_default_infra_image(image: str, instance_type: InstanceType) -> bool:
145
62
  """
146
63
  Check if an infrastructure image is the default image.
147
64
 
@@ -167,7 +84,7 @@ def is_default_infra_image(image: str, instance_type: InstanceType) -> bool:
167
84
  return image == f"{DEFAULT_DOCKER_REGISTRY}/{DEFAULT_NODE_IMAGE}"
168
85
 
169
86
 
170
- def image_exists_locally(client: DockerClient, image: str) -> bool:
87
+ def _image_exists_locally(client: DockerClient, image: str) -> bool:
171
88
  """
172
89
  Check if the image exists locally.
173
90
 
@@ -190,137 +107,9 @@ def image_exists_locally(client: DockerClient, image: str) -> bool:
190
107
  return True
191
108
 
192
109
 
193
- def mount_config_file(ctx: AppContext, config_file: str) -> list[docker.types.Mount]:
194
- """
195
- Mount the config file in the container.
196
-
197
- Parameters
198
- ----------
199
- ctx : AppContext
200
- The context object
201
- config_file : str
202
- The path to the config file
203
-
204
- Returns
205
- -------
206
- list[docker.types.Mount]
207
- The mounts to use
208
- """
209
- info("Creating mounts")
210
- return [docker.types.Mount(config_file, str(ctx.config_file), type="bind")]
211
-
212
-
213
- def mount_source(mount_src: str) -> docker.types.Mount:
214
- """
215
- Mount the vantage6 source code in the container.
216
-
217
- Parameters
218
- ----------
219
- mount_src : str
220
- The path to the source code
221
-
222
- Returns
223
- -------
224
- docker.types.Mount | None
225
- The mount to use
226
- """
227
- if mount_src:
228
- mount_src = os.path.abspath(mount_src)
229
- return docker.types.Mount("/vantage6", mount_src, type="bind")
230
-
231
-
232
- def mount_database(
233
- ctx: ServerContext | AlgorithmStoreContext, type_: InstanceType
234
- ) -> tuple[docker.types.Mount, dict]:
235
- """
236
- Mount database in the container if it is file-based (e.g. a SQLite DB).
237
-
238
- Parameters
239
- ----------
240
- ctx : AppContext
241
- The context object
242
- type_ : InstanceType
243
- The type of instance to mount the database for
244
-
245
- Returns
246
- -------
247
- docker.types.Mount | None
248
- The mount to use
249
- dict | None
250
- The environment variables to use
251
- """
252
- # FIXME: code duplication with cli_server_import()
253
- # try to mount database
254
- uri = ctx.config["uri"]
255
- url = make_url(uri)
256
- environment_vars = {}
257
- mount = None
258
-
259
- # If host is None, we're dealing with a file-based DB, like SQLite
260
- if url.host is None:
261
- db_path = url.database
262
-
263
- if not os.path.isabs(db_path):
264
- # We're dealing with a relative path here -> make it absolute
265
- db_path = ctx.data_dir / url.database
266
-
267
- basename = os.path.basename(db_path)
268
- dirname = os.path.dirname(db_path)
269
- os.makedirs(dirname, exist_ok=True)
270
-
271
- # we're mounting the entire folder that contains the database
272
- mount = docker.types.Mount("/mnt/database/", dirname, type="bind")
273
-
274
- if type_ == InstanceType.SERVER:
275
- environment_vars = {
276
- ServerGlobals.DB_URI_ENV_VAR.value: f"sqlite:////mnt/database/{basename}",
277
- ServerGlobals.CONFIG_NAME_ENV_VAR.value: ctx.config_file_name,
278
- }
279
- elif type_ == InstanceType.ALGORITHM_STORE:
280
- environment_vars = {
281
- AlgoStoreGlobals.DB_URI_ENV_VAR.value: f"sqlite:////mnt/database/{basename}",
282
- AlgoStoreGlobals.CONFIG_NAME_ENV_VAR.value: ctx.config_file_name,
283
- }
284
- else:
285
- warning(
286
- f"Database could not be transferred, make sure {url.host} "
287
- "is reachable from the Docker container"
288
- )
289
- info("Consider using the docker-compose method to start a server")
290
-
291
- return mount, environment_vars
292
-
293
-
294
- # TODO v5+ remove this function, it is replaced by the `attach_logs` function in
295
- # `vantage6.cli.common.utils`
296
- def attach_logs(container: Container, type_: InstanceType) -> None:
297
- """
298
- Attach container logs to the console if specified.
299
-
300
- Parameters
301
- ----------
302
- container : Container
303
- The container to attach the logs from
304
- type_ : InstanceType
305
- The type of instance to attach the logs for
306
- """
307
- logs = container.attach(stream=True, logs=True, stdout=True)
308
- Thread(target=print_log_worker, args=(logs,), daemon=True).start()
309
- while True:
310
- try:
311
- time.sleep(1)
312
- except KeyboardInterrupt:
313
- info("Closing log file. Keyboard Interrupt.")
314
- info(
315
- "Note that your server is still running! Shut it down "
316
- f"with {Fore.RED}v6 {type_} stop{Style.RESET_ALL}"
317
- )
318
- exit(0)
319
-
320
-
321
110
  def helm_install(
322
111
  release_name: str,
323
- chart_name: str,
112
+ chart_name: ChartName,
324
113
  values_file: str | PathLike | None = None,
325
114
  context: str | None = None,
326
115
  namespace: str | None = None,
@@ -361,6 +150,7 @@ def helm_install(
361
150
  chart_name,
362
151
  "--repo",
363
152
  DEFAULT_CHART_REPO,
153
+ # TODO v5+ remove this flag when we have a stable release
364
154
  "--devel", # ensure using latest version including pre-releases
365
155
  ]
366
156
 
@@ -380,14 +170,18 @@ def helm_install(
380
170
  check=True,
381
171
  )
382
172
  info(
383
- f"Successfully installed release '{release_name}' using chart '{chart_name}'."
173
+ f"Successfully installed release '{release_name}' using chart "
174
+ f"'{chart_name}'."
384
175
  )
385
- except subprocess.CalledProcessError as e:
386
- error(f"Failed to install release '{release_name}': {e.stderr}")
176
+ except subprocess.CalledProcessError:
177
+ error(f"Failed to install release '{release_name}'.")
178
+ exit(1)
387
179
  except FileNotFoundError:
388
180
  error(
389
- "Helm command not found. Please ensure Helm is installed and available in the PATH."
181
+ "Helm command not found. Please ensure Helm is installed and available in "
182
+ "the PATH."
390
183
  )
184
+ exit(1)
391
185
 
392
186
 
393
187
  def start_port_forward(
@@ -2,8 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  import subprocess
4
4
 
5
-
6
5
  from vantage6.common import error, info, warning
6
+
7
7
  from vantage6.cli.utils import validate_input_cmd_args
8
8
 
9
9
 
@@ -1,4 +1,6 @@
1
- import enum
1
+ import json
2
+ import subprocess
3
+ from pathlib import Path
2
4
  from subprocess import Popen
3
5
  from typing import Iterable
4
6
 
@@ -10,7 +12,174 @@ from colorama import Fore, Style
10
12
  from vantage6.common import error, warning
11
13
  from vantage6.common.globals import APPNAME, STRING_ENCODING, InstanceType
12
14
 
15
+ from vantage6.cli.config import CliConfig
13
16
  from vantage6.cli.context import select_context_class
17
+ from vantage6.cli.utils import validate_input_cmd_args
18
+
19
+
20
+ def select_context_and_namespace(
21
+ context: str | None = None,
22
+ namespace: str | None = None,
23
+ ) -> tuple[str, str]:
24
+ """
25
+ Select the context and namespace to use.
26
+
27
+ This uses the CLI config to compare the provided context and namespace with the
28
+ last used context and namespace. If the provided context and namespace are not
29
+ the same as the last used context and namespace, the CLI config is updated.
30
+
31
+ Parameters
32
+ ----------
33
+ context : str, optional
34
+ The Kubernetes context to use.
35
+ namespace : str, optional
36
+ The Kubernetes namespace to use.
37
+
38
+ Returns
39
+ -------
40
+ tuple[str, str]
41
+ The context and namespace to use
42
+ """
43
+ cli_config = CliConfig()
44
+
45
+ return cli_config.compare_changes_config(
46
+ context=context,
47
+ namespace=namespace,
48
+ )
49
+
50
+
51
+ def create_directory_if_not_exists(directory: Path) -> None:
52
+ """
53
+ Create a directory.
54
+ """
55
+ try:
56
+ directory.mkdir(parents=True, exist_ok=True)
57
+ except Exception as e:
58
+ error(f"Failed to create directory {directory}: {e}")
59
+ exit(1)
60
+
61
+
62
+ def find_running_service_names(
63
+ instance_type: InstanceType,
64
+ only_system_folders: bool = False,
65
+ only_user_folders: bool = False,
66
+ context: str | None = None,
67
+ namespace: str | None = None,
68
+ ) -> list[str]:
69
+ """
70
+ List running Vantage6 servers.
71
+
72
+ Parameters
73
+ ----------
74
+ instance_type : InstanceType
75
+ The type of instance to find running services for
76
+ only_system_folders : bool, optional
77
+ Whether to look for system-based services or not. By default False.
78
+ only_user_folders : bool, optional
79
+ Whether to look for user-based services or not. By default False.
80
+ context : str, optional
81
+ The Kubernetes context to use.
82
+ namespace : str, optional
83
+ The Kubernetes namespace to use.
84
+
85
+ Returns
86
+ -------
87
+ list[str]
88
+ List of release names that are running
89
+ """
90
+ # Input validation
91
+ validate_input_cmd_args(context, "context name", allow_none=True)
92
+ validate_input_cmd_args(namespace, "namespace name", allow_none=True)
93
+ validate_input_cmd_args(instance_type, "instance type", allow_none=False)
94
+ if only_system_folders and only_user_folders:
95
+ error("Cannot use both only_system_folders and only_user_folders")
96
+ exit(1)
97
+
98
+ # Create the command
99
+ command = [
100
+ "helm",
101
+ "list",
102
+ "--output",
103
+ "json", # Get structured output
104
+ ]
105
+
106
+ if context:
107
+ command.extend(["--kube-context", context])
108
+
109
+ if namespace:
110
+ command.extend(["--namespace", namespace])
111
+ else:
112
+ command.extend(["--all-namespaces"])
113
+
114
+ try:
115
+ result = subprocess.run(
116
+ command,
117
+ capture_output=True,
118
+ text=True,
119
+ check=True,
120
+ )
121
+ except subprocess.CalledProcessError as e:
122
+ error(f"Failed to list Helm releases: {e}")
123
+ return []
124
+ except FileNotFoundError:
125
+ error(
126
+ "Helm command not found. Please ensure Helm is installed and available in "
127
+ "the PATH."
128
+ )
129
+ return []
130
+
131
+ try:
132
+ releases = json.loads(result.stdout)
133
+ except json.JSONDecodeError:
134
+ error("Failed to parse Helm output as JSON")
135
+ return []
136
+
137
+ # filter services for the vantage6 services that are sought. These have
138
+ # the following pattern:
139
+ # f"{APPNAME}-{name}-{scope}-{instance_type.value}"
140
+
141
+ # filter for the instance type
142
+ svc_starts_with = f"{APPNAME}-"
143
+ if only_system_folders:
144
+ svc_ends_with = f"system-{instance_type.value}"
145
+ elif only_user_folders:
146
+ svc_ends_with = f"user-{instance_type.value}"
147
+ else:
148
+ svc_ends_with = f"-{instance_type.value}"
149
+
150
+ matching_services = []
151
+ for release in releases:
152
+ release_name = release.get("name", "")
153
+
154
+ # Check if this is a Vantage6 server release
155
+ is_matching_service = (
156
+ release_name.startswith(svc_starts_with)
157
+ and release_name.endswith(svc_ends_with)
158
+ and instance_type.value in release_name
159
+ )
160
+
161
+ if is_matching_service:
162
+ matching_services.append(release_name)
163
+
164
+ return matching_services
165
+
166
+
167
+ def select_running_service(
168
+ running_services: list[str],
169
+ instance_type: InstanceType,
170
+ ) -> str:
171
+ """
172
+ Select a running service from the list of running services.
173
+ """
174
+ try:
175
+ name = q.select(
176
+ f"Select the {instance_type.value} you wish to inspect:",
177
+ choices=running_services,
178
+ ).unsafe_ask()
179
+ except KeyboardInterrupt:
180
+ error("Aborted by user!")
181
+ exit(1)
182
+ return name
14
183
 
15
184
 
16
185
  def get_server_name(
@@ -20,30 +189,30 @@ def get_server_name(
20
189
  instance_type: InstanceType,
21
190
  ) -> str:
22
191
  """
23
- Get the version of a running server.
192
+ Get the full name of a running server.
24
193
 
25
194
  Parameters
26
195
  ----------
27
196
  name : str
28
- Name of the server to get the version from
197
+ Name of the server to get the full name from
29
198
  system_folders : bool
30
199
  Whether to use system folders or not
31
200
  running_server_names : list[str]
32
201
  The names of the running servers
33
202
  instance_type : InstanceType
34
- The type of instance to get the running servers from
203
+ The type of instance to get the full name from
35
204
  """
36
205
 
37
206
  if not name:
38
207
  if not running_server_names:
39
208
  error(
40
- f"No {instance_type}s are running! You can only check the version for "
41
- f"{instance_type}s that are running"
209
+ f"No {instance_type.value}s are running! You can only check the version"
210
+ f" for {instance_type.value}s that are running"
42
211
  )
43
212
  exit(1)
44
213
  try:
45
214
  name = q.select(
46
- f"Select the {instance_type} you wish to inspect:",
215
+ f"Select the {instance_type.value} you wish to inspect:",
47
216
  choices=running_server_names,
48
217
  ).unsafe_ask()
49
218
  except KeyboardInterrupt:
@@ -73,7 +242,7 @@ def get_running_servers(
73
242
  The names of the running servers
74
243
  """
75
244
  running_servers = client.containers.list(
76
- filters={"label": f"{APPNAME}-type={instance_type}"}
245
+ filters={"label": f"{APPNAME}-type={instance_type.value}"}
77
246
  )
78
247
  return [server.name for server in running_servers]
79
248
 
@@ -87,10 +256,9 @@ def get_server_configuration_list(instance_type: InstanceType) -> None:
87
256
  instance_type : InstanceType
88
257
  The type of instance to get the configurations for
89
258
  """
90
- client = docker.from_env()
91
259
  ctx_class = select_context_class(instance_type)
92
260
 
93
- running_server_names = get_running_servers(client, instance_type)
261
+ running_server_names = find_running_service_names(instance_type)
94
262
  header = "\nName" + (21 * " ") + "Status" + (10 * " ") + "System/User"
95
263
 
96
264
  click.echo(header)
@@ -100,28 +268,37 @@ def get_server_configuration_list(instance_type: InstanceType) -> None:
100
268
  stopped = Fore.RED + "Not running" + Style.RESET_ALL
101
269
 
102
270
  # system folders
103
- configs, f1 = ctx_class.available_configurations(system_folders=True)
271
+ configs, failed_imports_system = ctx_class.available_configurations(
272
+ system_folders=True
273
+ )
104
274
  for config in configs:
105
275
  status = (
106
276
  running
107
- if f"{APPNAME}-{config.name}-system-{instance_type}" in running_server_names
277
+ if f"{APPNAME}-{config.name}-system-{instance_type.value}"
278
+ in running_server_names
108
279
  else stopped
109
280
  )
110
281
  click.echo(f"{config.name:25}{status:25} System ")
111
282
 
112
283
  # user folders
113
- configs, f2 = ctx_class.available_configurations(system_folders=False)
284
+ configs, failed_imports_user = ctx_class.available_configurations(
285
+ system_folders=False
286
+ )
114
287
  for config in configs:
115
288
  status = (
116
289
  running
117
- if f"{APPNAME}-{config.name}-user-{instance_type}" in running_server_names
290
+ if f"{APPNAME}-{config.name}-user-{instance_type.value}"
291
+ in running_server_names
118
292
  else stopped
119
293
  )
120
294
  click.echo(f"{config.name:25}{status:25} User ")
121
295
 
122
296
  click.echo("-" * 85)
123
- if len(f1) + len(f2):
124
- warning(f"{Fore.RED}Failed imports: {len(f1) + len(f2)}{Style.RESET_ALL}")
297
+ if len(failed_imports_system) + len(failed_imports_user):
298
+ warning(
299
+ f"{Fore.RED}Failed imports: "
300
+ f"{len(failed_imports_system) + len(failed_imports_user)}{Style.RESET_ALL}"
301
+ )
125
302
 
126
303
 
127
304
  def print_log_worker(logs_stream: Iterable[bytes]) -> None:
@@ -175,3 +352,22 @@ def attach_logs(*labels: list[str]) -> None:
175
352
  command = ["kubectl", "logs", "--follow", "--selector", ",".join(labels)]
176
353
  process = Popen(command, stdout=None, stderr=None)
177
354
  process.wait()
355
+
356
+
357
+ def get_main_cli_command_name(instance_type: InstanceType) -> str:
358
+ """
359
+ Get the main CLI command name for a given instance type.
360
+
361
+ Parameters
362
+ ----------
363
+ instance_type : InstanceType
364
+ The type of instance to get the main CLI command name for
365
+ """
366
+ if instance_type == InstanceType.SERVER:
367
+ return "server"
368
+ elif instance_type == InstanceType.ALGORITHM_STORE:
369
+ return "algorithm-store"
370
+ elif instance_type == InstanceType.NODE:
371
+ return "node"
372
+ else:
373
+ raise ValueError(f"Invalid instance type: {instance_type}")
@@ -4,6 +4,8 @@ from schema import And, Optional, Or, Use
4
4
 
5
5
  from vantage6.common.configuration_manager import Configuration, ConfigurationManager
6
6
 
7
+ from vantage6.cli.globals import ALGO_STORE_TEMPLATE_FILE, SERVER_TEMPLATE_FILE
8
+
7
9
  LOGGING_VALIDATORS = {
8
10
  "level": And(
9
11
  Use(str), lambda lvl: lvl in ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")
@@ -26,6 +28,15 @@ class ServerConfiguration(Configuration):
26
28
  VALIDATORS = {}
27
29
 
28
30
 
31
+ class AlgorithmStoreConfiguration(Configuration):
32
+ """
33
+ Stores the algorithm store's configuration and defines a set of algorithm store-specific
34
+ validators.
35
+ """
36
+
37
+ VALIDATORS = {}
38
+
39
+
29
40
  class NodeConfiguration(Configuration):
30
41
  """
31
42
  Stores the node's configuration and defines a set of node-specific
@@ -114,6 +125,60 @@ class ServerConfigurationManager(ConfigurationManager):
114
125
  """
115
126
  return super().from_file(path, conf_class=ServerConfiguration)
116
127
 
128
+ def get_config_template(self) -> str:
129
+ """
130
+ Get the configuration template for the server.
131
+
132
+ Returns
133
+ -------
134
+ str
135
+ The configuration template for the server.
136
+ """
137
+ return super()._get_config_template(SERVER_TEMPLATE_FILE)
138
+
139
+
140
+ class AlgorithmStoreConfigurationManager(ConfigurationManager):
141
+ """
142
+ Maintains the algorithm store's configuration.
143
+
144
+ Parameters
145
+ ----------
146
+ name : str
147
+ Name of the configuration file.
148
+ """
149
+
150
+ def __init__(self, name, *args, **kwargs) -> None:
151
+ super().__init__(conf_class=AlgorithmStoreConfiguration, name=name)
152
+
153
+ @classmethod
154
+ def from_file(cls, path: str) -> Self:
155
+ """
156
+ Create a new instance of the AlgorithmStoreConfigurationManager from a
157
+ configuration file.
158
+
159
+ Parameters
160
+ ----------
161
+ path : str
162
+ Path to the configuration file.
163
+
164
+ Returns
165
+ -------
166
+ AlgorithmStoreConfigurationManager
167
+ A new instance of the AlgorithmStoreConfigurationManager.
168
+ """
169
+ return super().from_file(path, conf_class=AlgorithmStoreConfiguration)
170
+
171
+ def get_config_template(self) -> str:
172
+ """
173
+ Get the configuration template for the algorithm store.
174
+
175
+ Returns
176
+ -------
177
+ str
178
+ The configuration template for the algorithm store.
179
+ """
180
+ return super()._get_config_template(ALGO_STORE_TEMPLATE_FILE)
181
+
117
182
 
118
183
  class TestingConfigurationManager(ConfigurationManager):
119
184
  def __init__(self, name, *args, **kwargs):