oceanprotocol-job-details 0.3.3__py3-none-any.whl → 0.3.13__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.
@@ -1,4 +1,5 @@
1
1
  from .helpers import create_container, load_job_details
2
2
  from .ocean import JobDetails
3
+ from .executors import run_in_executor
3
4
 
4
- __all__ = [JobDetails, load_job_details, create_container] # type: ignore
5
+ __all__ = [JobDetails, load_job_details, create_container, run_in_executor] # type: ignore
@@ -8,7 +8,7 @@ from oceanprotocol_job_details.loaders.impl.job_details import JobDetailsLoader
8
8
  from oceanprotocol_job_details.domain import Paths
9
9
 
10
10
 
11
- InputParametersT = TypeVar("InputParametersT", bound=BaseModel)
11
+ InputParametersT = TypeVar("InputParametersT", BaseModel, None)
12
12
 
13
13
 
14
14
  class Container(containers.DeclarativeContainer, Generic[InputParametersT]):
@@ -1,7 +1,7 @@
1
1
  # mypy: disable-error-code=explicit-any
2
2
  from dataclasses import InitVar, dataclass, field
3
3
  from pathlib import Path
4
- from typing import Generator, List, Optional, Sequence, TypeAlias, TypeVar
4
+ from typing import Generator, List, Optional, Sequence, TypeAlias
5
5
 
6
6
  from pydantic import BaseModel, ConfigDict, Field, JsonValue
7
7
 
@@ -0,0 +1,25 @@
1
+ import asyncio
2
+ import inspect
3
+ from typing import Any, Callable, Coroutine, TypeVar
4
+
5
+ T = TypeVar("T")
6
+
7
+
8
+ async def run_in_executor(
9
+ obj: Callable[..., T]
10
+ | Callable[..., Coroutine[Any, Any, T]]
11
+ | Coroutine[Any, Any, T],
12
+ *args,
13
+ **kwargs,
14
+ ) -> T:
15
+ if inspect.iscoroutinefunction(obj):
16
+ return await obj(*args, **kwargs)
17
+
18
+ if inspect.iscoroutine(obj):
19
+ return await obj
20
+
21
+ if callable(obj):
22
+ loop = asyncio.get_running_loop()
23
+ return await loop.run_in_executor(None, obj, *args, **kwargs)
24
+
25
+ return obj
@@ -6,7 +6,7 @@ from oceanprotocol_job_details.di import Container
6
6
  from oceanprotocol_job_details.ocean import JobDetails
7
7
  from oceanprotocol_job_details.settings import JobSettings
8
8
 
9
- InputParametersT = TypeVar("InputParametersT", bound=BaseModel)
9
+ InputParametersT = TypeVar("InputParametersT", BaseModel, None)
10
10
 
11
11
 
12
12
  def create_container(config: Dict[str, Any]) -> Container[InputParametersT]: # type: ignore[explicit-any]
@@ -18,8 +18,8 @@ def create_container(config: Dict[str, Any]) -> Container[InputParametersT]: #
18
18
 
19
19
 
20
20
  def load_job_details(
21
- config: Dict[str, JsonValue],
22
- input_type: Type[InputParametersT],
21
+ config: Dict[str, JsonValue] = {},
22
+ input_type: Type[InputParametersT] | None = None,
23
23
  ) -> JobDetails[InputParametersT]:
