vantage6 4.2.1__py3-none-any.whl → 4.3.0b3__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.

Files changed (64) hide show
  1. tests_cli/test_example.py +0 -1
  2. tests_cli/test_node_cli.py +74 -79
  3. tests_cli/test_server_cli.py +22 -22
  4. tests_cli/test_wizard.py +41 -29
  5. vantage6/cli/__build__ +1 -1
  6. vantage6/cli/_version.py +11 -8
  7. vantage6/cli/algorithm/create.py +14 -14
  8. vantage6/cli/algorithm/update.py +9 -6
  9. vantage6/cli/algostore/attach.py +32 -0
  10. vantage6/cli/algostore/new.py +55 -0
  11. vantage6/cli/algostore/start.py +102 -0
  12. vantage6/cli/algostore/stop.py +60 -0
  13. vantage6/cli/cli.py +32 -12
  14. vantage6/cli/common/decorator.py +92 -0
  15. vantage6/cli/common/start.py +232 -0
  16. vantage6/cli/configuration_manager.py +22 -32
  17. vantage6/cli/configuration_wizard.py +255 -193
  18. vantage6/cli/context/__init__.py +86 -0
  19. vantage6/cli/context/algorithm_store.py +130 -0
  20. vantage6/cli/context/base_server.py +89 -0
  21. vantage6/cli/context/node.py +254 -0
  22. vantage6/cli/context/server.py +127 -0
  23. vantage6/cli/dev/create.py +180 -113
  24. vantage6/cli/dev/remove.py +20 -19
  25. vantage6/cli/dev/start.py +10 -10
  26. vantage6/cli/dev/stop.py +7 -5
  27. vantage6/cli/globals.py +24 -0
  28. vantage6/cli/node/attach.py +21 -10
  29. vantage6/cli/node/clean.py +4 -2
  30. vantage6/cli/node/common/__init__.py +15 -11
  31. vantage6/cli/node/create_private_key.py +58 -27
  32. vantage6/cli/node/files.py +14 -6
  33. vantage6/cli/node/list.py +18 -24
  34. vantage6/cli/node/new.py +21 -12
  35. vantage6/cli/node/remove.py +31 -22
  36. vantage6/cli/node/set_api_key.py +18 -12
  37. vantage6/cli/node/start.py +38 -12
  38. vantage6/cli/node/stop.py +32 -18
  39. vantage6/cli/node/version.py +23 -13
  40. vantage6/cli/rabbitmq/__init__.py +9 -9
  41. vantage6/cli/rabbitmq/definitions.py +24 -28
  42. vantage6/cli/rabbitmq/queue_manager.py +37 -40
  43. vantage6/cli/server/attach.py +16 -11
  44. vantage6/cli/server/common/__init__.py +37 -25
  45. vantage6/cli/server/files.py +1 -1
  46. vantage6/cli/server/import_.py +45 -37
  47. vantage6/cli/server/list.py +22 -23
  48. vantage6/cli/server/new.py +20 -14
  49. vantage6/cli/server/remove.py +5 -4
  50. vantage6/cli/server/shell.py +17 -6
  51. vantage6/cli/server/start.py +118 -174
  52. vantage6/cli/server/stop.py +31 -23
  53. vantage6/cli/server/version.py +16 -13
  54. vantage6/cli/test/common/diagnostic_runner.py +30 -34
  55. vantage6/cli/test/feature_tester.py +51 -25
  56. vantage6/cli/test/integration_test.py +69 -29
  57. vantage6/cli/utils.py +6 -5
  58. {vantage6-4.2.1.dist-info → vantage6-4.3.0b3.dist-info}/METADATA +5 -3
  59. vantage6-4.3.0b3.dist-info/RECORD +68 -0
  60. vantage6/cli/context.py +0 -416
  61. vantage6-4.2.1.dist-info/RECORD +0 -58
  62. {vantage6-4.2.1.dist-info → vantage6-4.3.0b3.dist-info}/WHEEL +0 -0
  63. {vantage6-4.2.1.dist-info → vantage6-4.3.0b3.dist-info}/entry_points.txt +0 -0
  64. {vantage6-4.2.1.dist-info → vantage6-4.3.0b3.dist-info}/top_level.txt +0 -0
