runnable 0.26.0__tar.gz → 0.27.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. {runnable-0.26.0 → runnable-0.27.0}/PKG-INFO +1 -1
  2. {runnable-0.26.0 → runnable-0.27.0}/extensions/catalog/minio.py +7 -4
  3. runnable-0.26.0/extensions/run_log_store/file_system.py → runnable-0.27.0/extensions/run_log_store/any_path.py +10 -51
  4. {runnable-0.26.0 → runnable-0.27.0}/extensions/run_log_store/chunked_fs.py +13 -9
  5. runnable-0.27.0/extensions/run_log_store/file_system.py +91 -0
  6. {runnable-0.26.0 → runnable-0.27.0}/extensions/run_log_store/generic_chunked.py +17 -11
  7. runnable-0.27.0/extensions/run_log_store/minio.py +111 -0
  8. {runnable-0.26.0 → runnable-0.27.0}/pyproject.toml +2 -1
  9. {runnable-0.26.0 → runnable-0.27.0}/.gitignore +0 -0
  10. {runnable-0.26.0 → runnable-0.27.0}/LICENSE +0 -0
  11. {runnable-0.26.0 → runnable-0.27.0}/README.md +0 -0
  12. {runnable-0.26.0 → runnable-0.27.0}/extensions/README.md +0 -0
  13. {runnable-0.26.0 → runnable-0.27.0}/extensions/__init__.py +0 -0
  14. {runnable-0.26.0 → runnable-0.27.0}/extensions/catalog/README.md +0 -0
  15. {runnable-0.26.0 → runnable-0.27.0}/extensions/catalog/any_path.py +0 -0
  16. {runnable-0.26.0 → runnable-0.27.0}/extensions/catalog/file_system.py +0 -0
  17. {runnable-0.26.0 → runnable-0.27.0}/extensions/catalog/pyproject.toml +0 -0
  18. {runnable-0.26.0 → runnable-0.27.0}/extensions/catalog/s3.py +0 -0
  19. {runnable-0.26.0 → runnable-0.27.0}/extensions/job_executor/README.md +0 -0
  20. {runnable-0.26.0 → runnable-0.27.0}/extensions/job_executor/__init__.py +0 -0
  21. {runnable-0.26.0 → runnable-0.27.0}/extensions/job_executor/k8s.py +0 -0
  22. {runnable-0.26.0 → runnable-0.27.0}/extensions/job_executor/k8s_job_spec.yaml +0 -0
  23. {runnable-0.26.0 → runnable-0.27.0}/extensions/job_executor/local.py +0 -0
  24. {runnable-0.26.0 → runnable-0.27.0}/extensions/job_executor/local_container.py +0 -0
  25. {runnable-0.26.0 → runnable-0.27.0}/extensions/job_executor/pyproject.toml +0 -0
  26. {runnable-0.26.0 → runnable-0.27.0}/extensions/nodes/README.md +0 -0
  27. {runnable-0.26.0 → runnable-0.27.0}/extensions/nodes/nodes.py +0 -0
  28. {runnable-0.26.0 → runnable-0.27.0}/extensions/nodes/pyproject.toml +0 -0
  29. {runnable-0.26.0 → runnable-0.27.0}/extensions/pipeline_executor/README.md +0 -0
  30. {runnable-0.26.0 → runnable-0.27.0}/extensions/pipeline_executor/__init__.py +0 -0
  31. {runnable-0.26.0 → runnable-0.27.0}/extensions/pipeline_executor/argo.py +0 -0
  32. {runnable-0.26.0 → runnable-0.27.0}/extensions/pipeline_executor/local.py +0 -0
  33. {runnable-0.26.0 → runnable-0.27.0}/extensions/pipeline_executor/local_container.py +0 -0
  34. {runnable-0.26.0 → runnable-0.27.0}/extensions/pipeline_executor/mocked.py +0 -0
  35. {runnable-0.26.0 → runnable-0.27.0}/extensions/pipeline_executor/pyproject.toml +0 -0
  36. {runnable-0.26.0 → runnable-0.27.0}/extensions/pipeline_executor/retry.py +0 -0
  37. {runnable-0.26.0 → runnable-0.27.0}/extensions/run_log_store/README.md +0 -0
  38. {runnable-0.26.0 → runnable-0.27.0}/extensions/run_log_store/__init__.py +0 -0
  39. {runnable-0.26.0 → runnable-0.27.0}/extensions/run_log_store/db/implementation_FF.py +0 -0
  40. {runnable-0.26.0 → runnable-0.27.0}/extensions/run_log_store/db/integration_FF.py +0 -0
  41. {runnable-0.26.0 → runnable-0.27.0}/extensions/run_log_store/pyproject.toml +0 -0
  42. {runnable-0.26.0 → runnable-0.27.0}/extensions/secrets/README.md +0 -0
  43. {runnable-0.26.0 → runnable-0.27.0}/extensions/secrets/dotenv.py +0 -0
  44. {runnable-0.26.0 → runnable-0.27.0}/extensions/secrets/pyproject.toml +0 -0
  45. {runnable-0.26.0 → runnable-0.27.0}/runnable/__init__.py +0 -0
  46. {runnable-0.26.0 → runnable-0.27.0}/runnable/catalog.py +0 -0
  47. {runnable-0.26.0 → runnable-0.27.0}/runnable/cli.py +0 -0
  48. {runnable-0.26.0 → runnable-0.27.0}/runnable/context.py +0 -0
  49. {runnable-0.26.0 → runnable-0.27.0}/runnable/datastore.py +0 -0
  50. {runnable-0.26.0 → runnable-0.27.0}/runnable/defaults.py +0 -0
  51. {runnable-0.26.0 → runnable-0.27.0}/runnable/entrypoints.py +0 -0
  52. {runnable-0.26.0 → runnable-0.27.0}/runnable/exceptions.py +0 -0
  53. {runnable-0.26.0 → runnable-0.27.0}/runnable/executor.py +0 -0
  54. {runnable-0.26.0 → runnable-0.27.0}/runnable/graph.py +0 -0
  55. {runnable-0.26.0 → runnable-0.27.0}/runnable/names.py +0 -0
  56. {runnable-0.26.0 → runnable-0.27.0}/runnable/nodes.py +0 -0
  57. {runnable-0.26.0 → runnable-0.27.0}/runnable/parameters.py +0 -0
  58. {runnable-0.26.0 → runnable-0.27.0}/runnable/pickler.py +0 -0
  59. {runnable-0.26.0 → runnable-0.27.0}/runnable/sdk.py +0 -0
  60. {runnable-0.26.0 → runnable-0.27.0}/runnable/secrets.py +0 -0
  61. {runnable-0.26.0 → runnable-0.27.0}/runnable/tasks.py +0 -0
  62. {runnable-0.26.0 → runnable-0.27.0}/runnable/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runnable
