runnable 0.34.0a1__py3-none-any.whl → 1.0.0__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.

Potentially problematic release.


This version of runnable might be problematic. Click here for more details.

Files changed (49) hide show
  1. extensions/catalog/any_path.py +13 -2
  2. extensions/job_executor/__init__.py +7 -5
  3. extensions/job_executor/emulate.py +106 -0
  4. extensions/job_executor/k8s.py +8 -8
  5. extensions/job_executor/local_container.py +13 -14
  6. extensions/nodes/__init__.py +0 -0
  7. extensions/nodes/conditional.py +243 -0
  8. extensions/nodes/fail.py +72 -0
  9. extensions/nodes/map.py +350 -0
  10. extensions/nodes/parallel.py +159 -0
  11. extensions/nodes/stub.py +89 -0
  12. extensions/nodes/success.py +72 -0
  13. extensions/nodes/task.py +92 -0
  14. extensions/pipeline_executor/__init__.py +27 -27
  15. extensions/pipeline_executor/argo.py +52 -46
  16. extensions/pipeline_executor/emulate.py +112 -0
  17. extensions/pipeline_executor/local.py +4 -4
  18. extensions/pipeline_executor/local_container.py +19 -79
  19. extensions/pipeline_executor/mocked.py +5 -9
  20. extensions/pipeline_executor/retry.py +6 -10
  21. runnable/__init__.py +2 -11
  22. runnable/catalog.py +6 -23
  23. runnable/cli.py +145 -48
  24. runnable/context.py +520 -28
  25. runnable/datastore.py +51 -54
  26. runnable/defaults.py +12 -34
  27. runnable/entrypoints.py +82 -440
  28. runnable/exceptions.py +35 -34
  29. runnable/executor.py +13 -20
  30. runnable/gantt.py +1141 -0
  31. runnable/graph.py +1 -1
  32. runnable/names.py +1 -1
  33. runnable/nodes.py +20 -16
  34. runnable/parameters.py +108 -51
  35. runnable/sdk.py +125 -204
  36. runnable/tasks.py +62 -85
  37. runnable/utils.py +6 -268
  38. runnable-1.0.0.dist-info/METADATA +122 -0
  39. runnable-1.0.0.dist-info/RECORD +73 -0
  40. {runnable-0.34.0a1.dist-info → runnable-1.0.0.dist-info}/entry_points.txt +9 -8
  41. extensions/nodes/nodes.py +0 -778
  42. extensions/nodes/torch.py +0 -273
  43. extensions/nodes/torch_config.py +0 -76
  44. extensions/tasks/torch.py +0 -286
  45. extensions/tasks/torch_config.py +0 -76
  46. runnable-0.34.0a1.dist-info/METADATA +0 -267
  47. runnable-0.34.0a1.dist-info/RECORD +0 -67
  48. {runnable-0.34.0a1.dist-info → runnable-1.0.0.dist-info}/WHEEL +0 -0
  49. {runnable-0.34.0a1.dist-info → runnable-1.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: runnable
3
+ Version: 1.0.0
4
+ Summary: Add your description here
5
+ Author-email: "Vammi, Vijay" <vijay.vammi@astrazeneca.com>
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: cloudpathlib>=0.20.0
9
+ Requires-Dist: dill>=0.3.9
10
+ Requires-Dist: pydantic>=2.10.3
11
+ Requires-Dist: python-dotenv>=1.0.1
12
+ Requires-Dist: rich>=13.9.4
13
+ Requires-Dist: ruamel-yaml>=0.18.6
14
+ Requires-Dist: setuptools>=75.6.0
15
+ Requires-Dist: stevedore>=5.4.0
16
+ Requires-Dist: typer>=0.17.3
17
+ Provides-Extra: docker
18
+ Requires-Dist: docker>=7.1.0; extra == 'docker'
19
+ Provides-Extra: examples
20
+ Requires-Dist: pandas>=2.2.3; extra == 'examples'
21
+ Provides-Extra: examples-torch
22
+ Requires-Dist: torch>=2.7.1; extra == 'examples-torch'
23
+ Provides-Extra: k8s
24
+ Requires-Dist: kubernetes>=31.0.0; extra == 'k8s'
25
+ Provides-Extra: notebook
26
+ Requires-Dist: ploomber-engine>=0.0.33; extra == 'notebook'
27
+ Provides-Extra: s3
28
+ Requires-Dist: cloudpathlib[s3]; extra == 's3'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # Runnable
32
+
33
+ <img style="float: right;" alt="Runnable" src="docs/assets/sport.png" width="100" height="100">
34
+
35
+ **Transform any Python function into a portable, trackable pipeline in seconds.**
36
+
37
+ <p align="center">
38
+ <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>
39
+ <a href="https://pypi.org/project/runnable/"><img alt="Pypi" src="https://badge.fury.io/py/runnable.svg"></a>
40
+ <a href="https://github.com/AstraZeneca/runnable/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache%202.0-blue.svg"></a>
41
+ <a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
42
+ <a href="https://github.com/python/mypy"><img alt="MyPy Checked" src="https://www.mypy-lang.org/static/mypy_badge.svg"></a>
43
+ <a href="https://github.com/AstraZeneca/runnable/actions/workflows/release.yaml"><img alt="Tests:" src="https://github.com/AstraZeneca/runnable/actions/workflows/release.yaml/badge.svg">
44
+ </p>
45
+
46
+ ---
47
+
48
+ ## 🚀 30-Second Transformation
49
+
50
+ **Your existing function (unchanged!):**
51
+
52
+ ```python
53
+ def analyze_sales():
54
+ total_revenue = 50000
55
+ best_product = "widgets"
56
+ return total_revenue, best_product
57
+ ```
58
+
59
+ **Make it runnable everywhere (2 lines):**
60
+
61
+ ```python
62
+ from runnable import PythonJob
63
+ PythonJob(function=analyze_sales).execute()
64
+ ```
65
+
66
+ **🎉 Success!** Your function now runs the same on laptop, containers, and Kubernetes with automatic tracking and reproducibility.
67
+
68
+ ## 🔗 Chain Functions Without Glue Code
69
+
70
+ ```python
71
+ def load_customer_data():
72
+ return {"count": 1500, "segments": ["premium", "standard"]}
73
+
74
+ def analyze_segments(customer_data): # Name matches = automatic connection
75
+ return {"premium_pct": 30, "growth_potential": "high"}
76
+
77
+ # What Runnable needs (same logic, no glue):
78
+ from runnable import Pipeline, PythonTask
79
+ Pipeline(steps=[
80
+ PythonTask(function=load_customer_data, returns=["customer_data"]),
81
+ PythonTask(function=analyze_segments, returns=["analysis"])
82
+ ]).execute()
83
+ ```
84
+
85
+ **Same pipeline runs unchanged on laptop, containers, and Kubernetes.**
86
+
87
+ ## ⚡ Installation
88
+
89
+ ```bash
90
+ pip install runnable
91
+ ```
92
+
93
+ ## 📊 Why Choose Runnable?
94
+
95
+ - **🎯 Easy to adopt**: Your code remains as-is, no decorators or imposed structure
96
+ - **🏗️ Bring your infrastructure**: Works with your platforms, not a replacement
97
+ - **📝 Reproducibility**: Automatic tracking without additional code
98
+ - **🔁 Retry failures**: Debug anywhere, retry from failure points
99
+ - **🧪 Testing**: Mock/patch pipeline steps, test functions normally
100
+ - **💔 Move on**: Easy removal - just delete runnable files, your code stays
101
+
102
+ ## 📖 Documentation
103
+
104
+ **[Complete Documentation →](https://astrazeneca.github.io/runnable/)**
105
+
106
+ ## 🔀 Pipeline Types
107
+
108
+ ### Linear Pipelines
109
+ Simple sequential execution of Python functions, notebooks, or shell scripts.
110
+
111
+ ### Parallel Branches
112
+ Execute multiple branches simultaneously for improved performance.
113
+
114
+ ### Map Patterns
115
+ Execute pipelines over iterable parameters for batch processing.
116
+
117
+ ### Arbitrary Nesting
118
+ Combine parallel, map, and sequential patterns as needed.
119
+
120
+ ---
121
+
122
+ **Ready to get started?** Check out our [30-second demo](https://astrazeneca.github.io/runnable/) for immediate results!
@@ -0,0 +1,73 @@
1
+ extensions/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ extensions/catalog/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ extensions/catalog/any_path.py,sha256=NUZjXwOE-osR9RIpi59UC_16GZPCbkjshJL6X6hPmYw,7725
5
+ extensions/catalog/file_system.py,sha256=T_qFPFfrmykoAMc1rjNi_DBb437me8WPRcFglwAK744,1767
6
+ extensions/catalog/minio.py,sha256=R3GvfCxN1GTcs4bQIAWh79_GHDTVd14gnpKlzwFeKUI,2363
7
+ extensions/catalog/pyproject.toml,sha256=lLNxY6v04c8I5QK_zKw_E6sJTArSJRA_V-79ktaA3Hk,279
8
+ extensions/catalog/s3.py,sha256=Sw5t8_kVRprn3uGGJCiHn7M9zw1CLaCOFj6YErtfG0o,287
9
+ extensions/job_executor/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ extensions/job_executor/__init__.py,sha256=9n2V4cLgwNuci0_62BvJTGA3Gf9h-aMUlAO-mKIOqYA,5958
11
+ extensions/job_executor/emulate.py,sha256=d9KI4If0DeRkKv9iCSKyZCziK_3ARsJvs5RUFo9yigc,3220
12
+ extensions/job_executor/k8s.py,sha256=W14u1xwJDtb-gyGdNl62IwWIs49AUO2oTAAxQCm6YT0,16456
13
+ extensions/job_executor/k8s_job_spec.yaml,sha256=7aFpxHdO_p6Hkc3YxusUOuAQTD1Myu0yTPX9DrhxbOg,1158
14
+ extensions/job_executor/local.py,sha256=3ZbCFXBvbLlMp10JTmQJJrjBKG2keHI6SH8hEvmHDkA,2230
15
+ extensions/job_executor/local_container.py,sha256=uoRbsyR5QiVytWJQtF7nXUA1h8wHAaQezedWFKl3btM,6914
16
+ extensions/job_executor/pyproject.toml,sha256=UIEgiCYHTXcRWSByNMFuKJFKgxTBpQqTqyUecIsb_Vc,286
17
+ extensions/nodes/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ extensions/nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ extensions/nodes/conditional.py,sha256=lsXLerIDWJk0fHo4EEngl8rYw6dN40EgKIgdBuvt8ro,8641
20
+ extensions/nodes/fail.py,sha256=P_wryruE2INiAmu4Vf7q4fTEkfbIMnhT71Y9IrOqRkM,2170
21
+ extensions/nodes/map.py,sha256=s0l07uAc6j8MO7Fqch0DzOE3_CsV6pBNHj5E3nf1S60,13659
22
+ extensions/nodes/parallel.py,sha256=cuxpR1e0KwuxvoZaSwiiEn9YmYskplbjLBWBzzU-Ti8,5952
23
+ extensions/nodes/pyproject.toml,sha256=YTu-ETN3JNFSkMzzWeOwn4m-O2nbRH-PmiPBALDCUw4,278
24
+ extensions/nodes/stub.py,sha256=o9DjBekNa9O4b0VQOiNOA9eNjJ3C2a9Sn9d2fX7KaWg,2715
25
+ extensions/nodes/success.py,sha256=yT4WkUI-1YN6qy4Ji6zSoZFXI9jOl6Ond4WxZRq-33k,2179
26
+ extensions/nodes/task.py,sha256=m5_s5u7lQDoTmeO6CG94btrG5If9AKm2-RvOzvm0fDc,3147
27
+ extensions/pipeline_executor/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ extensions/pipeline_executor/__init__.py,sha256=JqJFGgLOUaDINUi4_xC3zoDSZxDrUYLNuHQVzr8-ByE,24620
29
+ extensions/pipeline_executor/argo.py,sha256=5nEItAv-gNVi2sylZA4spKLWfcKuJ3zyQx3RekoLb28,38240
30
+ extensions/pipeline_executor/emulate.py,sha256=ziaIzEpYgVOm2PPCY8bnRdoevMwS8OY9aEUXpwCFQR0,3547
31
+ extensions/pipeline_executor/local.py,sha256=_8dtj88mI3xeZT4UPwtHNtbyi_VVzz_lpIxvC0UZS-g,1887
32
+ extensions/pipeline_executor/local_container.py,sha256=oJsd7Pcxur2ZzaBqTN6IUk_ZnMqYkxrK65BVKo_2P2k,10262
33
+ extensions/pipeline_executor/mocked.py,sha256=ZT57hhQzOub6wUyp-uKrpDUu7iliQ0Do_jtirJb3eUY,5596
34
+ extensions/pipeline_executor/pyproject.toml,sha256=ykTX7srR10PBYb8LsIwEj8vIPPIEZQ5V_R7VYbZ-ido,291
35
+ extensions/pipeline_executor/retry.py,sha256=sBfZiS9ryw_hNCMAza82mXyV1wPjOJb20EEF9f5FUng,6790
36
+ extensions/run_log_store/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
+ extensions/run_log_store/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
+ extensions/run_log_store/any_path.py,sha256=0nN_LHbm2W6AHkerQmsVHq3EoybFQF8lxpCicacHo8Y,2861
39
+ extensions/run_log_store/chunked_fs.py,sha256=wHMKcAx6uFI4OOTp7QWCdGq9WvEFesbLp9VxHZU28l0,3341
40
+ extensions/run_log_store/chunked_minio.py,sha256=Itfkw4Ycf0uLCqxH3Uk_itmVgT7ipJp05yKfD22WBiY,4007
41
+ extensions/run_log_store/file_system.py,sha256=hhrbhSnuzv8yzBr6DAu45NT8-sawPP86WA2-LY70vjw,2781
42
+ extensions/run_log_store/generic_chunked.py,sha256=EnhRxlqm1jG-Tdxul4sY8OeCX5fK9FY2v8DZanX9-5o,20455
43
+ extensions/run_log_store/minio.py,sha256=omrKDSdRzmnVBg9xXkkdQb-icBIgBDRdpmwGRlMyCGk,3453
44
+ extensions/run_log_store/pyproject.toml,sha256=YnmXsFvFG9uv_c0spLYBsNI_1sbktqxtHsOuClyvZ3g,288
45
+ extensions/run_log_store/db/implementation_FF.py,sha256=euTnh0xzNF0e_DyfHQ4W-kG1AwTr8u7OuO3_cZkR5bM,5237
46
+ extensions/run_log_store/db/integration_FF.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
+ extensions/secrets/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
+ extensions/secrets/dotenv.py,sha256=nADHXI6KJ_LUYOIe5EbtYH-21OBebSNVr0Pjb1GlZ7w,1573
49
+ extensions/secrets/pyproject.toml,sha256=mLJNImNcBlbLKHh-0ugVWT9V83R4RibyyYDtBCSqVF4,282
50
+ runnable/__init__.py,sha256=MN9x2jmQb2eOr-rap1DXLzNSC926U-aad_YwENzG52w,509
51
+ runnable/catalog.py,sha256=6l0tT0jwHi40aE6fhQMgYtYe_-2As-bRKztAKiFvy3o,3842
52
+ runnable/cli.py,sha256=q6-5TnrOpqJmGQ8VOfm-nBT1g2UAFo-9znqNqECyZvU,12987
53
+ runnable/context.py,sha256=mLpq5rtMsPawjnaN9Woq7HWZ1FAppeudZtYMT5vf6Fo,17594
54
+ runnable/datastore.py,sha256=2pYg4i1JRMzw_CUUIsPOWt7wYPiGBamfo-CPVAkEH54,32375
55
+ runnable/defaults.py,sha256=4UYuShnjEyWP529UlFnubvkBpOcczKIdE4jEOhPBwl4,3076
56
+ runnable/entrypoints.py,sha256=46prgr3_FYtBMlRbUXIDSpgZUBgaxcdJAekXhgEIj7M,6578
57
+ runnable/exceptions.py,sha256=t5tSlYqe_EjU5liXu32yLLh_yrnXeFL93BuXfmQzV98,3268
58
+ runnable/executor.py,sha256=CwzHkeGVpocACZLzfFS94TzKeiaPLv4NtXtvT3eoocY,15222
59
+ runnable/gantt.py,sha256=hdFovfvnxDK3tAQOl6OLAiaxLBAE-wjPyszPVk5Ogds,40726
60
+ runnable/graph.py,sha256=ukJo_sqtBRD_ZX7ULbd2GnvpToAwGHcAowXPcqKjC4Q,16543
61
+ runnable/names.py,sha256=A9ldUyULXuWjJ1MoXihHqlg-xeTVX-oWYTO5Ah0trmo,8128
62
+ runnable/nodes.py,sha256=JHBxJib7SSQXY51bLHBXUvb0DlNSLNvyqz3JNEDLt8c,16926
63
+ runnable/parameters.py,sha256=zxP_KnSoGFpo7fwKE7zlrQ7CWRvA30SK_8TeMipNzcU,8131
64
+ runnable/pickler.py,sha256=ydJ_eti_U1F4l-YacFp7BWm6g5vTn04UXye25S1HVok,2684
65
+ runnable/sdk.py,sha256=blLBWzXV2x7jxKQXWpjmeJ9k22jt5CKBQBqQpnt4agk,32587
66
+ runnable/secrets.py,sha256=4L_dBFxTgr8r_hHUD6RlZEtqaOHDRsFG5PXO5wlvMI0,2324
67
+ runnable/tasks.py,sha256=7yuoeG4ZqfxFUmN4mPS4i6kbQmzEpAwbPQweAUWY-ic,31366
68
+ runnable/utils.py,sha256=amHW3KR_NGTDysGHcSafhh5WJUX7GPBSxqdPyzAIhao,11350
69
+ runnable-1.0.0.dist-info/METADATA,sha256=RL4wbnhywrdotJhuSGwaIBRJDglUKAbuWEe004G5BWQ,4297
70
+ runnable-1.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
71
+ runnable-1.0.0.dist-info/entry_points.txt,sha256=KkxihZ0LLEiwvFl7RquyqZ0tp2fJDIs7DgzHYDlmc3U,2018
72
+ runnable-1.0.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
73
+ runnable-1.0.0.dist-info/RECORD,,
@@ -8,26 +8,27 @@ minio = extensions.catalog.minio:MinioCatalog
8
8
  s3 = extensions.catalog.s3:S3Catalog
9
9
 
10
10
  [job_executor]
11
+ emulator = extensions.job_executor.emulate:EmulatorJobExecutor
11
12
  k8s-job = extensions.job_executor.k8s:K8sJobExecutor
12
13
  local = extensions.job_executor.local:LocalJobExecutor
13
14
  local-container = extensions.job_executor.local_container:LocalContainerJobExecutor
14
15
  mini-k8s-job = extensions.job_executor.k8s:MiniK8sJobExecutor
15
16
 
16
17
  [nodes]
17
- dag = extensions.nodes.nodes:DagNode
18
- fail = extensions.nodes.nodes:FailNode
19
- map = extensions.nodes.nodes:MapNode
20
- parallel = extensions.nodes.nodes:ParallelNode
21
- stub = extensions.nodes.nodes:StubNode
22
- success = extensions.nodes.nodes:SuccessNode
23
- task = extensions.nodes.nodes:TaskNode
24
- torch = extensions.nodes.torch:TorchNode
18
+ conditional = extensions.nodes.conditional:ConditionalNode
19
+ fail = extensions.nodes.fail:FailNode
20
+ map = extensions.nodes.map:MapNode
21
+ parallel = extensions.nodes.parallel:ParallelNode
22
+ stub = extensions.nodes.stub:StubNode
23
+ success = extensions.nodes.success:SuccessNode
24
+ task = extensions.nodes.task:TaskNode
25
25
 
26
26
  [pickler]
27
27
  pickle = runnable.pickler:NativePickler
28
28
 
29
29
  [pipeline_executor]
30
30
  argo = extensions.pipeline_executor.argo:ArgoExecutor
31
+ emulator = extensions.pipeline_executor.emulate:Emulator
31
32
  local = extensions.pipeline_executor.local:LocalExecutor
32
33
  local-container = extensions.pipeline_executor.local_container:LocalContainerExecutor
33
34
  mocked = extensions.pipeline_executor.mocked:MockedExecutor