vantage6-algorithm-store 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.
- vantage6/algorithm/store/__init__.py +290 -0
- vantage6/algorithm/store/_version.py +23 -0
- vantage6/algorithm/store/db.py +71 -0
- vantage6/algorithm/store/globals.py +18 -0
- vantage6/algorithm/store/model/__init__.py +6 -0
- vantage6/algorithm/store/model/algorithm.py +44 -0
- vantage6/algorithm/store/model/argument.py +36 -0
- vantage6/algorithm/store/model/base.py +424 -0
- vantage6/algorithm/store/model/common/enums.py +29 -0
- vantage6/algorithm/store/model/database.py +33 -0
- vantage6/algorithm/store/model/function.py +43 -0
- vantage6/algorithm/store/model/vantage6_server.py +38 -0
- vantage6/algorithm/store/resource/__init__.py +88 -0
- vantage6/algorithm/store/resource/algorithm.py +340 -0
- vantage6/algorithm/store/resource/schema/input_schema.py +96 -0
- vantage6/algorithm/store/resource/schema/output_schema.py +56 -0
- vantage6/algorithm/store/resource/vantage6_server.py +242 -0
- vantage6/algorithm/store/resource/version.py +61 -0
- vantage6/algorithm/store/wsgi.py +16 -0
- vantage6_algorithm_store-4.3.0b3.dist-info/METADATA +192 -0
- vantage6_algorithm_store-4.3.0b3.dist-info/RECORD +24 -0
- vantage6_algorithm_store-4.3.0b3.dist-info/WHEEL +5 -0
- vantage6_algorithm_store-4.3.0b3.dist-info/entry_points.txt +2 -0
- vantage6_algorithm_store-4.3.0b3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,290 @@
|
|
|
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
|
+
import os
|
|
10
|
+
from gevent import monkey
|
|
11
|
+
|
|
12
|
+
# This is a workaround for readthedocs
|
|
13
|
+
if not os.environ.get("READTHEDOCS"):
|
|
14
|
+
# flake8: noqa: E402 (ignore import error)
|
|
15
|
+
monkey.patch_all()
|
|
16
|
+
|
|
17
|
+
import importlib
|
|
18
|
+
import logging
|
|
19
|
+
import json
|
|
20
|
+
import traceback
|
|
21
|
+
|
|
22
|
+
from http import HTTPStatus
|
|
23
|
+
from werkzeug.exceptions import HTTPException
|
|
24
|
+
from flask import Flask, make_response, request, send_from_directory, Request, Response
|
|
25
|
+
from flask_cors import CORS
|
|
26
|
+
from flask_marshmallow import Marshmallow
|
|
27
|
+
from flask_restful import Api
|
|
28
|
+
from flask_principal import Principal
|
|
29
|
+
from flasgger import Swagger
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
from vantage6.common import logger_name
|
|
33
|
+
from vantage6.common.globals import APPNAME
|
|
34
|
+
from vantage6.cli.context.algorithm_store import AlgorithmStoreContext
|
|
35
|
+
from vantage6.algorithm.store._version import __version__
|
|
36
|
+
from vantage6.algorithm.store.globals import API_PATH
|
|
37
|
+
|
|
38
|
+
# TODO the following are simply copies of the same files in the server - refactor
|
|
39
|
+
from vantage6.algorithm.store.model.base import Base, DatabaseSessionManager, Database
|
|
40
|
+
from vantage6.algorithm.store import db
|
|
41
|
+
|
|
42
|
+
# TODO move server imports to common / refactor
|
|
43
|
+
from vantage6.server.resource.common.output_schema import HATEOASModelSchema
|
|
44
|
+
from vantage6.server.permission import PermissionManager
|
|
45
|
+
from vantage6.algorithm.store.globals import RESOURCES, SERVER_MODULE_NAME
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
module_name = logger_name(__name__)
|
|
49
|
+
log = logging.getLogger(module_name)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class AlgorithmStoreApp:
|
|
53
|
+
"""
|
|
54
|
+
Vantage6 server instance.
|
|
55
|
+
|
|
56
|
+
Attributes
|
|
57
|
+
----------
|
|
58
|
+
ctx : AlgorithmStoreContext
|
|
59
|
+
Context object that contains the configuration of the algorithm store.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(self, ctx: AlgorithmStoreContext) -> None:
|
|
63
|
+
"""Create a vantage6-server application."""
|
|
64
|
+
|
|
65
|
+
self.ctx = ctx
|
|
66
|
+
|
|
67
|
+
# initialize, configure Flask
|
|
68
|
+
self.app = Flask(
|
|
69
|
+
SERVER_MODULE_NAME,
|
|
70
|
+
root_path=Path(__file__),
|
|
71
|
+
template_folder=Path(__file__).parent / "templates",
|
|
72
|
+
static_folder=Path(__file__).parent / "static",
|
|
73
|
+
)
|
|
74
|
+
self.debug: dict = self.ctx.config.get("debug", {})
|
|
75
|
+
self.configure_flask()
|
|
76
|
+
|
|
77
|
+
# Setup SQLAlchemy and Marshmallow for marshalling/serializing
|
|
78
|
+
self.ma = Marshmallow(self.app)
|
|
79
|
+
|
|
80
|
+
# Setup Principal, granular API access manegement
|
|
81
|
+
self.principal = Principal(self.app, use_sessions=False)
|
|
82
|
+
|
|
83
|
+
# Enable cross-origin resource sharing
|
|
84
|
+
self.cors = CORS(self.app)
|
|
85
|
+
|
|
86
|
+
# SWAGGER documentation
|
|
87
|
+
self.swagger = Swagger(self.app, template={})
|
|
88
|
+
|
|
89
|
+
# setup the permission manager for the API endpoints
|
|
90
|
+
# self.permissions = PermissionManager()
|
|
91
|
+
|
|
92
|
+
# Api - REST JSON-rpc
|
|
93
|
+
self.api = Api(self.app)
|
|
94
|
+
self.configure_api()
|
|
95
|
+
self.load_resources()
|
|
96
|
+
|
|
97
|
+
# set the server version
|
|
98
|
+
self.__version__ = __version__
|
|
99
|
+
|
|
100
|
+
log.info("Initialization done")
|
|
101
|
+
|
|
102
|
+
def configure_flask(self) -> None:
|
|
103
|
+
"""Configure the Flask settings of the vantage6 server."""
|
|
104
|
+
|
|
105
|
+
# let us handle exceptions
|
|
106
|
+
self.app.config["PROPAGATE_EXCEPTIONS"] = True
|
|
107
|
+
|
|
108
|
+
# Open Api Specification (f.k.a. swagger)
|
|
109
|
+
self.app.config["SWAGGER"] = {
|
|
110
|
+
"title": f"{APPNAME} algorithm store",
|
|
111
|
+
"uiversion": "3",
|
|
112
|
+
"openapi": "3.0.0",
|
|
113
|
+
"version": __version__,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
debug_mode = self.debug.get("flask", False)
|
|
117
|
+
if debug_mode:
|
|
118
|
+
log.debug("Flask debug mode enabled")
|
|
119
|
+
self.app.debug = debug_mode
|
|
120
|
+
|
|
121
|
+
def _get_request_path(request: Request) -> str:
|
|
122
|
+
"""
|
|
123
|
+
Return request extension of request URL, e.g.
|
|
124
|
+
http://localhost:5000/api/task/1 -> api/task/1
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
request: Request
|
|
129
|
+
Flask request object
|
|
130
|
+
|
|
131
|
+
Returns
|
|
132
|
+
-------
|
|
133
|
+
string:
|
|
134
|
+
The endpoint path of the request
|
|
135
|
+
"""
|
|
136
|
+
return request.url.replace(request.url_root, "")
|
|
137
|
+
|
|
138
|
+
# before request
|
|
139
|
+
@self.app.before_request
|
|
140
|
+
def do_before_request():
|
|
141
|
+
"""Before every flask request method."""
|
|
142
|
+
# Add log message before each request
|
|
143
|
+
log.debug(
|
|
144
|
+
"Received request: %s %s", request.method, _get_request_path(request)
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# This will obtain a (scoped) db session from the session factory
|
|
148
|
+
# that is linked to the flask request global `g`. In every endpoint
|
|
149
|
+
# we then can access the database by using this session. We ensure
|
|
150
|
+
# that the session is removed (and uncommited changes are rolled
|
|
151
|
+
# back) at the end of every request.
|
|
152
|
+
DatabaseSessionManager.new_session()
|
|
153
|
+
|
|
154
|
+
@self.app.after_request
|
|
155
|
+
def remove_db_session(response):
|
|
156
|
+
"""After every flask request.
|
|
157
|
+
|
|
158
|
+
This will close the database session created by the
|
|
159
|
+
`before_request`.
|
|
160
|
+
"""
|
|
161
|
+
DatabaseSessionManager.clear_session()
|
|
162
|
+
return response
|
|
163
|
+
|
|
164
|
+
@self.app.errorhandler(HTTPException)
|
|
165
|
+
def error_remove_db_session(error: HTTPException):
|
|
166
|
+
"""In case an HTTP-exception occurs during the request.
|
|
167
|
+
|
|
168
|
+
It is important to close the db session to avoid having dangling
|
|
169
|
+
sessions.
|
|
170
|
+
"""
|
|
171
|
+
if error.code == 404:
|
|
172
|
+
log.debug("404 error for route '%s'", _get_request_path(request))
|
|
173
|
+
else:
|
|
174
|
+
log.warning("HTTP Exception occured during request")
|
|
175
|
+
log.debug("%s", traceback.format_exc())
|
|
176
|
+
DatabaseSessionManager.clear_session()
|
|
177
|
+
return error.get_response()
|
|
178
|
+
|
|
179
|
+
@self.app.errorhandler(Exception)
|
|
180
|
+
def error2_remove_db_session(error):
|
|
181
|
+
"""In case an exception occurs during the request.
|
|
182
|
+
|
|
183
|
+
It is important to close the db session to avoid having dangling
|
|
184
|
+
sessions.
|
|
185
|
+
"""
|
|
186
|
+
log.exception("Exception occured during request")
|
|
187
|
+
DatabaseSessionManager.clear_session()
|
|
188
|
+
return {
|
|
189
|
+
"msg": "An unexpected error occurred on the server!"
|
|
190
|
+
}, HTTPStatus.INTERNAL_SERVER_ERROR
|
|
191
|
+
|
|
192
|
+
@self.app.route("/robots.txt")
|
|
193
|
+
def static_from_root():
|
|
194
|
+
return send_from_directory(self.app.static_folder, request.path[1:])
|
|
195
|
+
|
|
196
|
+
def configure_api(self) -> None:
|
|
197
|
+
"""Define global API output and its structure."""
|
|
198
|
+
|
|
199
|
+
# helper to create HATEOAS schemas
|
|
200
|
+
HATEOASModelSchema.api = self.api
|
|
201
|
+
|
|
202
|
+
# whatever you get try to json it
|
|
203
|
+
@self.api.representation("application/json")
|
|
204
|
+
# pylint: disable=unused-argument
|
|
205
|
+
def output_json(
|
|
206
|
+
data: Base | list[Base], code: HTTPStatus, headers: dict = None
|
|
207
|
+
) -> Response:
|
|
208
|
+
"""
|
|
209
|
+
Return jsonified data for request responses.
|
|
210
|
+
|
|
211
|
+
Parameters
|
|
212
|
+
----------
|
|
213
|
+
data: Base | list[Base]
|
|
214
|
+
The data to be jsonified
|
|
215
|
+
code: HTTPStatus
|
|
216
|
+
The HTTP status code of the response
|
|
217
|
+
headers: dict
|
|
218
|
+
Additional headers to be added to the response
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
if isinstance(data, Base):
|
|
222
|
+
data = db.jsonable(data)
|
|
223
|
+
elif isinstance(data, list) and len(data) and isinstance(data[0], Base):
|
|
224
|
+
data = db.jsonable(data)
|
|
225
|
+
|
|
226
|
+
resp = make_response(json.dumps(data), code)
|
|
227
|
+
resp.headers.extend(headers or {})
|
|
228
|
+
return resp
|
|
229
|
+
|
|
230
|
+
def load_resources(self) -> None:
|
|
231
|
+
"""Import the modules containing API resources."""
|
|
232
|
+
|
|
233
|
+
# make services available to the endpoints, this way each endpoint can
|
|
234
|
+
# make use of 'em.
|
|
235
|
+
services = {
|
|
236
|
+
"api": self.api,
|
|
237
|
+
# "permissions": self.permissions,
|
|
238
|
+
"config": self.ctx.config,
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
for res in RESOURCES:
|
|
242
|
+
module = importlib.import_module("vantage6.algorithm.store.resource." + res)
|
|
243
|
+
module.setup(self.api, API_PATH, services)
|
|
244
|
+
|
|
245
|
+
def start(self) -> None:
|
|
246
|
+
"""
|
|
247
|
+
Start the server.
|
|
248
|
+
|
|
249
|
+
Before server is really started, some database settings are checked and
|
|
250
|
+
(re)set where appropriate.
|
|
251
|
+
"""
|
|
252
|
+
return self
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def run_server(config: str, system_folders: bool = True) -> AlgorithmStoreApp:
|
|
256
|
+
"""
|
|
257
|
+
Run a vantage6 server.
|
|
258
|
+
|
|
259
|
+
Parameters
|
|
260
|
+
----------
|
|
261
|
+
config: str
|
|
262
|
+
Configuration file path
|
|
263
|
+
system_folders: bool
|
|
264
|
+
Whether to use system or user folders. Default is True.
|
|
265
|
+
|
|
266
|
+
Returns
|
|
267
|
+
-------
|
|
268
|
+
AlgorithmStoreApp
|
|
269
|
+
A running instance of the vantage6 server
|
|
270
|
+
"""
|
|
271
|
+
ctx = AlgorithmStoreContext.from_external_config_file(config, system_folders)
|
|
272
|
+
allow_drop_all = ctx.config["allow_drop_all"]
|
|
273
|
+
Database().connect(uri=ctx.get_database_uri(), allow_drop_all=allow_drop_all)
|
|
274
|
+
return AlgorithmStoreApp(ctx).start()
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def run_dev_server(server_app: AlgorithmStoreApp, *args, **kwargs) -> None:
|
|
278
|
+
"""
|
|
279
|
+
Run a vantage6 development server (outside of a Docker container).
|
|
280
|
+
|
|
281
|
+
Parameters
|
|
282
|
+
----------
|
|
283
|
+
server_app: AlgorithmStoreApp
|
|
284
|
+
Instance of a vantage6 server
|
|
285
|
+
"""
|
|
286
|
+
log.warning("*" * 80)
|
|
287
|
+
log.warning(" DEVELOPMENT SERVER ".center(80, "*"))
|
|
288
|
+
log.warning("*" * 80)
|
|
289
|
+
kwargs.setdefault("log_output", False)
|
|
290
|
+
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, "beta", __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}"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# TODO this is almost a copy of the same file in the server package. Refactor
|
|
2
|
+
# TODO this file is awkward...
|
|
3
|
+
import logging
|
|
4
|
+
import datetime
|
|
5
|
+
|
|
6
|
+
import enum
|
|
7
|
+
import sqlalchemy as sql
|
|
8
|
+
|
|
9
|
+
# Note: by importing these classes, the classes are registered in the Base's
|
|
10
|
+
# SQLAlchemy metadata. This is required for SQLAlchemy to be able to map the
|
|
11
|
+
# classes to the database tables, and e.g. initialize the database tables on
|
|
12
|
+
# startup.
|
|
13
|
+
from vantage6.algorithm.store.model import Base, Algorithm, Argument, Database, Function
|
|
14
|
+
from vantage6.common import logger_name
|
|
15
|
+
from vantage6.common.globals import STRING_ENCODING
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
module_name = logger_name(__name__)
|
|
19
|
+
log = logging.getLogger(module_name)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def jsonable(value: list[Base] | Base) -> list | dict:
|
|
23
|
+
"""
|
|
24
|
+
Convert a (list of) SQLAlchemy instance(s) to native Python objects.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
value : list[Base] | Base
|
|
29
|
+
A single SQLAlchemy instance or a list of SQLAlchemy instances
|
|
30
|
+
|
|
31
|
+
Returns
|
|
32
|
+
-------
|
|
33
|
+
list | dict
|
|
34
|
+
A single Python object or a list of Python objects
|
|
35
|
+
|
|
36
|
+
Raises
|
|
37
|
+
------
|
|
38
|
+
Exception
|
|
39
|
+
If the value is not an instance of db.Base or a list of db.Base
|
|
40
|
+
"""
|
|
41
|
+
if isinstance(value, list):
|
|
42
|
+
return [jsonable(i) for i in value]
|
|
43
|
+
|
|
44
|
+
elif isinstance(value, Base):
|
|
45
|
+
log.debug(f"preparing={value}")
|
|
46
|
+
retval = dict()
|
|
47
|
+
mapper = sql.inspect(value.__class__)
|
|
48
|
+
|
|
49
|
+
columns = [
|
|
50
|
+
c.key for c in mapper.columns if c.key not in value._hidden_attributes
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
for column in columns:
|
|
54
|
+
# log.debug(f"processing column={column}")
|
|
55
|
+
column_value = getattr(value, column)
|
|
56
|
+
|
|
57
|
+
if isinstance(column_value, enum.Enum):
|
|
58
|
+
column_value = column_value.value
|
|
59
|
+
elif isinstance(column_value, datetime.datetime):
|
|
60
|
+
column_value = column_value.isoformat()
|
|
61
|
+
elif isinstance(column_value, bytes):
|
|
62
|
+
log.debug("decoding bytes!")
|
|
63
|
+
column_value = column_value.decode(STRING_ENCODING)
|
|
64
|
+
|
|
65
|
+
retval[column] = column_value
|
|
66
|
+
|
|
67
|
+
return retval
|
|
68
|
+
|
|
69
|
+
# FIXME: does it make sense to raise an exception or should base types
|
|
70
|
+
# (or other JSON-serializable types) just be returned as-is?
|
|
71
|
+
raise Exception("value should be instance of db.Base or list!")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from vantage6.common.globals import APPNAME
|
|
4
|
+
|
|
5
|
+
# TODO cleanup this file
|
|
6
|
+
#
|
|
7
|
+
# INSTALLATION SETTINGS
|
|
8
|
+
#
|
|
9
|
+
# PACKAGE_FOLDER = Path(__file__).parent.parent.parent
|
|
10
|
+
|
|
11
|
+
SERVER_MODULE_NAME = APPNAME + "-algorithm-store"
|
|
12
|
+
|
|
13
|
+
# URL extension for the API endpoints
|
|
14
|
+
API_PATH = "/api"
|
|
15
|
+
|
|
16
|
+
# Which resources should be initialized. These names correspond to the
|
|
17
|
+
# file-names in the resource directory
|
|
18
|
+
RESOURCES = ["version", "algorithm", "vantage6_server"]
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from vantage6.algorithm.store.model.base import Base
|
|
2
|
+
from vantage6.algorithm.store.model.algorithm import Algorithm
|
|
3
|
+
from vantage6.algorithm.store.model.argument import Argument
|
|
4
|
+
from vantage6.algorithm.store.model.database import Database
|
|
5
|
+
from vantage6.algorithm.store.model.function import Function
|
|
6
|
+
from vantage6.algorithm.store.model.vantage6_server import Vantage6Server
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from sqlalchemy import Column, String
|
|
3
|
+
from sqlalchemy.orm import relationship
|
|
4
|
+
|
|
5
|
+
from vantage6.algorithm.store.model.base import Base
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Algorithm(Base):
|
|
9
|
+
"""
|
|
10
|
+
Table that describes which algorithms are available.
|
|
11
|
+
|
|
12
|
+
Attributes
|
|
13
|
+
----------
|
|
14
|
+
name : str
|
|
15
|
+
Name of the algorithm
|
|
16
|
+
description: str
|
|
17
|
+
Description of the algorithm
|
|
18
|
+
image : str
|
|
19
|
+
Docker image URL
|
|
20
|
+
partitioning : str
|
|
21
|
+
Type of partitioning
|
|
22
|
+
vantage6_version : str
|
|
23
|
+
Version of vantage6 that the algorithm is built with
|
|
24
|
+
|
|
25
|
+
functions : list[:class:`~.model.function.function`]
|
|
26
|
+
List of functions that are available in the algorithm
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# fields
|
|
30
|
+
name = Column(String)
|
|
31
|
+
description = Column(String)
|
|
32
|
+
image = Column(String)
|
|
33
|
+
# status = Column(String)
|
|
34
|
+
# code_url = Column(String)
|
|
35
|
+
# documentation_url = Column(String)
|
|
36
|
+
partitioning = Column(String)
|
|
37
|
+
vantage6_version = Column(String)
|
|
38
|
+
|
|
39
|
+
# relationships
|
|
40
|
+
functions = relationship("Function", back_populates="algorithm")
|
|
41
|
+
# developers = relationship("Developer", back_populates='algorithms')
|
|
42
|
+
# reviewers = relationship("Reviewer", back_populates='algorithms')
|
|
43
|
+
# preprocessing = relationship("Preprocessing",
|
|
44
|
+
# back_populates='algorithms')
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from sqlalchemy import Column, String, ForeignKey
|
|
3
|
+
from sqlalchemy.orm import relationship
|
|
4
|
+
|
|
5
|
+
from vantage6.algorithm.store.model.base import Base
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Argument(Base):
|
|
9
|
+
"""
|
|
10
|
+
Table that describes function arguments.
|
|
11
|
+
|
|
12
|
+
Each of these arguments is linked to a function within an algorithm. This
|
|
13
|
+
describes details on the arguments that are provided to the function.
|
|
14
|
+
|
|
15
|
+
Attributes
|
|
16
|
+
----------
|
|
17
|
+
name : str
|
|
18
|
+
Name of the argument
|
|
19
|
+
description : str
|
|
20
|
+
Description of the argument
|
|
21
|
+
function_id : str
|
|
22
|
+
ID of the algorithm that this function belongs to
|
|
23
|
+
function : :class:`~.model.algorithm.algorithm`
|
|
24
|
+
Algorithm function that this argument belongs to
|
|
25
|
+
type_ : str
|
|
26
|
+
Type of the argument
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
# fields
|
|
30
|
+
name = Column(String)
|
|
31
|
+
description = Column(String)
|
|
32
|
+
function_id = Column(String, ForeignKey("function.id"))
|
|
33
|
+
type_ = Column(String)
|
|
34
|
+
|
|
35
|
+
# relationships
|
|
36
|
+
function = relationship("Function", back_populates="arguments")
|