oceanprotocol-job-details 0.1.5__tar.gz → 0.2.1__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.
Files changed (21) hide show
  1. {oceanprotocol_job_details-0.1.5 → oceanprotocol_job_details-0.2.1}/.gitignore +2 -1
  2. {oceanprotocol_job_details-0.1.5 → oceanprotocol_job_details-0.2.1}/PKG-INFO +13 -20
  3. oceanprotocol_job_details-0.2.1/README.md +52 -0
  4. oceanprotocol_job_details-0.2.1/oceanprotocol_job_details/__init__.py +4 -0
  5. oceanprotocol_job_details-0.2.1/oceanprotocol_job_details/di.py +44 -0
  6. {oceanprotocol_job_details-0.1.5 → oceanprotocol_job_details-0.2.1}/oceanprotocol_job_details/loaders/impl/ddo.py +12 -6
  7. {oceanprotocol_job_details-0.1.5 → oceanprotocol_job_details-0.2.1}/oceanprotocol_job_details/loaders/impl/files.py +14 -37
  8. oceanprotocol_job_details-0.2.1/oceanprotocol_job_details/loaders/impl/job_details.py +35 -0
  9. {oceanprotocol_job_details-0.1.5 → oceanprotocol_job_details-0.2.1}/oceanprotocol_job_details/ocean.py +97 -8
  10. oceanprotocol_job_details-0.2.1/oceanprotocol_job_details/paths.py +28 -0
  11. {oceanprotocol_job_details-0.1.5 → oceanprotocol_job_details-0.2.1}/pyproject.toml +6 -2
  12. oceanprotocol_job_details-0.1.5/README.md +0 -60
  13. oceanprotocol_job_details-0.1.5/oceanprotocol_job_details/config.py +0 -54
  14. oceanprotocol_job_details-0.1.5/oceanprotocol_job_details/job_details.py +0 -47
  15. oceanprotocol_job_details-0.1.5/oceanprotocol_job_details/loaders/impl/__init__.py +0 -0
  16. oceanprotocol_job_details-0.1.5/oceanprotocol_job_details/loaders/impl/job_details.py +0 -26
  17. oceanprotocol_job_details-0.1.5/oceanprotocol_job_details/utils.py +0 -33
  18. {oceanprotocol_job_details-0.1.5 → oceanprotocol_job_details-0.2.1}/LICENSE +0 -0
  19. {oceanprotocol_job_details-0.1.5/oceanprotocol_job_details → oceanprotocol_job_details-0.2.1/oceanprotocol_job_details/loaders}/__init__.py +0 -0
  20. {oceanprotocol_job_details-0.1.5/oceanprotocol_job_details/loaders → oceanprotocol_job_details-0.2.1/oceanprotocol_job_details/loaders/impl}/__init__.py +0 -0
  21. {oceanprotocol_job_details-0.1.5 → oceanprotocol_job_details-0.2.1}/oceanprotocol_job_details/loaders/loader.py +0 -0
@@ -3,4 +3,5 @@ dist
3
3
 
4
4
  *egg-info
5
5
  __pycache__
6
- .pytest_cache
6
+ .pytest_cache
7
+ .vscode
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oceanprotocol-job-details
3
- Version: 0.1.5
3
+ Version: 0.2.1
4
4
  Summary: A Python package to get details from OceanProtocol jobs
5
5
  Project-URL: Homepage, https://github.com/AgrospAI/oceanprotocol-job-details
6
6
  Project-URL: Issues, https://github.com/AgrospAI/oceanprotocol-job-details/issues
@@ -18,6 +18,7 @@ Classifier: Operating System :: OS Independent
18
18
  Classifier: Programming Language :: Python :: 3
19
19
  Requires-Python: >=3.10
20
20
  Requires-Dist: dataclasses-json>=0.6.7
21
+ Requires-Dist: dependency-injector>=4.48.2
21
22
  Requires-Dist: orjson>=3.11.3
22
23
  Description-Content-Type: text/markdown
23
24
 
@@ -36,10 +37,10 @@ pip install oceanprotocol-job-details
36
37
  As a simple library, we only need to import the main object and use it once:
37
38
 
38
39
  ```Python
39
- from oceanprotocol_job_details.job_details import OceanProtocolJobDetails
40
+ from oceanprotocol_job_details import JobDetails
40
41
 
41
42
  # Having no algorithm input parameters
42
- job_details = OceanProtocolJobDetails().load() # type: ignore
43
+ job_details = JobDetails.load()
43
44
 
44
45
  ```