3
- Version: 0.26.0
3
+ Version: 0.27.0
4
4
  Summary: Add your description here
5
5
  Author-email: "Vammi, Vijay" <vijay.vammi@astrazeneca.com>
6
6
  License-File: LICENSE
@@ -4,6 +4,7 @@ from pathlib import Path
4
4
  from typing import Any
5
5
 
6
6
  from cloudpathlib import CloudPath, S3Client, S3Path
7
+ from pydantic import Field, SecretStr
7
8
 
8
9
  from extensions.catalog.any_path import AnyPathCatalog
9
10
  from runnable import defaults
@@ -25,9 +26,9 @@ def get_minio_client(
25
26
  class MinioCatalog(AnyPathCatalog):
26
27
  service_name: str = "minio"
27
28
 
28
- endpoint_url: str = "http://localhost:9002"
29
- aws_access_key_id: str = "minioadmin"
30
- aws_secret_access_key: str = "minioadmin"
29
+ endpoint_url: str = Field(default="http://localhost:9002")
30
+ aws_access_key_id: SecretStr = SecretStr(secret_value="minioadmin")
31
+ aws_secret_access_key: SecretStr = SecretStr(secret_value="minioadmin")
31
32
  bucket: str = "runnable"
32
33
 
33
34
  def get_summary(self) -> dict[str, Any]:
@@ -44,7 +45,9 @@ class MinioCatalog(AnyPathCatalog):
44
45
  return S3Path(
45
46
  f"s3://{self.bucket}/{run_id}/{self.compute_data_folder}".strip("."),
46
47
  client=get_minio_client(
47
- self.endpoint_url, self.aws_access_key_id, self.aws_secret_access_key
48
+ self.endpoint_url,
49
+ self.aws_access_key_id.get_secret_value(),
50
+ self.aws_secret_access_key.get_secret_value(),
48
51
  ),
49
52
  )
50
53
 
@@ -1,15 +1,14 @@
1
- import json
2
1
  import logging
3
- from pathlib import Path
2
+ from abc import abstractmethod
4
3
  from typing import Any, Dict
5
4
 
6
- from runnable import defaults, exceptions, utils
5
+ from runnable import defaults, exceptions
7
6
  from runnable.datastore import BaseRunLogStore, RunLog
8
7
 
9
8
  logger = logging.getLogger(defaults.LOGGER_NAME)
10
9
 
11
10
 
12
- class FileSystemRunLogstore(BaseRunLogStore):
11
+ class AnyPathRunLogStore(BaseRunLogStore):
13
12
  """
14
13
  In this type of Run Log store, we use a file system to store the JSON run log.
15
14
 
@@ -43,51 +42,11 @@ class FileSystemRunLogstore(BaseRunLogStore):
43
42
 
44
43
  return summary
45
44
 
46
- def write_to_folder(self, run_log: RunLog):
47
- """
48
- Write the run log to the folder
49
-
50
- Args:
51
- run_log (RunLog): The run log to be added to the database
52
- """
53
- write_to = self.log_folder_name
54
- utils.safe_make_dir(write_to)
55
-
56
- write_to_path = Path(write_to)
57
- run_id = run_log.run_id
58
- json_file_path = write_to_path / f"{run_id}.json"
59
-
60
- with json_file_path.open("w") as fw:
61
- json.dump(run_log.model_dump(), fw, ensure_ascii=True, indent=4) # pylint: disable=no-member
62
-
63
- def get_from_folder(self, run_id: str) -> RunLog:
64
- """
65
- Look into the run log folder for the run log for the run id.
66
-
67
- If the run log does not exist, raise an exception. If it does, decode it
68
- as a RunLog and return it
45
+ @abstractmethod
46
+ def write_to_path(self, run_log: RunLog): ...
69
47
 
70
- Args:
71
- run_id (str): The requested run id to retrieve the run log store
72
-
73
- Raises:
74
- FileNotFoundError: If the Run Log has not been found.
75
-
76
- Returns:
77
- RunLog: The decoded Run log
78
- """
79
- write_to = self.log_folder_name
80
-
81
- read_from_path = Path(write_to)
82
- json_file_path = read_from_path / f"{run_id}.json"
83
-
84
- if not json_file_path.exists():
85
- raise FileNotFoundError(f"Expected {json_file_path} is not present")
86
-
87
- with json_file_path.open("r") as fr:
88
- json_str = json.load(fr)
89
- run_log = RunLog(**json_str) # pylint: disable=no-member
90
- return run_log
48
+ @abstractmethod
49
+ def read_from_path(self, run_id: str) -> RunLog: ...
91
50
 
92
51
  def create_run_log(
93
52
  self,
@@ -116,7 +75,7 @@ class FileSystemRunLogstore(BaseRunLogStore):
116
75
  tag=tag,
117
76
  status=status,
118
77
  )
119
- self.write_to_folder(run_log)
78
+ self.write_to_path(run_log)
120
79
  return run_log
121
80
 
122
81
  def get_run_log_by_id(
@@ -130,7 +89,7 @@ class FileSystemRunLogstore(BaseRunLogStore):
130
89
  """
131
90
  try:
132
91
  logger.info(f"{self.service_name} Getting a Run Log for : {run_id}")
133
- run_log = self.get_from_folder(run_id)
92
+ run_log = self.read_from_path(run_id)
134
93
  return run_log
135
94
  except FileNotFoundError as e:
136
95
  raise exceptions.RunLogNotFoundError(run_id) from e
@@ -142,4 +101,4 @@ class FileSystemRunLogstore(BaseRunLogStore):
142
101
  logger.info(
143
102
  f"{self.service_name} Putting the run log in the DB: {run_log.run_id}"
144
103
  )
145
- self.write_to_folder(run_log)
104
+ self.write_to_path(run_log)
@@ -2,14 +2,16 @@ import json
2
2
  import logging
3
3
  from pathlib import Path
4
4
  from string import Template
5
- from typing import Any, Dict, Optional, Sequence, Union
5
+ from typing import Any, Dict, Optional, Union
6
+
7
+ from cloudpathlib import CloudPath
6
8
 
7
9
  from extensions.run_log_store.generic_chunked import ChunkedRunLogStore
8
10
  from runnable import defaults, utils
9
11
 
10
12
  logger = logging.getLogger(defaults.LOGGER_NAME)
11
13
 
12
- T = Union[str, Path]
14
+ MixT = Union[CloudPath, Path]
13
15
 
14
16
 
15
17
  class ChunkedFileSystemRunLogStore(ChunkedRunLogStore):
@@ -28,7 +30,7 @@ class ChunkedFileSystemRunLogStore(ChunkedRunLogStore):
28
30
 
29
31
  def get_matches(
30
32
  self, run_id: str, name: str, multiple_allowed: bool = False
31
- ) -> Optional[Union[Sequence[T], T]]:
33
+ ) -> Optional[Union[list[Path], list[CloudPath], MixT]]:
32
34
  """
33
35
  Get contents of files matching the pattern name*
34
36
 
@@ -78,7 +80,7 @@ class ChunkedFileSystemRunLogStore(ChunkedRunLogStore):
78
80
 
79
81
  return str(name) + ".json"
80
82
 
81
- def _store(self, run_id: str, contents: dict, name: Union[Path, str], insert=False):
83
+ def _store(self, run_id: str, contents: dict, name: MixT, insert=False):
82
84
  """
