ocean-runner 0.2.19__tar.gz → 0.2.21__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ocean-runner
3
- Version: 0.2.19
3
+ Version: 0.2.21
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,10 +17,12 @@ 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: aiofiles>=25.1.0
20
21
  Requires-Dist: oceanprotocol-job-details>=0.2.8
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
25
+ Requires-Dist: types-aiofiles>=25.1.0.20251011
24
26
  Description-Content-Type: text/markdown
25
27
 
26
28
  # ocean-runner
@@ -1,9 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import asyncio
4
+ import inspect
3
5
  from dataclasses import InitVar, asdict, 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
10
  from oceanprotocol_job_details import JobDetails # type: ignore
9
11
 
@@ -11,16 +13,19 @@ 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
- def default_error_callback(algorithm: Algorithm, e: Exception) -> None:
25
+
26
+ def default_error_callback(algorithm: Algorithm, error: Exception) -> None:
22
27
  algorithm.logger.exception("Error during algorithm execution")
23
- raise e
28
+ raise error
24
29
 
25
30
 
26
31
  def default_validation(algorithm: Algorithm) -> None:
@@ -29,10 +34,33 @@ 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(
46
+ function: Callable[..., T | Awaitable[T]],
47
+ *args,
48
+ **kwargs,
49
+ ) -> T:
50
+ result = function(*args, **kwargs)
51
+
52
+ if inspect.isawaitable(result):
53
+ return await result
54
+
55
+ return result
56
+
57
+
58
+ @dataclass(slots=True)
59
+ class Functions(Generic[InputT, ResultT]):
60
+ validate: ValidateFuncT = field(default=default_validation, init=False)
61
+ run: RunFuncT | None = field(default=None, init=False)
62
+ save: SaveFuncT = field(default=default_save, init=False)
63
+ error: ErrorFuncT = field(default=default_error_callback, init=False)
36
64
 
37
65
 
38
66
  @dataclass
@@ -44,33 +72,13 @@ class Algorithm(Generic[InputT, ResultT]):
44
72
  """
45
73
 
46
74
  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
75
 
51
- # Decorator-registered callbacks
52
- _validate_fn: ValidateFuncT = field(
53
- default=default_validation,
54
- init=False,
55
- repr=False,
56
- )
76
+ logger: Logger = field(init=False, repr=False)
57
77
 
58
- _run_fn: RunFuncT = field(
59
- default=None,
60
- init=False,
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,
78
+ _job_details: JobDetails[InputT] = field(init=False)
79
+ _result: ResultT | None = field(default=None, init=False)
80
+ _functions: Functions[InputT, ResultT] = field(
81
+ default_factory=Functions, init=False, repr=False
74
82
  )
75
83
 
76
84
  def __post_init__(self, config: Config[InputT] | None) -> None:
@@ -127,27 +135,26 @@ class Algorithm(Generic[InputT, ResultT]):
127
135
  # ---------------------------
128
136
 
129
137
  def validate(self, fn: ValidateFuncT) -> ValidateFuncT:
130
- self._validate_fn = fn
138
+ self._functions.validate = fn
131
139
  return fn
132
140
 
133
141
  def run(self, fn: RunFuncT) -> RunFuncT:
134
- self._run_fn = fn
142
+ self._functions.run = fn
135
143
  return fn
136
144
 
137
145
  def save_results(self, fn: SaveFuncT) -> SaveFuncT:
138
- self._save_fn = fn
146
+ self._functions.save = fn
139
147
  return fn
140
148
 
141
149
  def on_error(self, fn: ErrorFuncT) -> ErrorFuncT:
142
- self._error_callback = fn
150
+ self._functions.error = fn
143
151
  return fn
144
152
 
145
153
  # ---------------------------
146
154
  # Execution Pipeline
147
155
  # ---------------------------
148
156
 
149
- def __call__(self) -> ResultT | None:
150
- """Executes the algorithm pipeline: validate → run → save_results."""
157
+ async def execute(self) -> ResultT | None:
151
158
  # Load job details
152
159
  self._job_details = JobDetails.load(
153
160
  _type=self.configuration.custom_input,
@@ -161,21 +168,27 @@ class Algorithm(Generic[InputT, ResultT]):
161
168
  self.logger.debug(asdict(self.job_details))
162
169
 
163
170
  try:
164
- # Validation step
165
- self._validate_fn(self)
171
+ await execute(self._functions.validate, self)
166
172
 
167
- # Run step
168
- if self._run_fn:
173
+ if self._functions.run:
169
174
  self.logger.info("Running algorithm...")
170
- self._result = self._run_fn(self)
175
+ self._result = await execute(self._functions.run, self)
171
176
  else:
172
177
  self.logger.error("No run() function defined. Skipping execution.")
173
178
  self._result = None
174
179
 
175
- # Save step
176
- self._save_fn(self, self._result, self.job_details.paths.outputs)
180
+ await execute(
181
+ self._functions.save,
182
+ algorithm=self,
183
+ result=self._result,
184
+ base=self.job_details.paths.outputs,
185
+ )
177
186
 
178
187
  except Exception as e:
179
- self._error_callback(self, e)
188
+ await execute(self._functions.error, self, e)
180
189
 
181
190
  return self._result
191
+
192
+ def __call__(self) -> ResultT | None:
193
+ """Executes the algorithm pipeline: validate → run → save_results."""
194
+ return asyncio.run(self.execute())
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ocean-runner"
3
- version = "0.2.19"
3
+ version = "0.2.21"
4
4
  description = "A fluent API for OceanProtocol algorithms"
5
5
  authors = [
6
6
  { name = "AgrospAI", email = "agrospai@udl.cat" },
@@ -15,10 +15,12 @@ classifiers = [
15
15
  "License :: OSI Approved :: MIT License",
16
16
  ]
17
17
  dependencies = [
18
+ "aiofiles>=25.1.0",
18
19
  "oceanprotocol-job-details>=0.2.8",
19
20
  "pydantic>=2.12.5",
20
21
  "pydantic-settings>=2.12.0",
21
22
  "pytest>=8.4.2",
23
+ "types-aiofiles>=25.1.0.20251011",
22
24
  ]
23
25
 
24
26
  [project.urls]
File without changes
File without changes
File without changes