runnable 0.3.0__tar.gz → 0.7.2__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. {runnable-0.3.0 → runnable-0.7.2}/PKG-INFO +24 -8
  2. {runnable-0.3.0 → runnable-0.7.2}/README.md +22 -5
  3. {runnable-0.3.0 → runnable-0.7.2}/pyproject.toml +25 -17
  4. {runnable-0.3.0 → runnable-0.7.2}/runnable/__init__.py +13 -15
  5. {runnable-0.3.0 → runnable-0.7.2}/runnable/cli.py +1 -4
  6. {runnable-0.3.0 → runnable-0.7.2}/runnable/context.py +2 -2
  7. {runnable-0.3.0 → runnable-0.7.2}/runnable/datastore.py +65 -23
  8. {runnable-0.3.0 → runnable-0.7.2}/runnable/defaults.py +4 -2
  9. {runnable-0.3.0 → runnable-0.7.2}/runnable/entrypoints.py +8 -16
  10. {runnable-0.3.0 → runnable-0.7.2}/runnable/executor.py +3 -44
  11. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/__init__.py +32 -171
  12. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/mocked/implementation.py +4 -59
  13. runnable-0.7.2/runnable/extensions/executor/retry/implementation.py +158 -0
  14. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/nodes.py +84 -82
  15. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/run_log_store/file_system/implementation.py +0 -2
  16. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/run_log_store/generic_chunked.py +0 -2
  17. runnable-0.7.2/runnable/extensions/secrets/env_secrets/__init__.py +0 -0
  18. {runnable-0.3.0 → runnable-0.7.2}/runnable/nodes.py +6 -6
  19. {runnable-0.3.0 → runnable-0.7.2}/runnable/parameters.py +13 -80
  20. {runnable-0.3.0 → runnable-0.7.2}/runnable/sdk.py +169 -32
  21. runnable-0.7.2/runnable/tasks.py +466 -0
  22. {runnable-0.3.0 → runnable-0.7.2}/runnable/utils.py +0 -15
  23. runnable-0.3.0/runnable/interaction.py +0 -404
  24. runnable-0.3.0/runnable/tasks.py +0 -395
  25. {runnable-0.3.0 → runnable-0.7.2}/LICENSE +0 -0
  26. {runnable-0.3.0 → runnable-0.7.2}/runnable/catalog.py +0 -0
  27. {runnable-0.3.0 → runnable-0.7.2}/runnable/exceptions.py +0 -0
  28. {runnable-0.3.0 → runnable-0.7.2}/runnable/experiment_tracker.py +0 -0
  29. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/__init__.py +0 -0
  30. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/catalog/__init__.py +0 -0
  31. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/catalog/file_system/__init__.py +0 -0
  32. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/catalog/file_system/implementation.py +0 -0
  33. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/catalog/k8s_pvc/__init__.py +0 -0
  34. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/catalog/k8s_pvc/implementation.py +0 -0
  35. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/catalog/k8s_pvc/integration.py +0 -0
  36. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/argo/__init__.py +0 -0
  37. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/argo/implementation.py +0 -0
  38. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/argo/specification.yaml +0 -0
  39. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/k8s_job/__init__.py +0 -0
  40. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/k8s_job/implementation_FF.py +0 -0
  41. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/k8s_job/integration_FF.py +0 -0
  42. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/local/__init__.py +0 -0
  43. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/local/implementation.py +0 -0
  44. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/local_container/__init__.py +0 -0
  45. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/local_container/implementation.py +0 -0
  46. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/executor/mocked/__init__.py +0 -0
  47. {runnable-0.3.0/runnable/extensions/experiment_tracker → runnable-0.7.2/runnable/extensions/executor/retry}/__init__.py +0 -0
  48. {runnable-0.3.0/runnable/extensions/experiment_tracker/mlflow → runnable-0.7.2/runnable/extensions/experiment_tracker}/__init__.py +0 -0
  49. {runnable-0.3.0/runnable/extensions/run_log_store → runnable-0.7.2/runnable/extensions/experiment_tracker/mlflow}/__init__.py +0 -0
  50. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/experiment_tracker/mlflow/implementation.py +0 -0
  51. {runnable-0.3.0/runnable/extensions/run_log_store/chunked_file_system → runnable-0.7.2/runnable/extensions/run_log_store}/__init__.py +0 -0
  52. {runnable-0.3.0/runnable/extensions/run_log_store/chunked_k8s_pvc → runnable-0.7.2/runnable/extensions/run_log_store/chunked_file_system}/__init__.py +0 -0
  53. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/run_log_store/chunked_file_system/implementation.py +0 -0
  54. {runnable-0.3.0/runnable/extensions/run_log_store/file_system → runnable-0.7.2/runnable/extensions/run_log_store/chunked_k8s_pvc}/__init__.py +0 -0
  55. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/run_log_store/chunked_k8s_pvc/implementation.py +0 -0
  56. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/run_log_store/chunked_k8s_pvc/integration.py +0 -0
  57. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/run_log_store/db/implementation_FF.py +0 -0
  58. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/run_log_store/db/integration_FF.py +0 -0
  59. {runnable-0.3.0/runnable/extensions/run_log_store/k8s_pvc → runnable-0.7.2/runnable/extensions/run_log_store/file_system}/__init__.py +0 -0
  60. {runnable-0.3.0/runnable/extensions/secrets → runnable-0.7.2/runnable/extensions/run_log_store/k8s_pvc}/__init__.py +0 -0
  61. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/run_log_store/k8s_pvc/implementation.py +0 -0
  62. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/run_log_store/k8s_pvc/integration.py +0 -0
  63. {runnable-0.3.0/runnable/extensions/secrets/dotenv → runnable-0.7.2/runnable/extensions/secrets}/__init__.py +0 -0
  64. {runnable-0.3.0/runnable/extensions/secrets/env_secrets → runnable-0.7.2/runnable/extensions/secrets/dotenv}/__init__.py +0 -0
  65. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/secrets/dotenv/implementation.py +0 -0
  66. {runnable-0.3.0 → runnable-0.7.2}/runnable/extensions/secrets/env_secrets/implementation.py +0 -0
  67. {runnable-0.3.0 → runnable-0.7.2}/runnable/graph.py +0 -0
  68. {runnable-0.3.0 → runnable-0.7.2}/runnable/integration.py +0 -0
  69. {runnable-0.3.0 → runnable-0.7.2}/runnable/names.py +0 -0
  70. {runnable-0.3.0 → runnable-0.7.2}/runnable/pickler.py +0 -0
  71. {runnable-0.3.0 → runnable-0.7.2}/runnable/secrets.py +0 -0