83
85
  Store the contents against the name in the folder.
84
86
 
@@ -87,15 +89,16 @@ class ChunkedFileSystemRunLogStore(ChunkedRunLogStore):
87
89
  contents (dict): The dict to store
88
90
  name (str): The name to store as
89
91
  """
92
+ log_folder_with_run_id = self.log_folder_with_run_id(run_id=run_id)
90
93
  if insert:
91
- name = self.log_folder_with_run_id(run_id=run_id) / name
94
+ name = log_folder_with_run_id / name
92
95
 
93
- utils.safe_make_dir(self.log_folder_with_run_id(run_id=run_id))
96
+ utils.safe_make_dir(log_folder_with_run_id)
94
97
 
95
- with open(self.safe_suffix_json(name), "w") as fw:
98
+ with open(log_folder_with_run_id / self.safe_suffix_json(name.name), "w") as fw:
96
99
  json.dump(contents, fw, ensure_ascii=True, indent=4)
97
100
 
98
- def _retrieve(self, name: Union[str, Path]) -> dict:
101
+ def _retrieve(self, run_id: str, name: MixT) -> dict:
99
102
  """
100
103
  Does the job of retrieving from the folder.
101
104
 
@@ -106,8 +109,9 @@ class ChunkedFileSystemRunLogStore(ChunkedRunLogStore):
106
109
  dict: The contents
