ocean-runner 0.2.19__py3-none-any.whl → 0.2.23__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.
- ocean_runner/config.py +2 -2
- ocean_runner/py.typed +0 -0
- ocean_runner/runner.py +69 -59
- {ocean_runner-0.2.19.dist-info → ocean_runner-0.2.23.dist-info}/METADATA +3 -2
- ocean_runner-0.2.23.dist-info/RECORD +8 -0
- ocean_runner-0.2.19.dist-info/RECORD +0 -7
- {ocean_runner-0.2.19.dist-info → ocean_runner-0.2.23.dist-info}/WHEEL +0 -0
- {ocean_runner-0.2.19.dist-info → ocean_runner-0.2.23.dist-info}/licenses/LICENSE +0 -0
ocean_runner/config.py
CHANGED
|
@@ -27,8 +27,8 @@ class Environment(BaseSettings):
|
|
|
27
27
|
description="Base data directory, defaults to '/data'",
|
|
28
28
|
)
|
|
29
29
|
|
|
30
|
-
dids:
|
|
31
|
-
|
|
30
|
+
dids: list[Path] | str | None = Field(
|
|
31
|
+
default_factory=list,
|
|
32
32
|
validation_alias=Keys.DIDS.value,
|
|
33
33
|
description='Datasets DID\'s, format: ["XXXX"]',
|
|
34
34
|
)
|
ocean_runner/py.typed
ADDED
|
File without changes
|
ocean_runner/runner.py
CHANGED
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import asyncio
|
|
4
|
+
import inspect
|
|
5
|
+
from dataclasses import InitVar, dataclass, field
|
|
4
6
|
from logging import Logger
|
|
5
7
|
from pathlib import Path
|
|
6
|
-
from typing import Callable, Generic, TypeVar
|
|
8
|
+
from typing import Awaitable, Callable, Generic, TypeAlias, TypeVar
|
|
7
9
|
|
|
8
|
-
from oceanprotocol_job_details import JobDetails # type: ignore
|
|
10
|
+
from oceanprotocol_job_details import load_job_details, JobDetails # type: ignore
|
|
9
11
|
|
|
10
12
|
from ocean_runner.config import Config
|
|
11
13
|
|
|
12
14
|
InputT = TypeVar("InputT")
|
|
13
15
|
ResultT = TypeVar("ResultT")
|
|
16
|
+
T = TypeVar("T")
|
|
14
17
|
|
|
15
|
-
ValidateFuncT = Callable[["Algorithm"], None]
|
|
16
|
-
RunFuncT = Callable[["Algorithm"], ResultT] | None
|
|
17
|
-
SaveFuncT = Callable[["Algorithm", ResultT, Path], None]
|
|
18
|
-
ErrorFuncT = Callable[["Algorithm", Exception], None]
|
|
19
18
|
|
|
19
|
+
Algo: TypeAlias = "Algorithm[InputT, ResultT]"
|
|
20
|
+
ValidateFuncT: TypeAlias = Callable[[Algo], None | Awaitable[None] | None]
|
|
21
|
+
RunFuncT: TypeAlias = Callable[[Algo], ResultT | Awaitable[ResultT]]
|
|
22
|
+
SaveFuncT: TypeAlias = Callable[[Algo, ResultT, Path], Awaitable[None] | None]
|
|
23
|
+
ErrorFuncT: TypeAlias = Callable[[Algo, Exception], Awaitable[None] | None]
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
|
|
26
|
+
def default_error_callback(algorithm: Algorithm, error: Exception) -> None:
|
|
22
27
|
algorithm.logger.exception("Error during algorithm execution")
|
|
23
|
-
raise
|
|
28
|
+
raise error
|
|
24
29
|
|
|
25
30
|
|
|
26
31
|
def default_validation(algorithm: Algorithm) -> None:
|
|
@@ -29,10 +34,29 @@ def default_validation(algorithm: Algorithm) -> None:
|
|
|
29
34
|
assert algorithm.job_details.files, "Files missing"
|
|
30
35
|
|
|
31
36
|
|
|
32
|
-
def default_save(algorithm: Algorithm, result: ResultT, base: Path) -> None:
|
|
37
|
+
async def default_save(algorithm: Algorithm, result: ResultT, base: Path) -> None:
|
|
38
|
+
import aiofiles
|
|
39
|
+
|
|
33
40
|
algorithm.logger.info("Saving results using default save")
|
|
34
|
-
with open(base / "result.txt", "w+") as f:
|
|
35
|
-
f.write(str(result))
|
|
41
|
+
async with aiofiles.open(base / "result.txt", "w+") as f:
|
|
42
|
+
await f.write(str(result))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
async def execute(function: Callable[..., T | Awaitable[T]], *args, **kwargs) -> T:
|
|
46
|
+
result = function(*args, **kwargs)
|
|
47
|
+
|
|
48
|
+
if inspect.isawaitable(result):
|
|
49
|
+
return await result
|
|
50
|
+
|
|
51
|
+
return result
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass(slots=True)
|
|
55
|
+
class Functions(Generic[InputT, ResultT]):
|
|
56
|
+
validate: ValidateFuncT = field(default=default_validation, init=False)
|
|
57
|
+
run: RunFuncT | None = field(default=None, init=False)
|
|
58
|
+
save: SaveFuncT = field(default=default_save, init=False)
|
|
59
|
+
error: ErrorFuncT = field(default=default_error_callback, init=False)
|
|
36
60
|
|
|
37
61
|
|
|
38
62
|
@dataclass
|
|
@@ -44,33 +68,13 @@ class Algorithm(Generic[InputT, ResultT]):
|
|
|
44
68
|
"""
|
|
45
69
|
|
|
46
70
|
config: InitVar[Config[InputT] | None] = field(default=None)
|
|
47
|
-
logger: Logger = field(init=False)
|
|
48
|
-
_job_details: JobDetails[InputT] = field(init=False)
|
|
49
|
-
_result: ResultT | None = field(default=None, init=False)
|
|
50
71
|
|
|
51
|
-
|
|
52
|
-
_validate_fn: ValidateFuncT = field(
|
|
53
|
-
default=default_validation,
|
|
54
|
-
init=False,
|
|
55
|
-
repr=False,
|
|
56
|
-
)
|
|
72
|
+
logger: Logger = field(init=False, repr=False)
|
|
57
73
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
repr=False
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
_save_fn: SaveFuncT = field(
|
|
65
|
-
default=default_save,
|
|
66
|
-
init=False,
|
|
67
|
-
repr=False,
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
_error_callback: ErrorFuncT = field(
|
|
71
|
-
default=default_error_callback,
|
|
72
|
-
init=False,
|
|
73
|
-
repr=False,
|
|
74
|
+
_job_details: JobDetails[InputT] = field(init=False)
|
|
75
|
+
_result: ResultT | None = field(default=None, init=False)
|
|
76
|
+
_functions: Functions[InputT, ResultT] = field(
|
|
77
|
+
default_factory=Functions, init=False, repr=False
|
|
74
78
|
)
|
|
75
79
|
|
|
76
80
|
def __post_init__(self, config: Config[InputT] | None) -> None:
|
|
@@ -127,55 +131,61 @@ class Algorithm(Generic[InputT, ResultT]):
|
|
|
127
131
|
# ---------------------------
|
|
128
132
|
|
|
129
133
|
def validate(self, fn: ValidateFuncT) -> ValidateFuncT:
|
|
130
|
-
self.
|
|
134
|
+
self._functions.validate = fn
|
|
131
135
|
return fn
|
|
132
136
|
|
|
133
137
|
def run(self, fn: RunFuncT) -> RunFuncT:
|
|
134
|
-
self.
|
|
138
|
+
self._functions.run = fn
|
|
135
139
|
return fn
|
|
136
140
|
|
|
137
141
|
def save_results(self, fn: SaveFuncT) -> SaveFuncT:
|
|
138
|
-
self.
|
|
142
|
+
self._functions.save = fn
|
|
139
143
|
return fn
|
|
140
144
|
|
|
141
145
|
def on_error(self, fn: ErrorFuncT) -> ErrorFuncT:
|
|
142
|
-
self.
|
|
146
|
+
self._functions.error = fn
|
|
143
147
|
return fn
|
|
144
148
|
|
|
145
149
|
# ---------------------------
|
|
146
150
|
# Execution Pipeline
|
|
147
151
|
# ---------------------------
|
|
148
152
|
|
|
149
|
-
def
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
153
|
+
async def execute(self) -> ResultT | None:
|
|
154
|
+
self._job_details = load_job_details(
|
|
155
|
+
{
|
|
156
|
+
"base_dir": self.configuration.environment.base_dir,
|
|
157
|
+
"dids": self.configuration.environment.dids or [],
|
|
158
|
+
"secret": self.configuration.environment.secret,
|
|
159
|
+
"transformation_did": self.configuration.environment.transformation_did,
|
|
160
|
+
},
|
|
161
|
+
self.configuration.custom_input,
|
|
158
162
|
)
|
|
159
163
|
|
|
160
164
|
self.logger.info("Loaded JobDetails")
|
|
161
|
-
self.logger.debug(
|
|
165
|
+
self.logger.debug(self.job_details.model_dump())
|
|
162
166
|
|
|
163
167
|
try:
|
|
164
|
-
|
|
165
|
-
self._validate_fn(self)
|
|
168
|
+
await execute(self._functions.validate, self)
|
|
166
169
|
|
|
167
|
-
|
|
168
|
-
if self._run_fn:
|
|
170
|
+
if self._functions.run:
|
|
169
171
|
self.logger.info("Running algorithm...")
|
|
170
|
-
self._result = self.
|
|
172
|
+
self._result = await execute(self._functions.run, self)
|
|
171
173
|
else:
|
|
172
174
|
self.logger.error("No run() function defined. Skipping execution.")
|
|
173
175
|
self._result = None
|
|
174
176
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
await execute(
|
|
178
|
+
self._functions.save,
|
|
179
|
+
algorithm=self,
|
|
180
|
+
result=self._result,
|
|
181
|
+
base=self.job_details.paths.outputs,
|
|
182
|
+
)
|
|
177
183
|
|
|
178
184
|
except Exception as e:
|
|
179
|
-
self.
|
|
185
|
+
await execute(self._functions.error, self, e)
|
|
180
186
|
|
|
181
187
|
return self._result
|
|
188
|
+
|
|
189
|
+
def __call__(self) -> ResultT | None:
|
|
190
|
+
"""Executes the algorithm pipeline: validate → run → save_results."""
|
|
191
|
+
return asyncio.run(self.execute())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ocean-runner
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.23
|
|
4
4
|
Summary: A fluent API for OceanProtocol algorithms
|
|
5
5
|
Project-URL: Homepage, https://github.com/AgrospAI/ocean-runner
|
|
6
6
|
Project-URL: Issues, https://github.com/AgrospAI/ocean-runner/issues
|
|
@@ -17,7 +17,8 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
17
17
|
Classifier: Operating System :: OS Independent
|
|
18
18
|
Classifier: Programming Language :: Python :: 3
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
|
-
Requires-Dist:
|
|
20
|
+
Requires-Dist: aiofiles>=25.1.0
|
|
21
|
+
Requires-Dist: oceanprotocol-job-details>=0.3.4
|
|
21
22
|
Requires-Dist: pydantic-settings>=2.12.0
|
|
22
23
|
Requires-Dist: pydantic>=2.12.5
|
|
23
24
|
Requires-Dist: pytest>=8.4.2
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
ocean_runner/__init__.py,sha256=hRyMrE7K0DEbNRa-iNwA2xFOM85JJvjeKIdiWvcOm4Y,154
|
|
2
|
+
ocean_runner/config.py,sha256=_P8MbKGzL36p8LO_m6nj3cPB0h6L2YL8satxUNXXnUI,1927
|
|
3
|
+
ocean_runner/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
ocean_runner/runner.py,sha256=0-McElMM_dzubLUbRdeDaE0WY_dNj0IN_5cGen4-4bM,6242
|
|
5
|
+
ocean_runner-0.2.23.dist-info/METADATA,sha256=HkaOEgMvm98GQT9VsGMSN6FwTNzzMnocGpZyKu4HgSs,6667
|
|
6
|
+
ocean_runner-0.2.23.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
7
|
+
ocean_runner-0.2.23.dist-info/licenses/LICENSE,sha256=_B25KqK4amoADWkMN150tnZFm_Fy7VvZpvIC8ZydWdI,1053
|
|
8
|
+
ocean_runner-0.2.23.dist-info/RECORD,,
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
ocean_runner/__init__.py,sha256=hRyMrE7K0DEbNRa-iNwA2xFOM85JJvjeKIdiWvcOm4Y,154
|
|
2
|
-
ocean_runner/config.py,sha256=paN2I3ISIxRO1isCIuUgNsL9dsRhEc_n6KjTH6yNZU4,1919
|
|
3
|
-
ocean_runner/runner.py,sha256=VaayC8UXn2Iyl1RuUcTap9vyTyDYkvm16p3ucaRAOhQ,5527
|
|
4
|
-
ocean_runner-0.2.19.dist-info/METADATA,sha256=4n10dG0cfNAPraB9qJ4WcINyzJNFAxwDQtfZufbs0sU,6635
|
|
5
|
-
ocean_runner-0.2.19.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
6
|
-
ocean_runner-0.2.19.dist-info/licenses/LICENSE,sha256=_B25KqK4amoADWkMN150tnZFm_Fy7VvZpvIC8ZydWdI,1053
|
|
7
|
-
ocean_runner-0.2.19.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|