@@ -3,14 +3,16 @@ import questionary as q
3
3
  from pathlib import Path
4
4
 
5
5
  from vantage6.common import generate_apikey
6
- from vantage6.common.globals import DATABASE_TYPES
6
+ from vantage6.common.globals import DATABASE_TYPES, InstanceType
7
7
  from vantage6.common.client.node_client import NodeClient
8
+ from vantage6.common.context import AppContext
8
9
  from vantage6.common import error, warning
9
- from vantage6.cli.context import NodeContext, ServerContext
10
+ from vantage6.cli.context import select_context_class
10
11
  from vantage6.cli.configuration_manager import (
11
12
  NodeConfigurationManager,
12
- ServerConfigurationManager
13
+ ServerConfigurationManager,
13
14
  )
15
+ from vantage6.cli.globals import AlgoStoreGlobals, ServerGlobals
14
16
 
15
17
 
16
18
  def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
@@ -29,75 +31,69 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
29
31
  dict
30
32
  Dictionary with the new node configuration
31
33
  """
32
- config = q.prompt([
33
- {
34
- "type": "text",
35
- "name": "api_key",
36
- "message": "Enter given api-key:"
37
- },
38
- {
39
- "type": "text",
40
- "name": "server_url",
41
- "message": "The base-URL of the server:",
42
- "default": "http://localhost"
43
- },
44
- {
45
- "type": "text",
46
- "name": "port",
47
- "message": "Enter port to which the server listens:",
48
- "default": "5000"
49
- },
50
- {
51
- "type": "text",
52
- "name": "api_path",
53
- "message": "Path of the api:",
54
- "default": "/api"
55
- },
56
- {
57
- "type": "text",
58
- "name": "task_dir",
59
- "message": "Task directory path:",
60
- "default": str(dirs["data"])
61
- }
62
- ])
63
-
64
- config["databases"] = list()
65
- while q.confirm("Do you want to add a database?").ask():
66
- db_label = q.prompt([
34
+ config = q.prompt(
35
+ [
36
+ {"type": "text", "name": "api_key", "message": "Enter given api-key:"},
67
37
  {
68
38
  "type": "text",
69
- "name": "label",
70
- "message": "Enter unique label for the database:",
71
- "default": "default"
72
- }
73
- ])
74
- db_path = q.prompt([
39
+ "name": "server_url",
40
+ "message": "The base-URL of the server:",
41
+ "default": "http://localhost",
42
+ },
43
+ {
44
+ "type": "text",
45
+ "name": "port",
46
+ "message": "Enter port to which the server listens:",
47
+ "default": "5000",
48
+ },
75
49
  {
76
50
  "type": "text",
77
- "name": "uri",
78
- "message": "Database URI:"
79
- }
80
- ])
51
+ "name": "api_path",
52
+ "message": "Path of the api:",
53
+ "default": "/api",
54
+ },
55
+ {
56
+ "type": "text",
57
+ "name": "task_dir",
58
+ "message": "Task directory path:",
59
+ "default": str(dirs["data"]),
60
+ },
61
+ ]
62
+ )
63
+
64
+ config["databases"] = list()
65
+ while q.confirm("Do you want to add a database?").ask():
66
+ db_label = q.prompt(
67
+ [
68
+ {
69
+ "type": "text",
70
+ "name": "label",
71
+ "message": "Enter unique label for the database:",
72
+ "default": "default",
73
+ }
74
+ ]
75
+ )
76
+ db_path = q.prompt(
77
+ [{"type": "text", "name": "uri", "message": "Database URI:"}]
78
+ )
81
79
  db_type = q.select("Database type:", choices=DATABASE_TYPES).ask()
82
80
 
83
81
  config["databases"].append(
84
- {
85
- "label": db_label.get("label"),
86
- "uri": db_path.get("uri"),
87
- "type": db_type
88
- }
82
+ {"label": db_label.get("label"), "uri": db_path.get("uri"), "type": db_type}
89
83
  )
90
84
 
91
- res = q.select("Which level of logging would you like?",
92
- choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL",
93
- "NOTSET"]).ask()
85
+ res = q.select(
86
+ "Which level of logging would you like?",
87
+ choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NOTSET"],
88
+ ).ask()
94
89
 
95
90
  is_add_vpn = q.confirm(
96
- "Do you want to connect to a VPN server?", default=False).ask()
91
+ "Do you want to connect to a VPN server?", default=False
92
+ ).ask()
97
93
  if is_add_vpn:
98
- config['vpn_subnet'] = q.text(
94
+ config["vpn_subnet"] = q.text(
99
95
  message="Subnet of the VPN server you want to connect to:",
100
- default='10.76.0.0/16'
96
+ default="10.76.0.0/16",
101
97
  ).ask()
102
98
 
103
99
  config["logging"] = {
@@ -113,19 +109,20 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
113
109
  {"name": "engineio.client", "level": "warning"},
114
110
  {"name": "docker.utils.config", "level": "warning"},
115
111
  {"name": "docker.auth", "level": "warning"},
116
- ]
112
+ ],
117
113
  }
118
114
 
119
115
  # Check if we can login to the server to retrieve collaboration settings
120
- client = NodeClient(config['server_url'], config['port'],
121
- config['api_path'])
116
+ client = NodeClient(config["server_url"], config["port"], config["api_path"])
122
117
  try:
123
- client.authenticate(config['api_key'])
118
+ client.authenticate(config["api_key"])
124
119
  except Exception as e:
125
120
  error(f"Could not authenticate with server: {e}")
126
121
  error("Please check (1) your API key and (2) if your server is online")
127
- warning("If you continue, you should provide your collaboration "
128
- "settings manually.")
122
+ warning(
123
+ "If you continue, you should provide your collaboration "
124
+ "settings manually."
125
+ )
129
126
  if q.confirm("Do you want to abort?", default=True).ask():
130
127
  exit(0)
131
128
 
@@ -134,140 +131,102 @@ def node_configuration_questionaire(dirs: dict, instance_name: str) -> dict:
134
131
  # TODO when we build collaboration policies, update this to provide
135
132
  # the node admin with a list of all policies, and whether or not
136
133
  # to accept them
137
- q.confirm(f"Encryption is {'enabled' if encryption else 'disabled'}"
138
- f" for this collaboration. Accept?", default=True).ask()
134
+ q.confirm(
135
+ f"Encryption is {'enabled' if encryption else 'disabled'}"
136
+ f" for this collaboration. Accept?",
137
+ default=True,
138
+ ).ask()
139
139
  else:
140
140
  encryption = q.confirm("Enable encryption?", default=True).ask()
141
141
 
142
- private_key = "" if not encryption else \
143
- q.text("Path to private key file:").ask()
142
+ private_key = "" if not encryption else q.text("Path to private key file:").ask()
144
143
 
145
- config["encryption"] = {
146
- "enabled": encryption == "true",
147
- "private_key": private_key
148
- }
144
+ config["encryption"] = {"enabled": encryption == "true", "private_key": private_key}
149
145
 
150
146
  return config
151
147
 
152
148
 
153
- def server_configuration_questionaire(instance_name: str) -> dict:
149
+ def _get_common_server_config(
150
+ instance_type: InstanceType, instance_name: str, include_api_path: bool = True
151
+ ) -> dict:
154
152
  """