@@ -1,15 +1,14 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: runnable
3
- Version: 0.3.0
3
+ Version: 0.7.2
4
4
  Summary: A Compute agnostic pipelining software
5
5
  Home-page: https://github.com/vijayvammi/runnable
6
6
  License: Apache-2.0
7
7
  Author: Vijay Vammi
8
8
  Author-email: mesanthu@gmail.com
9
- Requires-Python: >=3.8,<3.13
9
+ Requires-Python: >=3.9,<3.13
10
10
  Classifier: License :: OSI Approved :: Apache Software License
11
11
  Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.8
13
12
  Classifier: Programming Language :: Python :: 3.9
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
@@ -36,22 +35,39 @@ Description-Content-Type: text/markdown
36
35
 
37
36
 
38
37
 
39
- # Hello from runnable
40
38
 
41
39
 
42
40
  <p align="center">
43
- <img src="https://github.com/AstraZeneca/runnable-core/blob/main/assets/logo-readme.png?raw=true" alt="Logo"/>
41
+
42
+ ,////,
43
+ /// 6|
44
+ // _|
45
+ _/_,-'
46
+ _.-/'/ \ ,/;,
47
+ ,-' /' \_ \ / _/
48
+ `\ / _/\ ` /
49
+ | /, `\_/
50
+ | \'
51
+ /\_ /` /\
52
+ /' /_``--.__/\ `,. / \
53
+ |_/` `-._ `\/ `\ `.
54
+ `-.__/' `\ |
55
+ `\ \
56
+ `\ \
57
+ \_\__
58
+ \___)
59
+
44
60
  </p>
45
61
  <hr style="border:2px dotted orange">
46
62
 
47
63
  <p align="center">
48
64
  <a href="https://pypi.org/project/runnable/"><img alt="python:" src="https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10-blue.svg"></a>
49
65
  <a href="https://pypi.org/project/runnable/"><img alt="Pypi" src="https://badge.fury.io/py/runnable.svg"></a>
50
- <a href="https://github.com/AstraZeneca/runnable-core/blob/main/LICENSE"><img alt"License" src="https://img.shields.io/badge/license-Apache%202.0-blue.svg"></a>
66
+ <a href="https://github.com/vijayvammi/runnable/blob/main/LICENSE"><img alt"License" src="https://img.shields.io/badge/license-Apache%202.0-blue.svg"></a>
51
67
  <a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
