oceanprotocol-job-details 0.1.4__tar.gz → 0.2.0__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.
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/.gitignore +2 -1
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/PKG-INFO +3 -1
- oceanprotocol_job_details-0.2.0/oceanprotocol_job_details/di.py +44 -0
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/oceanprotocol_job_details/loaders/impl/ddo.py +12 -6
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/oceanprotocol_job_details/loaders/impl/files.py +14 -37
- oceanprotocol_job_details-0.2.0/oceanprotocol_job_details/loaders/impl/job_details.py +35 -0
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/oceanprotocol_job_details/ocean.py +90 -8
- oceanprotocol_job_details-0.2.0/oceanprotocol_job_details/paths.py +28 -0
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/pyproject.toml +6 -2
- oceanprotocol_job_details-0.1.4/oceanprotocol_job_details/config.py +0 -54
- oceanprotocol_job_details-0.1.4/oceanprotocol_job_details/job_details.py +0 -47
- oceanprotocol_job_details-0.1.4/oceanprotocol_job_details/loaders/impl/job_details.py +0 -25
- oceanprotocol_job_details-0.1.4/oceanprotocol_job_details/utils.py +0 -33
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/LICENSE +0 -0
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/README.md +0 -0
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/oceanprotocol_job_details/__init__.py +0 -0
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/oceanprotocol_job_details/loaders/__init__.py +0 -0
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/oceanprotocol_job_details/loaders/impl/__init__.py +0 -0
- {oceanprotocol_job_details-0.1.4 → oceanprotocol_job_details-0.2.0}/oceanprotocol_job_details/loaders/loader.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oceanprotocol-job-details
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
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,8 @@ 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
|
|
22
|
+
Requires-Dist: orjson>=3.11.3
|
|
21
23
|
Description-Content-Type: text/markdown
|
|
22
24
|
|
|
23
25
|
A Python package to get details from OceanProtocol jobs
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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,
|
|
17
|
-
assert
|
|
20
|
+
def __post_init__(self, files: list[Files]) -> None:
|
|
21
|
+
assert files, "Missing files"
|
|
18
22
|
|
|
19
|
-
object.__setattr__(self, "_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
|
|
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
|
-
|
|
21
|
-
return len(self.input_files)
|
|
7
|
+
from oceanprotocol_job_details.paths import Paths
|
|
22
8
|
|
|
23
|
-
|
|
24
|
-
|
|
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 =
|
|
45
|
+
base = self.paths.inputs / did
|
|
69
46
|
files.append(
|
|
70
47
|
DIDPaths(
|
|
71
48
|
did=did,
|
|
72
|
-
ddo=
|
|
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
|
|
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.
|
|
11
|
-
from oceanprotocol_job_details.
|
|
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
|
|
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:
|
|
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(
|
|
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 {
|
|
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,32 @@ 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(cls, _type: Type[T] | None = None) -> JobDetails[T]:
|
|
268
|
+
"""Load a JobDetails instance that holds the runtime details.
|
|
269
|
+
|
|
270
|
+
Loading it will check the following:
|
|
271
|
+
1. That the needed environment variables are set.
|
|
272
|
+
1. That the ocean protocol contains the needed data based on the passed environment variables.
|
|
273
|
+
|
|
274
|
+
Those needed environment variables are:
|
|
275
|
+
- DIDS: The DIDs of the inputs
|
|
276
|
+
- TRANSFORMATION_DID: The DID of the transformation algorithm
|
|
277
|
+
- SECRET (optional): A really secret secret
|
|
278
|
+
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
if _type is None:
|
|
282
|
+
_type = _EmptyJobDetails
|
|
283
|
+
|
|
284
|
+
container = Container()
|
|
285
|
+
container.config.from_dict(
|
|
286
|
+
{
|
|
287
|
+
"dids": os.environ.get("DIDS"),
|
|
288
|
+
"transformation_did": os.environ.get("TRANSFORMATION_DID"),
|
|
289
|
+
"secret": os.environ.get("SECRET"),
|
|
290
|
+
}
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
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.
|
|
3
|
+
version = "0.2.0"
|
|
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 = [
|
|
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,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,25 +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
|
-
def load(self) -> JobDetails[T]:
|
|
18
|
-
dids = os.environ.get("DIDS")
|
|
19
|
-
transformation_did = os.environ.get("TRANSFORMATION_DID")
|
|
20
|
-
secret = os.environ.get("SECRET")
|
|
21
|
-
|
|
22
|
-
files = FilesLoader(dids, transformation_did).load()
|
|
23
|
-
ddos = DDOLoader([f.ddo for f in files]).load()
|
|
24
|
-
|
|
25
|
-
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|