vantage6 5.0.0a29__py3-none-any.whl → 5.0.0a33__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.

vantage6/cli/__init__.py CHANGED
@@ -1,3 +1,7 @@
1
1
  """Command line interface for the vantage6 infrastructure."""
2
2
 
3
- from ._version import version_info, __version__ # noqa: F401
3
+ import importlib.metadata
4
+
5
+ # note that here we cannot use __package__ because __package__ resolves to vantage6.cli
6
+ # whereas the PyPi package is called vantage6
7
+ __version__ = importlib.metadata.version("vantage6")
@@ -19,8 +19,6 @@ from vantage6.common.algorithm_function import (
19
19
  )
20
20
  from vantage6.common.enum import AlgorithmArgumentType, AlgorithmStepType, StrEnumBase
21
21
 
22
- from vantage6.algorithm.tools import DecoratorStepType
23
-
24
22
  from vantage6.algorithm.client import AlgorithmClient
25
23
  from vantage6.algorithm.preprocessing.algorithm_json_data import (
26
24
  PREPROCESSING_FUNCTIONS_JSON_DATA,
@@ -120,7 +118,7 @@ class Function:
120
118
  # infrastructure-defined function
121
119
  if (
122
120
  not self.func.__module__.startswith("vantage6.algorithm.")
123
- or not self.json["name"] in PREPROCESSING_FUNCTIONS_JSON_DATA
121
+ or self.json["name"] not in PREPROCESSING_FUNCTIONS_JSON_DATA
124
122
  ):
125
123
  return
126
124
 
@@ -327,14 +325,8 @@ class Function:
327
325
  def _get_step_type(self) -> AlgorithmStepType | None:
328
326
  """Get the step type of the function"""
329
327
  decorator_type = get_vantage6_decorator_type(self.func)
330
- if decorator_type == DecoratorStepType.FEDERATED:
331
- return AlgorithmStepType.FEDERATED_COMPUTE
332
- elif decorator_type == DecoratorStepType.CENTRAL:
333
- return AlgorithmStepType.CENTRAL_COMPUTE
334
- elif decorator_type == DecoratorStepType.PREPROCESSING:
335
- return AlgorithmStepType.PREPROCESSING
336
- elif decorator_type == DecoratorStepType.DATA_EXTRACTION:
337
- return AlgorithmStepType.DATA_EXTRACTION
328
+ if decorator_type in AlgorithmStepType.list():
329
+ return decorator_type
338
330
  else:
339
331
  warning(
340
332
  f"Unsupported decorator type: {decorator_type} for function {self.name}"
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from vantage6.common.globals import APPNAME, InstanceType
4
4
 
5
- from vantage6.cli._version import __version__
5
+ from vantage6.cli import __version__
6
6
  from vantage6.cli.configuration_manager import ServerConfigurationManager
7
7
  from vantage6.cli.context.base_server import BaseServerContext
8
8
  from vantage6.cli.globals import (
@@ -7,7 +7,7 @@ from pathlib import Path
7
7
  from vantage6.common.context import AppContext
8
8
  from vantage6.common.globals import APPNAME, STRING_ENCODING, InstanceType
9
9
 
10
- from vantage6.cli._version import __version__
10
+ from vantage6.cli import __version__
11
11
  from vantage6.cli.configuration_manager import NodeConfigurationManager
12
12
  from vantage6.cli.globals import DEFAULT_NODE_SYSTEM_FOLDERS as N_FOL
13
13
 
@@ -40,7 +40,12 @@ class NodeContext(AppContext):
40
40
  logger_prefix: str = "",
41
41
  ):
42
42
  super().__init__(
43
- InstanceType.NODE, instance_name, system_folders=system_folders
43
+ InstanceType.NODE,
44
+ instance_name,
45
+ system_folders=system_folders,
46
+ config_file=config_file,
47
+ print_log_header=print_log_header,
48
+ logger_prefix=logger_prefix,
44
49
  )
45
50
  if print_log_header:
46
51
  self.log.info("vantage6 version '%s'", __version__)
@@ -4,7 +4,7 @@ from pathlib import Path
4
4
 
5
5
  from vantage6.common.globals import APPNAME, InstanceType
6
6
 
7
- from vantage6.cli._version import __version__
7
+ from vantage6.cli import __version__
8
8
  from vantage6.cli.configuration_manager import ServerConfigurationManager
9
9
  from vantage6.cli.context.base_server import BaseServerContext
10
10
  from vantage6.cli.globals import (
@@ -0,0 +1,54 @@
1
+ Metadata-Version: 2.4
2
+ Name: vantage6
3
+ Version: 5.0.0a33
4
+ Summary: vantage6 command line interface
5
+ Author: Vantage6 Team
6
+ Maintainer-email: Frank Martin <f.martin@iknl.nl>, Bart van Beusekom <b.vanbeusekom@iknl.nl>
7
+ License: MIT
8
+ Requires-Python: >=3.13
9
+ Requires-Dist: click==8.1.3
10
+ Requires-Dist: colorama==0.4.6
11
+ Requires-Dist: copier==9.2.0
12
+ Requires-Dist: docker==7.1.0
13
+ Requires-Dist: ipython==8.10.0
14
+ Requires-Dist: jinja2==3.1.6
15
+ Requires-Dist: kubernetes==28.1.0
16
+ Requires-Dist: pandas>=2.2.3
17
+ Requires-Dist: questionary==1.10.0
18
+ Requires-Dist: rich==13.5.2
19
+ Requires-Dist: schema==0.7.5
20
+ Requires-Dist: sqlalchemy==2.0.37
21
+ Requires-Dist: vantage6-client==5.0.0a33
22
+ Requires-Dist: vantage6-common==5.0.0a33
23
+ Provides-Extra: dev
24
+ Requires-Dist: black; extra == 'dev'
25
+ Requires-Dist: coverage==7.10.2; extra == 'dev'
26
+ Requires-Dist: pre-commit; extra == 'dev'
27
+ Description-Content-Type: text/markdown
28
+
29
+ <h1 align="center">
30
+ <br>
31
+ <a href="https://vantage6.ai"><img src="https://github.com/IKNL/guidelines/blob/master/resources/logos/vantage6.png?raw=true" alt="vantage6" width="350"></a>
32
+ </h1>
33
+
34
+ <h3 align=center> A Privacy Enhancing Technology (PET) Operations platform</h3>
35
+
36
+ ---
37
+
38
+ # Vantage6 CLI
39
+
40
+ This package provides the command-line interface (CLI) for managing vantage6
41
+ infrastructure instances, such as servers and nodes.
42
+
43
+ ## Documentation
44
+
45
+ For complete documentation, installation instructions, and usage examples, please see
46
+ the **[main Vantage6 README](https://github.com/vantage6/vantage6/blob/main/README.md)**
47
+ .
48
+
49
+ ## About Vantage6
50
+
51
+ Vantage6 is a Privacy Enhancing Technology (PET) Operations platform that enables
52
+ federated learning and multi-party computation. For more information, visit
53
+ [vantage6.ai](https://vantage6.ai) or join our
54
+ [Discord community](https://discord.gg/yAyFf6Y).
@@ -1,12 +1,4 @@
1
- tests_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- tests_cli/test_client_script.py,sha256=_Wf8nKEfq6HEnfUQtwZvyICEmEa1TngyI_orPRQ7ZNQ,683
3
- tests_cli/test_example.py,sha256=0fw_v-lgZEacshWSDwLNyLMA1_xc48bKUGM3ll-n1L0,146
4
- tests_cli/test_node_cli.py,sha256=jM-nZkcvdEwwHVgQi8C7cYAbTJOzVmFl60MFXYVH9ig,16798
5
- tests_cli/test_server_cli.py,sha256=i0XBybUPn0_ACOHBi8d6vFETut7szz3Zt8ttmZhWVPc,6545
6
- tests_cli/test_wizard.py,sha256=ds2gJeBasQ06-nzqsPSSxrj-COe4pCLPgqrlBVkCXkw,5021
7
- vantage6/cli/__build__,sha256=NRNaqmzCOJG0DLPzeMU6F6ESchDOYOElzPA-_P2uxFg,2
8
- vantage6/cli/__init__.py,sha256=ZXbeQ_-g2-M4XYteWZkoO5lMFYhqjm5doQgGy1fq8i0,125
9
- vantage6/cli/_version.py,sha256=iDijqhgy5jzZ0LAyzW1LlXeeuMcHWMyg9D8xbXtV7Ck,696
1
+ vantage6/cli/__init__.py,sha256=8KIgMPbZTNdkYlUrB8irpsUA7KdkFdLbNbMKixOP2dE,277
10
2
  vantage6/cli/cli.py,sha256=EeMfvBABKYauujZDR09IjpBgtbBg1sS1iJPuzre-AqM,6474
11
3
  vantage6/cli/config.py,sha256=Jqe3VcvoxPrFlvw7cuKt4-5oyL0YTZXvpNsqPybSAYk,7973
12
4
  vantage6/cli/configuration_manager.py,sha256=FV0RmiKmaGI2le8coUA4R5NTFUgPeph5XimxqgDhIsg,3332
@@ -14,7 +6,7 @@ vantage6/cli/configuration_wizard.py,sha256=6UB4YwBlCjRT88bHgp6VeDFgQklAM2g2WXS1
14
6
  vantage6/cli/globals.py,sha256=CxpxWXBLvAJR7st4-iRh95xbBZrn3qxKdbW3_7wmKY8,2245
15
7
  vantage6/cli/utils.py,sha256=mhCtsxCf8nOCaW3layW8aJGI0XAjGs0IuheCNj3o-IA,4397
16
8
  vantage6/cli/algorithm/create.py,sha256=kRT1BlBcb0fDaB2Q988WxtA6EyAZmOW5QoU2uhbwBIo,2075
17
- vantage6/cli/algorithm/generate_algorithm_json.py,sha256=zwWtPVx_J2QtGHW9GnR3X95l0e3aP-zNASM6ADiVnrM,19983
9
+ vantage6/cli/algorithm/generate_algorithm_json.py,sha256=huaqoadhz-2-Sy6SON9zFe_cAatvE7dtTQazvmNOgMA,19558
18
10
  vantage6/cli/algorithm/update.py,sha256=WwAfTnq0kTOgePUsBzGoo1AJQqGMn82E9Bjk1wf61CQ,1338
19
11
  vantage6/cli/algostore/attach.py,sha256=0WzLnKigJAelPpL5EaWcnRuUyQzMSofrrZfEzwDIvSw,311
20
12
  vantage6/cli/algostore/files.py,sha256=r89VRixK_K-c44qseq58Aa2Dqf1wEf8yompQRN5AVu4,580
@@ -28,10 +20,10 @@ vantage6/cli/common/start.py,sha256=6L_6NraS1U9Gj_UiQYkg4UE4bwjQkCQdTigb1L6fCm4,
28
20
  vantage6/cli/common/stop.py,sha256=CxW5OFZT7eacpln9J05ble2Q3xHCqyxYqJ00rPUbrVo,2645
29
21
  vantage6/cli/common/utils.py,sha256=z9NX_2hft2bkIvilnrtLV92ui62pIEhj-f3gCJcjcQ4,4970
30
22
  vantage6/cli/context/__init__.py,sha256=88LSA3h_v-t8PzjCrzl0vw1jkOdNUNr3nPo-L2e9onc,2684
31
- vantage6/cli/context/algorithm_store.py,sha256=qLNbc94q3EpVGUgGuNDObCPK3QfyKveKwmfolLBq8sE,3976
23
+ vantage6/cli/context/algorithm_store.py,sha256=s6T5coyGHyXHupE1EFvcXCL8A69a2gUe5-6w6jNNKko,3967
32
24
  vantage6/cli/context/base_server.py,sha256=paKSzNrKWD-J6eakHAtGELk2cD05A8NqoCAuQfF7c2s,2972
33
- vantage6/cli/context/node.py,sha256=GuBfarE1wqtU8S7Ww-DS0H8dJuLxBxqPZrdIwKBpGdU,7123
34
- vantage6/cli/context/server.py,sha256=vPcPtyHntdDXkOYcel2mb0JZbihnmFgizYMG8ajjnHg,4639
25
+ vantage6/cli/context/node.py,sha256=bjrBGopoqR0SVTYvKCmhhGTzdaX8wg0GLBKbiLKMIGQ,7264
26
+ vantage6/cli/context/server.py,sha256=Bnv25avqIv0eG79uuY6W8ZrktTDAcF82Gmeo-dKjbyI,4630
35
27
  vantage6/cli/dev/create.py,sha256=WBBPG9jyNvPQVb1koHX9y3VKQmlijlq-QBsYYzqqojg,21207
36
28
  vantage6/cli/dev/remove.py,sha256=kjmOqkMO0ZU5F-3KgQ05VlfQQCS5Ta6yLY32DU0rH7k,3917
37
29
  vantage6/cli/dev/data/km_dataset.csv,sha256=OrYF2ympb2QndiUOX_nTFGGB1HbAp2eOvZzrQ_PqJs4,31283
@@ -77,8 +69,7 @@ vantage6/cli/test/algo_test_scripts/algo_test_script.py,sha256=jfzXPmpL0HlE_eq1j
77
69
  vantage6/cli/test/common/diagnostic_runner.py,sha256=5-KgspYW0PncO_t_TrQzd_GSOXVwH-7bIVv-IHOxwQM,6598
78
70
  vantage6/cli/use/context.py,sha256=mEtOfbuLtYQlRh-ypif24WtOwgpcvXObX310mmXIkWY,1362
79
71
  vantage6/cli/use/namespace.py,sha256=MOd9H3GJwZ0cho0mmlHTRlGPLoQEiSnZIFDsFsvYw4Q,1643
80
- vantage6-5.0.0a29.dist-info/METADATA,sha256=fNk0o5hF7V6NS5PJVtO3A2Nwk2L45eVvzKX3tfv9U_I,10688
81
- vantage6-5.0.0a29.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
- vantage6-5.0.0a29.dist-info/entry_points.txt,sha256=YFBvwjxoeAGxYyPC-YevEgOBBYRGaXkS6jiOGGCLNy0,157
83
- vantage6-5.0.0a29.dist-info/top_level.txt,sha256=CYDIBS8jEfFq5YCs_Fuit54K9-3wdosZppTrsymIoUk,19
84
- vantage6-5.0.0a29.dist-info/RECORD,,
72
+ vantage6-5.0.0a33.dist-info/METADATA,sha256=ZaeekTWCozYRPHpHPBGCxXRxuw9ovIRH_Ld-VvJX9gs,1779
73
+ vantage6-5.0.0a33.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
74
+ vantage6-5.0.0a33.dist-info/entry_points.txt,sha256=RKVCMsD70s_Gp6If89uDlCphsZ9uLIOMt1gciv8EMDQ,53
75
+ vantage6-5.0.0a33.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ v6 = vantage6.cli.cli:cli_complete
tests_cli/__init__.py DELETED
File without changes
@@ -1,23 +0,0 @@
1
- # from click import UsageError
2
- # from vantage6.cli.test.client_script import cli_test_client_script
3
-
4
- # import click
5
- # import unittest
6
-
7
-
8
- # class TestScriptTest(unittest.TestCase):
9
- # def test_script_incorrect_usage(self):
10
- # ctx = click.Context(cli_test_client_script)
11
-
12
- # with self.assertRaises(UsageError):
13
- # ctx.invoke(
14
- # cli_test_client_script,
15
- # script="path/to/script.py",
16
- # task_arguments="{'my_arg': 1}",
17
- # )
18
-
19
- # with self.assertRaises(UsageError):
20
- # ctx.invoke(
21
- # cli_test_client_script,
22
- # task_arguments="not_a_json",
23
- # )
tests_cli/test_example.py DELETED
@@ -1,7 +0,0 @@
1
- import unittest
2
-
3
-
4
- class ExampleTest(unittest.TestCase):
5
- def test_example(self):
6
- self.assertTrue(True)
7
- self.assertFalse(False)
@@ -1,452 +0,0 @@
1
- import unittest
2
- import logging
3
- import os
4
- import contextlib
5
-
6
- from unittest.mock import MagicMock, patch
7
- from pathlib import Path
8
- from io import BytesIO, StringIO
9
- from click.testing import CliRunner
10
- from docker.errors import APIError
11
-
12
- from vantage6.common.globals import Ports
13
- from vantage6.cli.globals import APPNAME
14
- from vantage6.common import STRING_ENCODING
15
- from vantage6.cli.common.utils import print_log_worker
16
- from vantage6.cli.node.list import cli_node_list
17
- from vantage6.cli.node.new import cli_node_new_configuration
18
- from vantage6.cli.node.files import cli_node_files
19
- from vantage6.cli.node.start import cli_node_start
20
- from vantage6.cli.node.restart import cli_node_restart
21
- from vantage6.cli.node.stop import cli_node_stop
22
- from vantage6.cli.node.attach import cli_node_attach
23
- from vantage6.cli.node.create_private_key import cli_node_create_private_key
24
- from vantage6.cli.node.clean import cli_node_clean
25
- from vantage6.cli.node.common import create_client_and_authenticate
26
-
27
-
28
- class NodeCLITest(unittest.TestCase):
29
- @classmethod
30
- def setUpClass(cls):
31
- logging.getLogger("docker.utils.config").setLevel(logging.WARNING)
32
- return super().setUpClass()
33
-
34
- @patch("docker.DockerClient.ping")
35
- def test_list_docker_not_running(self, docker_ping):
36
- """An error is printed when docker is not running"""
37
- docker_ping.side_effect = Exception("Boom!")
38
-
39
- runner = CliRunner()
40
- result = runner.invoke(cli_node_list, [])
41
-
42
- # check exit code
43
- self.assertEqual(result.exit_code, 1)
44
-
45
- @patch("vantage6.cli.context.node.NodeContext.available_configurations")
46
- @patch("docker.DockerClient.ping")
47
- @patch("docker.DockerClient.containers")
48
- def test_list(self, containers, docker_ping, available_configurations):
49
- """A container list and their current status."""
50
- # https://docs.python.org/3/library/unittest.mock.html#mock-names-and-the-name-attribute
51
-
52
- # mock that docker-deamon is running
53
- docker_ping.return_value = True
54
-
55
- # docker deamon returns a list of running node-containers
56
- container1 = MagicMock()
57
- container1.name = f"{APPNAME}-iknl-user"
58
- containers.list.return_value = [container1]
59
-
60
- # returns a list of configurations and failed inports
61
- def side_effect(system_folders):
62
- config = MagicMock()
63
- config.name = "iknl"
64
- if not system_folders:
65
- return [[config], []]
66
- else:
67
- return [[config], []]
68
-
69
- available_configurations.side_effect = side_effect
70
-
71
- # invoke CLI method
72
- runner = CliRunner()
73
- result = runner.invoke(cli_node_list, [])
74
-
75
- # validate exit code
76
- self.assertEqual(result.exit_code, 0)
77
-
78
- # check printed lines
79
- self.assertEqual(
80
- result.output,
81
- "\nName Status System/User\n"
82
- "-----------------------------------------------------\n"
83
- "iknl Not running System \n"
84
- "iknl Running User \n"
85
- "-----------------------------------------------------\n",
86
- )
87
-
88
- @patch("vantage6.cli.node.new.configuration_wizard")
89
- @patch("vantage6.cli.node.new.ensure_config_dir_writable")
90
- @patch("vantage6.cli.node.common.NodeContext")
91
- def test_new_config(self, context, permissions, wizard):
92
- """No error produced when creating new configuration."""
93
- context.config_exists.return_value = False
94
- permissions.return_value = True
95
- wizard.return_value = "/some/file/path"
96
-
97
- runner = CliRunner()
98
- result = runner.invoke(
99
- cli_node_new_configuration,
100
- [
101
- "--name",
102
- "some-name",
103
- ],
104
- )
105
-
106
- # check that info message is produced
107
- self.assertEqual(result.output[:7], "[info ]")
108
-
109
- # check OK exit code
110
- self.assertEqual(result.exit_code, 0)
111
-
112
- @patch("vantage6.cli.node.new.configuration_wizard")
113
- def test_new_config_replace_whitespace_in_name(self, _):
114
- """Whitespaces are replaced in the name."""
115
-
116
- runner = CliRunner()
117
- result = runner.invoke(
118
- cli_node_new_configuration,
119
- [
120
- "--name",
121
- "some name",
122
- ],
123
- )
124
-
125
- self.assertEqual(
126
- result.output[:60],
127
- "[info ] - Replaced spaces from configuration name: some-name",
128
- )
129
-
130
- @patch("vantage6.cli.node.new.NodeContext")
131
- def test_new_config_already_exists(self, context):
132
- """No duplicate configurations are allowed."""
133
-
134
- context.config_exists.return_value = True
135
-
136
- runner = CliRunner()
137
- result = runner.invoke(
138
- cli_node_new_configuration,
139
- [
140
- "--name",
141
- "some-name",
142
- ],
143
- )
144
-
145
- # check that error is produced
146
- self.assertEqual(result.output[:7], "[error]")
147
-
148
- # check non-zero exit code
149
- self.assertEqual(result.exit_code, 1)
150
-
151
- @patch("vantage6.cli.node.new.ensure_config_dir_writable")
152
- @patch("vantage6.cli.node.common.NodeContext")
153
- def test_new_write_permissions(self, context, permissions):
154
- """User needs write permissions."""
155
-
156
- context.config_exists.return_value = False
157
- permissions.return_value = False
158
-
159
- runner = CliRunner()
160
- result = runner.invoke(
161
- cli_node_new_configuration,
162
- [
163
- "--name",
164
- "some-name",
165
- ],
166
- )
167
-
168
- # check that error is produced
169
- self.assertEqual(result.output[:7], "[error]")
170
-
171
- # check non-zero exit code
172
- self.assertEqual(result.exit_code, 1)
173
-
174
- @patch("vantage6.cli.node.common.NodeContext")
175
- @patch("vantage6.cli.node.files.NodeContext")
176
- @patch("vantage6.cli.node.common.select_configuration_questionaire")
177
- def test_files(self, select_config, context, common_context):
178
- """No errors produced when retrieving filepaths."""
179
-
180
- common_context.config_exists.return_value = True
181
- context.return_value = MagicMock(
182
- config_file="/file.yaml", log_file="/log.log", data_dir="/dir"
183
- )
184
- context.return_value.databases.items.return_value = [["label", "/file.db"]]
185
- select_config.return_value = "iknl"
186
-
187
- runner = CliRunner()
188
- result = runner.invoke(cli_node_files, [])
189
-
190
- # we check that no warnings have been produced
191
- self.assertEqual(result.output[:7], "[info ]")
192
-
193
- # check status code is OK
194
- self.assertEqual(result.exit_code, 0)
195
-
196
- @patch("vantage6.cli.node.common.NodeContext")
197
- def test_files_non_existing_config(self, context):
198
- """An error is produced when a non existing config is used."""
199
-
200
- context.config_exists.return_value = False
201
-
202
- runner = CliRunner()
203
- result = runner.invoke(cli_node_files, ["--name", "non-existing"])
204
-
205
- # Check that error is produced
206
- self.assertEqual(result.output[:7], "[error]")
207
-
208
- # check for non zero exit-code
209
- self.assertNotEqual(result.exit_code, 0)
210
-
211
- @patch("docker.DockerClient.volumes")
212
- @patch("vantage6.cli.node.start.pull_infra_image")
213
- @patch("vantage6.cli.common.decorator.get_context")
214
- @patch("docker.DockerClient.containers")
215
- @patch("vantage6.cli.node.start.check_docker_running", return_value=True)
216
- def test_start(self, check_docker, client, context, pull, volumes):
217
- # client.containers = MagicMock(name="docker.DockerClient.containers")
218
- client.list.return_value = []
219
- volume = MagicMock()
220
- volume.name = "data-vol-name"
221
- volumes.create.return_value = volume
222
- context.config_exists.return_value = True
223
-
224
- ctx = MagicMock(
225
- data_dir=Path("data"),
226
- log_dir=Path("logs"),
227
- config_dir=Path("configs"),
228
- databases=[{"label": "some_label", "uri": "data.csv", "type": "csv"}],
229
- )
230
-
231
- # cli_node_start() tests for truth value of a set-like object derived
232
- # from ctx.config.get('node_extra_env', {}). Default MagicMock() will
233
- # evaluate to True, empty dict to False. False signifies no overwritten
234
- # env vars, hence no error.
235
- def config_get_side_effect(key, default=None):
236
- if key == "node_extra_env":
237
- return {}
238
- return MagicMock()
239
-
240
- ctx.config.get.side_effect = config_get_side_effect
241
- ctx.get_data_file.return_value = "data.csv"
242
- ctx.name = "some-name"
243
- context.return_value = ctx
244
-
245
- runner = CliRunner()
246
-
247
- # Should fail when starting node with non-existing database CSV file
248
- with runner.isolated_filesystem():
249
- result = runner.invoke(cli_node_start, ["--name", "some-name"])
250
- self.assertEqual(result.exit_code, 1)
251
-
252
- # now do it with a SQL database which doesn't have to be an existing file
253
- ctx.databases = [{"label": "some_label", "uri": "data.db", "type": "sql"}]
254
- with runner.isolated_filesystem():
255
- result = runner.invoke(cli_node_start, ["--name", "some-name"])
256
- self.assertEqual(result.exit_code, 0)
257
-
258
- def _setup_stop_test(self, containers):
259
- container1 = MagicMock()
260
- container1.name = f"{APPNAME}-iknl-user"
261
- containers.list.return_value = [container1]
262
-
263
- @patch("docker.DockerClient.containers")
264
- @patch("vantage6.cli.node.stop.check_docker_running", return_value=True)
265
- @patch("vantage6.cli.node.stop.NodeContext")
266
- @patch("vantage6.cli.node.stop.delete_volume_if_exists")
267
- def test_stop(self, delete_volume, node_context, check_docker, containers):
268
- self._setup_stop_test(containers)
269
-
270
- runner = CliRunner()
271
-
272
- result = runner.invoke(cli_node_stop, ["--name", "iknl"])
273
-
274
- self.assertEqual(
275
- result.output, "[info ] - Stopped the vantage6-iknl-user Node.\n"
276
- )
277
-
278
- self.assertEqual(result.exit_code, 0)
279
-
280
- @patch("docker.DockerClient.containers")
281
- @patch("vantage6.cli.node.stop.check_docker_running", return_value=True)
282
- @patch("vantage6.cli.node.stop.NodeContext")
283
- @patch("vantage6.cli.node.stop.delete_volume_if_exists")
284
- @patch("vantage6.cli.node.restart.subprocess.run")
285
- def test_restart(
286
- self, subprocess_run, delete_volume, node_context, check_docker, containers
287
- ):
288
- """Restart a node without errors."""
289
- self._setup_stop_test(containers)
290
- # The subprocess.run() function is called with the command to start the node.
291
- # Unfortunately it is hard to test this, so we just return a successful run
292
- subprocess_run.return_value = MagicMock(returncode=0)
293
- runner = CliRunner()
294
- with runner.isolated_filesystem():
295
- result = runner.invoke(cli_node_restart, ["--name", "iknl"])
296
- self.assertEqual(result.exit_code, 0)
297
-
298
- @patch("vantage6.cli.node.attach.attach_logs")
299
- def test_attach(self, attach_logs):
300
- """Attach docker logs without errors."""
301
- runner = CliRunner()
302
- runner.invoke(cli_node_attach)
303
- attach_logs.assert_called_once_with("app=node")
304
-
305
- @patch("vantage6.cli.node.clean.q")
306
- @patch("docker.DockerClient.volumes")
307
- @patch("vantage6.cli.node.clean.check_docker_running", return_value=True)
308
- def test_clean(self, check_docker, volumes, q):
309
- """Clean Docker volumes without errors."""
310
- volume1 = MagicMock()
311
- volume1.name = "some-name-tmpvol"
312
- volumes.list.return_value = [volume1]
313
-
314
- question = MagicMock(name="pop-the-question")
315
- question.ask.return_value = True
316
- q.confirm.return_value = question
317
-
318
- runner = CliRunner()
319
- result = runner.invoke(cli_node_clean)
320
-
321
- # check exit code
322
- self.assertEqual(result.exit_code, 0)
323
-
324
- @patch("vantage6.cli.node.create_private_key.create_client_and_authenticate")
325
- @patch("vantage6.cli.node.common.NodeContext")
326
- @patch("vantage6.cli.node.create_private_key.NodeContext")
327
- def test_create_private_key(self, context, common_context, client):
328
- common_context.config_exists.return_value = True
329
- context.return_value.type_data_folder.return_value = Path(".")
330
- client.return_value = MagicMock(whoami=MagicMock(organization_name="Test"))
331
- # client.whoami.organization_name = "Test"
332
- runner = CliRunner()
333
-
334
- result = runner.invoke(cli_node_create_private_key, ["--name", "application"])
335
-
336
- self.assertEqual(result.exit_code, 0)
337
-
338
- # remove the private key file again
339
- os.remove("privkey_Test.pem")
340
-
341
- @patch("vantage6.cli.node.create_private_key.RSACryptor")
342
- @patch("vantage6.cli.node.create_private_key.create_client_and_authenticate")
343
- @patch("vantage6.cli.node.common.NodeContext")
344
- @patch("vantage6.cli.node.create_private_key.NodeContext")
345
- def test_create_private_key_overwite(
346
- self, context, common_context, client, cryptor
347
- ):
348
- common_context.config_exists.return_value = True
349
- context.return_value.type_data_folder.return_value = Path(".")
350
- client.return_value = MagicMock(whoami=MagicMock(organization_name="Test"))
351
- cryptor.create_public_key_bytes.return_value = b""
352
- # client.whoami.organization_name = "Test"
353
-
354
- runner = CliRunner()
355
-
356
- # overwrite
357
- with runner.isolated_filesystem():
358
- with open("privkey_iknl.pem", "w") as f:
359
- f.write("does-not-matter")
360
-
361
- result = runner.invoke(
362
- cli_node_create_private_key,
363
- ["--name", "application", "--overwrite", "--organization-name", "iknl"],
364
- )
365
- self.assertEqual(result.exit_code, 0)
366
-
367
- # do not overwrite
368
- with runner.isolated_filesystem():
369
- with open("privkey_iknl.pem", "w") as f:
370
- f.write("does-not-matter")
371
-
372
- result = runner.invoke(
373
- cli_node_create_private_key,
374
- ["--name", "application", "--organization-name", "iknl"],
375
- )
376
-
377
- # print(result.output)
378
-
379
- self.assertEqual(result.exit_code, 0)
380
-
381
- @patch("vantage6.cli.node.common.NodeContext")
382
- def test_create_private_key_config_not_found(self, context):
383
- context.config_exists.return_value = False
384
-
385
- runner = CliRunner()
386
- result = runner.invoke(cli_node_create_private_key, ["--name", "application"])
387
-
388
- self.assertEqual(result.exit_code, 1)
389
-
390
- @patch("vantage6.cli.node.clean.q")
391
- @patch("docker.DockerClient.volumes")
392
- @patch("vantage6.common.docker.addons.check_docker_running")
393
- def test_clean_docker_error(self, check_docker, volumes, q):
394
- volume1 = MagicMock()
395
- volume1.name = "some-name-tmpvol"
396
- volume1.remove.side_effect = APIError("Testing")
397
- volumes.list.return_value = [volume1]
398
- question = MagicMock(name="pop-the-question")
399
- question.ask.return_value = True
400
- q.confirm.return_value = question
401
-
402
- runner = CliRunner()
403
- result = runner.invoke(cli_node_clean)
404
-
405
- # check exit code
406
- self.assertEqual(result.exit_code, 1)
407
-
408
- def test_print_log_worker(self):
409
- stream = BytesIO("Hello!".encode(STRING_ENCODING))
410
- temp_stdout = StringIO()
411
- with contextlib.redirect_stdout(temp_stdout):
412
- print_log_worker(stream)
413
- output = temp_stdout.getvalue().strip()
414
- self.assertEqual(output, "Hello!")
415
-
416
- @patch("vantage6.cli.node.common.info")
417
- @patch("vantage6.cli.node.common.debug")
418
- @patch("vantage6.cli.node.common.error")
419
- @patch("vantage6.cli.node.common.UserClient")
420
- def test_client(self, client, error, debug, info):
421
- ctx = MagicMock(
422
- config={
423
- "server_url": "localhost",
424
- "port": Ports.DEV_SERVER.value,
425
- "api_path": "",
426
- }
427
- )
428
-
429
- # should not trigger an exception
430
- try:
431
- create_client_and_authenticate(ctx)
432
- except Exception:
433
- self.fail("Raised an exception!")
434
-
435
- # client raises exception
436
- client.side_effect = Exception("Boom!")
437
- with self.assertRaises(Exception):
438
- create_client_and_authenticate(ctx)
439
-
440
- # TODO this function has been moved to the common package. A test should
441
- # be added there instead of here
442
- # @patch("vantage6.cli.node.error")
443
- # def test_check_docker(self, error):
444
- # docker = MagicMock()
445
- # try:
446
- # check_docker_running()
447
- # except Exception:
448
- # self.fail("Exception raised!")
449
-
450
- # docker.ping.side_effect = Exception("Boom!")
451
- # with self.assertRaises(SystemExit):
452
- # check_docker_running()
@@ -1,180 +0,0 @@
1
- import unittest
2
- from pathlib import Path
3
- from unittest.mock import MagicMock, patch
4
-
5
- from click.testing import CliRunner
6
-
7
- from vantage6.common.globals import APPNAME, InstanceType
8
-
9
- from vantage6.cli.common.utils import attach_logs
10
- from vantage6.cli.server.attach import cli_server_attach
11
- from vantage6.cli.server.files import cli_server_files
12
- from vantage6.cli.server.import_ import cli_server_import
13
- from vantage6.cli.server.list import cli_server_configuration_list
14
- from vantage6.cli.server.new import cli_server_new
15
- from vantage6.cli.server.start import cli_server_start
16
- from vantage6.cli.server.stop import cli_server_stop
17
-
18
-
19
- class ServerCLITest(unittest.TestCase):
20
- @patch("vantage6.cli.server.start.NetworkManager")
21
- @patch("vantage6.cli.server.start.docker.types.Mount")
22
- @patch("os.makedirs")
23
- @patch("vantage6.cli.server.start.pull_infra_image")
24
- @patch("vantage6.cli.common.decorator.get_context")
25
- @patch("vantage6.cli.server.start.docker.from_env")
26
- @patch("vantage6.cli.common.start.check_docker_running", return_value=True)
27
- def test_start(
28
- self,
29
- docker_check,
30
- containers,
31
- context,
32
- pull,
33
- os_makedirs,
34
- mount,
35
- network_manager,
36
- ):
37
- """Start server without errors"""
38
- container1 = MagicMock()
39
- container1.containers.name = f"{APPNAME}-iknl-system"
40
- containers.containers.list.return_value = [container1]
41
- containers.containers.run.return_value = True
42
-
43
- # mount.types.Mount.return_value = MagicMock()
44
-
45
- ctx = MagicMock(
46
- config={"uri": "sqlite:///file.db", "port": 9999},
47
- config_file="/config.yaml",
48
- data_dir=Path("."),
49
- )
50
- ctx.config_exists.return_value = True
51
- ctx.name = "not-running"
52
- context.return_value = ctx
53
-
54
- runner = CliRunner()
55
- result = runner.invoke(cli_server_start, ["--name", "not-running"])
56
-
57
- self.assertEqual(result.exit_code, 0)
58
-
59
- @patch("vantage6.cli.server.common.ServerContext")
60
- @patch("docker.DockerClient.containers")
61
- @patch("vantage6.cli.server.list.check_docker_running", return_value=True)
62
- def test_configuration_list(self, docker_check, containers, context):
63
- """Configuration list without errors."""
64
- container1 = MagicMock()
65
- container1.name = f"{APPNAME}-iknl-system"
66
- containers.list.return_value = [container1]
67
-
68
- config = MagicMock()
69
- config.name = "iknl"
70
- context.available_configurations.return_value = ([config], [])
71
-
72
- runner = CliRunner()
73
- result = runner.invoke(cli_server_configuration_list)
74
-
75
- self.assertEqual(result.exit_code, 0)
76
- self.assertIsNone(result.exception)
77
-
78
- @patch("vantage6.cli.common.decorator.get_context")
79
- def test_files(self, context):
80
- """Configuration files without errors."""
81
-
82
- ctx = context.return_value = MagicMock(
83
- log_file="/log_file.log", config_file="/iknl.yaml"
84
- )
85
- ctx.get_database_uri.return_value = "sqlite:///test.db"
86
-
87
- runner = CliRunner()
88
- result = runner.invoke(cli_server_files, ["--name", "iknl"])
89
-
90
- self.assertIsNone(result.exception)
91
- self.assertEqual(result.exit_code, 0)
92
-
93
- @patch("docker.DockerClient.containers")
94
- @patch("vantage6.cli.server.import_.print_log_worker")
95
- @patch("vantage6.cli.server.import_.click.Path")
96
- @patch("vantage6.cli.server.import_.pull_image")
97
- @patch("vantage6.cli.server.import_.check_docker_running", return_value=True)
98
- @patch("vantage6.cli.common.decorator.get_context")
99
- def test_import(self, context, docker_check, pull, click_path, log, containers):
100
- """Import entities without errors."""
101
- click_path.return_value = MagicMock()
102
-
103
- ctx = MagicMock()
104
- ctx.name = "some-name"
105
- context.return_value = ctx
106
-
107
- runner = CliRunner()
108
- with runner.isolated_filesystem():
109
- with open("some.yaml", "w") as fp:
110
- fp.write("does-not-matter")
111
- result = runner.invoke(cli_server_import, ["--name", "iknl", "some.yaml"])
112
-
113
- self.assertIsNone(result.exception)
114
- self.assertEqual(result.exit_code, 0)
115
-
116
- @patch("vantage6.cli.server.new.configuration_wizard")
117
- @patch("vantage6.cli.server.new.ensure_config_dir_writable")
118
- @patch("vantage6.cli.server.new.ServerContext")
119
- def test_new(self, context, permissions, wizard):
120
- """New configuration without errors."""
121
-
122
- context.config_exists.return_value = False
123
- permissions.return_value = True
124
- wizard.return_value = "/some/file.yaml"
125
-
126
- runner = CliRunner()
127
- result = runner.invoke(cli_server_new, ["--name", "iknl"])
128
-
129
- self.assertIsNone(result.exception)
130
- self.assertEqual(result.exit_code, 0)
131
-
132
- @patch("vantage6.cli.server.stop.docker.from_env")
133
- def test_stop(self, containers):
134
- """Stop server without errors."""
135
-
136
- container1 = MagicMock()
137
- container1.name = f"{APPNAME}-iknl-system-{InstanceType.SERVER}"
138
- containers.containers.list.return_value = [container1]
139
-
140
- runner = CliRunner()
141
- result = runner.invoke(cli_server_stop, ["--name", "iknl"])
142
-
143
- self.assertIsNone(result.exception)
144
- self.assertEqual(result.exit_code, 0)
145
-
146
- @patch("vantage6.cli.server.attach.attach_logs")
147
- def test_attach(self, attach_logs):
148
- """Attach logs to the console without errors."""
149
- runner = CliRunner()
150
- result = runner.invoke(cli_server_attach)
151
-
152
- self.assertIsNone(result.exception)
153
- self.assertEqual(result.exit_code, 0)
154
- attach_logs.assert_called_once_with(
155
- "app=vantage6-server", "component=vantage6-server"
156
- )
157
-
158
- @patch("vantage6.cli.common.utils.Popen")
159
- def test_attach_logs(self, mock_popen):
160
- # Mock the Popen instance and its methods
161
- mock_process = mock_popen.return_value
162
- mock_process.wait.return_value = None
163
-
164
- # Call the function with a sample label
165
- attach_logs("app=node", "env=dev")
166
-
167
- # Construct the expected command
168
- expected_command = [
169
- "devspace",
170
- "logs",
171
- "--follow",
172
- "--label-selector",
173
- "app=node,env=dev",
174
- ]
175
-
176
- # Verify that Popen was called with the expected command
177
- mock_popen.assert_called_once_with(expected_command, stdout=None, stderr=None)
178
-
179
- # Verify that wait was called on the process
180
- mock_process.wait.assert_called_once()
tests_cli/test_wizard.py DELETED
@@ -1,141 +0,0 @@
1
- import unittest
2
- from pathlib import Path
3
- from unittest.mock import MagicMock, patch
4
-
5
- from vantage6.common.globals import InstanceType, NodePolicy
6
-
7
- from vantage6.cli.configuration_wizard import (
8
- configuration_wizard,
9
- node_configuration_questionaire,
10
- select_configuration_questionaire,
11
- server_configuration_questionaire,
12
- )
13
-
14
- module_path = "vantage6.cli.configuration_wizard"
15
-
16
-
17
- class WizardTest(unittest.TestCase):
18
- @staticmethod
19
- def prompts(*args, **kwargs):
20
- result = {}
21
- for arg in args[0]:
22
- name = arg["name"]
23
- if name == "default": # default db path
24
- result[name] = "/some/path/db.sqlite"
25
- else:
26
- if "default" in arg:
27
- result[name] = arg["default"]
28
- else:
29
- result[name] = None
30
- return result
31
-
32
- @patch("vantage6.cli.configuration_wizard.NodeClient.authenticate")
33
- def test_node_wizard(self, authenticate):
34
- """An error is printed when docker is not running"""
35
- authenticate.return_value = None
36
-
37
- with patch(f"{module_path}.q") as q:
38
- q.unsafe_prompt.side_effect = self.prompts
39
- q.confirm.return_value.unsafe_ask.side_effect = [
40
- True, # add a database
41
- False, # don't enable two-factor authentication
42
- True, # add VPN server
43
- True, # add algorithm policies
44
- True, # add single algorithms to allowed_algorithms
45
- "some-image", # algorithm image to whitelist
46
- False, # don't add another algorithm image
47
- True, # add algorithm stores to allowed_algorithm_stores
48
- "some-store", # algorithm store to whitelist
49
- False, # don't add another algorithm store
50
- False, # answer question on combining policies on store level and
51
- # single algorithm level
52
- False, # don't abort if no server connection is made to pull
53
- # collaboration settings
54
- True, # Enable encryption
55
- ]
56
- dirs = MagicMock(data="/")
57
- config = node_configuration_questionaire(dirs, "iknl")
58
-
59
- keys = [
60
- "api_key",
61
- "server_url",
62
- "port",
63
- "api_path",
64
- "task_dir",
65
- "databases",
66
- "logging",
67
- "encryption",
68
- "vpn_subnet",
69
- ]
70
- for key in keys:
71
- self.assertIn(key, config)
72
- nested_keys = [
73
- ["policies", NodePolicy.ALLOWED_ALGORITHMS.value],
74
- ["policies", NodePolicy.ALLOWED_ALGORITHM_STORES.value],
75
- ]
76
- for nesting in nested_keys:
77
- current_config = config
78
- for key in nesting:
79
- self.assertIn(key, current_config)
80
- current_config = current_config[key]
81
-
82
- def test_server_wizard(self):
83
- with patch(f"{module_path}.q") as q:
84
- q.unsafe_prompt.side_effect = self.prompts
85
- q.confirm.return_value.unsafe_ask.side_effect = [
86
- True,
87
- True,
88
- True,
89
- True,
90
- True,
91
- True,
92
- False,
93
- ]
94
-
95
- config = server_configuration_questionaire("vantage6")
96
-
97
- keys = [
98
- "description",
99
- "ip",
100
- "port",
101
- "api_path",
102
- "uri",
103
- "allow_drop_all",
104
- "logging",
105
- "vpn_server",
106
- "rabbitmq",
107
- "two_factor_auth",
108
- "algorithm_stores",
109
- ]
110
-
111
- for key in keys:
112
- self.assertIn(key, config)
113
-
114
- @patch(f"{module_path}.node_configuration_questionaire")
115
- @patch(f"{module_path}.server_configuration_questionaire")
116
- @patch(f"{module_path}.ServerConfigurationManager")
117
- @patch(f"{module_path}.NodeConfigurationManager")
118
- @patch("vantage6.cli.configuration_wizard.AppContext")
119
- def test_configuration_wizard_interface(
120
- self, context, node_m, server_m, server_q, node_q
121
- ):
122
- context.instance_folders.return_value = {"config": "/some/path/"}
123
-
124
- file_ = configuration_wizard(InstanceType.NODE, "vtg6", False)
125
- self.assertEqual(Path("/some/path/vtg6.yaml"), file_)
126
-
127
- file_ = configuration_wizard(InstanceType.SERVER, "vtg6", True)
128
- self.assertEqual(Path("/some/path/vtg6.yaml"), file_)
129
-
130
- @patch("vantage6.cli.configuration_wizard.AppContext.available_configurations")
131
- def test_select_configuration(self, available_configurations):
132
- config = MagicMock()
133
- config.name = "vtg6"
134
-
135
- available_configurations.return_value = [[config], []]
136
-
137
- with patch(f"{module_path}.q") as q:
138
- q.select.return_value.unsafe_ask.return_value = "vtg6"
139
- name = select_configuration_questionaire(InstanceType.NODE, True)
140
-
141
- self.assertEqual(name, "vtg6")
vantage6/cli/__build__ DELETED
@@ -1 +0,0 @@
1
- 29
vantage6/cli/_version.py DELETED
@@ -1,23 +0,0 @@
1
- import os
2
- import json
3
-
4
- here = os.path.abspath(os.path.dirname(__file__))
5
-
6
- with open(os.path.join(here, "__build__")) as fp:
7
- __build__ = json.load(fp)
8
-
9
- # Module version
10
- version_info = (5, 0, 0, "alpha", __build__, 0)
11
-
12
- # Module version stage suffix map
13
- _specifier_ = {"alpha": "a", "beta": "b", "candidate": "rc", "final": ""}
14
- version = f"{version_info[0]}.{version_info[1]}.{version_info[2]}"
15
- pre_release = (
16
- ""
17
- if version_info[3] == "final"
18
- else _specifier_[version_info[3]] + str(version_info[4])
19
- )
20
- post_release = "" if not version_info[5] else f".post{version_info[5]}"
21
-
22
- # Module version accessible using thomas.__version__
23
- __version__ = f"{version}{pre_release}{post_release}"
@@ -1,238 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: vantage6
3
- Version: 5.0.0a29
4
- Summary: vantage6 command line interface
5
- Home-page: https://github.com/vantage6/vantage6
6
- Requires-Python: >=3.13
7
- Description-Content-Type: text/markdown
8
- Requires-Dist: click==8.1.3
9
- Requires-Dist: colorama==0.4.6
10
- Requires-Dist: copier==9.2.0
11
- Requires-Dist: docker==7.1.0
12
- Requires-Dist: ipython==8.10.0
13
- Requires-Dist: jinja2==3.1.6
14
- Requires-Dist: kubernetes==28.1.0
15
- Requires-Dist: pandas>=2.2.3
16
- Requires-Dist: questionary==1.10.0
17
- Requires-Dist: rich==13.5.2
18
- Requires-Dist: schema==0.7.5
19
- Requires-Dist: sqlalchemy==2.0.37
20
- Requires-Dist: vantage6-common==5.0.0a29
21
- Requires-Dist: vantage6-client==5.0.0a29
22
- Provides-Extra: dev
23
- Requires-Dist: coverage==6.4.4; extra == "dev"
24
- Requires-Dist: black; extra == "dev"
25
- Requires-Dist: pre-commit; extra == "dev"
26
- Dynamic: description
27
- Dynamic: description-content-type
28
- Dynamic: home-page
29
- Dynamic: provides-extra
30
- Dynamic: requires-dist
31
- Dynamic: requires-python
32
- Dynamic: summary
33
-
34
- <h1 align="center">
35
- <br>
36
- <a href="https://vantage6.ai"><img src="https://github.com/IKNL/guidelines/blob/master/resources/logos/vantage6.png?raw=true" alt="vantage6" width="350"></a>
37
- </h1>
38
-
39
- <h3 align=center> A Privacy Enhancing Technology (PET) Operations platform</h3>
40
- <h3 align="center">
41
-
42
- <!-- Badges go here-->
43
-
44
- [![Release](https://github.com/vantage6/vantage6/actions/workflows/release.yml/badge.svg)](https://github.com/vantage6/vantage6/actions/workflows/release.yml)
45
- [![PyPI vantage6](https://badge.fury.io/py/vantage6.svg)](https://badge.fury.io/py/vantage6)
46
- [![Unittests](https://github.com/vantage6/vantage6/actions/workflows/unit_tests.yml/badge.svg)](https://github.com/vantage6/vantage6/actions/workflows/unit_tests.yml)
47
- [![Coverage Status](https://coveralls.io/repos/github/vantage6/vantage6/badge.svg?branch=main)](https://coveralls.io/github/vantage6/vantage6?branch=main)
48
- [![Codacy Badge](https://app.codacy.com/project/badge/Grade/2e60ac3b3f284620805f7399cba317be)](https://app.codacy.com/gh/vantage6/vantage6/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
49
- [![DOI](https://zenodo.org/badge/492818831.svg)](https://zenodo.org/badge/latestdoi/492818831)
50
- [![Discord](https://img.shields.io/discord/643526403207331841)](https://discord.gg/yAyFf6Y)
51
- [![Research software directory](https://img.shields.io/badge/rsd-vantage6-deepskyblue)](https://research-software-directory.org/software/vantage6)
52
-
53
- </h3>
54
-
55
- <p align="center">
56
- <a href="#books-quickstart">Quickstart</a> •
57
- <a href="#project-structure">Project structure</a> •
58
- <a href="#gift_heart-join-the-community">Join the community</a> •
59
- <a href="#scroll-license">License</a> •
60
- <a href="#black_nib-code-of-conduct">Code of conduct</a> •
61
- <a href="#black_nib-references">References</a>
62
- </p>
63
-
64
- ---
65
-
66
- This repository is contains all the **vantage6** infrastructure source code. The **vantage6** technology enables to manage and deploy privacy enhancing technologies like Federated Learning (FL) and Multi-Party Computation (MPC). Please visit our [website](https://vantage6.ai) to learn more!
67
-
68
- You can find more (user) documentation at [readthedocs](https://docs.vantage6.ai). If you have any questions, suggestions or just want to chat about federated learning: join our [Discord)](https://discord.gg/yAyFf6Y) channel.
69
-
70
- ## Infrastructure overview
71
-
72
- ![Vantage6 architecture overview](docs/images/overview-infrastructure.png)
73
-
74
- _A High level overview of the vantage6 infrastructure. Vantage6 has both a
75
- client-server and peer-to-peer architecture. The client is used by the researcher to
76
- create (PET) computation requests. It is also used to manage users, organizations and
77
- collaborations. The server contains users, organizations, collaborations, tasks and
78
- their results. It provides a central access point for both the clients and nodes. The
79
- nodes have access to privacy sensitive data and handle computation requests retrieved
80
- from the server. Computation request are executed as separate containers on the node.
81
- These containers are connected to containers at other nodes by a internal network._
82
-
83
- ## :books: Quickstart
84
-
85
- ### Requirements
86
-
87
- The **vantage6** infrastructure is delivered in Docker images. To run these images, you
88
- need to have [Docker](https://docs.docker.com/get-docker/) installed. To install the
89
- latest version of the vantage6 CLI, you need to have
90
- [Python](https://www.python.org/downloads/), we recommend using an environment manager
91
- like [mini-conda](https://docs.conda.io/en/latest/miniconda.html).
92
-
93
- Install the latest version of the vantage6 CLI by using:
94
-
95
- ```bash
96
- pip install vantage6
97
- ```
98
-
99
- This install the `v6` commands, which allows you to manage your nodes and servers. To view all available options, run:
100
-
101
- ```bash
102
- v6 --help
103
- ```
104
-
105
- For example you can create a local test setup by using:
106
-
107
- ```bash
108
- v6 dev create-demo-network
109
- ```
110
-
111
- This creates a local network with a server and two nodes. You can start the network by running:
112
-
113
- ```bash
114
- v6 dev start-demo-network
115
- ```
116
-
117
- This will start the server and nodes in the background. You can view the logs by running:
118
-
119
- ```bash
120
- # View node logs
121
- v6 node attach
122
-
123
- # View server logs
124
- v6 server attach
125
- ```
126
-
127
- From here you can use the [vantage6-client](https://pypi.org/project/vantage6-client)
128
- to interact with the server. The demo network has a pre-configured organization with
129
- the following credentials:
130
-
131
- - Username: `dev_admin`
132
- - Password: `password`
133
-
134
- For example, you can create a new organization by running:
135
-
136
- ```python
137
- from vantage6.client import Client
138
-
139
- client = Client(
140
- server_url='http://127.0.0.1:7601/api',
141
- auth_url='http://127.0.0.1:8080',
142
- log_level='debug'
143
- )
144
- client.authenticate()
145
- client.setup_encryption(None)
146
-
147
- client.organization.create(
148
- name='My organization',
149
- address1='My address',
150
- address2='My address',
151
- zipcode='1234AB',
152
- country='The Netherlands',
153
- domain='my-organization.com'
154
- )
155
- ```
156
-
157
- You can find more (user) documentation at [readthedocs](https://docs.vantage6.ai)
158
-
159
- ## Project structure
160
-
161
- ### PYPI packages
162
-
163
- This repository is home to 6 PyPi packages:
164
-
165
- - [vantage6](https://pypi.org/project/vantage6) -> _CLI for managing node and server instances_
166
- - [vantage6-client](https://pypi.org/project/vantage6-client) -> _Python client for interacting with the vantage6-server_
167
- - [vantage6-algorithm-tools](https://pypi.org/project/vantage6-algorithm-tools) -> _Python tools to facilitate algorithm development_
168
- - [vantage6-node](https://pypi.org/project/vantage6-node) -> _Node application package_
169
- - [vantage6-server](https://pypi.org/project/vantage6-server) -> _Server application package_
170
- - [vantage6-algorithm-store](https://pypi.org/project/vantage6-algorithm-store) -> _Algorithm store application package_
171
- - [vantage6-common](https://pypi.org/project/vantage6-common) -> _Package with common vantage6 functions_
172
- - [vantage6-backend-common](https://pypi.org/project/vantage6-backend-common) -> _Package with functions common to central server and algorithm store_
173
-
174
- **Note that when using vantage6 you do not install the _server_ and _node_ packages. These are delivered to you in Docker images.**
175
-
176
- This repository also hosts the code for the vantage6 user interface (UI). The UI
177
- is an Angular web application that can be used to interact with the vantage6 server
178
- easily.
179
-
180
- ### Docker images
181
-
182
- The vantage6 infrastructure is delivered in Docker images. All Docker images are stored
183
- in our private [Harbor](https://goharbor.io/) registry. The most important images are:
184
-
185
- - `harbor2.vantage6.ai/infrastructure/node:VERSION` -> _Node application Docker image_
186
- - `harbor2.vantage6.ai/infrastructure/server:VERSION` -> _Server application Docker image_
187
- - `harbor2.vantage6.ai/infrastructure/ui:VERSION` -> _User interface Docker image_
188
- - `harbor2.vantage6.ai/infrastructure/algorithm-store:VERSION` -> _Algorithm store Docker image_
189
-
190
- with `VERSION` being the full semantic version of the vantage6 infrastructure, e.g.
191
- `4.0.0` or `4.1.0rc0`.
192
-
193
- Several other images are used to support the infrastructure:
194
-
195
- - `harbor2.vantage6.ai/infrastructure/infrastructure-base:VERSION` -> _Base image for the infrastructure_
196
- - `harbor2.vantage6.ai/infrastructure/alpine` -> _Alpine image used for vpn traffic forwarding_
197
-
198
- And finally there are some images released for algorithm development:
199
-
200
- - `harbor2.vantage6.ai/infrastructure/algorithm-base:MAJOR.MINOR` -> _Base image for algorithm development_
201
- - `harbor2.vantage6.ai/infrastructure/algorithm-ohdsi-base:MAJOR.MINOR` -> _Extended algorithm base image for OHDSI algorithm development_
202
-
203
- ## :gift_heart: Join the community!
204
-
205
- We hope to continue developing, improving, and supporting **vantage6** with the help of
206
- the federated learning community. If you are interested in contributing, first of all,
207
- thank you! Second, please take a look at our
208
- [contributing guidelines](https://docs.vantage6.ai/en/main/devops/contribute.html)
209
- and our [code of conduct](CODE_OF_CONDUCT.md).
210
-
211
- <a href="https://github.com/vantage6/vantage6/graphs/contributors">
212
- <img src="https://contrib.rocks/image?repo=vantage6/vantage6" />
213
- </a>
214
-
215
- ## :scroll: License
216
-
217
- This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
218
-
219
- ## :black_nib: Code of Conduct
220
-
221
- Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). **By participating in any way in this project you agree to abide by its terms.**
222
-
223
- ## :black_nib: References
224
-
225
- If you are using **vantage6**, please cite this repository as well as the accompanying papers as follows:
226
-
227
- > - F. Martin, M. Sieswerda, H. Alradhi, et al. vantage6. Available at https://doi.org/10.5281/zenodo.7221216. Accessed on MONTH, 20XX.
228
- > - A. Moncada-Torres, F. Martin, M. Sieswerda, J. van Soest, G. Gelijnse. VANTAGE6: an open source priVAcy preserviNg federaTed leArninG infrastructurE for Secure Insight eXchange. AMIA Annual Symposium Proceedings, 2020, p. 870-877. [[BibTeX](https://arturomoncadatorres.com/bibtex/moncada-torres2020vantage6.txt), [PDF](https://vantage6.ai/vantage6/)]
229
- > - D. Smits\*, B. van Beusekom\*, F. Martin, L. Veen, G. Geleijnse, A. Moncada-Torres, An Improved Infrastructure for Privacy-Preserving Analysis of Patient Data, Proceedings of the International Conference of Informatics, Management, and Technology in Healthcare (ICIMTH), vol. 25, 2022, p. 144-147. [[BibTeX](https://arturomoncadatorres.com/bibtex/smits2022improved.txt), [PDF](https://ebooks.iospress.nl/volumearticle/60190)]
230
-
231
- ---
232
-
233
- <p align="center">
234
- <a href="https://vantage6.ai">vantage6.ai</a> •
235
- <a href="https://discord.gg/yAyFf6Y">Discord</a> •
236
- <a href="https://vantage6.discourse.group/">Discourse</a> •
237
- <a href="https://docs.vantage6.ai">User documentation</a>
238
- </p>
@@ -1,5 +0,0 @@
1
- [console_scripts]
2
- v6 = vantage6.cli.cli:cli_complete
3
- vdev = vantage6.cli.cli:cli_dev
4
- vnode = vantage6.cli.cli:cli_node
5
- vserver = vantage6.cli.cli:cli_server
@@ -1,2 +0,0 @@
1
- tests_cli
2
- vantage6