45
46
 
@@ -48,15 +49,16 @@ If our algorithm has custom input parameters and we want to load them into our a
48
49
  ```Python
49
50
 
50
51
  from dataclasses import dataclass
51
- from oceanprotocol_job_details.job_details import OceanProtocolJobDetails
52
- from oceanprotocol_job_details.ocean import JobDetails
52
+ from oceanprotocol_job_details import JobDetails
53
+
53
54
 
54
55
  @dataclass
55
- class Input:
56
+ class InputParameters:
56
57
  name: str
57
58
  age: int
58
59
 
59
- job_details: JobDetails[Input] = OceanProtocolJobDetails(Input).load()
60
+
61
+ job_details: JobDetails[InputParameters] = JobDetails.load(InputParameters)
60
62
 
61
63
  # Usage (is type hinted)
62
64
  job_details.input_parameters.name
@@ -64,20 +66,11 @@ job_details.input_parameters.age
64
66
 
65
67
  ```
66
68
 
67
- Assumes the following directory structure:
68
- ```
69
- <ROOT_FOLDER>
70
- └───data
71
- ├───ddos
72
- ├───transformation
73
- ├───inputs
74
- └───logs
75
- ```
69
+ Assumes the directory structure of OceanProtocol algorithms.
76
70
 
77
71
  ### Core functionalities
78
72
 
