ocean-runner 0.1.0__py3-none-any.whl → 0.1.3__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.
@@ -0,0 +1,4 @@
1
+ from ocean_runner.config import Config, Environment
2
+ from ocean_runner.runner import Algorithm
3
+
4
+ __all__ = [Config, Algorithm, Environment]
ocean_runner/config.py ADDED
@@ -0,0 +1,48 @@
1
+ from dataclasses import asdict, dataclass, field
2
+ from logging import Logger
3
+ import os
4
+ from pathlib import Path
5
+ from typing import Callable, Iterable, TypeVar
6
+
7
+ T = TypeVar("T")
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class Environment:
12
+ """Environment variables mock"""
13
+
14
+ base_dir: str | None = field(default=os.environ.get("BASE_DIR", None))
15
+ """Base data directory, defaults to '/data'"""
16
+
17
+ dids: str = field(default=os.environ.get("DIDS"))
18
+ """Datasets DID's, format: '["XXXX"]'"""
19
+
20
+ transformation_did: str = field(default=os.environ.get("TRANSFORMATION_DID"))
21
+ """Transformation (algorithm) DID"""
22
+
23
+ secret: str = field(default=os.environ.get("SECRET"))
24
+ """Super secret secret"""
25
+
26
+ dict = asdict
27
+
28
+
29
+ @dataclass
30
+ class Config:
31
+ """Algorithm overall configuration"""
32
+
33
+ custom_input: T | None = None
34
+ """Algorithm's custom input types, must be a dataclass_json"""
35
+
36
+ error_callback: Callable[[Exception], None] = None
37
+ """Callback to execute upon exceptions"""
38
+
39
+ logger: Logger | None = None
40
+ """Logger to use in the algorithm"""
41
+
42
+ source_paths: Iterable[Path] = field(
43
+ default_factory=lambda: [Path("/algorithm/src")]
44
+ )
45
+ """Paths that should be included so the code executes correctly"""
46
+
47
+ environment: Environment = Environment()
48
+ """Mock of environment data"""
ocean_runner/runner.py ADDED
@@ -0,0 +1,126 @@
1
+ from dataclasses import InitVar, asdict, dataclass, field
2
+ from logging import Logger
3
+ from pathlib import Path
4
+ from typing import Callable, Generic, Self, TypeVar
5
+
6
+ from oceanprotocol_job_details import JobDetails
7
+
8
+ from ocean_runner.config import Config
9
+
10
+ JobDetailsT = TypeVar(
11
+ "JobDetailsT",
12
+ )
13
+ ResultT = TypeVar("ResultT")
14
+
15
+
16
+ def default_error_callback(e: Exception) -> None:
17
+ raise e
18
+
19
+
20
+ def default_validation(algorithm: "Algorithm") -> None:
21
+ algorithm.logger.info("Validating input using default validation")
22
+
23
+ assert algorithm.job_details.ddos, "DDOs missing"
24
+ assert algorithm.job_details.files, "Files missing"
25
+
26
+
27
+ def default_save(*, result: ResultT, base: Path, algorithm: "Algorithm") -> None:
28
+ algorithm.logger.info("Saving results using default save")
29
+
30
+ with open(base / "result.txt", "w+") as f:
31
+ f.write(str(result))
32
+
33
+
34
+ @dataclass
35
+ class Algorithm(Generic[JobDetailsT, ResultT]):
36
+
37
+ config: InitVar[Config | None] = None
38
+
39
+ # Load from config
40
+ logger: Logger = field(init=False)
41
+ error_callback: Callable[[Exception], None] = field(init=False)
42
+
43
+ _job_details: JobDetails[JobDetailsT] = field(init=False)
44
+ _result: ResultT | None = field(default=None, init=False)
45
+
46
+ def __post_init__(self, config: Config | None) -> None:
47
+ config = config or Config()
48
+
49
+ # Use config or use a default implementation
50
+ self.error_callback = config.error_callback or default_error_callback
51
+
52
+ if config.logger:
53
+ self.logger = config.logger
54
+ else:
55
+ import logging
56
+
57
+ logging.basicConfig(
58
+ level=logging.DEBUG,
59
+ format="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
60
+ datefmt="%Y-%m-%d %H:%M:%S",
61
+ )
62
+
63
+ self.logger = logging.getLogger("ocean_runner")
64
+
65
+ if isinstance(config.environment.base_dir, str):
66
+ config.environment.base_dir = Path(config.environment.base_dir)
67
+
68
+ if config.source_paths:
69
+ import sys
70
+
71
+ sys.path.extend([str(path.absolute()) for path in config.source_paths])
72
+ self.logger.debug(f"Added [{len(config.source_paths)}] entries to PATH")
73
+
74
+ self._job_details = JobDetails.load(
75
+ config.custom_input,
76
+ **config.environment.dict(),
77
+ )
78
+
79
+ self.logger.info("Loaded JobDetails")
80
+ self.logger.debug(asdict(self.job_details))
81
+
82
+ class Error(RuntimeError): ...
83
+
84
+ @property
85
+ def job_details(self) -> JobDetails:
86
+ if not self._job_details:
87
+ raise Algorithm.Error("JobDetails not initialized or missing")
88
+ return self._job_details
89
+
90
+ @property
91
+ def result(self) -> ResultT:
92
+ if not self._result:
93
+ raise Algorithm.Error("Result missing, run the algorithm first")
94
+ return self._result
95
+
96
+ def validate(self, callback: Callable[[Self], None] = default_validation) -> Self:
97
+ self.logger.info("Validating instance...")
98
+ try:
99
+ callback(self)
100
+ except Exception as e:
101
+ self.error_callback(e)
102
+
103
+ return self
104
+
105
+ def run(self, callable: Callable[[Self], ResultT]) -> Self:
106
+ self.logger.info("Running algorithm ...")
107
+ try:
108
+ self._result = callable(self)
109
+ except Exception as e:
110
+ self.error_callback(e)
111
+
112
+ return self
113
+
114
+ def save_results(
115
+ self,
116
+ callable: Callable[[ResultT, Path, "Algorithm"], None] = default_save,
117
+ ) -> None:
118
+ self.logger.info("Saving results...")
119
+ try:
120
+ callable(
121
+ results=self.result,
122
+ base_path=self.job_details.paths.outputs,
123
+ algorithm=self,
124
+ )
125
+ except Exception as e:
126
+ self.error_callback(e)
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ocean-runner
3
- Version: 0.1.0
4
- Summary: A Python PyPI package template
3
+ Version: 0.1.3
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
7
- Author-email: John Doe <john.doe@foo.bar>
7
+ Author-email: AgrospAI <agrospai@udl.cat>, Christian López <christian.lopez@udl.cat>
8
8
  License: Copyright 2025 spin3l