52
68
  <a href="https://github.com/python/mypy"><img alt="MyPy Checked" src="https://www.mypy-lang.org/static/mypy_badge.svg"></a>
53
- <a href="https://github.com/AstraZeneca/runnable-core/actions/workflows/release.yaml"><img alt="Tests:" src="https://github.com/AstraZeneca/runnable-core/actions/workflows/release.yaml/badge.svg">
54
- <a href="https://github.com/AstraZeneca/runnable-core/actions/workflows/docs.yaml"><img alt="Docs:" src="https://github.com/AstraZeneca/runnable-core/actions/workflows/docs.yaml/badge.svg">
69
+ <a href="https://github.com/vijayvammi/runnable/actions/workflows/release.yaml"><img alt="Tests:" src="https://github.com/vijayvammi/runnable/actions/workflows/release.yaml/badge.svg">
70
+ <a href="https://github.com/vijayvammi/runnable/actions/workflows/docs.yaml"><img alt="Docs:" src="https://github.com/vijayvammi/runnable/actions/workflows/docs.yaml/badge.svg">
55
71
  </p>
56
72
  <hr style="border:2px dotted orange">
57
73
 
@@ -1,21 +1,38 @@
1
1
 
2
2
 
3
- # Hello from runnable
4
3
 
5
4
 
6
5
  <p align="center">
7
- <img src="https://github.com/AstraZeneca/runnable-core/blob/main/assets/logo-readme.png?raw=true" alt="Logo"/>
6
+
7
+ ,////,
8
+ /// 6|
9
+ // _|
10
+ _/_,-'
11
+ _.-/'/ \ ,/;,
12
+ ,-' /' \_ \ / _/
13
+ `\ / _/\ ` /
14
+ | /, `\_/
15
+ | \'
16
+ /\_ /` /\
17
+ /' /_``--.__/\ `,. / \
18
+ |_/` `-._ `\/ `\ `.
19
+ `-.__/' `\ |
20
+ `\ \
21
+ `\ \
22
+ \_\__
23
+ \___)
24
+
8
25
  </p>
9
26
  <hr style="border:2px dotted orange">
10
27
 
11
28
  <p align="center">
12
29
  <a href="https://pypi.org/project/runnable/"><img alt="python:" src="https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10-blue.svg"></a>
13
30
  <a href="https://pypi.org/project/runnable/"><img alt="Pypi" src="https://badge.fury.io/py/runnable.svg"></a>
14
- <a href="https://github.com/AstraZeneca/runnable-core/blob/main/LICENSE"><img alt"License" src="https://img.shields.io/badge/license-Apache%202.0-blue.svg"></a>
31
+ <a href="https://github.com/vijayvammi/runnable/blob/main/LICENSE"><img alt"License" src="https://img.shields.io/badge/license-Apache%202.0-blue.svg"></a>
15
32
  <a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
16
33
  <a href="https://github.com/python/mypy"><img alt="MyPy Checked" src="https://www.mypy-lang.org/static/mypy_badge.svg"></a>
17
- <a href="https://github.com/AstraZeneca/runnable-core/actions/workflows/release.yaml"><img alt="Tests:" src="https://github.com/AstraZeneca/runnable-core/actions/workflows/release.yaml/badge.svg">
18
- <a href="https://github.com/AstraZeneca/runnable-core/actions/workflows/docs.yaml"><img alt="Docs:" src="https://github.com/AstraZeneca/runnable-core/actions/workflows/docs.yaml/badge.svg">
34
+ <a href="https://github.com/vijayvammi/runnable/actions/workflows/release.yaml"><img alt="Tests:" src="https://github.com/vijayvammi/runnable/actions/workflows/release.yaml/badge.svg">
35
+ <a href="https://github.com/vijayvammi/runnable/actions/workflows/docs.yaml"><img alt="Docs:" src="https://github.com/vijayvammi/runnable/actions/workflows/docs.yaml/badge.svg">
19
36
  </p>
20
37
  <hr style="border:2px dotted orange">
21
38
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "runnable"
3
- version = "0.3.0"
3
+ version = "0.7.2"
4
4
  description = "A Compute agnostic pipelining software"
5
5
  authors = ["Vijay Vammi <mesanthu@gmail.com>"]
6
6
  license = "Apache-2.0"
@@ -10,25 +10,25 @@ repository = "https://github.com/vijayvammi/runnable"
10
10
  documentation = "https://github.com/vijayvammi/runnable"
