ocean-runner 0.2.12__py3-none-any.whl → 0.2.14__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.

Potentially problematic release.


This version of ocean-runner might be problematic. Click here for more details.

ocean_runner/config.py CHANGED
@@ -2,7 +2,7 @@ import os
2
2
  from dataclasses import asdict, dataclass, field
3
3
  from logging import Logger
4
4
  from pathlib import Path
5
- from typing import Callable, Iterable, TypeVar
5
+ from typing import Iterable, TypeVar
6
6
 
7
7
  T = TypeVar("T")
8
8
 
@@ -43,9 +43,6 @@ class Config:
43
43
  custom_input: T | None = None
44
44
  """Algorithm's custom input types, must be a dataclass_json"""
45
45
 
46
- error_callback: Callable[[Exception], None] = None
47
- """Callback to execute upon exceptions"""
48
-
49
46
  logger: Logger | None = None
50
47
  """Logger to use in the algorithm"""
51
48
 
@@ -54,7 +51,5 @@ class Config:
54
51
  )
55
52
  """Paths that should be included so the code executes correctly"""
56
53
 
57
- environment: Environment = field(
58
- default_factory=lambda: Environment(),
59
- )
54
+ environment: Environment = field(default_factory=lambda: Environment())
60
55
  """Mock of environment data"""
ocean_runner/runner.py CHANGED
@@ -9,49 +9,52 @@ from oceanprotocol_job_details import JobDetails
9
9
 
10
10
  from ocean_runner.config import Config
11
11
 
12
- JobDetailsT = TypeVar(
13
- "JobDetailsT",
14
- )
12
+ JobDetailsT = TypeVar("JobDetailsT")
15
13
  ResultT = TypeVar("ResultT")
16
14
 
17
15
 
18
- def default_error_callback(_: Algorithm, e: Exception) -> None:
16
+ def default_error_callback(_, e: Exception) -> None:
19
17
  raise e
20
18
 
21
19
 
22
20
  def default_validation(algorithm: Algorithm) -> None:
23
21
  algorithm.logger.info("Validating input using default validation")
24
-
25
22
  assert algorithm.job_details.ddos, "DDOs missing"
26
23
  assert algorithm.job_details.files, "Files missing"
27
24
 
28
25
 
29
26
  def default_save(*, result: ResultT, base: Path, algorithm: Algorithm) -> None:
30
27
  algorithm.logger.info("Saving results using default save")
31
-
32
28
  with open(base / "result.txt", "w+") as f:
33
29
  f.write(str(result))
34
30
 
35
31
 
36
32
  @dataclass
37
33
  class Algorithm(Generic[JobDetailsT, ResultT]):
34
+ """
35
+ A configurable algorithm runner that behaves like a FastAPI app:
36
+ - You register `validate`, `run`, and `save_results` via decorators.
37
+ - You execute the full pipeline by calling `app()`.
38
+ """
38
39
 
39
40
  config: InitVar[Config | None] = None
40
-
41
- # Load from config
42
41
  logger: Logger = field(init=False)
43
-
44
42
  _job_details: JobDetails[JobDetailsT] = field(init=False)
45
43
  _result: ResultT | None = field(default=None, init=False)
46
44
 
47
- error_callback = default_error_callback
45
+ error_callback: Callable[[Algorithm, Exception], None] = default_error_callback
46
+
47
+ # Decorator-registered callbacks
48
+ _validate_fn: Callable[[Algorithm], None] | None = field(default=None, init=False)
49
+ _run_fn: Callable[[Algorithm], ResultT] | None = field(default=None, init=False)
50
+ _save_fn: Callable[[ResultT, Path, Algorithm], None] | None = field(
51
+ default=None, init=False
52
+ )
48
53
 
49
54
  def __post_init__(self, config: Config | None) -> None:
50
55
  config: Config = config or Config()
51
56
 
52
- if config.error_callback:
53
- self.error_callback = config.error_callback
54
-
57
+ # Configure logger
55
58
  if config.logger:
56
59
  self.logger = config.logger
57
60
  else:
@@ -62,18 +65,20 @@ class Algorithm(Generic[JobDetailsT, ResultT]):
62
65
  format="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
63
66
  datefmt="%Y-%m-%d %H:%M:%S",
64
67
  )
65
-
66
68
  self.logger = logging.getLogger("ocean_runner")
67
69
 
70
+ # Normalize base_dir
68
71
  if isinstance(config.environment.base_dir, str):
69
72
  config.environment.base_dir = Path(config.environment.base_dir)
70
73
 
74
+ # Extend sys.path for custom imports
71
75
  if config.source_paths:
72
76
  import sys
73
77
 
74
78
  sys.path.extend([str(path.absolute()) for path in config.source_paths])
75
79
  self.logger.debug(f"Added [{len(config.source_paths)}] entries to PATH")
76
80
 