107
110
  """
108
111
  contents: dict = {}
112
+ log_folder_with_run_id = self.log_folder_with_run_id(run_id=run_id)
109
113
 
110
- with open(self.safe_suffix_json(name), "r") as fr:
114
+ with open(log_folder_with_run_id / self.safe_suffix_json(name.name), "r") as fr:
111
115
  contents = json.load(fr)
112
116
 
113
117
  return contents
@@ -0,0 +1,91 @@
1
+ import json
2
+ import logging
3
+ from pathlib import Path
4
+ from typing import Any, Dict
5
+
6
+ from extensions.run_log_store.any_path import AnyPathRunLogStore
7
+ from runnable import defaults, utils
8
+ from runnable.datastore import RunLog
9
+
10
+ logger = logging.getLogger(defaults.LOGGER_NAME)
11
+
12
+
13
+ class FileSystemRunLogstore(AnyPathRunLogStore):
14
+ """
15
+ In this type of Run Log store, we use a file system to store the JSON run log.
16
+
17
+ Every single run is stored as a different file which makes it compatible across other store types.
18
+
19
+ When to use:
20
+ When locally testing a pipeline and have the need to compare across runs.
21
+ Its fully featured and perfectly fine if your local environment is where you would do everything.
22
+
23
+ Do not use:
24
+ If you need parallelization on local, this run log would not support it.
25
+
26
+ Example config:
27
+
28
+ run_log:
29
+ type: file-system
30
+ config:
31
+ log_folder: The folder to out the logs. Defaults to .run_log_store
32
+
33
+ """
34
+
35
+ service_name: str = "file-system"
36
+ log_folder: str = defaults.LOG_LOCATION_FOLDER
37
+
38
+ @property
39
+ def log_folder_name(self):
40
+ return self.log_folder
41
+
42
+ def get_summary(self) -> Dict[str, Any]:
43
+ summary = {"Type": self.service_name, "Location": self.log_folder}
44
+
45
+ return summary
46
+
47
+ def write_to_path(self, run_log: RunLog):
48
+ """
49
+ Write the run log to the folder
50
+
51
+ Args:
52
+ run_log (RunLog): The run log to be added to the database
53
+ """
54
+ write_to = self.log_folder_name
55
+ utils.safe_make_dir(write_to)
56
+
57
+ write_to_path = Path(write_to)
58
+ run_id = run_log.run_id
59
+ json_file_path = write_to_path / f"{run_id}.json"
60
+
61
+ with json_file_path.open("w") as fw:
62
+ json.dump(run_log.model_dump(), fw, ensure_ascii=True, indent=4) # pylint: disable=no-member
63
+
64
+ def read_from_path(self, run_id: str) -> RunLog:
65
+ """
66
+ Look into the run log folder for the run log for the run id.
67
+
68
+ If the run log does not exist, raise an exception. If it does, decode it
69
+ as a RunLog and return it
70
+
71
+ Args:
72
+ run_id (str): The requested run id to retrieve the run log store
73
+
74
+ Raises:
75
+ FileNotFoundError: If the Run Log has not been found.
76
+
77
+ Returns:
78
+ RunLog: The decoded Run log
79
+ """
80
+ write_to = self.log_folder_name
81
+
82
+ read_from_path = Path(write_to)
83
+ json_file_path = read_from_path / f"{run_id}.json"
84
+
85
+ if not json_file_path.exists():
86
+ raise FileNotFoundError(f"Expected {json_file_path} is not present")
87
+
88
+ with json_file_path.open("r") as fr:
89
+ json_str = json.load(fr)
90
+ run_log = RunLog(**json_str) # pylint: disable=no-member
91
+ return run_log
@@ -4,7 +4,9 @@ from abc import abstractmethod
4
4
  from enum import Enum
5
5
  from pathlib import Path
6
6
  from string import Template
7
- from typing import Any, Dict, Optional, Sequence, Union
7
+ from typing import Any, Dict, Optional, Union
8
+
9
+ from cloudpathlib import CloudPath
8
10
 
9
11
  from runnable import defaults, exceptions
10
12
  from runnable.datastore import (
@@ -21,7 +23,7 @@ from runnable.datastore import (
21
23
  logger = logging.getLogger(defaults.LOGGER_NAME)
22
24
 
23
25
 
24
- T = Union[str, Path] # Holds str, path
26
+ MixT = Union[CloudPath, Path] # Holds str, path
25
27
 
26
28
 
27
29
  class EntityNotFoundError(Exception):
@@ -87,7 +89,7 @@ class ChunkedRunLogStore(BaseRunLogStore):
87
89
  @abstractmethod
88
90
  def get_matches(
89
91
  self, run_id: str, name: str, multiple_allowed: bool = False
90
- ) -> Optional[Union[Sequence[T], T]]:
92
+ ) -> Optional[Union[list[Path], list[CloudPath], MixT]]:
91
93
  """