11
11
 
12
12
  [tool.poetry.dependencies]
13
- python = ">=3.8,<3.13"
13
+ python = ">=3.9,<3.13"
14
14
  "ruamel.yaml" = "*"
15
15
  "ruamel.yaml.clib" = "*"
16
16
  pydantic = "^2.5"
17
17
  stevedore = "^3.5.0"
18
18
  "click" = "*"
19
19
  click-plugins = "^1.1.1"
20
- typing-extensions ={ version= "*", python = "<3.8" }
21
- docker ={ version = "*", optional = true }
22
- sqlalchemy ={ version = "*", optional = true }
20
+ typing-extensions = { version = "*", python = "<3.8" }
21
+ docker = { version = "*", optional = true }
22
+ sqlalchemy = { version = "*", optional = true }
23
23
  rich = "^13.5.2"
24
- mlflow-skinny ={ version = "*", optional = true }
24
+ mlflow-skinny = { version = "*", optional = true }
25
25
  ploomber-engine = "^0.0.31"
26
26
 
27
27
  [tool.poetry.group.docs.dependencies]
28
28
  mkdocs = "*"
29
29
  mkdocs-material = "*"
30
30
  mkdocs-section-index = "^0.3.5"
31
- mkdocstrings = {extras = ["python"], version = "^0.24.0"}
31
+ mkdocstrings = { extras = ["python"], version = "^0.24.0" }
32
32
  nbconvert = "^7.13.1"
33
33
  mkdocs-click = "^0.8.1"
34
34
 
@@ -39,6 +39,13 @@ pyinstaller = "^5.13.2"
39
39
  # Run the performace tests poetry run python -m pyflame -p ./flamegraph.pl runnable/entrypoints.py
40
40
  pyflame = "^0.3.1"
41
41
 
42
+
43
+ [tool.poetry.group.tutorial.dependencies]
44
+ pandas = "^2.2.1"
45
+ numpy = "^1.26.4"
46
+ scikit-learn = "^1.4.1.post1"
47
+ en-core-web-sm = { url = "https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.7.1/en_core_web_sm-3.7.1.tar.gz" }
48
+
42
49
  [tool.poetry.extras]
43
50
  docker = ['docker']
44
51
  notebook = ['ploomber-engine']
@@ -59,7 +66,7 @@ gitlint = "^0.19.1"
59
66
 
60
67
 
61
68
  [tool.poetry.scripts]
62
- runnable= 'runnable.cli:cli'
69
+ runnable = 'runnable.cli:cli'
63
70
 
64
71
 
65
72
  # Plugins for Executors
@@ -68,6 +75,7 @@ runnable= 'runnable.cli:cli'
68
75
  "local-container" = "runnable.extensions.executor.local_container.implementation:LocalContainerExecutor"
69
76
  "argo" = "runnable.extensions.executor.argo.implementation:ArgoExecutor"
70
77
  "mocked" = "runnable.extensions.executor.mocked.implementation:MockedExecutor"
78
+ "retry" = "runnable.extensions.executor.retry.implementation:RetryExecutor"
71
79
 
72
80
  # Plugins for Catalog
73
81
  [tool.poetry.plugins."catalog"]
@@ -122,7 +130,7 @@ line-length = 120
122
130
 
123
131
  [tool.ruff]
124
132
  # Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default.
125
- select = ["E", "F","W","I001"]
133
+ select = ["E", "F", "W", "I001"]
126
134
 
127
135
  ignore = []
128
136
 
@@ -152,12 +160,14 @@ exclude = [
152
160
  "dist",
153
161
  "node_modules",
154
162
  "venv",
163
+ "examples/kubeflow",
164
+ "examples/tutorials/",
155
165
  ]
156
166
  per-file-ignores = {}
157
167
 
158
168
  # Builtins
159
169
 
160
- builtins=["__version__"]
170
+ builtins = ["__version__"]
161
171
 
162
172
  # Same as Black.
163
173
  line-length = 120
@@ -204,9 +214,7 @@ branch = true
204
214
 
205
215
  [tool.coverage.report]
206
216
  # Regexes for lines to exclude from consideration
207
- exclude_lines = [
208
- "pragma: no cover"
209
- ]
217
+ exclude_lines = ["pragma: no cover"]
210
218
 
211
219
  include_namespace_packages = true
212
220
  show_missing = true