79
- Given the Ocean Protocol job details structure as in [https://github.com/GX4FM-Base-X/pontus-x-ontology](Pontus-X Ontology), parses the passed algorithm parameters into an object to use in your algorithms.
73
+ Given the Ocean Protocol job details structure, parses the passed algorithm parameters into an object to use in your algorithms.
80
74
 
81
- 1. Parsing JSON
82
- 1. Validation
83
- 1. Metadata and service extraction
75
+ 1. Input parameter JSON parsing and validation
76
+ 1. Metadata and service extraction from the directory structure.
@@ -0,0 +1,52 @@
1
+ A Python package to get details from OceanProtocol jobs
2
+
3
+ ---
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ pip install oceanprotocol-job-details
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ As a simple library, we only need to import the main object and use it once:
14
+
15
+ ```Python
16
+ from oceanprotocol_job_details import JobDetails
17
+
18
+ # Having no algorithm input parameters
19
+ job_details = JobDetails.load()
20
+
21
+ ```
22
+
23
+ If our algorithm has custom input parameters and we want to load them into our algorithm, we can do it as follows:
24
+
25
+ ```Python
26
+
27
+ from dataclasses import dataclass
28
+ from oceanprotocol_job_details import JobDetails
29
+
30
+
31
+ @dataclass
32
+ class InputParameters:
33
+ name: str
34
+ age: int
35
+
36
+
37
+ job_details: JobDetails[InputParameters] = JobDetails.load(InputParameters)
38
+
39
+ # Usage (is type hinted)
40
+ job_details.input_parameters.name
41
+ job_details.input_parameters.age
42
+
43
+ ```
44
+
45
+ Assumes the directory structure of OceanProtocol algorithms.
46
+
47
+ ### Core functionalities
48
+
49
+ Given the Ocean Protocol job details structure, parses the passed algorithm parameters into an object to use in your algorithms.
50
+
51
+ 1. Input parameter JSON parsing and validation
52
+ 1. Metadata and service extraction from the directory structure.
@@ -0,0 +1,4 @@
1
+ from ocean import JobDetails
2
+
3
+
4
+ __all__ = [JobDetails]
@@ -0,0 +1,44 @@
1
+ from dependency_injector import containers, providers
2
+
3
+ from oceanprotocol_job_details.loaders.impl.ddo import DDOLoader
4
+ from oceanprotocol_job_details.loaders.impl.files import FilesLoader
5
+ from oceanprotocol_job_details.loaders.impl.job_details import JobDetailsLoader
6
+ from oceanprotocol_job_details.paths import Paths
7
+
8
+
9
+ class Container(containers.DeclarativeContainer):
10
+
11
+ config = providers.Configuration()
12
+
13
+ paths = providers.Singleton(Paths)
14
+
15
+ file_loader = providers.Factory(
16
+ FilesLoader,
17
+ dids=config.dids,
18
+ transformation_did=config.transformation_did,
19
+ paths=paths,
20
+ )
21
+
22
+ files = providers.Factory(
23
+ lambda loader: loader.load(),
24
+ loader=file_loader,
25
+ )
26
+
27
+ # DDOLoader depends on Files loaded from FilesLoader
28
+ ddo_loader = providers.Factory(
29
+ DDOLoader,
30
+ files=files,
31
+ )
32
+
33
+ ddos = providers.Factory(
34
+ lambda loader: loader.load(),
35
+ loader=ddo_loader,
36
+ )
37
+
38
+ job_details_loader = providers.Factory(
39
+ JobDetailsLoader,
40
+ files=files,
41
+ secret=config.secret,
42
+ paths=paths,
43
+ ddos=ddos,
44
+ )
@@ -1,24 +1,30 @@
1
+ from __future__ import annotations
2
+
1
3
  from dataclasses import InitVar, dataclass, field
2
4
  from pathlib import Path
3
- from typing import final
5
+ from typing import TYPE_CHECKING, final
4
6
 
5
- from oceanprotocol_job_details.ocean import DDO
7
+ if TYPE_CHECKING:
8
+ from oceanprotocol_job_details.ocean import DDO, Files
6
9
 
7
10
 
8
11
  @final
9
12
  @dataclass(frozen=True)
10
13
  class DDOLoader:
11
- ddo_paths: InitVar[list[Path]]
14
+
15
+ files: InitVar[list[Files]]
12
16
  """The files to load the DDOs from"""
13
17
 
14
18
  _ddo_paths: list[Path] = field(init=False)
15
19
 
16
- def __post_init__(self, ddo_paths: list[Path]) -> None:
17
- assert ddo_paths, "Missing DDO paths"
20
+ def __post_init__(self, files: list[Files]) -> None:
21
+ assert files, "Missing files"
18
22
 
19
- object.__setattr__(self, "_ddo_paths", ddo_paths)
23
+ object.__setattr__(self, "_ddo_paths", [f.ddo for f in files])
20
24
 
21
25
  def load(self) -> list[DDO]:
26
+ from oceanprotocol_job_details.ocean import DDO
27
+
22
28
  ddos = []
23
29
  for path in self._ddo_paths:
24
30
  with open(path, "r") as f:
@@ -1,53 +1,28 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
4
  from dataclasses import InitVar, dataclass, field
3
- from pathlib import Path
4
- from typing import Iterator, Sequence, final
5
-
6
- from oceanprotocol_job_details.config import config
7
-
8
-
9
- @dataclass(frozen=True)
10
- class DIDPaths:
11
- did: str
12
- ddo: Path
13
- input_files: Sequence[Path]
14
-
15
- def __post_init__(self) -> None:
16
- assert self.ddo.exists(), f"DDO {self.ddo} does not exist"
17
- for input_file in self.input_files:
18
- assert input_file.exists(), f"File {input_file} does not exist"
5
+ from typing import TYPE_CHECKING, Sequence, final
19
6
 
20
- def __len__(self) -> int:
21
- return len(self.input_files)
7
+ from oceanprotocol_job_details.paths import Paths
22
8
 
23
-
24
- @dataclass(frozen=True)
25
- class Files:
26
- _files: Sequence[DIDPaths]
27
-
28
- @property
29
- def files(self) -> Sequence[DIDPaths]:
30
- return self._files
31
-
32
- def __getitem__(self, index: int) -> DIDPaths:
33
- return self.files[index]
34
-
35
- def __iter__(self) -> Iterator[DIDPaths]:
36
- return iter(self.files)
37
-
38
- def __len__(self) -> int:
39
- return len(self.files)
9
+ if TYPE_CHECKING:
10
+ from oceanprotocol_job_details.ocean import DIDPaths, Files
40
11
 
41
12
 
42
13
  @final
43
14
  @dataclass(frozen=True)
44
15
  class FilesLoader:
16
+
45
17
  dids: InitVar[str | None]
46
18
  """Input DIDs"""
47
19
 
48
20
  transformation_did: InitVar[str | None]
49
21
  """DID for the transformation algorithm"""
50
22
 
23
+ paths: Paths
24
+ """Path configurations of the project"""
25
+
51
26
  _dids: Sequence[str] = field(init=False)
52
27
  _transformation_did: str = field(init=False)
53
28
 
@@ -63,13 +38,15 @@ class FilesLoader:
63
38
  object.__setattr__(self, "_transformation_did", transformation_did)
64
39
 
65
40
  def load(self) -> Files:
41
+ from oceanprotocol_job_details.ocean import DIDPaths, Files
42
+
66
43
  files: list[DIDPaths] = []
67
44
  for did in self._dids:
68
- base = Path(config.path_inputs) / did
45
+ base = self.paths.inputs / did
69
46
  files.append(
70
47
  DIDPaths(
71
48
  did=did,
72
- ddo=Path(config.path_ddos) / did,
49
+ ddo=self.paths.ddos / did,
73
50
  input_files=list(base.iterdir()),
74
51
  )
75
52
  )
@@ -0,0 +1,35 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import TYPE_CHECKING, Generic, Type, TypeVar, final
5
+
6
+ from oceanprotocol_job_details.paths import Paths
7
+
8
+ if TYPE_CHECKING:
9
+ from oceanprotocol_job_details.ocean import DDO, Files, JobDetails
10
+
11
+
12
+ T = TypeVar("T")
13
+
14
+
15
+ @final
16
+ @dataclass(frozen=True)
17
+ class JobDetailsLoader(Generic[T]):
18
+
19
+ _type: Type[T] = field(repr=False)
20
+
21
+ files: Files
22
+ secret: str
23
+ paths: Paths
24
+ ddos: list[DDO]
25
+
26
+ def load(self) -> JobDetails[T]:
27
+ from oceanprotocol_job_details.ocean import JobDetails
28
+
29
+ return JobDetails(
30
+ files=self.files,
31
+ secret=self.secret,
32
+ ddos=self.ddos,
33
+ paths=self.paths,
34
+ _type=self._type,
35
+ )
@@ -1,17 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import os
1
5
  from dataclasses import dataclass, field
2
6
  from functools import cached_property
3
- from typing import Any, Generic, Optional, Type, TypeVar, final
7
+ from pathlib import Path
8
+ from typing import Any, Generic, Iterator, Optional, Sequence, Type, TypeVar, final
4
9
 
5
10
  import orjson
6
-
7
11
  from dataclasses_json import config as dc_config
8
12
  from dataclasses_json import dataclass_json
9
13
 
10
- from oceanprotocol_job_details.config import config
11
- from oceanprotocol_job_details.loaders.impl.files import Files
14
+ from oceanprotocol_job_details.di import Container
15
+ from oceanprotocol_job_details.paths import Paths
12
16
 
13
17
  T = TypeVar("T")
14
18
 
19
+ logging.basicConfig(
20
+ level=logging.INFO,
21
+ format="%(asctime)s [%(threadName)s] [%(levelname)s] %(message)s",
22
+ handlers=[logging.StreamHandler()],
23
+ )
24
+ logger = logging.getLogger(__name__)
25
+
15
26
 
16
27
  @dataclass_json
17
28
  @dataclass
@@ -29,7 +40,7 @@ class Credentials:
29
40
 
30
41
  @dataclass_json
31
42
  @dataclass
32
- class Container:
43
+ class DockerContainer:
33
44
  image: str
34
45
  tag: str
35
46
  entrypoint: str
@@ -38,7 +49,7 @@ class Container:
38
49
  @dataclass_json
39
50
  @dataclass
40
51
  class Algorithm: # type: ignore
41
- container: Container
52
+ container: DockerContainer
42
53
  language: str
43
54
  version: str
44
55
  consumerParameters: Any # type: ignore
@@ -157,6 +168,39 @@ class DDO:
157
168
  purgatory: Purgatory
158
169
 
159
170
 
171
+ @dataclass(frozen=True)
172
+ class DIDPaths:
173
+ did: str
174
+ ddo: Path
175
+ input_files: Sequence[Path]
176
+
177
+ def __post_init__(self) -> None:
178
+ assert self.ddo.exists(), f"DDO {self.ddo} does not exist"
179
+ for input_file in self.input_files:
180
+ assert input_file.exists(), f"File {input_file} does not exist"
181
+
182
+ def __len__(self) -> int:
183
+ return len(self.input_files)
184
+
185
+
186
+ @dataclass(frozen=True)
187
+ class Files:
188
+ _files: Sequence[DIDPaths]
189
+
190
+ @property
191
+ def files(self) -> Sequence[DIDPaths]:
192
+ return self._files
193
+
194
+ def __getitem__(self, index: int) -> DIDPaths:
195
+ return self.files[index]
196
+
197
+ def __iter__(self) -> Iterator[DIDPaths]:
198
+ return iter(self.files)
199
+
200
+ def __len__(self) -> int:
201
+ return len(self.files)
202
+
203
+
160
204
  def _normalize_json(value):
161
205
  if isinstance(value, str):
162
206
  try:
@@ -171,6 +215,12 @@ def _normalize_json(value):
171
215
  return value
172
216
 
173
217
 
218
+ @final
219
+ @dataclass_json
220
+ @dataclass
221
+ class _EmptyJobDetails: ...
222
+
223
+
174
224
  @final
175
225
  @dataclass_json
176
226
  @dataclass(frozen=True)
@@ -181,6 +231,9 @@ class JobDetails(Generic[T]):
181
231
  ddos: list[DDO]
182
232
  """list of paths to the DDOs"""
183
233
 
234
+ paths: Paths
235
+ """Configuration paths"""
236
+
184
237
  # Store the type explicitly to avoid issues
185
238
  _type: Type[T] = field(repr=False)
186
239
 
@@ -195,11 +248,11 @@ class JobDetails(Generic[T]):
195
248
  def input_parameters(self) -> T:
196
249
  """Read the input parameters and return them in an instance of the dataclass T"""
197
250
 
198
- with open(config.path_algorithm_custom_parameters, "r") as f:
251
+ with open(self.paths.algorithm_custom_parameters, "r") as f:
199
252
  raw = f.read().strip()
200
253
  if not raw:
201
254
  raise ValueError(
202
- f"Custom parameters file {config.path_algorithm_custom_parameters} is empty"
255
+ f"Custom parameters file {self.paths.algorithm_custom_parameters} is empty"
203
256
  )
204
257
  try:
205
258
  parsed = _normalize_json(orjson.loads(raw))
@@ -209,3 +262,39 @@ class JobDetails(Generic[T]):
209
262
  f"Failed to parse input paramers into {self._type.__name__}: {e}\n"
210
263
  f"Raw content: {raw}"
211
264
  ) from e
