vantage6-algorithm-store 4.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. vantage6-algorithm-store-4.3.0/PKG-INFO +168 -0
  2. vantage6-algorithm-store-4.3.0/setup.cfg +4 -0
  3. vantage6-algorithm-store-4.3.0/setup.py +55 -0
  4. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/__build__ +1 -0
  5. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/__init__.py +358 -0
  6. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/_version.py +23 -0
  7. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/db.py +83 -0
  8. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/default_roles.py +85 -0
  9. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/globals.py +22 -0
  10. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/__init__.py +15 -0
  11. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/algorithm.py +44 -0
  12. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/argument.py +36 -0
  13. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/base.py +426 -0
  14. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/common/enums.py +37 -0
  15. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/database.py +33 -0
  16. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/developer_algorithm_association.py +15 -0
  17. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/function.py +43 -0
  18. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/permission.py +30 -0
  19. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/review.py +45 -0
  20. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/role.py +80 -0
  21. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/role_rule_association.py +17 -0
  22. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/rule.py +96 -0
  23. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/user.py +146 -0
  24. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/model/vantage6_server.py +42 -0
  25. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/permission.py +290 -0
  26. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/resource/__init__.py +291 -0
  27. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/resource/algorithm.py +540 -0
  28. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/resource/role.py +176 -0
  29. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/resource/rule.py +217 -0
  30. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/resource/schema/input_schema.py +104 -0
  31. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/resource/schema/output_schema.py +150 -0
  32. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/resource/user.py +431 -0
  33. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/resource/vantage6_server.py +242 -0
  34. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/resource/version.py +62 -0
  35. vantage6-algorithm-store-4.3.0/vantage6/algorithm/store/wsgi.py +17 -0
  36. vantage6-algorithm-store-4.3.0/vantage6_algorithm_store.egg-info/PKG-INFO +168 -0
  37. vantage6-algorithm-store-4.3.0/vantage6_algorithm_store.egg-info/SOURCES.txt +38 -0
  38. vantage6-algorithm-store-4.3.0/vantage6_algorithm_store.egg-info/dependency_links.txt +1 -0
  39. vantage6-algorithm-store-4.3.0/vantage6_algorithm_store.egg-info/requires.txt +17 -0
  40. vantage6-algorithm-store-4.3.0/vantage6_algorithm_store.egg-info/top_level.txt +1 -0
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.1
2
+ Name: vantage6-algorithm-store
3
+ Version: 4.3.0
4
+ Summary: Vantage6 algorithm store
5
+ Home-page: https://github.com/vantage6/vantage6
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Provides-Extra: dev
9
+
10
+ <h1 align="center">
11
+ <br>
12
+ <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>
13
+ </h1>
14
+
15
+ <h3 align=center> A Privacy Enhancing Technology (PET) Operations platform</h3>
16
+ <h3 align="center">
17
+
18
+ <!-- Badges go here-->
19
+ [![Release](https://github.com/vantage6/vantage6/actions/workflows/release.yml/badge.svg)](https://github.com/vantage6/vantage6/actions/workflows/release.yml)
20
+ [![PyPI vantage6](https://badge.fury.io/py/vantage6.svg)](https://badge.fury.io/py/vantage6)
21
+ [![Unittests](https://github.com/vantage6/vantage6/actions/workflows/unit_tests.yml/badge.svg)](https://github.com/vantage6/vantage6/actions/workflows/unit_tests.yml)
22
+ [![Coverage Status](https://coveralls.io/repos/github/vantage6/vantage6/badge.svg?branch=main)](https://coveralls.io/github/vantage6/vantage6?branch=main)
23
+ [![Codacy Badge](https://app.codacy.com/project/badge/Grade/2e60ac3b3f284620805f7399cba317be)](https://www.codacy.com/gh/vantage6/vantage6/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=vantage6/vantage6&amp;utm_campaign=Badge_Grade)
24
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.7382602.svg)](https://doi.org/10.5281/zenodo.7382602)
25
+ </h3>
26
+
27
+ <p align="center">
28
+ <a href="#books-quickstart">Quickstart</a> •
29
+ <a href="#project-structure">Project structure</a> •
30
+ <a href="#gift_heart-join-the-community">Join the community</a> •
31
+ <a href="#black_nib-references">References</a>
32
+ </p>
33
+
34
+
35
+ -----------------------------------------------------------------------------------------------------
36
+ 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 (vantage6.ai)](https://vantage6.ai) to learn more!
37
+
38
+ You can find more (user) documentation at [readthedocs (docs.vantage6.ai)](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)](https://discord.gg/yAyFf6Y) channel.
39
+
40
+ ## Infrastructure overview
41
+
42
+ ![Vantage6 architecture overview](docs/images/overview-infrastructure.png)
43
+
44
+ *A High level overview of the vantage6 infrastructure. Vantage6 has both a client-server and peer-to-peer architecture. The client is used by the researcher to create (PET) computation requests. It is also used to manage users, organizations and collaborations. The server contains users, organizations, collaborations, tasks and their results. It provides a central access point for both the clients and nodes. The nodes have access to privacy sensitive data and handle computation requests retrieved from the server. Computation request are executed as separate containers on the node. These containers are connected to containers at other nodes by a VPN network.*
45
+
46
+ ## :books: Quickstart
47
+
48
+ ### Requirements
49
+ The **vantage6** infrastructure is delivered in Docker images. To run these images, you need to have [Docker](https://docs.docker.com/get-docker/) installed. To install the latest version of the vantage6 CLI, you need to have [Python](https://www.python.org/downloads/), we recommend using an environment manager like [mini-conda](https://docs.conda.io/en/latest/miniconda.html).
50
+
51
+ Install the latest version of the vantage6 CLI by using:
52
+ ```bash
53
+ pip install vantage6
54
+ ```
55
+
56
+ This install the `v6` commands, which allows you to manage your nodes and servers. To view all available options, run:
57
+
58
+ ```bash
59
+ v6 --help
60
+ ```
61
+
62
+ For example you can create a local test setup by using:
63
+
64
+ ```bash
65
+ v6 dev create-demo-network
66
+ ```
67
+
68
+ This creates a local network with a server and two nodes. You can start the network by running:
69
+
70
+ ```bash
71
+ v6 dev start-demo-network
72
+ ```
73
+
74
+ This will start the server and nodes in the background. You can view the logs by running:
75
+
76
+ ```bash
77
+ # View node logs
78
+ v6 node attach
79
+
80
+ # View server logs
81
+ v6 server attach
82
+ ```
83
+
84
+ From here you can use the [vantage6-client](https://pypi.org/project/vantage6-client) to interact with the server. The demo network has a pre-configured organization with the following credentials:
85
+
86
+ * Username: `org_1-admin`
87
+ * Password: `password`
88
+
89
+ For example, you can create a new organization by running:
90
+
91
+ ```python
92
+ from vantage6.client import Client
93
+
94
+ client = Client('http://127.0.0.1', 5000, '/api', log_level='debug')
95
+ client.authenticate('org_1-admin', 'password')
96
+ client.setup_encryption(None)
97
+
98
+ client.organization.create(
99
+ name='My organization',
100
+ address1='My address',
101
+ address2='My address',
102
+ zipcode='1234AB',
103
+ country='The Netherlands',
104
+ domain='my-organization.com'
105
+ )
106
+ ```
107
+
108
+ You can find more (user) documentation at [readthedocs (docs.vantage6.ai)](https://docs.vantage6.ai)
109
+
110
+ ## Project structure
111
+
112
+ ### PYPI packages
113
+ This repository is home to 6 PyPi packages:
114
+
115
+ * [vantage6](https://pypi.org/project/vantage6) -> _CLI for managing node and server instances_
116
+ * [vantage6-client](https://pypi.org/project/vantage6-client) -> _Python client for interacting with the vantage6-server_
117
+ * [vantage6-algorithm-tools](https://pypi.org/project/vantage6-algorithm-tools) -> _Python tools to facilitate algorithm development_
118
+ * [vantage6-node](https://pypi.org/project/vantage6-node) -> _Node application package_
119
+ * [vantage6-server](https://pypi.org/project/vantage6-server) -> _Server application package_
120
+ * [vantage6-algorithm-store](https://pypi.org/project/vantage6-algorithm-store) -> _Algorithm store application package_
121
+ * [vantage6-common](https://pypi.org/project/vantage6-common) -> _Package with common vantage6 functions_
122
+ * [vantage6-backend-common](https://pypi.org/project/vantage6-backend-common) -> _Package with functions common to central server and algorithm store_
123
+
124
+ **Note that when using vantage6 you do not install the _server_ and _node_ packages. These are delivered to you in Docker images.**
125
+
126
+ ### Docker images
127
+ The vantage6 infrastructure is delivered in Docker images. All Docker images are stored in our private [Harbor](https://goharbor.io/) registry. The most important images contain the server and node:
128
+
129
+ * `harbor2.vantage6.ai/infrastructure/node:VERSION` -> _Node application Docker image_
130
+ * `harbor2.vantage6.ai/infrastructure/server:VERSION` -> _Server application Docker image_
131
+
132
+ with `VERSION` being the full semantic version of the vantage6 infrastructure, e.g. `4.0.0` or `4.1.0rc0`.
133
+
134
+ Several other images are used to support the infrastructure:
135
+
136
+ * `harbor2.vantage6.ai/infrastructure/infrastructure-base:VERSION` -> _Base image for the infrastructure_
137
+ * `harbor2.vantage6.ai/infrastructure/squid:VERSION` -> _Squid proxy image used for the whitelisting service_
138
+ * `harbor2.vantage6.ai/infrastructure/alpine` -> _Alpine image used for vpn traffic forwarding_
139
+ * `harbor2.vantage6.ai/infrastructure/vpn-client` -> _VPN image used to connect to the VPN_
140
+ * `harbor2.vantage6.ai/infrastructure/vpn-configurator` -> _VPN image used for initialization_
141
+ * `harbor2.vantage6.ai/infrastructure/ssh-tunnel` -> _SSH tunnel image used for connecting algorithms to external services_
142
+
143
+ And finally there are some images released for algorithm development:
144
+
145
+ * `harbor2.vantage6.ai/infrastructure/algorithm-base:MAJOR.MINOR` -> _Base image for algorithm development_
146
+ * `harbor2.vantage6.ai/infrastructure/algorithm-ohdsi-base:MAJOR.MINOR` -> _Extended algorithm base image for OHDSI algorithm development_
147
+
148
+ ## :gift_heart: Join the community!
149
+ We hope to continue developing, improving, and supporting **vantage6** with the help of the federated learning community. If you are interested in contributing, first of all, thank you! Second, please take a look at our [contributing guidelines](https://docs.vantage6.ai/en/main/devops/contribute.html)
150
+
151
+ <a href="https://github.com/vantage6/vantage6/graphs/contributors">
152
+ <img src="https://contrib.rocks/image?repo=vantage6/vantage6" />
153
+ </a>
154
+
155
+ ## :black_nib: References
156
+ If you are using **vantage6**, please cite this repository as well as the accompanying papers as follows:
157
+
158
+ > * F. Martin, M. Sieswerda, H. Alradhi, et al. vantage6. Available at https://doi.org/10.5281/zenodo.7221216. Accessed on MONTH, 20XX.
159
+ > * 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/)]
160
+ > * 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)]
161
+
162
+ -----------------------------------------------------------------------------------------------------
163
+ <p align="center">
164
+ <a href="https://vantage6.ai">vantage6.ai</a> •
165
+ <a href="https://discord.gg/yAyFf6Y">Discord</a> •
166
+ <a href="https://vantage6.discourse.group/">Discourse</a> •
167
+ <a href="https://docs.vantage6.ai">User documentation</a> •
168
+ </p>
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,55 @@
1
+ import codecs
2
+ import os
3
+
4
+ from os import path
5
+ from setuptools import setup, find_namespace_packages
6
+ from pathlib import Path
7
+
8
+ # get current directory
9
+ here = Path(path.abspath(path.dirname(__file__)))
10
+ parent_dir = here.parent.absolute()
11
+
12
+ # get the long description from the README file
13
+ with codecs.open(path.join(parent_dir, "README.md"), encoding="utf-8") as f:
14
+ long_description = f.read()
15
+
16
+ # Read the API version from disk. This file should be located in the package
17
+ # folder, since it's also used to set the pkg.__version__ variable.
18
+ version_path = os.path.join(here, "vantage6", "algorithm", "store", "_version.py")
19
+ version_ns = {"__file__": version_path}
20
+ with codecs.open(version_path) as f:
21
+ exec(f.read(), {}, version_ns)
22
+
23
+ # setup the package
24
+ setup(
25
+ name="vantage6-algorithm-store",
26
+ version=version_ns["__version__"],
27
+ description="Vantage6 algorithm store",
28
+ long_description=long_description,
29
+ long_description_content_type="text/markdown",
30
+ url="https://github.com/vantage6/vantage6",
31
+ packages=find_namespace_packages(),
32
+ python_requires=">=3.10",
33
+ install_requires=[
34
+ "flasgger==0.9.5",
35
+ "flask==2.2.5",
36
+ "Flask-Cors==3.0.10",
37
+ "Flask-Principal==0.4.0",
38
+ "flask-marshmallow==0.15.0",
39
+ "Flask-RESTful==0.3.10",
40
+ "gevent==23.9.1",
41
+ "marshmallow==3.19.0",
42
+ "requests==2.31.0",
43
+ "schema==0.7.5",
44
+ "SQLAlchemy==1.4.46",
45
+ "werkzeug==3.0.1",
46
+ f'vantage6 == {version_ns["__version__"]}',
47
+ f'vantage6-common == {version_ns["__version__"]}',
48
+ ],
49
+ extras_require={"dev": ["coverage==6.4.4"]},
50
+ package_data={
51
+ "vantage6.algorithm.store": [
52
+ "__build__",
53
+ ],
54
+ },
55
+ )
@@ -0,0 +1,358 @@
1
+ """
2
+ The algorithm store holds the algorithms that are available to the vantage6
3
+ nodes. It is a repository of algorithms that can be coupled to a vantage6
4
+ server. The algorithms are stored in a database and can be managed through
5
+ the API. Note that is possible to couple multiple algorithm stores to a
6
+ vantage6 server. This allows both coupling a community store and a private
7
+ store to a vantage6 server.
8
+ """
9
+
10
+ import os
11
+ from gevent import monkey
12
+
13
+ from vantage6.algorithm.store.default_roles import get_default_roles
14
+
15
+ # This is a workaround for readthedocs
16
+ if not os.environ.get("READTHEDOCS"):
17
+ # flake8: noqa: E402 (ignore import error)
18
+ monkey.patch_all()
19
+
20
+ # pylint: disable=C0413, C0411
21
+ import importlib
22
+ import logging
23
+ import json
24
+ import traceback
25
+
26
+ from http import HTTPStatus
27
+ from werkzeug.exceptions import HTTPException
28
+ from flask import Flask, make_response, request, send_from_directory, Request, Response
29
+ from flask_cors import CORS
30
+ from flask_marshmallow import Marshmallow
31
+ from flask_restful import Api
32
+ from flask_principal import Principal
33
+ from flasgger import Swagger
34
+ from pathlib import Path
35
+
36
+ from vantage6.common import logger_name
37
+ from vantage6.common.globals import APPNAME
38
+ from vantage6.backend.common.resource.output_schema import BaseHATEOASModelSchema
39
+
40
+ # TODO move this to common, then remove dependency on CLI in algorithm store
41
+ from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
42
+ from vantage6.algorithm.store._version import __version__
43
+ from vantage6.algorithm.store.globals import API_PATH, HOST_URI_ENV
44
+ from vantage6.algorithm.store.globals import RESOURCES, SERVER_MODULE_NAME
45
+
46
+ # TODO the following are simply copies of the same files in the server - refactor
47
+ from vantage6.algorithm.store.model.base import Base, DatabaseSessionManager, Database
48
+ from vantage6.algorithm.store import db
49
+
50
+ # TODO move server imports to common / refactor
51
+ from vantage6.algorithm.store.permission import PermissionManager
52
+
53
+ module_name = logger_name(__name__)
54
+ log = logging.getLogger(module_name)
55
+
56
+
57
+ class AlgorithmStoreApp:
58
+ """
59
+ Vantage6 server instance.
60
+
61
+ Attributes
62
+ ----------
63
+ ctx : AlgorithmStoreContext
64
+ Context object that contains the configuration of the algorithm store.
65
+ """
66
+
67
+ def __init__(self, ctx: AlgorithmStoreContext) -> None:
68
+ """Create a vantage6-server application."""
69
+
70
+ self.ctx = ctx
71
+
72
+ # initialize, configure Flask
73
+ self.app = Flask(
74
+ SERVER_MODULE_NAME,
75
+ root_path=Path(__file__),
76
+ template_folder=Path(__file__).parent / "templates",
77
+ static_folder=Path(__file__).parent / "static",
78
+ )
79
+ self.debug: dict = self.ctx.config.get("debug", {})
80
+ self.configure_flask()
81
+
82
+ # Setup SQLAlchemy and Marshmallow for marshalling/serializing
83
+ self.ma = Marshmallow(self.app)
84
+
85
+ # Setup Principal, granular API access manegement
86
+ self.principal = Principal(self.app, use_sessions=False)
87
+
88
+ # Enable cross-origin resource sharing
89
+ self.cors = CORS(self.app)
90
+
91
+ # SWAGGER documentation
92
+ self.swagger = Swagger(self.app, template={})
93
+
94
+ # setup the permission manager for the API endpoints
95
+ self.permissions = PermissionManager()
96
+
97
+ # Api - REST JSON-rpc
98
+ self.api = Api(self.app)
99
+ self.configure_api()
100
+ self.load_resources()
101
+
102
+ # set the server version
103
+ self.__version__ = __version__
104
+
105
+ # set environment variable for dev environment
106
+ host_uri = self.ctx.config.get("dev", {}).get("host_uri")
107
+ if host_uri:
108
+ os.environ[HOST_URI_ENV] = host_uri
109
+
110
+ log.info("Initialization done")
111
+
112
+ def configure_flask(self) -> None:
113
+ """Configure the Flask settings of the vantage6 server."""
114
+
115
+ # let us handle exceptions
116
+ self.app.config["PROPAGATE_EXCEPTIONS"] = True
117
+
118
+ # Open Api Specification (f.k.a. swagger)
119
+ self.app.config["SWAGGER"] = {
120
+ "title": f"{APPNAME} algorithm store",
121
+ "uiversion": "3",
122
+ "openapi": "3.0.0",
123
+ "version": __version__,
124
+ }
125
+
126
+ debug_mode = self.debug.get("flask", False)
127
+ if debug_mode:
128
+ log.debug("Flask debug mode enabled")
129
+ self.app.debug = debug_mode
130
+
131
+ def _get_request_path(request: Request) -> str:
132
+ """
133
+ Return request extension of request URL, e.g.
134
+ http://localhost:5000/api/task/1 -> api/task/1
135
+
136
+ Parameters
137
+ ----------
138
+ request: Request
139
+ Flask request object
140
+
141
+ Returns
142
+ -------
143
+ string:
144
+ The endpoint path of the request
145
+ """
146
+ return request.url.replace(request.url_root, "")
147
+
148
+ # before request
149
+ @self.app.before_request
150
+ def do_before_request():
151
+ """Before every flask request method."""
152
+ # Add log message before each request
153
+ log.debug(
154
+ "Received request: %s %s", request.method, _get_request_path(request)
155
+ )
156
+
157
+ # This will obtain a (scoped) db session from the session factory
158
+ # that is linked to the flask request global `g`. In every endpoint
159
+ # we then can access the database by using this session. We ensure
160
+ # that the session is removed (and uncommited changes are rolled
161
+ # back) at the end of every request.
162
+ DatabaseSessionManager.new_session()
163
+
164
+ @self.app.after_request
165
+ def remove_db_session(response):
166
+ """After every flask request.
167
+
168
+ This will close the database session created by the
169
+ `before_request`.
170
+ """
171
+ DatabaseSessionManager.clear_session()
172
+ return response
173
+
174
+ @self.app.errorhandler(HTTPException)
175
+ def error_remove_db_session(error: HTTPException):
176
+ """In case an HTTP-exception occurs during the request.
177
+
178
+ It is important to close the db session to avoid having dangling
179
+ sessions.
180
+ """
181
+ if error.code == 404:
182
+ log.debug("404 error for route '%s'", _get_request_path(request))
183
+ else:
184
+ log.warning("HTTP Exception occured during request")
185
+ log.debug("%s", traceback.format_exc())
186
+ DatabaseSessionManager.clear_session()
187
+ return error.get_response()
188
+
189
+ @self.app.errorhandler(Exception)
190
+ def error2_remove_db_session(error):
191
+ """In case an exception occurs during the request.
192
+
193
+ It is important to close the db session to avoid having dangling
194
+ sessions.
195
+ """
196
+ log.exception("Exception occured during request")
197
+ DatabaseSessionManager.clear_session()
198
+ return {
199
+ "msg": "An unexpected error occurred on the server!"
200
+ }, HTTPStatus.INTERNAL_SERVER_ERROR
201
+
202
+ @self.app.route("/robots.txt")
203
+ def static_from_root():
204
+ return send_from_directory(self.app.static_folder, request.path[1:])
205
+
206
+ def configure_api(self) -> None:
207
+ """Define global API output and its structure."""
208
+
209
+ # helper to create HATEOAS schemas
210
+ BaseHATEOASModelSchema.api = self.api
211
+
212
+ # whatever you get try to json it
213
+ @self.api.representation("application/json")
214
+ # pylint: disable=unused-argument
215
+ def output_json(
216
+ data: Base | list[Base], code: HTTPStatus, headers: dict = None
217
+ ) -> Response:
218
+ """
219
+ Return jsonified data for request responses.
220
+
221
+ Parameters
222
+ ----------
223
+ data: Base | list[Base]
224
+ The data to be jsonified
225
+ code: HTTPStatus
226
+ The HTTP status code of the response
227
+ headers: dict
228
+ Additional headers to be added to the response
229
+ """
230
+
231
+ if isinstance(data, Base):
232
+ data = db.jsonable(data)
233
+ elif isinstance(data, list) and len(data) and isinstance(data[0], Base):
234
+ data = db.jsonable(data)
235
+
236
+ resp = make_response(json.dumps(data), code)
237
+ resp.headers.extend(headers or {})
238
+ return resp
239
+
240
+ def load_resources(self) -> None:
241
+ """Import the modules containing API resources."""
242
+
243
+ # make services available to the endpoints, this way each endpoint can
244
+ # make use of 'em.
245
+ services = {
246
+ "api": self.api,
247
+ "config": self.ctx.config,
248
+ "permissions": self.permissions,
249
+ }
250
+
251
+ for res in RESOURCES:
252
+ module = importlib.import_module("vantage6.algorithm.store.resource." + res)
253
+ module.setup(self.api, API_PATH, services)
254
+
255
+ @staticmethod
256
+ def _add_default_roles() -> None:
257
+ for role in get_default_roles():
258
+ if not db.Role.get_by_name(role["name"]):
259
+ log.warn("Creating new default role %s", role["name"])
260
+ new_role = db.Role(
261
+ name=role["name"],
262
+ description=role["description"],
263
+ rules=role["rules"],
264
+ )
265
+ new_role.save()
266
+
267
+ def start(self) -> None:
268
+ """
269
+ Start the server.
270
+
271
+ Before server is really started, some database settings are checked and
272
+ (re)set where appropriate.
273
+ """
274
+ self._add_default_roles()
275
+
276
+ # add whitelisted server and root user from config file if they do not exist
277
+ if root_user := self.ctx.config.get("root_user", {}):
278
+ whitelisted_uri = root_user.get("v6_server_uri")
279
+ root_username = root_user.get("username")
280
+ if whitelisted_uri and root_username:
281
+ if not (v6_server := db.Vantage6Server.get_by_url(whitelisted_uri)):
282
+ log.debug("This server will be whitelisted: %s", whitelisted_uri)
283
+ v6_server = db.Vantage6Server(url=whitelisted_uri)
284
+ v6_server.save()
285
+
286
+ # if the user does not exist already, add it
287
+ if not db.User.get_by_server(
288
+ username=root_username, v6_server_id=v6_server.id
289
+ ):
290
+ log.warning("Creating root user")
291
+
292
+ root = db.Role.get_by_name("Root")
293
+
294
+ user = db.User(
295
+ v6_server_id=v6_server.id,
296
+ username=root_username,
297
+ roles=[root],
298
+ )
299
+ user.save()
300
+ else:
301
+ log.info(
302
+ "The root user given in the configuration already exists -"
303
+ " no action taken."
304
+ )
305
+
306
+ else:
307
+ log.warning(
308
+ "No v6_server_uri and/or username found in the configuration file "
309
+ "in the root_user section. This means no-one can alter resources on"
310
+ " this server, unless one or more users were already authorized to "
311
+ "make changes to the algorithm store previously."
312
+ )
313
+ else:
314
+ log.warning(
315
+ "No root user found in the configuration file. This means "
316
+ "no-one can alter resources on this server, unless one or "
317
+ "more users were already authorized to make changes to the "
318
+ "algorithm store prevoiusly."
319
+ )
320
+ return self
321
+
322
+
323
+ def run_server(config: str, system_folders: bool = True) -> AlgorithmStoreApp:
324
+ """
325
+ Run a vantage6 server.
326
+
327
+ Parameters
328
+ ----------
329
+ config: str
330
+ Configuration file path
331
+ system_folders: bool
332
+ Whether to use system or user folders. Default is True.
333
+
334
+ Returns
335
+ -------
336
+ AlgorithmStoreApp
337
+ A running instance of the vantage6 server
338
+ """
339
+ ctx = AlgorithmStoreContext.from_external_config_file(config, system_folders)
340
+ allow_drop_all = ctx.config["allow_drop_all"]
341
+ Database().connect(uri=ctx.get_database_uri(), allow_drop_all=allow_drop_all)
342
+ return AlgorithmStoreApp(ctx).start()
343
+
344
+
345
+ def run_dev_server(server_app: AlgorithmStoreApp, *args, **kwargs) -> None:
346
+ """
347
+ Run a vantage6 development server (outside of a Docker container).
348
+
349
+ Parameters
350
+ ----------
351
+ server_app: AlgorithmStoreApp
352
+ Instance of a vantage6 server
353
+ """
354
+ log.warning("*" * 80)
355
+ log.warning(" DEVELOPMENT SERVER ".center(80, "*"))
356
+ log.warning("*" * 80)
357
+ kwargs.setdefault("log_output", False)
358
+ server_app.socketio.run(server_app.app, *args, **kwargs)
@@ -0,0 +1,23 @@
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 = (4, 3, 0, "final", __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}"