digitalhub-runtime-python 0.5.0b10__tar.gz → 0.6.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.
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/PKG-INFO +2 -2
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/__init__.py +1 -1
- digitalhub_runtime_python-0.6.0/digitalhub_runtime_python/entities/functions/models.py +101 -0
- digitalhub_runtime_python-0.6.0/digitalhub_runtime_python/entities/functions/spec.py +108 -0
- digitalhub_runtime_python-0.6.0/digitalhub_runtime_python/entities/runs/spec.py +78 -0
- digitalhub_runtime_python-0.6.0/digitalhub_runtime_python/entities/tasks/models.py +12 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/entities/tasks/spec.py +20 -21
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/entities/tasks/status.py +6 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/runtimes/kind_registry.py +1 -1
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/runtimes/runtime.py +45 -32
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/utils/configuration.py +29 -0
- digitalhub_runtime_python-0.6.0/digitalhub_runtime_python/utils/env.py +3 -0
- digitalhub_runtime_python-0.6.0/digitalhub_runtime_python/utils/inputs.py +146 -0
- digitalhub_runtime_python-0.6.0/digitalhub_runtime_python/utils/nuclio_configuration.py +98 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/utils/outputs.py +32 -7
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python.egg-info/PKG-INFO +2 -2
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python.egg-info/SOURCES.txt +3 -0
- digitalhub_runtime_python-0.6.0/digitalhub_runtime_python.egg-info/requires.txt +1 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/pyproject.toml +3 -3
- digitalhub_runtime_python-0.5.0b10/digitalhub_runtime_python/entities/functions/spec.py +0 -139
- digitalhub_runtime_python-0.5.0b10/digitalhub_runtime_python/entities/runs/spec.py +0 -53
- digitalhub_runtime_python-0.5.0b10/digitalhub_runtime_python/entities/tasks/models.py +0 -31
- digitalhub_runtime_python-0.5.0b10/digitalhub_runtime_python/utils/inputs.py +0 -149
- digitalhub_runtime_python-0.5.0b10/digitalhub_runtime_python.egg-info/requires.txt +0 -1
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/LICENSE.txt +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/README.md +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/entities/__init__.py +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/entities/functions/__init__.py +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/entities/functions/status.py +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/entities/runs/__init__.py +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/entities/runs/status.py +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/entities/tasks/__init__.py +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/runtimes/__init__.py +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python/utils/utils.py +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python.egg-info/dependency_links.txt +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/digitalhub_runtime_python.egg-info/top_level.txt +0 -0
- {digitalhub_runtime_python-0.5.0b10 → digitalhub_runtime_python-0.6.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: digitalhub-runtime-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Python runtime for DHCore
|
|
5
5
|
Author-email: Fondazione Bruno Kessler <dslab@fbk.eu>, Matteo Martini <mmartini@fbk.eu>
|
|
6
6
|
License: Apache License
|
|
@@ -228,6 +228,6 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
228
228
|
Requires-Python: >=3.9
|
|
229
229
|
Description-Content-Type: text/markdown
|
|
230
230
|
License-File: LICENSE.txt
|
|
231
|
-
Requires-Dist: digitalhub[ml]
|
|
231
|
+
Requires-Dist: digitalhub[ml]>=0.6.0b
|
|
232
232
|
|
|
233
233
|
# SDK for DHCore
|
|
@@ -27,7 +27,7 @@ registry.register(func_kind, func_info)
|
|
|
27
27
|
|
|
28
28
|
# Tasks
|
|
29
29
|
entity_type = EntityTypes.TASKS.value
|
|
30
|
-
for i in ["job", "build"]:
|
|
30
|
+
for i in ["job", "build", "serve"]:
|
|
31
31
|
task_kind = f"{func_kind}+{i}"
|
|
32
32
|
prefix = entity_type.removesuffix("s").capitalize()
|
|
33
33
|
suffix = i.capitalize()
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from digitalhub_core.entities.functions.models import SourceCodeParams, SourceCodeStruct
|
|
6
|
+
from digitalhub_core.utils.exceptions import EntityError
|
|
7
|
+
from digitalhub_core.utils.generic_utils import encode_source, encode_string
|
|
8
|
+
from digitalhub_core.utils.uri_utils import map_uri_scheme
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SourceCodeStructPython(SourceCodeStruct):
|
|
12
|
+
"""
|
|
13
|
+
Source code struct for python.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
source: str | None = None,
|
|
19
|
+
handler: str | None = None,
|
|
20
|
+
code: str | None = None,
|
|
21
|
+
base64: str | None = None,
|
|
22
|
+
lang: str | None = None,
|
|
23
|
+
init_function: str | None = None,
|
|
24
|
+
) -> None:
|
|
25
|
+
super().__init__(
|
|
26
|
+
source=source,
|
|
27
|
+
handler=handler,
|
|
28
|
+
code=code,
|
|
29
|
+
base64=base64,
|
|
30
|
+
lang=lang,
|
|
31
|
+
)
|
|
32
|
+
self.init_function = init_function
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def source_check(source: dict) -> dict:
|
|
36
|
+
"""
|
|
37
|
+
Check source. Overrides SourceCodeStruct.source_check.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
source : dict
|
|
42
|
+
Source.
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
dict
|
|
47
|
+
Checked source.
|
|
48
|
+
"""
|
|
49
|
+
# Source check
|
|
50
|
+
source_path = source.get("source")
|
|
51
|
+
code = source.get("code")
|
|
52
|
+
base64 = source.get("base64")
|
|
53
|
+
handler = source.get("handler")
|
|
54
|
+
source["lang"] = "python"
|
|
55
|
+
|
|
56
|
+
if handler is None:
|
|
57
|
+
raise EntityError("Handler must be provided.")
|
|
58
|
+
|
|
59
|
+
if source_path is None and code is None and base64 is None:
|
|
60
|
+
raise EntityError("Source must be provided.")
|
|
61
|
+
|
|
62
|
+
if base64 is not None:
|
|
63
|
+
return source
|
|
64
|
+
|
|
65
|
+
if code is not None:
|
|
66
|
+
source["base64"] = encode_string(code)
|
|
67
|
+
return source
|
|
68
|
+
|
|
69
|
+
if source_path is not None:
|
|
70
|
+
if map_uri_scheme(source_path) == "local":
|
|
71
|
+
if not (Path(source_path).suffix == ".py" and Path(source_path).is_file()):
|
|
72
|
+
raise EntityError("Source is not a valid python file.")
|
|
73
|
+
source["base64"] = encode_source(source_path)
|
|
74
|
+
else:
|
|
75
|
+
if handler is None:
|
|
76
|
+
raise EntityError("Handler must be provided if source is not local.")
|
|
77
|
+
|
|
78
|
+
return source
|
|
79
|
+
|
|
80
|
+
def to_dict(self) -> dict:
|
|
81
|
+
"""
|
|
82
|
+
Convert to dictionary.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
dict
|
|
87
|
+
Dictionary representation of the object.
|
|
88
|
+
"""
|
|
89
|
+
dict_ = super().to_dict()
|
|
90
|
+
if self.init_function is not None:
|
|
91
|
+
dict_["init_function"] = self.init_function
|
|
92
|
+
return dict_
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class SourceCodeParamsPython(SourceCodeParams):
|
|
96
|
+
"""
|
|
97
|
+
Source code params for python.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
init_function: str = None
|
|
101
|
+
"""Handler for init function."""
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from digitalhub_core.entities.functions.spec import FunctionParams, FunctionSpec
|
|
6
|
+
from digitalhub_runtime_python.entities.functions.models import SourceCodeParamsPython, SourceCodeStructPython
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FunctionSpecPython(FunctionSpec):
|
|
10
|
+
"""
|
|
11
|
+
Specification for a Function job.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
source: dict | None = None,
|
|
17
|
+
code_src: str | None = None,
|
|
18
|
+
handler: str | None = None,
|
|
19
|
+
code: str | None = None,
|
|
20
|
+
base64: str | None = None,
|
|
21
|
+
init_function: str | None = None,
|
|
22
|
+
lang: str | None = None,
|
|
23
|
+
image: str | None = None,
|
|
24
|
+
base_image: str | None = None,
|
|
25
|
+
python_version: str | None = None,
|
|
26
|
+
requirements: list | None = None,
|
|
27
|
+
) -> None:
|
|
28
|
+
super().__init__()
|
|
29
|
+
|
|
30
|
+
self.image = image
|
|
31
|
+
self.base_image = base_image
|
|
32
|
+
self.python_version = python_version
|
|
33
|
+
self.requirements = requirements
|
|
34
|
+
|
|
35
|
+
# Give source precedence
|
|
36
|
+
if source is not None:
|
|
37
|
+
source_dict = source
|
|
38
|
+
else:
|
|
39
|
+
source_dict = {
|
|
40
|
+
"source": code_src,
|
|
41
|
+
"handler": handler,
|
|
42
|
+
"code": code,
|
|
43
|
+
"base64": base64,
|
|
44
|
+
"lang": lang,
|
|
45
|
+
"init_function": init_function,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
source_checked = self.source_check(source_dict)
|
|
49
|
+
self.source = SourceCodeStructPython(**source_checked)
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def source_check(source: dict) -> dict:
|
|
53
|
+
"""
|
|
54
|
+
Check source.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
source : dict
|
|
59
|
+
Source.
|
|
60
|
+
|
|
61
|
+
Returns
|
|
62
|
+
-------
|
|
63
|
+
dict
|
|
64
|
+
Checked source.
|
|
65
|
+
"""
|
|
66
|
+
return SourceCodeStructPython.source_check(source)
|
|
67
|
+
|
|
68
|
+
def show_source_code(self) -> str:
|
|
69
|
+
"""
|
|
70
|
+
Show source code.
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
str
|
|
75
|
+
Source code.
|
|
76
|
+
"""
|
|
77
|
+
return self.source.show_source_code()
|
|
78
|
+
|
|
79
|
+
def to_dict(self) -> dict:
|
|
80
|
+
"""
|
|
81
|
+
Override to_dict to exclude code from source.
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
-------
|
|
85
|
+
dict
|
|
86
|
+
Dictionary representation of the object.
|
|
87
|
+
"""
|
|
88
|
+
dict_ = super().to_dict()
|
|
89
|
+
dict_["source"] = self.source.to_dict()
|
|
90
|
+
return dict_
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class FunctionParamsPython(FunctionParams, SourceCodeParamsPython):
|
|
94
|
+
"""
|
|
95
|
+
Function python parameters model.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
python_version: Literal["PYTHON3_9", "PYTHON3_10", "PYTHON3_11"]
|
|
99
|
+
"Python version"
|
|
100
|
+
|
|
101
|
+
image: str = None
|
|
102
|
+
"Image where the function will be executed"
|
|
103
|
+
|
|
104
|
+
base_image: str = None
|
|
105
|
+
"Base image used to build the image where the function will be executed"
|
|
106
|
+
|
|
107
|
+
requirements: list = None
|
|
108
|
+
"Requirements list to be installed in the image where the function will be executed"
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from digitalhub_ml.entities.runs.spec import RunParamsMl, RunSpecMl
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class RunSpecPython(RunSpecMl):
|
|
7
|
+
"""Run Python specification."""
|
|
8
|
+
|
|
9
|
+
def __init__(
|
|
10
|
+
self,
|
|
11
|
+
task: str,
|
|
12
|
+
local_execution: bool = False,
|
|
13
|
+
**kwargs,
|
|
14
|
+
) -> None:
|
|
15
|
+
super().__init__(task, local_execution)
|
|
16
|
+
|
|
17
|
+
self.source = kwargs.get("source")
|
|
18
|
+
self.image = kwargs.get("image")
|
|
19
|
+
self.base_image = kwargs.get("base_image")
|
|
20
|
+
self.python_version = kwargs.get("python_version")
|
|
21
|
+
self.requirements = kwargs.get("requirements")
|
|
22
|
+
|
|
23
|
+
self.function = kwargs.get("function")
|
|
24
|
+
self.node_selector = kwargs.get("node_selector")
|
|
25
|
+
self.volumes = kwargs.get("volumes")
|
|
26
|
+
self.resources = kwargs.get("resources")
|
|
27
|
+
self.affinity = kwargs.get("affinity")
|
|
28
|
+
self.tolerations = kwargs.get("tolerations")
|
|
29
|
+
self.env = kwargs.get("env")
|
|
30
|
+
self.secrets = kwargs.get("secrets")
|
|
31
|
+
self.backoff_limit = kwargs.get("backoff_limit")
|
|
32
|
+
self.schedule = kwargs.get("schedule")
|
|
33
|
+
self.replicas = kwargs.get("replicas")
|
|
34
|
+
|
|
35
|
+
# Task job
|
|
36
|
+
|
|
37
|
+
# Task build
|
|
38
|
+
self.instructions = kwargs.get("instructions")
|
|
39
|
+
|
|
40
|
+
self.inputs = kwargs.get("inputs")
|
|
41
|
+
self.outputs = kwargs.get("outputs")
|
|
42
|
+
self.parameters = kwargs.get("parameters")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class RunParamsPython(RunParamsMl):
|
|
46
|
+
"""Run Python parameters."""
|
|
47
|
+
|
|
48
|
+
# Function parameters
|
|
49
|
+
source: dict = None
|
|
50
|
+
image: str = None
|
|
51
|
+
base_image: str = None
|
|
52
|
+
python_version: str = None
|
|
53
|
+
requirements: list = None
|
|
54
|
+
|
|
55
|
+
# Task parameters
|
|
56
|
+
function: str = None
|
|
57
|
+
node_selector: list[dict] = None
|
|
58
|
+
volumes: list[dict] = None
|
|
59
|
+
resources: list[dict] = None
|
|
60
|
+
affinity: dict = None
|
|
61
|
+
tolerations: list[dict] = None
|
|
62
|
+
env: list[dict] = None
|
|
63
|
+
secrets: list[str] = None
|
|
64
|
+
|
|
65
|
+
# Task job
|
|
66
|
+
backoff_limit: int = None
|
|
67
|
+
|
|
68
|
+
# Task serve
|
|
69
|
+
service_type: str = None
|
|
70
|
+
replicas: int = None
|
|
71
|
+
|
|
72
|
+
# Task build
|
|
73
|
+
instructions: list[str] = None
|
|
74
|
+
|
|
75
|
+
# Run parameters
|
|
76
|
+
inputs: dict = None
|
|
77
|
+
outputs: dict = None
|
|
78
|
+
parameters: dict = None
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Task Python specification module.
|
|
3
|
-
"""
|
|
4
1
|
from __future__ import annotations
|
|
5
2
|
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
6
5
|
from digitalhub_core.entities.tasks.spec import TaskParamsK8s, TaskSpecK8s
|
|
7
|
-
from digitalhub_runtime_python.entities.tasks.models import ContextRef, ContextSource
|
|
8
6
|
|
|
9
7
|
|
|
10
8
|
class TaskSpecJob(TaskSpecK8s):
|
|
@@ -15,13 +13,9 @@ class TaskSpecJob(TaskSpecK8s):
|
|
|
15
13
|
function: str,
|
|
16
14
|
**kwargs,
|
|
17
15
|
) -> None:
|
|
18
|
-
"""
|
|
19
|
-
Constructor.
|
|
20
|
-
"""
|
|
21
16
|
super().__init__(function, **kwargs)
|
|
22
17
|
|
|
23
18
|
self.backoff_limit = kwargs.get("backoff_limit")
|
|
24
|
-
self.schedule = kwargs.get("schedule")
|
|
25
19
|
|
|
26
20
|
|
|
27
21
|
class TaskParamsJob(TaskParamsK8s):
|
|
@@ -29,6 +23,9 @@ class TaskParamsJob(TaskParamsK8s):
|
|
|
29
23
|
TaskParamsJob model.
|
|
30
24
|
"""
|
|
31
25
|
|
|
26
|
+
backoff_limit: int = None
|
|
27
|
+
"""Backoff limit."""
|
|
28
|
+
|
|
32
29
|
|
|
33
30
|
class TaskSpecBuild(TaskSpecK8s):
|
|
34
31
|
"""Task Build specification."""
|
|
@@ -36,18 +33,11 @@ class TaskSpecBuild(TaskSpecK8s):
|
|
|
36
33
|
def __init__(
|
|
37
34
|
self,
|
|
38
35
|
function: str,
|
|
39
|
-
context_refs: list | None = None,
|
|
40
|
-
context_sources: list | None = None,
|
|
41
36
|
instructions: list | None = None,
|
|
42
37
|
**kwargs,
|
|
43
38
|
) -> None:
|
|
44
|
-
"""
|
|
45
|
-
Constructor.
|
|
46
|
-
"""
|
|
47
39
|
super().__init__(function, **kwargs)
|
|
48
40
|
|
|
49
|
-
self.context_refs = context_refs
|
|
50
|
-
self.context_sources = context_sources
|
|
51
41
|
self.instructions = instructions
|
|
52
42
|
|
|
53
43
|
|
|
@@ -56,12 +46,6 @@ class TaskParamsBuild(TaskParamsK8s):
|
|
|
56
46
|
TaskParamsBuild model.
|
|
57
47
|
"""
|
|
58
48
|
|
|
59
|
-
context_refs: list[ContextRef] = None
|
|
60
|
-
"""Context references."""
|
|
61
|
-
|
|
62
|
-
context_sources: list[ContextSource] = None
|
|
63
|
-
"""Context sources."""
|
|
64
|
-
|
|
65
49
|
instructions: list[str] = None
|
|
66
50
|
"""Build instructions."""
|
|
67
51
|
|
|
@@ -69,8 +53,23 @@ class TaskParamsBuild(TaskParamsK8s):
|
|
|
69
53
|
class TaskSpecServe(TaskSpecK8s):
|
|
70
54
|
"""Task Serve specification."""
|
|
71
55
|
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
function: str,
|
|
59
|
+
replicas: int | None = None,
|
|
60
|
+
service_type: str | None = None,
|
|
61
|
+
**kwargs,
|
|
62
|
+
) -> None:
|
|
63
|
+
super().__init__(function, **kwargs)
|
|
64
|
+
|
|
65
|
+
self.replicas = replicas
|
|
66
|
+
self.service_type = service_type
|
|
67
|
+
|
|
72
68
|
|
|
73
69
|
class TaskParamsServe(TaskParamsK8s):
|
|
74
70
|
"""
|
|
75
71
|
TaskParamsServe model.
|
|
76
72
|
"""
|
|
73
|
+
|
|
74
|
+
replicas: int = None
|
|
75
|
+
service_type: Literal["ClusterIP", "NodePort", "LoadBalancer"] = "NodePort"
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Runtime class for running Python functions.
|
|
3
|
-
"""
|
|
4
1
|
from __future__ import annotations
|
|
5
2
|
|
|
6
3
|
import typing
|
|
@@ -10,11 +7,11 @@ from digitalhub_core.context.builder import get_context
|
|
|
10
7
|
from digitalhub_core.runtimes.base import Runtime
|
|
11
8
|
from digitalhub_core.utils.logger import LOGGER
|
|
12
9
|
from digitalhub_runtime_python.utils.configuration import get_function_from_source
|
|
13
|
-
from digitalhub_runtime_python.utils.inputs import
|
|
10
|
+
from digitalhub_runtime_python.utils.inputs import compose_inputs
|
|
14
11
|
from digitalhub_runtime_python.utils.outputs import build_status, parse_outputs
|
|
15
12
|
|
|
16
13
|
if typing.TYPE_CHECKING:
|
|
17
|
-
from digitalhub_core.runtimes.
|
|
14
|
+
from digitalhub_core.runtimes.kind_registry import KindRegistry
|
|
18
15
|
|
|
19
16
|
|
|
20
17
|
class RuntimePython(Runtime):
|
|
@@ -23,16 +20,13 @@ class RuntimePython(Runtime):
|
|
|
23
20
|
"""
|
|
24
21
|
|
|
25
22
|
def __init__(self, kind_registry: KindRegistry, project: str) -> None:
|
|
26
|
-
"""
|
|
27
|
-
Constructor.
|
|
28
|
-
"""
|
|
29
23
|
super().__init__(kind_registry, project)
|
|
30
24
|
ctx = get_context(self.project)
|
|
31
25
|
self.root = ctx.runtime_dir
|
|
32
|
-
self.
|
|
26
|
+
self.tmp_dir = ctx.tmp_dir
|
|
33
27
|
|
|
34
28
|
self.root.mkdir(parents=True, exist_ok=True)
|
|
35
|
-
self.
|
|
29
|
+
self.tmp_dir.mkdir(parents=True, exist_ok=True)
|
|
36
30
|
|
|
37
31
|
def build(self, function: dict, task: dict, run: dict) -> dict:
|
|
38
32
|
"""
|
|
@@ -70,16 +64,19 @@ class RuntimePython(Runtime):
|
|
|
70
64
|
LOGGER.info("Validating task.")
|
|
71
65
|
self._validate_task(run)
|
|
72
66
|
|
|
67
|
+
LOGGER.info("Validating run.")
|
|
68
|
+
self._validate_run(run)
|
|
69
|
+
|
|
73
70
|
LOGGER.info("Starting task.")
|
|
74
71
|
spec = run.get("spec")
|
|
75
72
|
project = run.get("project")
|
|
76
73
|
|
|
77
|
-
LOGGER.info("Collecting inputs.")
|
|
78
|
-
fnc_args = self._collect_inputs(spec)
|
|
79
|
-
|
|
80
74
|
LOGGER.info("Configuring execution.")
|
|
81
75
|
fnc, wrapped = self._configure_execution(spec)
|
|
82
76
|
|
|
77
|
+
LOGGER.info("Composing function arguments.")
|
|
78
|
+
fnc_args = self._compose_args(fnc, spec, project)
|
|
79
|
+
|
|
83
80
|
LOGGER.info("Executing run.")
|
|
84
81
|
if wrapped:
|
|
85
82
|
results: dict = self._execute(fnc, project, **fnc_args)
|
|
@@ -111,33 +108,26 @@ class RuntimePython(Runtime):
|
|
|
111
108
|
"""
|
|
112
109
|
raise NotImplementedError
|
|
113
110
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
####################
|
|
117
|
-
|
|
118
|
-
def _collect_inputs(self, spec: dict) -> dict:
|
|
111
|
+
@staticmethod
|
|
112
|
+
def _validate_run(run: dict) -> None:
|
|
119
113
|
"""
|
|
120
|
-
|
|
114
|
+
Check if run is locally allowed.
|
|
121
115
|
|
|
122
116
|
Parameters
|
|
123
117
|
----------
|
|
124
|
-
|
|
125
|
-
Run
|
|
126
|
-
project : str
|
|
127
|
-
Project name.
|
|
118
|
+
run : dict
|
|
119
|
+
Run object dictionary.
|
|
128
120
|
|
|
129
121
|
Returns
|
|
130
122
|
-------
|
|
131
|
-
|
|
132
|
-
Parameters.
|
|
123
|
+
None
|
|
133
124
|
"""
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
)
|
|
125
|
+
task_kind = run["spec"]["task"].split(":")[0]
|
|
126
|
+
local_execution = run["spec"]["local_execution"]
|
|
127
|
+
if task_kind != "python+job" and local_execution:
|
|
128
|
+
msg = f"Local execution not allowed for task kind {task_kind}."
|
|
129
|
+
LOGGER.exception(msg)
|
|
130
|
+
raise RuntimeError(msg)
|
|
141
131
|
|
|
142
132
|
####################
|
|
143
133
|
# Configuration
|
|
@@ -162,3 +152,26 @@ class RuntimePython(Runtime):
|
|
|
162
152
|
spec.get("source", {}),
|
|
163
153
|
)
|
|
164
154
|
return fnc, hasattr(fnc, "__wrapped__")
|
|
155
|
+
|
|
156
|
+
def _compose_args(self, func: Callable, spec: dict, project: str) -> dict:
|
|
157
|
+
"""
|
|
158
|
+
Collect inputs.
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
func : Callable
|
|
163
|
+
Function to execute.
|
|
164
|
+
spec : dict
|
|
165
|
+
Run specs.
|
|
166
|
+
project : str
|
|
167
|
+
Project name.
|
|
168
|
+
|
|
169
|
+
Returns
|
|
170
|
+
-------
|
|
171
|
+
dict
|
|
172
|
+
Parameters.
|
|
173
|
+
"""
|
|
174
|
+
inputs = spec.get("inputs", {})
|
|
175
|
+
parameters = spec.get("parameters", {})
|
|
176
|
+
local_execution = spec.get("local_execution")
|
|
177
|
+
return compose_inputs(inputs, parameters, local_execution, func, project)
|
|
@@ -43,6 +43,35 @@ def get_function_from_source(path: Path, source_spec: dict) -> Callable:
|
|
|
43
43
|
raise RuntimeError(msg) from e
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
def get_init_function(path: Path, source_spec: dict) -> Callable:
|
|
47
|
+
"""
|
|
48
|
+
Get function from source.
|
|
49
|
+
|
|
50
|
+
Parameters
|
|
51
|
+
----------
|
|
52
|
+
path : Path
|
|
53
|
+
Path where to save the function source.
|
|
54
|
+
source_spec : dict
|
|
55
|
+
Funcrion source spec.
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
Callable
|
|
60
|
+
Function.
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
if "init_function" not in source_spec:
|
|
64
|
+
return
|
|
65
|
+
function_code = save_function_source(path, source_spec)
|
|
66
|
+
handler_path, _ = parse_handler(source_spec["handler"])
|
|
67
|
+
function_path = (function_code / handler_path).with_suffix(".py")
|
|
68
|
+
return import_function(function_path, source_spec["init_function"])
|
|
69
|
+
except Exception as e:
|
|
70
|
+
msg = f"Some error occurred while getting init function. Exception: {e.__class__}. Error: {e.args}"
|
|
71
|
+
LOGGER.exception(msg)
|
|
72
|
+
raise RuntimeError(msg) from e
|
|
73
|
+
|
|
74
|
+
|
|
46
75
|
def parse_handler(handler: str) -> tuple:
|
|
47
76
|
"""
|
|
48
77
|
Parse handler.
|