265
+
266
+ @classmethod
267
+ def load(
268
+ cls,
269
+ _type: Type[T] | None = None,
270
+ dids: str | None = None,
271
+ transformation_did: str | None = None,
272
+ secret: str | None = None,
273
+ ) -> JobDetails[T]:
274
+ """Load a JobDetails instance that holds the runtime details.
275
+
276
+ Loading it will check the following:
277
+ 1. That the needed environment variables are set.
278
+ 1. That the ocean protocol contains the needed data based on the passed environment variables.
279
+
280
+ Those needed environment variables are:
281
+ - DIDS: The DIDs of the inputs
282
+ - TRANSFORMATION_DID: The DID of the transformation algorithm
283
+ - SECRET (optional): A really secret secret
284
+
285
+ """
286
+
287
+ if _type is None:
288
+ _type = _EmptyJobDetails
289
+
290
+ container = Container()
291
+ container.config.from_dict(
292
+ {
293
+ "dids": dids or os.environ.get("DIDS"),
294
+ "transformation_did": transformation_did
295
+ or os.environ.get("TRANSFORMATION_DID"),
296
+ "secret": secret or os.environ.get("SECRET"),
297
+ }
298
+ )
299
+
300
+ return container.job_details_loader(_type=_type).load()
@@ -0,0 +1,28 @@
1
+ from dataclasses import dataclass
2
+ from logging import getLogger
3
+ from pathlib import Path
4
+
5
+ logger = getLogger(__name__)
6
+
7
+
8
+ @dataclass
9
+ class Paths:
10
+ """Configuration class for the Ocean Protocol Job Details"""
11
+
12
+ data: Path = Path("/data")
13
+ """The path to the data directory"""
14
+
15
+ inputs: Path = data / "inputs"
16
+ """The path to the inputs directory"""
17
+
18
+ ddos: Path = data / "ddos"
19
+ """The path to the DDOs directory"""
20
+
21
+ outputs: Path = data / "outputs"
22
+ """The path to the outputs directory"""
23
+
24
+ logs: Path = data / "logs"
25
+ """The path to the logs directory"""
26
+
27
+ algorithm_custom_parameters: Path = inputs / "algoCustomData.json"
28
+ """The path to the algorithm's custom parameters file"""
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "oceanprotocol-job-details"
3
- version = "0.1.5"
3
+ version = "0.2.1"
4
4
  description = "A Python package to get details from OceanProtocol jobs"