@@ -218,10 +226,10 @@ exclude_also = [
218
226
 
219
227
  # Don't complain about abstract methods, they aren't run:
220
228
  "@(abc\\.)?abstractmethod",
221
- ]
229
+ ]
222
230
 
223
- omit =[
231
+ omit = [
224
232
  "runnable/cli.py",
225
233
  "runnable/extensions/executor/demo_renderer/*",
226
- "*FF.py"
227
- ]
234
+ "*FF.py",
235
+ ]
@@ -9,22 +9,20 @@ from runnable import defaults
9
9
  dictConfig(defaults.LOGGING_CONFIG)
10
10
  logger = logging.getLogger(defaults.LOGGER_NAME)
11
11
 
12
- from runnable.interaction import (
13
- end_interactive_session,
14
- get_experiment_tracker_context,
15
- get_from_catalog,
16
- get_object,
17
- get_parameter,
18
- get_run_id,
19
- get_run_log,
20
- get_secret,
21
- put_in_catalog,
22
- put_object,
23
- start_interactive_session,
24
- set_parameter,
25
- track_this,
12
+
13
+ from runnable.sdk import (
14
+ Stub,
15
+ Pipeline,
16
+ Parallel,
17
+ Map,
18
+ Catalog,
19
+ Success,
20
+ Fail,
21
+ PythonTask,
22
+ NotebookTask,
23
+ ShellTask,
24
+ pickled,
26
25
  ) # noqa
27
- from runnable.sdk import Stub, Pipeline, Task, Parallel, Map, Catalog, Success, Fail # noqa
28
26
 
29
27
 
30
28
  # TODO: Think of model registry as a central place to store models.
@@ -41,8 +41,7 @@ def cli():
41
41
  )
42
42
  @click.option("--tag", default="", help="A tag attached to the run")
43
43
  @click.option("--run-id", help="An optional run_id, one would be generated if not provided")
44
- @click.option("--use-cached", help="Provide the previous run_id to re-run.", show_default=True)
45
- def execute(file, config_file, parameters_file, log_level, tag, run_id, use_cached): # pragma: no cover
44
+ def execute(file, config_file, parameters_file, log_level, tag, run_id): # pragma: no cover
46
45
  """
47
46
  Execute a pipeline
48
47
 
@@ -59,7 +58,6 @@ def execute(file, config_file, parameters_file, log_level, tag, run_id, use_cach
59
58
  [default: ]
60
59
  --run-id TEXT An optional run_id, one would be generated if not
61
60
  provided
62
- --use-cached TEXT Provide the previous run_id to re-run.
63
61
  """
64
62
  logger.setLevel(log_level)
