digitalhub-runtime-python 0.5.0__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.
- digitalhub_runtime_python/__init__.py +44 -0
- digitalhub_runtime_python/entities/__init__.py +0 -0
- digitalhub_runtime_python/entities/functions/__init__.py +0 -0
- digitalhub_runtime_python/entities/functions/spec.py +144 -0
- digitalhub_runtime_python/entities/functions/status.py +9 -0
- digitalhub_runtime_python/entities/runs/__init__.py +0 -0
- digitalhub_runtime_python/entities/runs/spec.py +81 -0
- digitalhub_runtime_python/entities/runs/status.py +9 -0
- digitalhub_runtime_python/entities/tasks/__init__.py +0 -0
- digitalhub_runtime_python/entities/tasks/models.py +31 -0
- digitalhub_runtime_python/entities/tasks/spec.py +87 -0
- digitalhub_runtime_python/entities/tasks/status.py +15 -0
- digitalhub_runtime_python/runtimes/__init__.py +0 -0
- digitalhub_runtime_python/runtimes/kind_registry.py +15 -0
- digitalhub_runtime_python/runtimes/runtime.py +159 -0
- digitalhub_runtime_python/utils/configuration.py +251 -0
- digitalhub_runtime_python/utils/inputs.py +149 -0
- digitalhub_runtime_python/utils/outputs.py +204 -0
- digitalhub_runtime_python/utils/utils.py +73 -0
- digitalhub_runtime_python-0.5.0.dist-info/LICENSE.txt +216 -0
- digitalhub_runtime_python-0.5.0.dist-info/METADATA +233 -0
- digitalhub_runtime_python-0.5.0.dist-info/RECORD +24 -0
- digitalhub_runtime_python-0.5.0.dist-info/WHEEL +5 -0
- digitalhub_runtime_python-0.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from digitalhub_core.entities.entity_types import EntityTypes
|
|
4
|
+
from digitalhub_core.registry.registry import registry
|
|
5
|
+
from digitalhub_core.registry.utils import create_info
|
|
6
|
+
from digitalhub_runtime_python.utils.utils import handler
|
|
7
|
+
|
|
8
|
+
root = "digitalhub_runtime_python"
|
|
9
|
+
runtime_info = {
|
|
10
|
+
"module": f"{root}.runtimes.runtime",
|
|
11
|
+
"class_name": "RuntimePython",
|
|
12
|
+
"kind_registry_module": f"{root}.runtimes.kind_registry",
|
|
13
|
+
"kind_registry_class_name": "kind_registry",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
root_ent = f"{root}.entities"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Function
|
|
20
|
+
entity_type = EntityTypes.FUNCTIONS.value
|
|
21
|
+
func_kind = "python"
|
|
22
|
+
prefix = entity_type.removesuffix("s").capitalize()
|
|
23
|
+
suffix = func_kind.capitalize()
|
|
24
|
+
func_info = create_info(root_ent, entity_type, prefix, suffix, runtime_info)
|
|
25
|
+
registry.register(func_kind, func_info)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# Tasks
|
|
29
|
+
entity_type = EntityTypes.TASKS.value
|
|
30
|
+
for i in ["job", "build"]:
|
|
31
|
+
task_kind = f"{func_kind}+{i}"
|
|
32
|
+
prefix = entity_type.removesuffix("s").capitalize()
|
|
33
|
+
suffix = i.capitalize()
|
|
34
|
+
task_info = create_info(root_ent, entity_type, prefix, suffix, runtime_info)
|
|
35
|
+
registry.register(task_kind, task_info)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# Runs
|
|
39
|
+
entity_type = EntityTypes.RUNS.value
|
|
40
|
+
run_kind = f"{func_kind}+run"
|
|
41
|
+
prefix = entity_type.removesuffix("s").capitalize()
|
|
42
|
+
suffix = func_kind.capitalize()
|
|
43
|
+
run_info = create_info(root_ent, entity_type, prefix, suffix, runtime_info)
|
|
44
|
+
registry.register(run_kind, run_info)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Function Conatiner specification module.
|
|
3
|
+
"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from digitalhub_core.entities.functions.spec import FunctionParams, FunctionSpec, SourceCodeStruct
|
|
9
|
+
from digitalhub_core.utils.exceptions import EntityError
|
|
10
|
+
from digitalhub_core.utils.generic_utils import decode_string, encode_source, encode_string
|
|
11
|
+
from digitalhub_core.utils.uri_utils import map_uri_scheme
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FunctionSpecPython(FunctionSpec):
|
|
15
|
+
"""
|
|
16
|
+
Specification for a Function job.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
source: dict,
|
|
22
|
+
image: str | None = None,
|
|
23
|
+
base_image: str | None = None,
|
|
24
|
+
python_version: str | None = None,
|
|
25
|
+
requirements: list | None = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Constructor.
|
|
29
|
+
"""
|
|
30
|
+
super().__init__()
|
|
31
|
+
|
|
32
|
+
self.image = image
|
|
33
|
+
self.base_image = base_image
|
|
34
|
+
self.python_version = python_version
|
|
35
|
+
self.requirements = requirements
|
|
36
|
+
|
|
37
|
+
source = self._source_check(source)
|
|
38
|
+
self.source = SourceCodeStruct(**source)
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
def _source_check(source: dict) -> dict:
|
|
42
|
+
"""
|
|
43
|
+
Check source.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
source : dict
|
|
48
|
+
Source.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
dict
|
|
53
|
+
Checked source.
|
|
54
|
+
"""
|
|
55
|
+
if source is None:
|
|
56
|
+
raise EntityError("Source must be provided.")
|
|
57
|
+
|
|
58
|
+
# Source check
|
|
59
|
+
source_path = source.get("source")
|
|
60
|
+
code = source.get("code")
|
|
61
|
+
base64 = source.get("base64")
|
|
62
|
+
handler = source.get("handler")
|
|
63
|
+
source["lang"] = "python"
|
|
64
|
+
|
|
65
|
+
if handler is None:
|
|
66
|
+
raise EntityError("Handler must be provided.")
|
|
67
|
+
|
|
68
|
+
if source_path is None and code is None and base64 is None:
|
|
69
|
+
raise EntityError("Source must be provided.")
|
|
70
|
+
|
|
71
|
+
if base64 is not None:
|
|
72
|
+
return source
|
|
73
|
+
|
|
74
|
+
if code is not None:
|
|
75
|
+
source["base64"] = encode_string(code)
|
|
76
|
+
return source
|
|
77
|
+
|
|
78
|
+
if source_path is not None:
|
|
79
|
+
if map_uri_scheme(source_path) == "local":
|
|
80
|
+
if not (Path(source_path).suffix == ".py" and Path(source_path).is_file()):
|
|
81
|
+
raise EntityError("Source is not a valid python file.")
|
|
82
|
+
source["base64"] = encode_source(source_path)
|
|
83
|
+
else:
|
|
84
|
+
if handler is None:
|
|
85
|
+
raise EntityError("Handler must be provided if source is not local.")
|
|
86
|
+
|
|
87
|
+
return source
|
|
88
|
+
|
|
89
|
+
def show_source_code(self) -> str:
|
|
90
|
+
"""
|
|
91
|
+
Show source code.
|
|
92
|
+
|
|
93
|
+
Returns
|
|
94
|
+
-------
|
|
95
|
+
str
|
|
96
|
+
Source code.
|
|
97
|
+
"""
|
|
98
|
+
if self.source.code is not None:
|
|
99
|
+
return str(self.source.code)
|
|
100
|
+
if self.source.base64 is not None:
|
|
101
|
+
try:
|
|
102
|
+
return decode_string(self.source.base64)
|
|
103
|
+
except Exception:
|
|
104
|
+
raise EntityError("Something got wrong during source code decoding.")
|
|
105
|
+
if (self.source.source is not None) and (map_uri_scheme(self.source.source) == "local"):
|
|
106
|
+
try:
|
|
107
|
+
return Path(self.source.source).read_text()
|
|
108
|
+
except Exception:
|
|
109
|
+
raise EntityError("Cannot access source code.")
|
|
110
|
+
return ""
|
|
111
|
+
|
|
112
|
+
def to_dict(self) -> dict:
|
|
113
|
+
"""
|
|
114
|
+
Override to_dict to exclude code from source.
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
dict
|
|
119
|
+
Dictionary representation of the object.
|
|
120
|
+
"""
|
|
121
|
+
dict_ = super().to_dict()
|
|
122
|
+
dict_["source"] = self.source.to_dict()
|
|
123
|
+
return dict_
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class FunctionParamsPython(FunctionParams):
|
|
127
|
+
"""
|
|
128
|
+
Function python parameters model.
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
source: dict
|
|
132
|
+
"Source code"
|
|
133
|
+
|
|
134
|
+
image: str = None
|
|
135
|
+
"Image"
|
|
136
|
+
|
|
137
|
+
base_image: str = None
|
|
138
|
+
"Base image"
|
|
139
|
+
|
|
140
|
+
python_version: str = None
|
|
141
|
+
"Python version"
|
|
142
|
+
|
|
143
|
+
requirements: list = None
|
|
144
|
+
"Requirements list, as used by the runtime"
|
|
File without changes
|
|
@@ -0,0 +1,81 @@
|
|
|
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
|
+
"""
|
|
16
|
+
Constructor.
|
|
17
|
+
"""
|
|
18
|
+
super().__init__(task, local_execution)
|
|
19
|
+
|
|
20
|
+
self.source = kwargs.get("source")
|
|
21
|
+
self.image = kwargs.get("image")
|
|
22
|
+
self.base_image = kwargs.get("base_image")
|
|
23
|
+
self.python_version = kwargs.get("python_version")
|
|
24
|
+
self.requirements = kwargs.get("requirements")
|
|
25
|
+
|
|
26
|
+
self.function = kwargs.get("function")
|
|
27
|
+
self.node_selector = kwargs.get("node_selector")
|
|
28
|
+
self.volumes = kwargs.get("volumes")
|
|
29
|
+
self.resources = kwargs.get("resources")
|
|
30
|
+
self.affinity = kwargs.get("affinity")
|
|
31
|
+
self.tolerations = kwargs.get("tolerations")
|
|
32
|
+
self.env = kwargs.get("env")
|
|
33
|
+
self.secrets = kwargs.get("secrets")
|
|
34
|
+
self.backoff_limit = kwargs.get("backoff_limit")
|
|
35
|
+
self.schedule = kwargs.get("schedule")
|
|
36
|
+
self.replicas = kwargs.get("replicas")
|
|
37
|
+
|
|
38
|
+
# Task job
|
|
39
|
+
|
|
40
|
+
# Task build
|
|
41
|
+
self.instructions = kwargs.get("instructions")
|
|
42
|
+
|
|
43
|
+
self.inputs = kwargs.get("inputs")
|
|
44
|
+
self.outputs = kwargs.get("outputs")
|
|
45
|
+
self.parameters = kwargs.get("parameters")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class RunParamsPython(RunParamsMl):
|
|
49
|
+
"""Run Python parameters."""
|
|
50
|
+
|
|
51
|
+
# Function parameters
|
|
52
|
+
source: dict = None
|
|
53
|
+
image: str = None
|
|
54
|
+
base_image: str = None
|
|
55
|
+
python_version: str = None
|
|
56
|
+
requirements: list = None
|
|
57
|
+
|
|
58
|
+
# Task parameters
|
|
59
|
+
function: str = None
|
|
60
|
+
node_selector: list[dict] = None
|
|
61
|
+
volumes: list[dict] = None
|
|
62
|
+
resources: list[dict] = None
|
|
63
|
+
affinity: dict = None
|
|
64
|
+
tolerations: list[dict] = None
|
|
65
|
+
env: list[dict] = None
|
|
66
|
+
secrets: list[str] = None
|
|
67
|
+
|
|
68
|
+
# Task job
|
|
69
|
+
backoff_limit: int = None
|
|
70
|
+
|
|
71
|
+
# Task serve
|
|
72
|
+
service_type: str = None
|
|
73
|
+
replicas: int = None
|
|
74
|
+
|
|
75
|
+
# Task build
|
|
76
|
+
instructions: list[str] = None
|
|
77
|
+
|
|
78
|
+
# Run parameters
|
|
79
|
+
inputs: dict = None
|
|
80
|
+
outputs: dict = None
|
|
81
|
+
parameters: dict = None
|
|
File without changes
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CorePort(BaseModel):
|
|
7
|
+
"""
|
|
8
|
+
Port mapper model.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
port: int
|
|
12
|
+
target_port: int
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ContextRef(BaseModel):
|
|
16
|
+
"""
|
|
17
|
+
ContextRef model.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
destination: str = None
|
|
21
|
+
protocol: str = None
|
|
22
|
+
source: str = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ContextSource(BaseModel):
|
|
26
|
+
"""
|
|
27
|
+
ContextSource model.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
base64: str = None
|
|
31
|
+
name: str = None
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task Python specification module.
|
|
3
|
+
"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from typing import Literal
|
|
7
|
+
|
|
8
|
+
from digitalhub_core.entities.tasks.spec import TaskParamsK8s, TaskSpecK8s
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TaskSpecJob(TaskSpecK8s):
|
|
12
|
+
"""Task Job specification."""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
function: str,
|
|
17
|
+
**kwargs,
|
|
18
|
+
) -> None:
|
|
19
|
+
"""
|
|
20
|
+
Constructor.
|
|
21
|
+
"""
|
|
22
|
+
super().__init__(function, **kwargs)
|
|
23
|
+
|
|
24
|
+
self.backoff_limit = kwargs.get("backoff_limit")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class TaskParamsJob(TaskParamsK8s):
|
|
28
|
+
"""
|
|
29
|
+
TaskParamsJob model.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
backoff_limit: int = None
|
|
33
|
+
"""Backoff limit."""
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class TaskSpecBuild(TaskSpecK8s):
|
|
37
|
+
"""Task Build specification."""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
function: str,
|
|
42
|
+
instructions: list | None = None,
|
|
43
|
+
**kwargs,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""
|
|
46
|
+
Constructor.
|
|
47
|
+
"""
|
|
48
|
+
super().__init__(function, **kwargs)
|
|
49
|
+
|
|
50
|
+
self.instructions = instructions
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class TaskParamsBuild(TaskParamsK8s):
|
|
54
|
+
"""
|
|
55
|
+
TaskParamsBuild model.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
instructions: list[str] = None
|
|
59
|
+
"""Build instructions."""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class TaskSpecServe(TaskSpecK8s):
|
|
63
|
+
"""Task Serve specification."""
|
|
64
|
+
|
|
65
|
+
def __init__(
|
|
66
|
+
self,
|
|
67
|
+
function: str,
|
|
68
|
+
replicas: int | None = None,
|
|
69
|
+
service_type: str | None = None,
|
|
70
|
+
**kwargs,
|
|
71
|
+
) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Constructor.
|
|
74
|
+
"""
|
|
75
|
+
super().__init__(function, **kwargs)
|
|
76
|
+
|
|
77
|
+
self.replicas = replicas
|
|
78
|
+
self.service_type = service_type
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class TaskParamsServe(TaskParamsK8s):
|
|
82
|
+
"""
|
|
83
|
+
TaskParamsServe model.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
replicas: int = None
|
|
87
|
+
service_type: Literal["ClusterIP", "NodePort", "LoadBalancer"] = "NodePort"
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from digitalhub_core.runtimes.kind_registry import KindRegistry
|
|
4
|
+
|
|
5
|
+
kind_registry = KindRegistry(
|
|
6
|
+
{
|
|
7
|
+
"executable": {"kind": "python"},
|
|
8
|
+
"task": [
|
|
9
|
+
{"kind": "python+job", "action": "job"},
|
|
10
|
+
{"kind": "python+serve", "action": "serve"},
|
|
11
|
+
{"kind": "python+build", "action": "build"},
|
|
12
|
+
],
|
|
13
|
+
"run": {"kind": "python+run"},
|
|
14
|
+
}
|
|
15
|
+
)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Runtime class for running Python functions.
|
|
3
|
+
"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import typing
|
|
7
|
+
from typing import Callable
|
|
8
|
+
|
|
9
|
+
from digitalhub_core.context.builder import get_context
|
|
10
|
+
from digitalhub_core.runtimes.base import Runtime
|
|
11
|
+
from digitalhub_core.utils.logger import LOGGER
|
|
12
|
+
from digitalhub_runtime_python.utils.configuration import get_function_from_source
|
|
13
|
+
from digitalhub_runtime_python.utils.inputs import compose_inputs
|
|
14
|
+
from digitalhub_runtime_python.utils.outputs import build_status, parse_outputs
|
|
15
|
+
|
|
16
|
+
if typing.TYPE_CHECKING:
|
|
17
|
+
from digitalhub_core.runtimes.kind_registry import KindRegistry
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RuntimePython(Runtime):
|
|
21
|
+
"""
|
|
22
|
+
Runtime Python class.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, kind_registry: KindRegistry, project: str) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Constructor.
|
|
28
|
+
"""
|
|
29
|
+
super().__init__(kind_registry, project)
|
|
30
|
+
ctx = get_context(self.project)
|
|
31
|
+
self.root = ctx.runtime_dir
|
|
32
|
+
self.tmp_dir = ctx.tmp_dir
|
|
33
|
+
|
|
34
|
+
self.root.mkdir(parents=True, exist_ok=True)
|
|
35
|
+
self.tmp_dir.mkdir(parents=True, exist_ok=True)
|
|
36
|
+
|
|
37
|
+
def build(self, function: dict, task: dict, run: dict) -> dict:
|
|
38
|
+
"""
|
|
39
|
+
Build run spec.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
function : dict
|
|
44
|
+
The function.
|
|
45
|
+
task : dict
|
|
46
|
+
The task.
|
|
47
|
+
run : dict
|
|
48
|
+
The run.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
dict
|
|
53
|
+
The run spec.
|
|
54
|
+
"""
|
|
55
|
+
return {
|
|
56
|
+
**function.get("spec", {}),
|
|
57
|
+
**task.get("spec", {}),
|
|
58
|
+
**run.get("spec", {}),
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
def run(self, run: dict) -> dict:
|
|
62
|
+
"""
|
|
63
|
+
Run function.
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
-------
|
|
67
|
+
dict
|
|
68
|
+
Status of the executed run.
|
|
69
|
+
"""
|
|
70
|
+
LOGGER.info("Validating task.")
|
|
71
|
+
self._validate_task(run)
|
|
72
|
+
|
|
73
|
+
LOGGER.info("Starting task.")
|
|
74
|
+
spec = run.get("spec")
|
|
75
|
+
project = run.get("project")
|
|
76
|
+
|
|
77
|
+
LOGGER.info("Configuring execution.")
|
|
78
|
+
fnc, wrapped = self._configure_execution(spec)
|
|
79
|
+
|
|
80
|
+
LOGGER.info("Composing function arguments.")
|
|
81
|
+
fnc_args = self._compose_args(fnc, spec, project)
|
|
82
|
+
|
|
83
|
+
LOGGER.info("Executing run.")
|
|
84
|
+
if wrapped:
|
|
85
|
+
results: dict = self._execute(fnc, project, **fnc_args)
|
|
86
|
+
else:
|
|
87
|
+
exec_result = self._execute(fnc, **fnc_args)
|
|
88
|
+
LOGGER.info("Collecting outputs.")
|
|
89
|
+
results = parse_outputs(exec_result, list(spec.get("outputs", {})), project)
|
|
90
|
+
|
|
91
|
+
status = build_status(results, spec.get("outputs"))
|
|
92
|
+
|
|
93
|
+
# Return run status
|
|
94
|
+
LOGGER.info("Task completed, returning run status.")
|
|
95
|
+
return status
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
def _get_executable(action: str) -> Callable:
|
|
99
|
+
"""
|
|
100
|
+
Select function according to action.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
action : str
|
|
105
|
+
Action to execute.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
Callable
|
|
110
|
+
Function to execute.
|
|
111
|
+
"""
|
|
112
|
+
raise NotImplementedError
|
|
113
|
+
|
|
114
|
+
####################
|
|
115
|
+
# Configuration
|
|
116
|
+
####################
|
|
117
|
+
|
|
118
|
+
def _configure_execution(self, spec: dict) -> tuple[Callable, bool]:
|
|
119
|
+
"""
|
|
120
|
+
Configure execution.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
spec : dict
|
|
125
|
+
Run spec.
|
|
126
|
+
|
|
127
|
+
Returns
|
|
128
|
+
-------
|
|
129
|
+
Callable
|
|
130
|
+
Function to execute.
|
|
131
|
+
"""
|
|
132
|
+
fnc = get_function_from_source(
|
|
133
|
+
self.root,
|
|
134
|
+
spec.get("source", {}),
|
|
135
|
+
)
|
|
136
|
+
return fnc, hasattr(fnc, "__wrapped__")
|
|
137
|
+
|
|
138
|
+
def _compose_args(self, func: Callable, spec: dict, project: str) -> dict:
|
|
139
|
+
"""
|
|
140
|
+
Collect inputs.
|
|
141
|
+
|
|
142
|
+
Parameters
|
|
143
|
+
----------
|
|
144
|
+
func : Callable
|
|
145
|
+
Function to execute.
|
|
146
|
+
spec : dict
|
|
147
|
+
Run specs.
|
|
148
|
+
project : str
|
|
149
|
+
Project name.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
dict
|
|
154
|
+
Parameters.
|
|
155
|
+
"""
|
|
156
|
+
inputs = spec.get("inputs", {})
|
|
157
|
+
parameters = spec.get("parameters", {})
|
|
158
|
+
local_execution = spec.get("local_execution")
|
|
159
|
+
return compose_inputs(inputs, parameters, local_execution, func, project)
|