24
24
  """
25
25
  Load JobDetails for a given input_type using the config.
@@ -1,4 +1,5 @@
1
1
  from dataclasses import dataclass, field
2
+ from types import NoneType
2
3
  from typing import Generic, Type, TypeVar, final
3
4
 
4
5
  from pydantic import BaseModel
@@ -6,7 +7,7 @@ from pydantic import BaseModel
6
7
  from oceanprotocol_job_details.domain import DDO, Files, Paths
7
8
  from oceanprotocol_job_details.ocean import JobDetails
8
9
 
9
- T = TypeVar("T", bound=BaseModel)
10
+ T = TypeVar("T", BaseModel, None)
10
11
 
11
12
 
12
13
  @final
@@ -6,29 +6,25 @@ from pathlib import Path
6
6
  from typing import Generator, Generic, Tuple, Type, TypeVar, final
7
7
 
8
8
  import aiofiles
9
- from pydantic import BaseModel, ConfigDict, Secret, model_validator
9
+ from pydantic import BaseModel, ConfigDict, Secret
10
10
 
11
11
  from oceanprotocol_job_details.domain import DDO, Files, Paths
12
+ from oceanprotocol_job_details.executors import run_in_executor
12
13
 
13
- InputParemetersT = TypeVar("InputParemetersT", bound=BaseModel)
14
+ InputParametersT = TypeVar("InputParametersT", BaseModel, None)
14
15
 
15
16
 
16
17
  @final
17
- class JobDetails(BaseModel, Generic[InputParemetersT]): # type: ignore[explicit-any]
18
+ class JobDetails(BaseModel, Generic[InputParametersT]): # type: ignore[explicit-any]
18
19
  files: Files
19
20
  ddos: list[DDO]
20
21
  paths: Paths
21
- input_type: Type[InputParemetersT]
22
+ input_type: Type[InputParametersT] | None
22
23
  secret: Secret[str] | None = None
23
24
 
24
25
  model_config = ConfigDict(arbitrary_types_allowed=True, frozen=True)
25
26
 
26
- @model_validator(mode="after")
27
- def validate_type(self) -> JobDetails[InputParemetersT]:
28
- assert issubclass(self.input_type, BaseModel), (
29
- f"{self.input_type} must be subtype of pydantic.BaseModel"
30
- )
31
- return self
27
+ _input_parameters: InputParametersT | None = None
32
28
 
33
29
  def inputs(self) -> Generator[Tuple[int, Path], None, None]:
34
30
  yield from (
@@ -37,15 +33,20 @@ class JobDetails(BaseModel, Generic[InputParemetersT]): # type: ignore[explicit
37
33
  for file in files.input_files
38
34
  )
39
35
 
40
- @cached_property
41
- def input_parameters(self) -> InputParemetersT:
42
- return asyncio.run(self.ainput_parameters())
36
+ async def input_parameters(self) -> InputParametersT:
37
+ if self._input_parameters is None:
38
+ input_parameters = await self.ainput_parameters()
39
+ object.__setattr__(self, "_input_parameters", input_parameters)
40
+ return self._input_parameters
41
+
42
+ async def ainput_parameters(self) -> InputParametersT:
43
+ if self.input_type is None:
44
+ return None
43
45
 
44
- async def ainput_parameters(self) -> InputParemetersT:
45
46
  path = self.paths.algorithm_custom_parameters
46
47
  async with aiofiles.open(path) as f:
47
48
  raw = await f.read()
48
49
 
49
50
  raw = raw.strip()
50
51
  assert raw is not None, f"Empty file {path}"
51
- return self.input_type.model_validate_json(raw)
52
+ return self.input_type.model_validate_json(raw) # type: ignore
File without changes
@@ -23,7 +23,10 @@ class JobSettings(BaseSettings): # type: ignore[explicit-any]
23
23
 
24
24
  @field_validator("dids", mode="before")
25
25
  @classmethod
26
- def split_dids(cls, v: list[str] | str) -> list[str]:
26
+ def split_dids(cls, v: list[str] | str | None) -> list[str]:
27
+ if v is None:
28
+ return []
29
+
27
30
  if isinstance(v, str):
28
31
  data = orjson.loads(v)
29
32
  assert isinstance(data, list)
@@ -33,5 +36,7 @@ class JobSettings(BaseSettings): # type: ignore[explicit-any]
33
36
  @model_validator(mode="after")
34
37
  def validate_dids(self) -> Self:
35
38
  if not self.dids:
36
- self.dids.extend([f.name for f in (self.base_dir / "ddos").glob("*")])
39
+ self.dids.extend(
40
+ [f.name for f in (self.base_dir / "ddos").glob("*") if f.is_file()]
41
+ )
37
42
  return self
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oceanprotocol-job-details
3
- Version: 0.3.3
3
+ Version: 0.3.13
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
@@ -32,9 +32,7 @@ A Python package to get details from OceanProtocol jobs
32
32
 
33
33
  ```bash
34
34
  pip install oceanprotocol-job-details
35
- ```
36
-
37
- ```bash
35
+ #or
38
36
  uv add oceanprotocol-job-details
39
37
  ```
40
38
 
@@ -42,17 +40,15 @@ uv add oceanprotocol-job-details
42
40
 
43
41
  As a simple library, we only need to import `load_job_details` and run it. It will:
44
42
 
45
- 1. Fetch the needed parameters to populate the `JobDetails` instance from the environment variables or use the passed values to the function.
46
- 1. Look for the files corresponding to the passed DIDs in the filesystem according to the [Ocean Protocol Structure](#oceanprotocol-structure) and load them into the `JobDetails` instance.
43
+ 1. Read from disk the needed parameters to populate the `JobDetails` from the given `base_dir`. Looking for the files corresponding to the passed DIDs in the filesystem according to the [Ocean Protocol Structure](#oceanprotocol-structure).
44
+ 2. If given a `InputParameters` type that inherits from `pydantic.BaseModel`, it will create an instance from the environment variables.
47
45
 
48
46
  ### Minimal Example
49
47
 
50
48
  ```python
51
49
  from oceanprotocol_job_details import load_job_details
52
50
 
53
- class InputParameters(BaseModel): ...
54
-
55
- job_details = load_job_details({}, InputParameters)
51
+ job_details = load_job_details({"base_dir": "...", "transformation_did": "..."})
56
52
  ```
57
53
 
58
54
  ### Custom Input Parameters
@@ -73,11 +69,12 @@ class InputParameters(BaseModel):
73
69
  foo: Foo
74
70
 
75
71
 
76
- job_details = load_job_details({}, InputParameters)
72
+ job_details = load_job_details({"base_dir": "...", "transformation_did": "..."}, InputParameters)
77
73
 
78
74
  # Usage
79
- job_details.input_parameters.foo
80
- job_details.input_parameters.foo.bar
75
+ parameters = await job_details.input_parameters()
76
+ parameters.foo
77
+ parameters.foo.bar
81
78
  ```
82
79
 
83
80
  The values to fill the custom `InputParameters` will be parsed from the `algoCustomData.json` located next to the input data directories.
@@ -88,7 +85,7 @@ The values to fill the custom `InputParameters` will be parsed from the `algoCus
88
85
  from oceanprotocol_job_details import load_job_details
89
86
 
90
87
 
91
- job_details = load_job_details
88
+ job_details = load_job_details(...)
92
89
 
93
90
  for idx, file_path in job_details.inputs():
94
91
  ...
@@ -0,0 +1,18 @@
1
+ oceanprotocol_job_details/__init__.py,sha256=sq_C8Ey4_4oHiX9cO1wne7ZsWqs86WWgHfKQ5PMwwak,218
2
+ oceanprotocol_job_details/di.py,sha256=H4_n9NrNuRB2s9uarSkwDYzjD1i7sV8dySRfHt21QWM,1316
3
+ oceanprotocol_job_details/domain.py,sha256=ifw-hKFAJj0Gl_wJuH-51LQx4KPsCyEVDsT10xg9uBw,3842
4
+ oceanprotocol_job_details/executors.py,sha256=Csc1MaUf0-Ve4Wp80qIanL7reRTT2qA3W3QrSE2jQO4,556
5
+ oceanprotocol_job_details/helpers.py,sha256=ABm3oIRwPd-4XeCOIszCbfL2wkUJqVJJ2bqy3hR4jyw,1064
6
+ oceanprotocol_job_details/ocean.py,sha256=kq7tAHJ36s7piJ_WpXVaTmSAMe87tuwHDeMQB-xS0T4,1702
7
+ oceanprotocol_job_details/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ oceanprotocol_job_details/settings.py,sha256=o_1Hn2vl5hMk7bAkdS7GjE4nKOAyHm7dScO2_o2sPuY,1345
9
+ oceanprotocol_job_details/loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ oceanprotocol_job_details/loaders/loader.py,sha256=36X2s_0lN89kCUpItxEXfIzuBBNJySebP2B_tdWK2E0,186
11
+ oceanprotocol_job_details/loaders/impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ oceanprotocol_job_details/loaders/impl/ddo.py,sha256=XthrQFhmP85XSVzVjBlLePtTowGR3BAsmVp3jngiQ08,668
13
+ oceanprotocol_job_details/loaders/impl/files.py,sha256=Y2vFBT2T9w9zrdpmf550-LQJxwtNPUGa0UU6bBzk9AU,1145
14
+ oceanprotocol_job_details/loaders/impl/job_details.py,sha256=QwlUaG9KozkI1wX66oDTPg4TjGkvSsi8O-TctF6eWvo,724
15
+ oceanprotocol_job_details-0.3.13.dist-info/METADATA,sha256=9jFrlbS9oWNQXrHj_jY3ia16bA3HvdBeMt6nMdUguHk,4509
16
+ oceanprotocol_job_details-0.3.13.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
17
+ oceanprotocol_job_details-0.3.13.dist-info/licenses/LICENSE,sha256=ni3ix7P_GxK1W3VGC4fJ3o6QoCngCEpSuTJwO4nkpbw,1055
18
+ oceanprotocol_job_details-0.3.13.dist-info/RECORD,,
@@ -1,16 +0,0 @@
1
- oceanprotocol_job_details/__init__.py,sha256=nJMrZsEC5F1n9WF-v5QV095Yyc8UkhFw0AzD9o7X0IE,162
2
- oceanprotocol_job_details/di.py,sha256=lsogbmjvmPfkd0mjLvn9vYLIZebwJm5RNraWt7WE5LA,1316
3
- oceanprotocol_job_details/domain.py,sha256=2_USbeA_7VIEYS8DVb2MW6dCZasjiqIxQaGUnNUKspY,3851
4
- oceanprotocol_job_details/helpers.py,sha256=ubH_KjAROqYvn0mkbA0-89vpdKIhVNGZ0h9pQLfPNow,1045
5
- oceanprotocol_job_details/ocean.py,sha256=q8rgT5ycA2ifey3XNhUW0bcJwfMp7hpKU-6EVDeKV1o,1620
6
- oceanprotocol_job_details/settings.py,sha256=zgIYPzaXjsgcmuhT7L2ipSP-2eNaodugHZr0rn2Z420,1248
7
- oceanprotocol_job_details/loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- oceanprotocol_job_details/loaders/loader.py,sha256=36X2s_0lN89kCUpItxEXfIzuBBNJySebP2B_tdWK2E0,186
9
- oceanprotocol_job_details/loaders/impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- oceanprotocol_job_details/loaders/impl/ddo.py,sha256=XthrQFhmP85XSVzVjBlLePtTowGR3BAsmVp3jngiQ08,668
11
- oceanprotocol_job_details/loaders/impl/files.py,sha256=Y2vFBT2T9w9zrdpmf550-LQJxwtNPUGa0UU6bBzk9AU,1145
12
- oceanprotocol_job_details/loaders/impl/job_details.py,sha256=7mEdeTo-cmsWuqWPdN7btjLjo6p5Oa1_acjSLWL5tb8,697
13
- oceanprotocol_job_details-0.3.3.dist-info/METADATA,sha256=pDXdsInFTf36wYjsqWSd_ygeCDggozjueHlhF6OyvlQ,4416
14
- oceanprotocol_job_details-0.3.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
15
- oceanprotocol_job_details-0.3.3.dist-info/licenses/LICENSE,sha256=ni3ix7P_GxK1W3VGC4fJ3o6QoCngCEpSuTJwO4nkpbw,1055
16
- oceanprotocol_job_details-0.3.3.dist-info/RECORD,,