9
9
 
10
10
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
@@ -61,6 +61,9 @@ Algorithm(
61
61
 
62
62
  logger: ... # type: logging.Logger
63
63
  # Custom logger to use.
64
+
65
+ source_paths: ... # type: Iterable[Path]
66
+ # Source paths to include in the PATH
64
67
 
65
68
  environment: ...
66
69
  # type: ocean_runner.Environment. Mock of environment variables.
@@ -93,6 +96,11 @@ Algorithm(
93
96
  NOTE: it's not recommended to catch exceptions this way. Should re-raise and halt the execution.
94
97
  """
95
98
 
99
+ source_paths: [Path("/algorithm/src")],
100
+ """
101
+ Source paths to include in the PATH. '/algorithm/src' is the default since our templates place the algorithm source files there.
102
+ """
103
+
96
104
  logger: logger,
97
105
  """
98
106
  Custom logger to use in the Algorithm.
@@ -0,0 +1,7 @@
1
+ ocean_runner/__init__.py,sha256=awAmE6kZhuwcrD3gT7qFZArdhiuzW-EFTA6tGKhw06k,138
2
+ ocean_runner/config.py,sha256=9XSDHuNY5IspDi5ZZKmt2HX6yrI9gzeogCw-ATMCATs,1323
3
+ ocean_runner/runner.py,sha256=r02O2QHSc_eij1zI8soYzvjPXA8R-Khvg2XyCj58C-M,3770
4
+ ocean_runner-0.1.3.dist-info/METADATA,sha256=fJNuD7DqYooVxdhYpFJXTlJvZxLISJITxgooum2emlc,5781
5
+ ocean_runner-0.1.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
+ ocean_runner-0.1.3.dist-info/licenses/LICENSE,sha256=_B25KqK4amoADWkMN150tnZFm_Fy7VvZpvIC8ZydWdI,1053
7
+ ocean_runner-0.1.3.dist-info/RECORD,,
@@ -1,4 +0,0 @@
1
- ocean_runner-0.1.0.dist-info/METADATA,sha256=RNcTJa7JJDpda1CbBiRFUQgBANV0h8PR_b-TNuYgS2U,5420
2
- ocean_runner-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
3
- ocean_runner-0.1.0.dist-info/licenses/LICENSE,sha256=_B25KqK4amoADWkMN150tnZFm_Fy7VvZpvIC8ZydWdI,1053
4
- ocean_runner-0.1.0.dist-info/RECORD,,