155
- Questionary to generate a config file for the node instance.
153
+ Part of the questionaire that is common to all server types (vantage6
154
+ server and algorithm store server).
156
155
 
157
156
  Parameters
158
157
  ----------
158
+ instance_type : InstanceType
159
+ Type of server instance.
159
160
  instance_name : str
160
- Name of the node instance.
161
+ Name of the server instance.
162
+ include_api_path : bool
163
+ Whether to include the api path in the questionaire.
161
164
 
162
165
  Returns
163
166
  -------
164
167
  dict
165
- Dictionary with the new server configuration
168
+ Dictionary with new (partial) server configuration
166
169
  """
167
-
168
- config = q.prompt([
169
- {
170
- "type": "text",
171
- "name": "description",
172
- "message": "Enter a human-readable description:"
173
- },
174
- {
175
- "type": "text",
176
- "name": "ip",
177
- "message": "ip:",
178
- "default": "0.0.0.0"
179
- },
180
- {
181
- "type": "text",
182
- "name": "port",
183
- "message": "Enter port to which the server listens:",
184
- "default": "5000"
185
- },
186
- {
187
- "type": "text",
188
- "name": "api_path",
189
- "message": "Path of the api:",
190
- "default": "/api"
191
- },
192
- {
193
- "type": "text",
194
- "name": "uri",
195
- "message": "Database URI:",
196
- "default": "sqlite:///default.sqlite"
197
- },
198
- {
199
- "type": "select",
200
- "name": "allow_drop_all",
201
- "message": "Allowed to drop all tables: ",
202
- "choices": ["True", "False"]
203
- }
204
- ])
205
-
206
- constant_jwt_secret = q.confirm("Do you want a constant JWT secret?").ask()
207
- if constant_jwt_secret:
208
- config["jwt_secret_key"] = generate_apikey()
209
-
210
- res = q.select("Which level of logging would you like?",
211
- choices=["DEBUG", "INFO", "WARNING", "ERROR",
212
- "CRITICAL", "NOTSET"]).ask()
213
-
214
- is_mfa = q.confirm(
215
- "Do you want to enforce two-factor authentication?"
216
- ).ask()
217
- if is_mfa:
218
- config['two_factor_auth'] = is_mfa
219
-
220
- is_add_vpn = q.confirm(
221
- "Do you want to add a VPN server?", default=False).ask()
222
- if is_add_vpn:
223
- vpn_config = q.prompt([
224
- {
225
- "type": "text",
226
- "name": "url",
227
- "message": "VPN server URL:",
228
- },
170
+ config = q.prompt(
171
+ [
229
172
  {
230
173
  "type": "text",
231
- "name": "portal_username",
232
- "message": "VPN portal username:",
233
- },
234
- {
235
- "type": "password",
236
- "name": "portal_userpass",
237
- "message": "VPN portal password:",
174
+ "name": "description",
175
+ "message": "Enter a human-readable description:",
238
176
  },
177
+ {"type": "text", "name": "ip", "message": "ip:", "default": "0.0.0.0"},
239
178
  {
240
179
  "type": "text",
241
- "name": "client_id",
242
- "message": "VPN client username:",
180
+ "name": "port",
181
+ "message": "Enter port to which the server listens:",
182
+ "default": (
183
+ # Note that .value is required in YAML to get proper str value
184
+ ServerGlobals.PORT.value
185
+ if instance_type == InstanceType.SERVER
186
+ else AlgoStoreGlobals.PORT.value
187
+ ),
243
188
  },
244
- {
245
- "type": "password",
246
- "name": "client_secret",
247
- "message": "VPN client password:",
248
- },
249
- {
250
- "type": "text",
251
- "name": "redirect_url",
252
- "message": "Redirect url (should be local address of server)",
253
- "default": "http://localhost"
254
- }
255
- ])
256
- config['vpn_server'] = vpn_config
257
-
258
- is_add_rabbitmq = q.confirm(
259
- "Do you want to add a RabbitMQ message queue?").ask()
260
- if is_add_rabbitmq:
261
- rabbit_uri = q.text(
262
- message='Enter the URI for your RabbitMQ:'
263
- ).ask()
264
- run_rabbit_locally = q.confirm(
265
- "Do you want to run RabbitMQ locally? (Use only for testing)"
266
- ).ask()
267
- config['rabbitmq'] = {
268
- 'uri': rabbit_uri,
269
- 'start_with_server': run_rabbit_locally
270
- }
189
+ ]
190
+ )
191
+
192
+ # TODO v5+ remove api_path. It complicates configuration
193
+ if include_api_path:
194
+ config.update(
195
+ q.prompt(
196
+ [
197
+ {
198
+ "type": "text",
199
+ "name": "api_path",
200
+ "message": "Path of the api:",
201
+ "default": "/api",
202
+ }
203
+ ]
204
+ )
205
+ )
206
+
207
+ config.update(
208
+ q.prompt(
209
+ [
210
+ {
211
+ "type": "text",
212
+ "name": "uri",
213
+ "message": "Database URI:",
214
+ "default": "sqlite:///default.sqlite",
215
+ },
216
+ {
217
+ "type": "select",
218
+ "name": "allow_drop_all",
219
+ "message": "Allowed to drop all tables: ",
220
+ "choices": ["True", "False"],
221
+ },
222
+ ]
223
+ )
224
+ )
225
+
226
+ res = q.select(
227
+ "Which level of logging would you like?",
228
+ choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL", "NOTSET"],
229
+ ).ask()
271
230
 
272
231
  config["logging"] = {
273
232
  "level": res,
@@ -284,21 +243,123 @@ def server_configuration_questionaire(instance_name: str) -> dict:
284
243
  {"name": "engineio.server", "level": "warning"},
285
244
  {"name": "sqlalchemy.engine", "level": "warning"},
286
245
  {"name": "requests_oauthlib.oauth2_session", "level": "warning"},
287
- ]
246
+ ],
288
247
  }
289
248
 
290
249
  return config
291
250
 
292
251
 
293
- def configuration_wizard(type_: str, instance_name: str,
294
- system_folders: bool) -> Path:
252
+ def server_configuration_questionaire(instance_name: str) -> dict:
253
+ """
254
+ Questionary to generate a config file for the server instance.
255
+
256
+ Parameters
257
+ ----------
258
+ instance_name : str
259
+ Name of the server instance.
260
+
261
+ Returns
262
+ -------
263
+ dict
264
+ Dictionary with the new server configuration
265
+ """
266
+
267
+ config = _get_common_server_config(
268
+ InstanceType.SERVER, instance_name, include_api_path=True
269
+ )
270
+
271
+ constant_jwt_secret = q.confirm("Do you want a constant JWT secret?").ask()
272
+ if constant_jwt_secret:
273
+ config["jwt_secret_key"] = generate_apikey()
274
+
275
+ is_mfa = q.confirm("Do you want to enforce two-factor authentication?").ask()
276
+ if is_mfa:
277
+ config["two_factor_auth"] = is_mfa
278
+
279
+ is_add_vpn = q.confirm("Do you want to add a VPN server?", default=False).ask()
280
+ if is_add_vpn:
281
+ vpn_config = q.prompt(
282
+ [
283
+ {
284
+ "type": "text",
285
+ "name": "url",
286
+ "message": "VPN server URL:",
287
+ },
288
+ {
289
+ "type": "text",
290
+ "name": "portal_username",
291
+ "message": "VPN portal username:",
292
+ },
293
+ {
294
+ "type": "password",
295
+ "name": "portal_userpass",
296
+ "message": "VPN portal password:",
297
+ },
298
+ {
299
+ "type": "text",
300
+ "name": "client_id",
301
+ "message": "VPN client username:",
302
+ },
303
+ {
304
+ "type": "password",
305
+ "name": "client_secret",
306
+ "message": "VPN client password:",
307
+ },
308
+ {
309
+ "type": "text",
310
+ "name": "redirect_url",
311
+ "message": "Redirect url (should be local address of server)",
312
+ "default": "http://localhost",
313
+ },
314
+ ]
315
+ )
316
+ config["vpn_server"] = vpn_config
317
+
318
+ is_add_rabbitmq = q.confirm("Do you want to add a RabbitMQ message queue?").ask()
319
+ if is_add_rabbitmq:
320
+ rabbit_uri = q.text(message="Enter the URI for your RabbitMQ:").ask()
321
+ run_rabbit_locally = q.confirm(
322
+ "Do you want to run RabbitMQ locally? (Use only for testing)"
323
+ ).ask()
324
+ config["rabbitmq"] = {
325
+ "uri": rabbit_uri,
326
+ "start_with_server": run_rabbit_locally,
327
+ }
328
+
329
+ return config
330
+
331
+
332
+ def algo_store_configuration_questionaire(instance_name: str) -> dict:
333
+ """
334
+ Questionary to generate a config file for the algorithm store server
335
+ instance.
336
+
337
+ Parameters
338
+ ----------
339
+ instance_name : str
340
+ Name of the server instance.
341
+
342
+ Returns
343
+ -------
344
+ dict
345
+ Dictionary with the new server configuration
346
+ """
347
+ config = _get_common_server_config(
348
+ InstanceType.ALGORITHM_STORE, instance_name, include_api_path=False
349
+ )
350
+ return config
351
+
352
+
353
+ def configuration_wizard(
354
+ type_: InstanceType, instance_name: str, system_folders: bool
355
+ ) -> Path:
295
356
  """