65
63
  entrypoints.execute(
@@ -67,7 +65,6 @@ def execute(file, config_file, parameters_file, log_level, tag, run_id, use_cach
67
65
  pipeline_file=file,
68
66
  tag=tag,
69
67
  run_id=run_id,
70
- use_cached=use_cached,
71
68
  parameters_file=parameters_file,
72
69
  )
73
70
 
@@ -7,6 +7,7 @@ from runnable.datastore import BaseRunLogStore
7
7
  from runnable.executor import BaseExecutor
8
8
  from runnable.experiment_tracker import BaseExperimentTracker
9
9
  from runnable.graph import Graph
10
+ from runnable.pickler import BasePickler
10
11
  from runnable.secrets import BaseSecrets
11
12
 
12
13
 
@@ -16,6 +17,7 @@ class Context(BaseModel):
16
17
  secrets_handler: SerializeAsAny[BaseSecrets]
17
18
  catalog_handler: SerializeAsAny[BaseCatalog]
18
19
  experiment_tracker: SerializeAsAny[BaseExperimentTracker]
20
+ pickler: SerializeAsAny[BasePickler]
19
21
 
20
22
  pipeline_file: Optional[str] = ""
21
23
  parameters_file: Optional[str] = ""
@@ -24,8 +26,6 @@ class Context(BaseModel):
24
26
  tag: str = ""
25
27
  run_id: str = ""
26
28
  variables: Dict[str, str] = {}
27
- use_cached: bool = False
28
- original_run_id: str = ""
29
29
  dag: Optional[Graph] = None
30
30
  dag_hash: str = ""
31
31
  execution_plan: str = ""
@@ -1,10 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
+ import os
4
5
  from abc import ABC, abstractmethod
5
- from typing import Any, Dict, List, Optional, OrderedDict, Tuple, Union
6
+ from datetime import datetime
7
+ from typing import Annotated, Any, Dict, List, Literal, Optional, OrderedDict, Tuple, Union
6
8
 
7
- from pydantic import BaseModel, Field
9
+ from pydantic import BaseModel, Field, computed_field
10
+ from typing_extensions import TypeAliasType
8
11
 
9
12
  import runnable.context as context
10
13
  from runnable import defaults, exceptions
@@ -14,6 +17,11 @@ logger = logging.getLogger(defaults.LOGGER_NAME)
14
17
  # Once defined these classes are sealed to any additions unless a default is provided
15
18
  # Breaking this rule might make runnable backwardly incompatible
16
19
 
20
+ JSONType = TypeAliasType(
21
+ "JSONType",
22
+ Union[bool, int, float, str, None, List["JSONType"], Dict[str, "JSONType"]], # type: ignore
23
+ )
24
+
17
25
 
18
26
  class DataCatalog(BaseModel, extra="allow"):
19
27
  """
@@ -42,19 +50,66 @@ class DataCatalog(BaseModel, extra="allow"):
42
50
  return other.name == self.name
43
51
 
44
52
 
53
+ class JsonParameter(BaseModel):
54
+ kind: Literal["json"]
55
+ value: JSONType # type: ignore
56
+
57
+ def get_value(self) -> JSONType: # type: ignore
58
+ return self.value
59
+
60
+
61
+ class ObjectParameter(BaseModel):
62
+ kind: Literal["object"]
63
+ value: str # The name of the pickled object
64
+
65
+ @computed_field # type: ignore
66
+ @property
67
+ def description(self) -> str:
68
+ return f"Pickled object stored in catalog as: {self.value}"
69
+
70
+ @property
71
+ def file_name(self) -> str:
72
+ return f"{self.value}{context.run_context.pickler.extension}"
73
+
74
+ def get_value(self) -> Any:
75
+ # Get the pickled object
76
+ catalog_handler = context.run_context.catalog_handler
77
+
78
+ catalog_handler.get(name=self.file_name, run_id=context.run_context.run_id)
79
+ obj = context.run_context.pickler.load(path=self.file_name)
80
+ os.remove(self.file_name) # Remove after loading
81
+ return obj
82
+
83
+ def put_object(self, data: Any) -> None:
84
+ context.run_context.pickler.dump(data=data, path=self.file_name)
85
+
86
+ catalog_handler = context.run_context.catalog_handler
87
+ catalog_handler.put(name=self.file_name, run_id=context.run_context.run_id)
88
+ os.remove(self.file_name) # Remove after loading
89
+
90
+
91
+ Parameter = Annotated[Union[JsonParameter, ObjectParameter], Field(discriminator="kind")]
92
+
93
+
45
94
  class StepAttempt(BaseModel):
46
95
  """
47
96
  The captured attributes of an Attempt of a step.
48
97
  """
49
98
 
50
- attempt_number: int = 0
99
+ attempt_number: int = 1
51
100
  start_time: str = ""
52
101
  end_time: str = ""
53
- duration: str = "" #  end_time - start_time
54
102
  status: str = "FAIL"
55
103
  message: str = ""
56
- input_parameters: Dict[str, Any] = Field(default_factory=dict)
57
- output_parameters: Dict[str, Any] = Field(default_factory=dict)
104
+ input_parameters: Dict[str, Parameter] = Field(default_factory=dict)
105
+ output_parameters: Dict[str, Parameter] = Field(default_factory=dict)
106
+
107
+ @property
108
+ def duration(self):
109
+ start = datetime.fromisoformat(self.start_time)
110
+ end = datetime.fromisoformat(self.end_time)
111
+
112
+ return str(end - start)
58
113
 
59
114
 
60
115
  class CodeIdentity(BaseModel, extra="allow"):
@@ -169,12 +224,10 @@ class RunLog(BaseModel):
169
224
 
170
225
  run_id: str
171
226
  dag_hash: Optional[str] = None
172
- use_cached: bool = False
173
227
  tag: Optional[str] = ""
174
- original_run_id: Optional[str] = ""
175
228
  status: str = defaults.FAIL
176
229
  steps: OrderedDict[str, StepLog] = Field(default_factory=OrderedDict)
177
- parameters: Dict[str, Any] = Field(default_factory=dict)
230
+ parameters: Dict[str, Parameter] = Field(default_factory=dict)
178
231
  run_config: Dict[str, Any] = Field(default_factory=dict)
179
232
 
180
233
  def get_data_catalogs_by_stage(self, stage: str = "put") -> List[DataCatalog]:
@@ -374,7 +427,7 @@ class BaseRunLogStore(ABC, BaseModel):
374
427
  run_log.status = status
375
428
  self.put_run_log(run_log)
376
429
 
377
- def get_parameters(self, run_id: str, **kwargs) -> dict:
430
+ def get_parameters(self, run_id: str, **kwargs) -> Dict[str, Parameter]:
378
431
  """
379
432
  Get the parameters from the Run log defined by the run_id
380
433
 
@@ -393,7 +446,7 @@ class BaseRunLogStore(ABC, BaseModel):
393
446
  run_log = self.get_run_log_by_id(run_id=run_id)
394
447
  return run_log.parameters
395
448
 
396
- def set_parameters(self, run_id: str, parameters: dict, **kwargs):
449
+ def set_parameters(self, run_id: str, parameters: Dict[str, Parameter], **kwargs):
397
450
  """
398
451
  Update the parameters of the Run log with the new parameters
399
452
 
@@ -580,16 +633,7 @@ class BaseRunLogStore(ABC, BaseModel):
580
633
  step.branches[internal_branch_name] = branch_log # type: ignore
581
634
  self.put_run_log(run_log)
582
635
 
583
- def create_attempt_log(self, **kwargs) -> StepAttempt:
584
- """
585
- Returns an uncommitted step attempt log.
586
-
587
- Returns:
588
- StepAttempt: An uncommitted step attempt log
589
- """
590
- logger.info(f"{self.service_name} Creating an attempt log")
591
- return StepAttempt()
592
-
636
+ #
593
637
  def create_code_identity(self, **kwargs) -> CodeIdentity:
594
638
  """
595
639
  Creates an uncommitted Code identity class
@@ -659,9 +703,7 @@ class BufferRunLogstore(BaseRunLogStore):
659
703
  self.run_log = RunLog(
660
704
  run_id=run_id,
661
705
  dag_hash=dag_hash,
662
- use_cached=use_cached,
663
706
  tag=tag,
664
- original_run_id=original_run_id,
665
707
  status=status,
666
708
  )
667
709
  return self.run_log
@@ -35,12 +35,13 @@ class ServiceConfig(TypedDict):
35
35
  config: Mapping[str, Any]
36
36
 
37
37
 
38
- class runnableConfig(TypedDict, total=False):
38
+ class RunnableConfig(TypedDict, total=False):
39
39
  run_log_store: Optional[ServiceConfig]
40
40
  secrets: Optional[ServiceConfig]
41
41
  catalog: Optional[ServiceConfig]
42
42
  executor: Optional[ServiceConfig]
43
43
  experiment_tracker: Optional[ServiceConfig]
44
+ pickler: Optional[ServiceConfig]
44
45
 
45
46
 
46
47
  TypeMapVariable: TypeAlias = Optional[Dict[str, Union[str, int, float]]]
@@ -81,10 +82,11 @@ DEFAULT_CONTAINER_OUTPUT_PARAMETERS = "parameters.json"
81
82
 
82
83
  # Default services
83
84
  DEFAULT_EXECUTOR = ServiceConfig(type="local", config={})
84
- DEFAULT_RUN_LOG_STORE = ServiceConfig(type="buffered", config={})
85
+ DEFAULT_RUN_LOG_STORE = ServiceConfig(type="file-system", config={})
85
86
  DEFAULT_CATALOG = ServiceConfig(type="file-system", config={})
86
87
  DEFAULT_SECRETS = ServiceConfig(type="do-nothing", config={})
87
88
  DEFAULT_EXPERIMENT_TRACKER = ServiceConfig(type="do-nothing", config={})
89
+ DEFAULT_PICKLER = ServiceConfig(type="pickle", config={})
88
90
 
89
91
  # Map state
90
92
  MAP_PLACEHOLDER = "map_variable_placeholder"
@@ -9,12 +9,12 @@ from rich import print
9
9
 
10
10
  import runnable.context as context
11
11
  from runnable import defaults, graph, utils
12
- from runnable.defaults import ServiceConfig, runnableConfig
12
+ from runnable.defaults import RunnableConfig, ServiceConfig
13
13
 
14
14
  logger = logging.getLogger(defaults.LOGGER_NAME)
15
15
 
16
16
 
17
- def get_default_configs() -> runnableConfig:
17
+ def get_default_configs() -> RunnableConfig:
18
18
  """
19
19
  User can provide extensions as part of their code base, runnable-config.yaml provides the place to put them.
20
20
  """
@@ -37,7 +37,6 @@ def prepare_configurations(
37
37
  configuration_file: str = "",
38
38
  pipeline_file: str = "",
39
39
  tag: str = "",
40
- use_cached: str = "",
41
40
  parameters_file: str = "",
42
41
  force_local_executor: bool = False,
43
42
  ) -> context.Context:
@@ -51,7 +50,6 @@ def prepare_configurations(
51
50
  pipeline_file (str): The config/dag file
52
51
  run_id (str): The run id of the run.
53
52
  tag (str): If a tag is provided at the run time
54
- use_cached (str): Provide the run_id of the older run
55
53
 
56
54
  Returns:
57
55
  executor.BaseExecutor : A prepared executor as per the dag/config
@@ -64,7 +62,7 @@ def prepare_configurations(
64
62
  if configuration_file:
65
63
  templated_configuration = utils.load_yaml(configuration_file) or {}
66
64
 
67
- configuration: runnableConfig = cast(runnableConfig, templated_configuration)
65
+ configuration: RunnableConfig = cast(RunnableConfig, templated_configuration)
68
66
 
69
67
  # Run log settings, configuration over-rides everything
70
68
  run_log_config: Optional[ServiceConfig] = configuration.get("run_log_store", None)
@@ -84,6 +82,10 @@ def prepare_configurations(
84
82
  secrets_config = cast(ServiceConfig, runnable_defaults.get("secrets", defaults.DEFAULT_SECRETS))
85
83
  secrets_handler = utils.get_provider_by_name_and_type("secrets", secrets_config)
86
84
 
85
+ # pickler
86
+ pickler_config = cast(ServiceConfig, runnable_defaults.get("pickler", defaults.DEFAULT_PICKLER))
87
+ pickler_handler = utils.get_provider_by_name_and_type("pickler", pickler_config)
88
+
87
89
  # experiment tracker settings, configuration over-rides everything
88
90
  tracker_config: Optional[ServiceConfig] = configuration.get("experiment_tracker", None)
89
91
  if not tracker_config:
@@ -107,6 +109,7 @@ def prepare_configurations(
107
109
  run_log_store=run_log_store,
108
110
  catalog_handler=catalog_handler,
109
111
  secrets_handler=secrets_handler,
112
+ pickler=pickler_handler,
110
113
  experiment_tracker=tracker_handler,
111
114
  variables=variables,
112
115
  tag=tag,
@@ -141,11 +144,6 @@ def prepare_configurations(
141
144
  run_context.pipeline_file = pipeline_file
142
145
  run_context.dag = dag
143
146
 
144
- run_context.use_cached = False
145
- if use_cached:
146
- run_context.use_cached = True
147
- run_context.original_run_id = use_cached
148
-
149
147
  context.run_context = run_context
150
148
 
151
149
  return run_context
@@ -156,7 +154,6 @@ def execute(
156
154
  pipeline_file: str,
157
155
  tag: str = "",
158
156
  run_id: str = "",
159
- use_cached: str = "",
160
157
  parameters_file: str = "",
161
158
  ):
162
159
  # pylint: disable=R0914,R0913
@@ -168,10 +165,8 @@ def execute(
168
165
  pipeline_file (str): The config/dag file
169
166
  run_id (str): The run id of the run.
170
167
  tag (str): If a tag is provided at the run time
171
- use_cached (str): The previous run_id to use.
172
168
  parameters_file (str): The parameters being sent in to the application
173
169
  """
174
- # Re run settings
175
170
  run_id = utils.generate_run_id(run_id=run_id)
176
171
 
177
172
  run_context = prepare_configurations(
@@ -179,7 +174,6 @@ def execute(
179
174
  pipeline_file=pipeline_file,
180
175
  run_id=run_id,
181
176
  tag=tag,
182
- use_cached=use_cached,
183
177
  parameters_file=parameters_file,
184
178
  )
185
179
  print("Working with context:")
@@ -231,7 +225,6 @@ def execute_single_node(
231
225
  pipeline_file=pipeline_file,
232
226
  run_id=run_id,
233
227
  tag=tag,
234
- use_cached="",
235
228
  parameters_file=parameters_file,
236
229
  )
237
230
  print("Working with context:")
@@ -416,7 +409,6 @@ def fan(
416
409
  pipeline_file=pipeline_file,
417
410
  run_id=run_id,
418
411
  tag=tag,
419
- use_cached="",
420
412
  parameters_file=parameters_file,
421
413
  )
422
414
  print("Working with context:")