92
94
  Get contents of persistence layer matching the pattern name*
93
95
 
@@ -98,7 +100,7 @@ class ChunkedRunLogStore(BaseRunLogStore):
98
100
  ...
99
101
 
100
102
  @abstractmethod
101
- def _store(self, run_id: str, contents: dict, name: T, insert: bool = False):
103
+ def _store(self, run_id: str, contents: dict, name: MixT, insert: bool = False):
102
104
  """
103
105
  Store the contents against the name in the persistence layer.
104
106
 
@@ -110,7 +112,7 @@ class ChunkedRunLogStore(BaseRunLogStore):
110
112
  ...
111
113
 
112
114
  @abstractmethod
113
- def _retrieve(self, name: T) -> dict:
115
+ def _retrieve(self, run_id: str, name: MixT) -> dict:
114
116
  """
115
117
  Does the job of retrieving from the persistent layer.
116
118
 
@@ -140,7 +142,7 @@ class ChunkedRunLogStore(BaseRunLogStore):
140
142
  insert = False
141
143
 
142
144
  if match:
143
- existing_contents = self._retrieve(name=match) # type: ignore
145
+ existing_contents = self._retrieve(run_id=run_id, name=match) # type: ignore
144
146
  contents = dict(existing_contents, **contents)
145
147
  name_to_give = match # type: ignore