81
+ # Load job details
77
82
  self._job_details = JobDetails.load(
78
83
  _type=config.custom_input,
79
84
  base_dir=config.environment.base_dir,
@@ -85,6 +90,8 @@ class Algorithm(Generic[JobDetailsT, ResultT]):
85
90
  self.logger.info("Loaded JobDetails")
86
91
  self.logger.debug(asdict(self.job_details))
87
92
 
93
+ self.config = config
94
+
88
95
  class Error(RuntimeError): ...
89
96
 
90
97
  @property
@@ -99,45 +106,67 @@ class Algorithm(Generic[JobDetailsT, ResultT]):
99
106
  raise Algorithm.Error("Result missing, run the algorithm first")
100
107
  return self._result
101
108
 
102
- def validate(
103
- self,
104
- callback: Callable[[Self], None] = default_validation,
105
- ) -> Self:
106
- self.logger.info("Validating instance...")
107
- try:
108
- callback(self)
109
- except Exception as e:
110
- self.error_callback(e)
109
+ # ---------------------------
110
+ # Decorators (FastAPI-style)
111
+ # ---------------------------
111
112
 
112
- return self
113
+ def validate(self, fn: Callable[[Self], None]) -> Callable[[Self], None]:
114
+ self._validate_fn = fn
115
+ return fn
113
116
 
114
- def run(
115
- self,
116
- callable: Callable[[Self], ResultT],
117
- ) -> Self:
118
- self.logger.info("Running algorithm...")
119
- try:
120
- self._result = callable(self)
121
- except Exception as e:
122
- self.error_callback(e)
117
+ def run(self, fn: Callable[[Self], ResultT]) -> Callable[[Self], ResultT]:
118
+ self._run_fn = fn
119
+ return fn
120
+
121
+ def save_results(self, fn: Callable[[ResultT, Path, Algorithm], None]) -> Callable:
122
+ self._save_fn = fn
123
+ return fn
124
+
125
+ def on_error(self, fn: Callable[[Algorithm, Exception], None]) -> Callable:
126
+ self.error_callback = fn
127
+ return fn
123
128
 
124
- return self
129
+ # ---------------------------
130
+ # Execution Pipeline
131
+ # ---------------------------
125
132
 
126
- def save_results(
127
- self,
128
- callable: Callable[[ResultT, Path, Algorithm], None] = default_save,
129
- *,
130
- override_path: Path | None = None,
131
- ) -> None:
132
- self.logger.info("Saving results...")
133
+ def __call__(self) -> ResultT | None:
134
+ """Executes the algorithm pipeline: validate → run → save_results."""
133
135
  try:
134
- callable(
135
- results=self.result,
136
- base_path=override_path or self.job_details.paths.outputs,
137
- algorithm=self,
138
- )
139
- except Exception as e:
140
- self.error_callback(e)
136
+ # Validation step
137
+ if self._validate_fn:
138
+ self.logger.info("Running custom validation...")
139
+ self._validate_fn(self)
140
+ else:
141
+ self.logger.info("Running default validation...")
142
+ default_validation(self)
143
+
144
+ # Run step
145
+ if self._run_fn:
146
+ self.logger.info("Running algorithm...")
147
+ self._result = self._run_fn(self)
148
+ else:
149
+ self.logger.warning("No run() function defined. Skipping execution.")
150
+ self._result = None
151
+
152
+ # Save step
153
+ if self._save_fn:
154
+ self.logger.info("Saving results...")
155
+ self._save_fn(
156
+ self._result,
157
+ self.job_details.paths.outputs,
158
+ self,
159
+ )
160
+ else:
161
+ self.logger.info("No save_results() defined. Using default.")
162
+ default_save(
163
+ result=self._result,
164
+ base=self.job_details.paths.outputs,
165
+ algorithm=self,
166
+ )
141
167
 
168
+ except Exception as e:
169
+ self.logger.exception("Error during algorithm execution")
170
+ self.error_callback(self, e)
142
171
 
143
- __all__ = [Algorithm]
172
+ return self._result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ocean-runner
3
- Version: 0.2.12
3
+ Version: 0.2.14
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
@@ -0,0 +1,7 @@
1
+ ocean_runner/__init__.py,sha256=awAmE6kZhuwcrD3gT7qFZArdhiuzW-EFTA6tGKhw06k,138
2
+ ocean_runner/config.py,sha256=gyyUotPJ7n8wPPdsJZIBUT4zBlkoNbhV876JDTdPNsY,1398
3
+ ocean_runner/runner.py,sha256=AM4GlgpGGOSLa_TfO8rAdWmTGTPTZoTT84LNtUswTXw,5762
4
+ ocean_runner-0.2.14.dist-info/METADATA,sha256=bIdyxazZ4mWCOUW7JULJaykDgDCd03yZ91CWG4BbsT8,5919
5
+ ocean_runner-0.2.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
+ ocean_runner-0.2.14.dist-info/licenses/LICENSE,sha256=_B25KqK4amoADWkMN150tnZFm_Fy7VvZpvIC8ZydWdI,1053
7
+ ocean_runner-0.2.14.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- ocean_runner/__init__.py,sha256=awAmE6kZhuwcrD3gT7qFZArdhiuzW-EFTA6tGKhw06k,138
2
- ocean_runner/config.py,sha256=EgloiUTLBvca4B_pr2eNa8kHYfsyVE73ZxszLCbiDYY,1525
3
- ocean_runner/runner.py,sha256=LXkVNYsqELsXciI8T8RWtfbNpI-_kUAtW1aQzsnOAfU,4075
4
- ocean_runner-0.2.12.dist-info/METADATA,sha256=k9dRV2nI-i3_ZJPETo2DnuDzasRqx_YZhFe3pVy-20M,5919
5
- ocean_runner-0.2.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
- ocean_runner-0.2.12.dist-info/licenses/LICENSE,sha256=_B25KqK4amoADWkMN150tnZFm_Fy7VvZpvIC8ZydWdI,1053
7
- ocean_runner-0.2.12.dist-info/RECORD,,