5
5
  authors = [
6
6
  { name = "Christian López García", email = "christian.lopez@udl.cat" },
@@ -13,7 +13,11 @@ classifiers = [
13
13
  "Operating System :: OS Independent",
14
14
  "License :: OSI Approved :: MIT License",
15
15
  ]
16
- dependencies = ["dataclasses-json>=0.6.7", "orjson>=3.11.3"]
16
+ dependencies = [
17
+ "dataclasses-json>=0.6.7",
18
+ "dependency-injector>=4.48.2",
19
+ "orjson>=3.11.3",
20
+ ]
17
21
 
18
22
  [project.urls]
19
23
  Homepage = "https://github.com/AgrospAI/oceanprotocol-job-details"
@@ -1,60 +0,0 @@
1
- A Python package to get details from OceanProtocol jobs
2
-
3
- ---
4
-
5
- ## Installation
6
-
7
- ```
8
- pip install oceanprotocol-job-details
9
- ```
10
-
11
- ## Usage
12
-
13
- As a simple library, we only need to import the main object and use it once:
14
-
15
- ```Python
16
- from oceanprotocol_job_details.job_details import OceanProtocolJobDetails
17
-
18
- # Having no algorithm input parameters
19
- job_details = OceanProtocolJobDetails().load() # type: ignore
20
-
21
- ```
22
-
23
- If our algorithm has custom input parameters and we want to load them into our algorithm, we can do it as follows:
24
-
25
- ```Python
26
-
27
- from dataclasses import dataclass
28
- from oceanprotocol_job_details.job_details import OceanProtocolJobDetails
29
- from oceanprotocol_job_details.ocean import JobDetails
30
-
31
- @dataclass
32
- class Input:
33
- name: str
34
- age: int
35
-
36
- job_details: JobDetails[Input] = OceanProtocolJobDetails(Input).load()
37
-
38
- # Usage (is type hinted)
39
- job_details.input_parameters.name
40
- job_details.input_parameters.age
41
-
42
- ```
43
-
44
- Assumes the following directory structure:
45
- ```
46
- <ROOT_FOLDER>
47
- └───data
48
- ├───ddos
49
- ├───transformation
50
- ├───inputs
51
- └───logs
52
- ```
53
-
54
- ### Core functionalities
55
-
56
- Given the Ocean Protocol job details structure as in [https://github.com/GX4FM-Base-X/pontus-x-ontology](Pontus-X Ontology), parses the passed algorithm parameters into an object to use in your algorithms.
57
-
58
- 1. Parsing JSON
59
- 1. Validation
60
- 1. Metadata and service extraction
@@ -1,54 +0,0 @@
1
- from dataclasses import dataclass, fields
2
- from logging import getLogger
3
- from pathlib import Path
4
-
5
- logger = getLogger(__name__)
6
-
7
-
8
- @dataclass
9
- class Config:
10
- """Configuration class for the Ocean Protocol Job Details"""
11
-
12
- path_data: Path = Path("/data")
13
- """The path to the data directory"""
14
-
15
- path_inputs: Path = path_data / "inputs"
16
- """The path to the inputs directory"""
17
-
18
- path_ddos: Path = path_data / "ddos"
19
- """The path to the DDOs directory"""
20
-
21
- path_outputs: Path = path_data / "outputs"
22
- """The path to the outputs directory"""
23
-
24
- path_logs: Path = path_data / "logs"
25
- """The path to the logs directory"""
26
-
27
- path_algorithm_custom_parameters: Path = path_inputs / "algoCustomData.json"
28
- """The path to the algorithm's custom parameters file"""
29
-
30
-
31
- config = Config()
32
-
33
-
34
- def update_config_from(base: Path) -> None:
35
- """Updates the configuration to use the new base path, ensures that the base path exists.
36
-
37
- Args:
38
- base (Path): The new base path to use.
39
- """
40
-
41
- logger.info(f"Updating config to use base path: {base}")
42
-
43
- base.mkdir(parents=True, exist_ok=True)
44
-
45
- for field in fields(config):
46
- current_value = getattr(config, field.name)
47
- if not isinstance(current_value, Path):
48
- raise ValueError(f"Field {field.name} is n|ot a Path")
49
-
50
- rel_path = Path(current_value).relative_to("/data")
51
- object.__setattr__(config, field.name, base / rel_path)
52
-
53
-
54
- __all__ = ["config"]
@@ -1,47 +0,0 @@
1
- import logging
2
- from dataclasses import dataclass
3
- from typing import Generic, Type, TypeVar
4
-
5
- from dataclasses_json import dataclass_json
6
-
7
- from oceanprotocol_job_details.loaders.impl.job_details import JobDetailsLoader
8
- from oceanprotocol_job_details.loaders.loader import Loader
9
- from oceanprotocol_job_details.ocean import JobDetails
10
-
11
- logging.basicConfig(
12
- level=logging.INFO,
13
- format="%(asctime)s [%(threadName)s] [%(levelname)s] %(message)s",
14
- handlers=[logging.StreamHandler()],
15
- )
16
- logger = logging.getLogger(__name__)
17
-
18
-
19
- @dataclass_json
20
- @dataclass
21
- class _EmptyJobDetails: ...
22
-
23
-
24
- T = TypeVar("T")
25
-
26
-
27
- class OceanProtocolJobDetails(Generic[T]):
28
- """The JobDetails class is a dataclass that holds the details of the current job.
29
-
30
- Loading it will check the following:
31
- 1. That the needed environment variables are set
32
- 1. That the ocean protocol contains the needed data based on the passed environment variables
33
-
34
- Those needed environment variables are:
35
- - DIDS: The DIDs of the inputs
36
- - TRANSFORMATION_DID: The DID of the transformation algorithm
37
- - SECRET (optional): A really secret secret
38
-
39
- """
40
-
41
- def __init__(self, _type: Type[T] | None = None) -> None:
42
- if _type is None:
43
- _type = _EmptyJobDetails # type: ignore[assignment]
44
- self.job_details_loader: Loader[JobDetails[T]] = JobDetailsLoader(_type) # type: ignore[arg-type]
45
-
46
- def load(self) -> JobDetails[T]:
47
- return self.job_details_loader.load()
@@ -1,26 +0,0 @@
1
- import os
2
- from dataclasses import dataclass, field
3
- from typing import Generic, Type, TypeVar, final
4
-
5
- from oceanprotocol_job_details.loaders.impl.ddo import DDOLoader
6
- from oceanprotocol_job_details.loaders.impl.files import FilesLoader
7
- from oceanprotocol_job_details.ocean import JobDetails
8
-
9
- T = TypeVar("T")
10
-
11
-
12
- @final
13
- @dataclass(frozen=True)
14
- class JobDetailsLoader(Generic[T]):
15
- _type: Type[T] = field(repr=False)
16
-
17
-
18
- def load(self) -> JobDetails[T]:
19
- dids = os.environ.get("DIDS")
20
- transformation_did = os.environ.get("TRANSFORMATION_DID")
21
- secret = os.environ.get("SECRET")
22
-
23
- files = FilesLoader(dids, transformation_did).load()
24
- ddos = DDOLoader([f.ddo for f in files]).load()
25
-
26
- return JobDetails(files=files, secret=secret, ddos=ddos, _type=self._type)
@@ -1,33 +0,0 @@
1
- from logging import getLogger
2
- from typing import Mapping, Optional, TypeVar
3
-
4
- T = TypeVar("T")
5
- logger = getLogger(__name__)
6
-
7
-
8
- def get(
9
- map: Mapping[str, T],
10
- key: str,
11
- default: Optional[T] = None,
12
- ) -> T | None:
13
- """Get the value of a key from a dictionary, if not found return the default value if given, otherwise raise a KeyError
14
-
15
- :param map: original map to get the item from
16
- :type map: Mapping[str, T]
17
- :param key: key to get the value from
18
- :type key: str
19
- :param default: default value if missing, defaults to None
20
- :type default: Optional[T], optional
21
- :raises KeyError: if the value is missing and no default is provided
22
- :return: value of the key
23
- :rtype: T
24
- """
25
-
26
- if key in map.keys():
27
- return map.get(key)
28
-
29
- if default is None:
30
- raise KeyError(f"Key {key} not found")
31
-
32
- logger.info(f"Key {key} not found, returning default value {default}")
33
- return default