146
148
  else:
@@ -149,7 +151,9 @@ class ChunkedRunLogStore(BaseRunLogStore):
149
151
  )
150
152
  insert = True
151
153
 
152
- self._store(run_id=run_id, contents=contents, name=name_to_give, insert=insert)
154
+ self._store(
155
+ run_id=run_id, contents=contents, name=Path(name_to_give), insert=insert
156
+ )
153
157
 
154
158
  def retrieve(
155
159
  self, run_id: str, log_type: LogTypes, name: str = "", multiple_allowed=False
@@ -190,13 +194,13 @@ class ChunkedRunLogStore(BaseRunLogStore):
190
194
 
191
195
  if matches:
192
196
  if not multiple_allowed:
193
- contents = self._retrieve(name=matches) # type: ignore
197
+ contents = self._retrieve(run_id=run_id, name=matches) # type: ignore
194
198
  model = self.ModelTypes[log_type.name].value
195
199
  return model(**contents)
196
200
 
197
201
  models = []
198
202
  for match in matches: # type: ignore
199
- contents = self._retrieve(name=match)
203
+ contents = self._retrieve(run_id=run_id, name=match)
200
204
  model = self.ModelTypes[log_type.name].value
201
205
  models.append(model(**contents))
202
206
  return models
@@ -225,7 +229,9 @@ class ChunkedRunLogStore(BaseRunLogStore):
225
229
  # No branch logs are found
226
230
  return {}
227
231
  # Forcing get_matches to always return a list is a better design
228
- epoch_created = [str(match).split("-")[-1] for match in matches] # type: ignore
232
+
233
+ assert isinstance(matches, list)
234
+ epoch_created = [str(match).split("-")[-1] for match in matches]
229
235
 
230
236
  # sort matches by epoch created
231
237
  epoch_created, matches = zip(*sorted(zip(epoch_created, matches))) # type: ignore
@@ -234,7 +240,7 @@ class ChunkedRunLogStore(BaseRunLogStore):
234
240
 
235
241
  for match in matches:
236
242
  model = self.ModelTypes[log_type.name].value
237
- log_model = model(**self._retrieve(match))
243
+ log_model = model(**self._retrieve(run_id=run_id, name=match))
238
244
  logs[log_model.internal_name] = log_model # type: ignore
239
245
 
240
246
  return logs
@@ -0,0 +1,111 @@
1
+ import json
2
+ import logging
3
+ from functools import lru_cache
4
+ from typing import Any, Dict
5
+
6
+ from cloudpathlib import S3Client, S3Path
7
+ from pydantic import Field, SecretStr
8
+
9
+ from extensions.run_log_store.any_path import AnyPathRunLogStore
10
+ from runnable import defaults
11
+ from runnable.datastore import RunLog
12
+
13
+ logger = logging.getLogger(defaults.LOGGER_NAME)
14
+
15
+
16
+ @lru_cache
17
+ def get_minio_client(
18
+ endpoint_url: str, aws_access_key_id: str, aws_secret_access_key: str
19
+ ) -> S3Client:
20
+ return S3Client(
21
+ endpoint_url=endpoint_url,
22
+ aws_access_key_id=aws_access_key_id,
23
+ aws_secret_access_key=aws_secret_access_key,
24
+ )
25
+
26
+
27
+ class MinioRunLogStore(AnyPathRunLogStore):
28
+ """
29
+ In this type of Run Log store, we use a file system to store the JSON run log.
30
+
31
+ Every single run is stored as a different file which makes it compatible across other store types.
32
+
33
+ When to use:
34
+ When locally testing a pipeline and have the need to compare across runs.
35
+ Its fully featured and perfectly fine if your local environment is where you would do everything.
36
+
37
+ Do not use:
38
+ If you need parallelization on local, this run log would not support it.
39
+
40
+ Example config:
41
+
42
+ run_log:
43
+ type: file-system
44
+ config:
45
+ log_folder: The folder to out the logs. Defaults to .run_log_store
46
+
47
+ """
48
+
49
+ service_name: str = "file-system"
50
+
51
+ endpoint_url: str = Field(default="http://localhost:9002")
52
+ aws_access_key_id: SecretStr = SecretStr(secret_value="minioadmin")
53
+ aws_secret_access_key: SecretStr = SecretStr(secret_value="minioadmin")
54
+ bucket: str = Field(default="runnable/run-logs")
55
+
56
+ def get_summary(self) -> Dict[str, Any]:
57
+ summary = {"Type": self.service_name, "Location": self.log_folder}
58
+
59
+ return summary
60
+
61
+ def get_run_log_bucket(self) -> S3Path:
62
+ run_id = self._context.run_id
63
+
64
+ return S3Path(
65
+ f"s3://{self.bucket}/{run_id}/",
66
+ client=get_minio_client(
67
+ self.endpoint_url,
68
+ self.aws_access_key_id.get_secret_value(),
69
+ self.aws_secret_access_key.get_secret_value(),
70
+ ),
71
+ )
72
+
73
+ def write_to_path(self, run_log: RunLog):
74
+ """
75
+ Write the run log to the folder
76
+
77
+ Args:
78
+ run_log (RunLog): The run log to be added to the database
79
+ """
80
+ run_log_bucket = self.get_run_log_bucket()
81
+ run_log_bucket.mkdir(parents=True, exist_ok=True)
82
+
83
+ run_log_object = run_log_bucket / f"{run_log.run_id}.json"
84
+ run_log_object.write_text(
85
+ json.dumps(run_log.model_dump_json(), ensure_ascii=True, indent=4)
86
+ )
87
+
88
+ def read_from_path(self, run_id: str) -> RunLog:
89
+ """
90
+ Look into the run log folder for the run log for the run id.
91
+
92
+ If the run log does not exist, raise an exception. If it does, decode it
93
+ as a RunLog and return it
94
+
95
+ Args:
96
+ run_id (str): The requested run id to retrieve the run log store
97
+
98
+ Raises:
99
+ FileNotFoundError: If the Run Log has not been found.
100
+
101
+ Returns:
102
+ RunLog: The decoded Run log
103
+ """
104
+ run_log_bucket = self.get_run_log_bucket()
105
+
106
+ run_log_object = run_log_bucket / f"{run_id}.json"
107
+
108
+ run_log_text = json.loads(run_log_object.read_text())
109
+ run_log = RunLog(**json.loads(run_log_text))
110
+
111
+ return run_log
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "runnable"
3
- version = "0.26.0"
3
+ version = "0.27.0"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -122,6 +122,7 @@ include = [
122
122
  [project.entry-points.'run_log_store']
123
123
  "buffered" = "runnable.datastore:BufferRunLogstore"
124
124
  file-system = "extensions.run_log_store.file_system:FileSystemRunLogstore"
125
+ "minio" = "extensions.run_log_store.minio:MinioRunLogStore"
125
126
  "chunked-fs" = "extensions.run_log_store.chunked_fs:ChunkedFileSystemRunLogStore"
126
127
 
127
128
  [project.entry-points.'pickler']
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes