ocean-runner 0.2.2__tar.gz → 0.2.4__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.2
3
+ Version: 0.2.4
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
@@ -26,6 +26,14 @@ Description-Content-Type: text/markdown
26
26
  Ocean Runner is a package that brings a fluent API for APP creation and running in the scope of OceanProtocol.
27
27
 
28
28
 
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install ocean-runner
33
+ # or
34
+ uv add ocean-runner
35
+ ```
36
+
29
37
  ## Usage
30
38
 
31
39
  ### Minimal Example
@@ -126,6 +134,11 @@ Algorithm(
126
134
  """
127
135
  Random secret to use while testing.
128
136
  """
137
+
138
+ runtime: "dev",
139
+ """
140
+ Runtime mode. "dev" to run normally, "test" to run pytest
141
+ """
129
142
  )
130
143
  """
131
144
  Should not be needed in production algorithms, used to mock environment variables, defaults to using env.
@@ -3,6 +3,14 @@
3
3
  Ocean Runner is a package that brings a fluent API for APP creation and running in the scope of OceanProtocol.
4
4
 
5
5
 
6
+ ## Installation
7
+
8
+ ```bash
9
+ pip install ocean-runner
10
+ # or
11
+ uv add ocean-runner
12
+ ```
13
+
6
14
  ## Usage
7
15
 
8
16
  ### Minimal Example
@@ -103,6 +111,11 @@ Algorithm(
103
111
  """
104
112
  Random secret to use while testing.
105
113
  """
114
+
115
+ runtime: "dev",
116
+ """
117
+ Runtime mode. "dev" to run normally, "test" to run pytest
118
+ """
106
119
  )
107
120
  """
108
121
  Should not be needed in production algorithms, used to mock environment variables, defaults to using env.
@@ -1,28 +1,41 @@
1
+ import os
1
2
  from dataclasses import asdict, dataclass, field
2
3
  from logging import Logger
3
- import os
4
4
  from pathlib import Path
5
- from typing import Callable, Iterable, TypeVar
5
+ from typing import Callable, Iterable, Literal, TypeVar
6
6
 
7
7
  T = TypeVar("T")
8
8
 
9
9
 
10
- @dataclass(frozen=True)
10
+ @dataclass
11
11
  class Environment:
12
12
  """Environment variables mock"""
13
13
 
14
- base_dir: str | None = field(default=os.environ.get("BASE_DIR", None))
14
+ base_dir: str | None = field(
15
+ default_factory=lambda: os.environ.get("BASE_DIR", None),
16
+ )
15
17
  """Base data directory, defaults to '/data'"""
16
18
 
17
- dids: str = field(default=os.environ.get("DIDS"))
19
+ dids: str = field(
20
+ default_factory=lambda: os.environ.get("DIDS"),
21
+ )
18
22
  """Datasets DID's, format: '["XXXX"]'"""
19
23
 
20
- transformation_did: str = field(default=os.environ.get("TRANSFORMATION_DID"))
24
+ transformation_did: str = field(
25
+ default_factory=lambda: os.environ.get("TRANSFORMATION_DID"),
26
+ )
21
27
  """Transformation (algorithm) DID"""
22
28
 
23
- secret: str = field(default=os.environ.get("SECRET"))
29
+ secret: str = field(
30
+ default_factory=lambda: os.environ.get("SECRET"),
31
+ )
24
32
  """Super secret secret"""
25
33
 
34
+ runtime: Literal["dev", "test"] = field(
35
+ default_factory=lambda: os.environ.get("RUNTIME", "dev").lower()
36
+ )
37
+ """Select runtime mode"""
38
+
26
39
  dict = asdict
27
40
 
28
41
 
@@ -44,5 +57,7 @@ class Config:
44
57
  )
45
58
  """Paths that should be included so the code executes correctly"""
46
59
 
47
- environment: Environment = Environment()
60
+ environment: Environment = field(
61
+ default_factory=lambda: Environment(),
62
+ )
48
63
  """Mock of environment data"""
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from dataclasses import InitVar, asdict, dataclass, field
2
4
  from logging import Logger
3
5
  from pathlib import Path
@@ -6,6 +8,7 @@ from typing import Callable, Generic, Self, TypeVar
6
8
  from oceanprotocol_job_details import JobDetails
7
9
 
8
10
  from ocean_runner.config import Config
11
+ from ocean_runner.runtime_mode import RuntimeMode
9
12
 
10
13
  JobDetailsT = TypeVar(
11
14
  "JobDetailsT",
@@ -13,24 +16,37 @@ JobDetailsT = TypeVar(
13
16
  ResultT = TypeVar("ResultT")
14
17
 
15
18
 
16
- def default_error_callback(e: Exception) -> None:
19
+ def default_error_callback(_: Algorithm, e: Exception) -> None:
17
20
  raise e
18
21
 
19
22
 
20
- def default_validation(algorithm: "Algorithm") -> None:
23
+ def default_validation(algorithm: Algorithm) -> None:
21
24
  algorithm.logger.info("Validating input using default validation")
22
25
 
23
26
  assert algorithm.job_details.ddos, "DDOs missing"
24
27
  assert algorithm.job_details.files, "Files missing"
25
28
 
26
29
 
27
- def default_save(*, result: ResultT, base: Path, algorithm: "Algorithm") -> None:
30
+ def default_save(*, result: ResultT, base: Path, algorithm: Algorithm) -> None:
28
31
  algorithm.logger.info("Saving results using default save")
29
32
 
30
33
  with open(base / "result.txt", "w+") as f:
31
34
  f.write(str(result))
32
35
 
33
36
 
37
+ def default_test_run(algorithm: Algorithm) -> int:
38
+ import pytest
39
+
40
+ result = pytest.main()
41
+
42
+ if result == 0:
43
+ algorithm.logger.info("Passed all tests")
44
+ else:
45
+ algorithm.logger.error("Some tests failed")
46
+
47
+ return result
48
+
49
+
34
50
  @dataclass
35
51
  class Algorithm(Generic[JobDetailsT, ResultT]):
36
52
 
@@ -38,16 +54,18 @@ class Algorithm(Generic[JobDetailsT, ResultT]):
38
54
 
39
55
  # Load from config
40
56
  logger: Logger = field(init=False)
41
- error_callback: Callable[[Exception], None] = field(init=False)
42
57
 
43
58
  _job_details: JobDetails[JobDetailsT] = field(init=False)
44
59
  _result: ResultT | None = field(default=None, init=False)
60
+ _runtime: RuntimeMode = field(default=RuntimeMode.DEV, init=False)
61
+
62
+ error_callback = default_error_callback
45
63
 
46
64
  def __post_init__(self, config: Config | None) -> None:
47
- config = config or Config()
65
+ config: Config = config or Config()
48
66
 
49
- # Use config or use a default implementation
50
- self.error_callback = config.error_callback or default_error_callback
67
+ if config.error_callback:
68
+ self.error_callback = config.error_callback
51
69
 
52
70
  if config.logger:
53
71
  self.logger = config.logger
@@ -71,9 +89,14 @@ class Algorithm(Generic[JobDetailsT, ResultT]):
71
89
  sys.path.extend([str(path.absolute()) for path in config.source_paths])
72
90
  self.logger.debug(f"Added [{len(config.source_paths)}] entries to PATH")
73
91
 
92
+ self._runtime = RuntimeMode(config.environment.runtime) or self._runtime
93
+
74
94
  self._job_details = JobDetails.load(
75
- config.custom_input,
76
- **config.environment.dict(),
95
+ _type=config.custom_input,
96
+ base_dir=config.environment.base_dir,
97
+ dids=config.environment.dids,
98
+ transformation_did=config.environment.transformation_did,
99
+ secret=config.environment.secret,
77
100
  )
78
101
 
79
102
  self.logger.info("Loaded JobDetails")
@@ -103,8 +126,11 @@ class Algorithm(Generic[JobDetailsT, ResultT]):
103
126
  return self
104
127
 
105
128
  def run(self, callable: Callable[[Self], ResultT]) -> Self:
106
- self.logger.info("Running algorithm ...")
129
+ self.logger.info("Running algorithm...")
107
130
  try:
131
+ if self._runtime == RuntimeMode.TEST:
132
+ callable = default_test_run
133
+
108
134
  self._result = callable(self)
109
135
  except Exception as e:
110
136
  self.error_callback(e)
@@ -113,7 +139,7 @@ class Algorithm(Generic[JobDetailsT, ResultT]):
113
139
 
114
140
  def save_results(
115
141
  self,
116
- callable: Callable[[ResultT, Path, "Algorithm"], None] = default_save,
142
+ callable: Callable[[ResultT, Path, Algorithm], None] = default_save,
117
143
  ) -> None:
118
144
  self.logger.info("Saving results...")
119
145
  try:
@@ -124,3 +150,6 @@ class Algorithm(Generic[JobDetailsT, ResultT]):
124
150
  )
125
151
  except Exception as e:
126
152
  self.error_callback(e)
153
+
154
+
155
+ __all__ = [Algorithm]
@@ -0,0 +1,6 @@
1
+ from enum import Enum
2
+
3
+
4
+ class RuntimeMode(Enum):
5
+ DEV = "dev"
6
+ TEST = "test"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ocean-runner"
3
- version = "0.2.2"
3
+ version = "0.2.4"
4
4
  description = "A fluent API for OceanProtocol algorithms"
5
5
  authors = [
6
6
  { name = "AgrospAI", email = "agrospai@udl.cat" },
File without changes
File without changes