296
357
  Create a configuration file for a node or server instance.
297
358
 
298
359
  Parameters
299
360
  ----------
300
- type_ : str
301
- Type of the instance. Either "node" or "server"
361
+ type_ : InstanceType
362
+ Type of the instance to create a configuration for
302
363
  instance_name : str
303
364
  Name of the instance
304
365
  system_folders : bool
@@ -310,15 +371,18 @@ def configuration_wizard(type_: str, instance_name: str,
310
371
  Path to the configuration file
311
372
  """
312
373
  # for defaults and where to save the config
313
- dirs = NodeContext.instance_folders(type_, instance_name, system_folders)
374
+ dirs = AppContext.instance_folders(type_, instance_name, system_folders)
314
375
 
315
376
  # invoke questionaire to create configuration file
316
- if type_ == "node":
377
+ if type_ == InstanceType.NODE:
317
378
  conf_manager = NodeConfigurationManager
318
379
  config = node_configuration_questionaire(dirs, instance_name)
319
- else:
380
+ elif type_ == InstanceType.SERVER:
320
381
  conf_manager = ServerConfigurationManager
321
382
  config = server_configuration_questionaire(instance_name)
383
+ else:
384
+ conf_manager = ServerConfigurationManager
385
+ config = algo_store_configuration_questionaire(instance_name)
322
386
 
323
387
  # in the case of an environment we need to add it to the current
324
388
  # configuration. In the case of application we can simply overwrite this
@@ -336,15 +400,15 @@ def configuration_wizard(type_: str, instance_name: str,
336
400
  return config_file
337
401
 
338
402
 
339
- def select_configuration_questionaire(type_: str, system_folders: bool) -> str:
403
+ def select_configuration_questionaire(type_: InstanceType, system_folders: bool) -> str:
340
404
  """
341
405
  Ask which configuration the user wants to use. It shows only configurations
342
406
  that are in the default folder.
343
407
 
344
408
  Parameters
345
409
  ----------
346
- type_ : str
347
- Type of the instance. Either "node" or "server"
410
+ type_ : InstanceType
411
+ Type of the instance to create a configuration for
348
412
  system_folders : bool
349
413
  Whether to use the system folders or not
350
414
 
@@ -353,21 +417,19 @@ def select_configuration_questionaire(type_: str, system_folders: bool) -> str:
353
417
  str
354
418
  Name of the configuration
355
419
  """
356
- context = NodeContext if type_ == "node" else ServerContext
420
+ context = select_context_class(type_)
357
421
  configs, _ = context.available_configurations(system_folders)
358
422
 
359
423
  # each collection (file) can contain multiple configs. (e.g. test,
360
424
  # dev)
361
425
  choices = []
362
426
  for config_collection in configs:
363
- choices.append(q.Choice(
364
- title=f"{config_collection.name:25}",
365
- value=config_collection.name
366
- ))
427
+ choices.append(
428
+ q.Choice(title=f"{config_collection.name:25}", value=config_collection.name)
429
+ )
367
430
 
368
431
  if not choices:
369
432
  raise Exception("No configurations could be found!")
370
433
 
371
434
  # pop the question
372
- return q.select("Select the configuration you want to use:",
373
- choices=choices).ask()
435
+ return q.select("Select the configuration you want to use:", choices=choices).ask()
@@ -0,0 +1,86 @@
1
+ """
2
+ The context module in the CLI package contains the Context classes of instances
3
+ started from the CLI, such as nodes and servers. These contexts are related to
4
+ the host system and therefore part of the CLI package.
5
+
6
+ All classes are derived from the abstract AppContext class and provide the
7
+ vantage6 applications with naming conventions, standard file locations, and
8
+ more.
9
+ """
10
+ from colorama import Fore, Style
11
+
12
+ from vantage6.common.globals import InstanceType
13
+ from vantage6.common import error
14
+ from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
15
+ from vantage6.cli.context.node import NodeContext
16
+ from vantage6.cli.context.server import ServerContext
17
+
18
+
19
+ def select_context_class(
20
+ type_: InstanceType,
21
+ ) -> ServerContext | NodeContext | AlgorithmStoreContext:
22
+ """
23
+ Select the context class based on the type of instance.
24
+
25
+ Parameters
26
+ ----------
27
+ type_ : InstanceType
28
+ The type of instance for which the context should be inserted
29
+
30
+ Returns
31
+ -------
32
+ ServerContext | NodeContext | AlgorithmStoreContext
33
+ Specialized subclass of AppContext for the given instance type
34
+
35
+ Raises
36
+ ------
37
+ NotImplementedError
38
+ If the type_ is not implemented
39
+ """
40
+ if type_ == InstanceType.SERVER:
41
+ return ServerContext
42
+ elif type_ == InstanceType.ALGORITHM_STORE:
43
+ return AlgorithmStoreContext
44
+ elif type_ == InstanceType.NODE:
45
+ return NodeContext
46
+ else:
47
+ raise NotImplementedError
48
+
49
+
50
+ def get_context(
51
+ type_: InstanceType, name: str, system_folders: bool
52
+ ) -> ServerContext | NodeContext | AlgorithmStoreContext:
53
+ """
54
+ Load the server context from the configuration file.
55
+
56
+ Parameters
57
+ ----------
58
+ type_ : InstanceType
59
+ The type of instance to get the context for
60
+ name : str
61
+ Name of the instance
62
+ system_folders : bool
63
+ Wether to use system folders or if False, the user folders
64
+
65
+ Returns
66
+ -------
67
+ AppContext
68
+ Specialized subclass context of AppContext for the given instance type
69
+ """
70
+ ctx_class = select_context_class(type_)
71
+ if not ctx_class.config_exists(name, system_folders):
72
+ scope = "system" if system_folders else "user"
73
+ error(
74
+ f"Configuration {Fore.RED}{name}{Style.RESET_ALL} does not "
75
+ f"exist in the {Fore.RED}{scope}{Style.RESET_ALL} folders!"
76
+ )
77
+ exit(1)
78
+
79
+ # We do not want to log this here, we do this in the container and not on
80
+ # the host. We only want CLI logging here.
81
+ ctx_class.LOGGING_ENABLED = False
82
+
83
+ # create server context, and initialize db
84
+ ctx = ctx_class(name, system_folders=system_folders)
85
+
86
+ return ctx