runnable 0.12.2__tar.gz → 0.12.3__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- runnable-0.12.3/PKG-INFO +270 -0
- runnable-0.12.3/README.md +234 -0
- {runnable-0.12.2 → runnable-0.12.3}/pyproject.toml +34 -34
- {runnable-0.12.2 → runnable-0.12.3}/runnable/sdk.py +150 -101
- runnable-0.12.2/PKG-INFO +0 -453
- runnable-0.12.2/README.md +0 -417
- {runnable-0.12.2 → runnable-0.12.3}/LICENSE +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/catalog.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/cli.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/context.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/datastore.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/defaults.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/entrypoints.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/exceptions.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/executor.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/catalog/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/catalog/file_system/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/catalog/file_system/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/catalog/k8s_pvc/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/catalog/k8s_pvc/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/catalog/k8s_pvc/integration.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/argo/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/argo/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/argo/specification.yaml +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/k8s_job/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/k8s_job/implementation_FF.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/k8s_job/integration_FF.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/local/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/local/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/local_container/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/local_container/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/mocked/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/mocked/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/retry/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/executor/retry/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/nodes.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/chunked_file_system/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/chunked_file_system/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/chunked_k8s_pvc/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/chunked_k8s_pvc/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/chunked_k8s_pvc/integration.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/db/implementation_FF.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/db/integration_FF.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/file_system/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/file_system/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/generic_chunked.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/k8s_pvc/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/k8s_pvc/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/run_log_store/k8s_pvc/integration.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/secrets/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/secrets/dotenv/__init__.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/extensions/secrets/dotenv/implementation.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/graph.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/integration.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/names.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/nodes.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/parameters.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/pickler.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/secrets.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/tasks.py +0 -0
- {runnable-0.12.2 → runnable-0.12.3}/runnable/utils.py +0 -0
runnable-0.12.3/PKG-INFO
ADDED
@@ -0,0 +1,270 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: runnable
|
3
|
+
Version: 0.12.3
|
4
|
+
Summary: A Compute agnostic pipelining software
|
5
|
+
Home-page: https://github.com/vijayvammi/runnable
|
6
|
+
License: Apache-2.0
|
7
|
+
Author: Vijay Vammi
|
8
|
+
Author-email: mesanthu@gmail.com
|
9
|
+
Requires-Python: >=3.9,<3.13
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
16
|
+
Provides-Extra: database
|
17
|
+
Provides-Extra: docker
|
18
|
+
Provides-Extra: notebook
|
19
|
+
Requires-Dist: click
|
20
|
+
Requires-Dist: click-plugins (>=1.1.1,<2.0.0)
|
21
|
+
Requires-Dist: dill (>=0.3.8,<0.4.0)
|
22
|
+
Requires-Dist: docker ; extra == "docker"
|
23
|
+
Requires-Dist: mlflow-skinny
|
24
|
+
Requires-Dist: ploomber-engine (>=0.0.31,<0.0.32) ; extra == "notebook"
|
25
|
+
Requires-Dist: pydantic (>=2.5,<3.0)
|
26
|
+
Requires-Dist: rich (>=13.5.2,<14.0.0)
|
27
|
+
Requires-Dist: ruamel.yaml
|
28
|
+
Requires-Dist: ruamel.yaml.clib
|
29
|
+
Requires-Dist: sqlalchemy ; extra == "database"
|
30
|
+
Requires-Dist: stevedore (>=3.5.0,<4.0.0)
|
31
|
+
Requires-Dist: typing-extensions ; python_version < "3.8"
|
32
|
+
Project-URL: Documentation, https://github.com/vijayvammi/runnable
|
33
|
+
Project-URL: Repository, https://github.com/vijayvammi/runnable
|
34
|
+
Description-Content-Type: text/markdown
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
</p>
|
42
|
+
<hr style="border:2px dotted orange">
|
43
|
+
|
44
|
+
<p align="center">
|
45
|
+
<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>
|
46
|
+
<a href="https://pypi.org/project/runnable/"><img alt="Pypi" src="https://badge.fury.io/py/runnable.svg"></a>
|
47
|
+
<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>
|
48
|
+
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
|
49
|
+
<a href="https://github.com/python/mypy"><img alt="MyPy Checked" src="https://www.mypy-lang.org/static/mypy_badge.svg"></a>
|
50
|
+
<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">
|
51
|
+
</p>
|
52
|
+
<hr style="border:2px dotted orange">
|
53
|
+
|
54
|
+
|
55
|
+
[Please check here for complete documentation](https://astrazeneca.github.io/runnable/)
|
56
|
+
|
57
|
+
## Example
|
58
|
+
|
59
|
+
The below data science flavored code is a well-known
|
60
|
+
[iris example from scikit-learn](https://scikit-learn.org/stable/auto_examples/linear_model/plot_iris_logistic.html).
|
61
|
+
|
62
|
+
|
63
|
+
```python
|
64
|
+
"""
|
65
|
+
Example of Logistic regression using scikit-learn
|
66
|
+
https://scikit-learn.org/stable/auto_examples/linear_model/plot_iris_logistic.html
|
67
|
+
"""
|
68
|
+
|
69
|
+
import matplotlib.pyplot as plt
|
70
|
+
import numpy as np
|
71
|
+
from sklearn import datasets
|
72
|
+
from sklearn.inspection import DecisionBoundaryDisplay
|
73
|
+
from sklearn.linear_model import LogisticRegression
|
74
|
+
|
75
|
+
|
76
|
+
def load_data():
|
77
|
+
# import some data to play with
|
78
|
+
iris = datasets.load_iris()
|
79
|
+
X = iris.data[:, :2] # we only take the first two features.
|
80
|
+
Y = iris.target
|
81
|
+
|
82
|
+
return X, Y
|
83
|
+
|
84
|
+
|
85
|
+
def model_fit(X: np.ndarray, Y: np.ndarray, C: float = 1e5):
|
86
|
+
logreg = LogisticRegression(C=C)
|
87
|
+
logreg.fit(X, Y)
|
88
|
+
|
89
|
+
return logreg
|
90
|
+
|
91
|
+
|
92
|
+
def generate_plots(X: np.ndarray, Y: np.ndarray, logreg: LogisticRegression):
|
93
|
+
_, ax = plt.subplots(figsize=(4, 3))
|
94
|
+
DecisionBoundaryDisplay.from_estimator(
|
95
|
+
logreg,
|
96
|
+
X,
|
97
|
+
cmap=plt.cm.Paired,
|
98
|
+
ax=ax,
|
99
|
+
response_method="predict",
|
100
|
+
plot_method="pcolormesh",
|
101
|
+
shading="auto",
|
102
|
+
xlabel="Sepal length",
|
103
|
+
ylabel="Sepal width",
|
104
|
+
eps=0.5,
|
105
|
+
)
|
106
|
+
|
107
|
+
# Plot also the training points
|
108
|
+
plt.scatter(X[:, 0], X[:, 1], c=Y, edgecolors="k", cmap=plt.cm.Paired)
|
109
|
+
|
110
|
+
plt.xticks(())
|
111
|
+
plt.yticks(())
|
112
|
+
|
113
|
+
plt.savefig("iris_logistic.png")
|
114
|
+
|
115
|
+
# TODO: What is the right value?
|
116
|
+
return 0.6
|
117
|
+
|
118
|
+
|
119
|
+
## Without any orchestration
|
120
|
+
def main():
|
121
|
+
X, Y = load_data()
|
122
|
+
logreg = model_fit(X, Y, C=1.0)
|
123
|
+
generate_plots(X, Y, logreg)
|
124
|
+
|
125
|
+
|
126
|
+
## With runnable orchestration
|
127
|
+
def runnable_pipeline():
|
128
|
+
# The below code can be anywhere
|
129
|
+
from runnable import Catalog, Pipeline, PythonTask, metric, pickled
|
130
|
+
|
131
|
+
# X, Y = load_data()
|
132
|
+
load_data_task = PythonTask(
|
133
|
+
function=load_data,
|
134
|
+
name="load_data",
|
135
|
+
returns=[pickled("X"), pickled("Y")], # (1)
|
136
|
+
)
|
137
|
+
|
138
|
+
# logreg = model_fit(X, Y, C=1.0)
|
139
|
+
model_fit_task = PythonTask(
|
140
|
+
function=model_fit,
|
141
|
+
name="model_fit",
|
142
|
+
returns=[pickled("logreg")],
|
143
|
+
)
|
144
|
+
|
145
|
+
# generate_plots(X, Y, logreg)
|
146
|
+
generate_plots_task = PythonTask(
|
147
|
+
function=generate_plots,
|
148
|
+
name="generate_plots",
|
149
|
+
terminate_with_success=True,
|
150
|
+
catalog=Catalog(put=["iris_logistic.png"]), # (2)
|
151
|
+
returns=[metric("score")],
|
152
|
+
)
|
153
|
+
|
154
|
+
pipeline = Pipeline(
|
155
|
+
steps=[load_data_task, model_fit_task, generate_plots_task],
|
156
|
+
) # (4)
|
157
|
+
|
158
|
+
pipeline.execute()
|
159
|
+
|
160
|
+
return pipeline
|
161
|
+
|
162
|
+
|
163
|
+
if __name__ == "__main__":
|
164
|
+
# main()
|
165
|
+
runnable_pipeline()
|
166
|
+
|
167
|
+
```
|
168
|
+
|
169
|
+
|
170
|
+
1. Return two serialized objects X and Y.
|
171
|
+
2. Store the file `iris_logistic.png` for future reference.
|
172
|
+
3. Define the sequence of tasks.
|
173
|
+
4. Define a pipeline with the tasks
|
174
|
+
|
175
|
+
The difference between native driver and runnable orchestration:
|
176
|
+
|
177
|
+
!!! tip inline end "Notebooks and Shell scripts"
|
178
|
+
|
179
|
+
You can execute notebooks and shell scripts too!!
|
180
|
+
|
181
|
+
They can be written just as you would want them, *plain old notebooks and scripts*.
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
<div class="annotate" markdown>
|
187
|
+
|
188
|
+
```diff
|
189
|
+
|
190
|
+
- X, Y = load_data()
|
191
|
+
+load_data_task = PythonTask(
|
192
|
+
+ function=load_data,
|
193
|
+
+ name="load_data",
|
194
|
+
+ returns=[pickled("X"), pickled("Y")], (1)
|
195
|
+
+ )
|
196
|
+
|
197
|
+
-logreg = model_fit(X, Y, C=1.0)
|
198
|
+
+model_fit_task = PythonTask(
|
199
|
+
+ function=model_fit,
|
200
|
+
+ name="model_fit",
|
201
|
+
+ returns=[pickled("logreg")],
|
202
|
+
+ )
|
203
|
+
|
204
|
+
-generate_plots(X, Y, logreg)
|
205
|
+
+generate_plots_task = PythonTask(
|
206
|
+
+ function=generate_plots,
|
207
|
+
+ name="generate_plots",
|
208
|
+
+ terminate_with_success=True,
|
209
|
+
+ catalog=Catalog(put=["iris_logistic.png"]), (2)
|
210
|
+
+ )
|
211
|
+
|
212
|
+
|
213
|
+
+pipeline = Pipeline(
|
214
|
+
+ steps=[load_data_task, model_fit_task, generate_plots_task], (3)
|
215
|
+
|
216
|
+
```
|
217
|
+
</div>
|
218
|
+
|
219
|
+
|
220
|
+
---
|
221
|
+
|
222
|
+
- [x] ```Domain``` code remains completely independent of ```driver``` code.
|
223
|
+
- [x] The ```driver``` function has an equivalent and intuitive runnable expression
|
224
|
+
- [x] Reproducible by default, runnable stores metadata about code/data/config for every execution.
|
225
|
+
- [x] The pipeline is `runnable` in any environment.
|
226
|
+
|
227
|
+
|
228
|
+
## Documentation
|
229
|
+
|
230
|
+
[More details about the project and how to use it available here](https://astrazeneca.github.io/runnable/).
|
231
|
+
|
232
|
+
<hr style="border:2px dotted orange">
|
233
|
+
|
234
|
+
## Installation
|
235
|
+
|
236
|
+
The minimum python version that runnable supports is 3.8
|
237
|
+
|
238
|
+
```shell
|
239
|
+
pip install runnable
|
240
|
+
```
|
241
|
+
|
242
|
+
Please look at the [installation guide](https://astrazeneca.github.io/runnable-core/usage)
|
243
|
+
for more information.
|
244
|
+
|
245
|
+
|
246
|
+
## Pipelines can be:
|
247
|
+
|
248
|
+
### Linear
|
249
|
+
|
250
|
+
A simple linear pipeline with tasks either
|
251
|
+
[python functions](https://astrazeneca.github.io/runnable-core/concepts/task/#python_functions),
|
252
|
+
[notebooks](https://astrazeneca.github.io/runnable-core/concepts/task/#notebooks), or [shell scripts](https://astrazeneca.github.io/runnable-core/concepts/task/#shell)
|
253
|
+
|
254
|
+
[](https://mermaid.live/edit#pako:eNpl0bFuwyAQBuBXQVdZTqTESpxMDJ0ytkszhgwnOCcoNo4OaFVZfvcSx20tGSQ4fn0wHB3o1hBIyLJOWGeDFJ3Iq7r90lfkkA9HHfmTUpnX1hFyLvrHzDLl_qB4-1BOOZGGD3TfSikvTDSNFqdj2sT2vBTr9euQlXNWjqycsN2c7UZWFMUE7udwP0L3y6JenNKiyfvz8t8_b-gavT9QJYY0PcDtjeTLptrAChriBq1JzeoeWkG4UkMKZCoN8k2Bcn1yGEN7_HYaZOBIK4h3g4EOFi-MDcgKa59SMja0_P7s_vAJ_Q_YOH6o)
|
255
|
+
|
256
|
+
### [Parallel branches](https://astrazeneca.github.io/runnable-core/concepts/parallel)
|
257
|
+
|
258
|
+
Execute branches in parallel
|
259
|
+
|
260
|
+
[](https://mermaid.live/edit#pako:eNp9k01rwzAMhv-K8S4ZtJCzDzuMLmWwwkh2KMQ7eImShiZ2sB1KKf3vs52PpsWNT7LySHqlyBeciRwwwUUtTtmBSY2-YsopR8MpQUfAdCdBBekWNBpvv6-EkFICzGAtWcUTDW3wYy20M7lr5QGBK2j-anBAkH4M1z6grnjpy17xAiTwDII07jj6HK8-VnVZBspITnpjztyoVkLLJOy3Qfrdm6gQEu2370Io7WLORo84PbRoA_oOl9BBg4UHbHR58UkMWq_fxjrOnhLRx1nH0SgkjlBjh7ekxNKGc0NelDLknhePI8qf7MVNr_31nm1wwNTeM2Ao6pmf-3y3Mp7WlqA7twOnXfKs17zt-6azmim1gQL1A0NKS3EE8hKZE4Yezm3chIVFiFe4AdmwKjdv7mIjKNYHaIBiYsycySPFlF8NxzotkjPPMNGygxXu2pxp2FSslKzBpGC1Ml7IKy3krn_E7i1f_wEayTcn)
|
261
|
+
|
262
|
+
### [loops or map](https://astrazeneca.github.io/runnable-core/concepts/map)
|
263
|
+
|
264
|
+
Execute a pipeline over an iterable parameter.
|
265
|
+
|
266
|
+
[](https://mermaid.live/edit#pako:eNqVlF1rwjAUhv9KyG4qKNR-3AS2m8nuBgN3Z0Sy5tQG20SSdE7E_76kVVEr2CY3Ied9Tx6Sk3PAmeKACc5LtcsKpi36nlGZFbXciHwfLN79CuWiBLMcEULWGkBSaeosA2OCxbxdXMd89Get2bZASsLiSyuvQE2mJZXIjW27t2rOmQZ3Gp9rD6UjatWnwy7q6zPPukd50WTydmemEiS_QbQ79RwxGoQY9UaMuojRA8TCXexzyHgQZNwbMu5Cxl3IXNX6OWMyiDHpzZh0GZMHjOK3xz2mgxjT3oxplzG9MPp5_nVOhwJjteDwOg3HyFj3L1dCcvh7DUc-iftX18n6Waet1xX8cG908vpKHO6OW7cvkeHm5GR2b3drdvaSGTODHLW37mxabYC8fLgRhlfxpjNdwmEets-Dx7gCXTHBXQc8-D2KbQEVUEzckjO9oZjKo9Ox2qr5XmaYWF3DGNdbzizMBHOVVWGSs9K4XeDCKv3ZttSmsx7_AYa341E)
|
267
|
+
|
268
|
+
### [Arbitrary nesting](https://astrazeneca.github.io/runnable-core/concepts/nesting/)
|
269
|
+
Any nesting of parallel within map and so on.
|
270
|
+
|
@@ -0,0 +1,234 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
</p>
|
7
|
+
<hr style="border:2px dotted orange">
|
8
|
+
|
9
|
+
<p align="center">
|
10
|
+
<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>
|
11
|
+
<a href="https://pypi.org/project/runnable/"><img alt="Pypi" src="https://badge.fury.io/py/runnable.svg"></a>
|
12
|
+
<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>
|
13
|
+
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
|
14
|
+
<a href="https://github.com/python/mypy"><img alt="MyPy Checked" src="https://www.mypy-lang.org/static/mypy_badge.svg"></a>
|
15
|
+
<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">
|
16
|
+
</p>
|
17
|
+
<hr style="border:2px dotted orange">
|
18
|
+
|
19
|
+
|
20
|
+
[Please check here for complete documentation](https://astrazeneca.github.io/runnable/)
|
21
|
+
|
22
|
+
## Example
|
23
|
+
|
24
|
+
The below data science flavored code is a well-known
|
25
|
+
[iris example from scikit-learn](https://scikit-learn.org/stable/auto_examples/linear_model/plot_iris_logistic.html).
|
26
|
+
|
27
|
+
|
28
|
+
```python
|
29
|
+
"""
|
30
|
+
Example of Logistic regression using scikit-learn
|
31
|
+
https://scikit-learn.org/stable/auto_examples/linear_model/plot_iris_logistic.html
|
32
|
+
"""
|
33
|
+
|
34
|
+
import matplotlib.pyplot as plt
|
35
|
+
import numpy as np
|
36
|
+
from sklearn import datasets
|
37
|
+
from sklearn.inspection import DecisionBoundaryDisplay
|
38
|
+
from sklearn.linear_model import LogisticRegression
|
39
|
+
|
40
|
+
|
41
|
+
def load_data():
|
42
|
+
# import some data to play with
|
43
|
+
iris = datasets.load_iris()
|
44
|
+
X = iris.data[:, :2] # we only take the first two features.
|
45
|
+
Y = iris.target
|
46
|
+
|
47
|
+
return X, Y
|
48
|
+
|
49
|
+
|
50
|
+
def model_fit(X: np.ndarray, Y: np.ndarray, C: float = 1e5):
|
51
|
+
logreg = LogisticRegression(C=C)
|
52
|
+
logreg.fit(X, Y)
|
53
|
+
|
54
|
+
return logreg
|
55
|
+
|
56
|
+
|
57
|
+
def generate_plots(X: np.ndarray, Y: np.ndarray, logreg: LogisticRegression):
|
58
|
+
_, ax = plt.subplots(figsize=(4, 3))
|
59
|
+
DecisionBoundaryDisplay.from_estimator(
|
60
|
+
logreg,
|
61
|
+
X,
|
62
|
+
cmap=plt.cm.Paired,
|
63
|
+
ax=ax,
|
64
|
+
response_method="predict",
|
65
|
+
plot_method="pcolormesh",
|
66
|
+
shading="auto",
|
67
|
+
xlabel="Sepal length",
|
68
|
+
ylabel="Sepal width",
|
69
|
+
eps=0.5,
|
70
|
+
)
|
71
|
+
|
72
|
+
# Plot also the training points
|
73
|
+
plt.scatter(X[:, 0], X[:, 1], c=Y, edgecolors="k", cmap=plt.cm.Paired)
|
74
|
+
|
75
|
+
plt.xticks(())
|
76
|
+
plt.yticks(())
|
77
|
+
|
78
|
+
plt.savefig("iris_logistic.png")
|
79
|
+
|
80
|
+
# TODO: What is the right value?
|
81
|
+
return 0.6
|
82
|
+
|
83
|
+
|
84
|
+
## Without any orchestration
|
85
|
+
def main():
|
86
|
+
X, Y = load_data()
|
87
|
+
logreg = model_fit(X, Y, C=1.0)
|
88
|
+
generate_plots(X, Y, logreg)
|
89
|
+
|
90
|
+
|
91
|
+
## With runnable orchestration
|
92
|
+
def runnable_pipeline():
|
93
|
+
# The below code can be anywhere
|
94
|
+
from runnable import Catalog, Pipeline, PythonTask, metric, pickled
|
95
|
+
|
96
|
+
# X, Y = load_data()
|
97
|
+
load_data_task = PythonTask(
|
98
|
+
function=load_data,
|
99
|
+
name="load_data",
|
100
|
+
returns=[pickled("X"), pickled("Y")], # (1)
|
101
|
+
)
|
102
|
+
|
103
|
+
# logreg = model_fit(X, Y, C=1.0)
|
104
|
+
model_fit_task = PythonTask(
|
105
|
+
function=model_fit,
|
106
|
+
name="model_fit",
|
107
|
+
returns=[pickled("logreg")],
|
108
|
+
)
|
109
|
+
|
110
|
+
# generate_plots(X, Y, logreg)
|
111
|
+
generate_plots_task = PythonTask(
|
112
|
+
function=generate_plots,
|
113
|
+
name="generate_plots",
|
114
|
+
terminate_with_success=True,
|
115
|
+
catalog=Catalog(put=["iris_logistic.png"]), # (2)
|
116
|
+
returns=[metric("score")],
|
117
|
+
)
|
118
|
+
|
119
|
+
pipeline = Pipeline(
|
120
|
+
steps=[load_data_task, model_fit_task, generate_plots_task],
|
121
|
+
) # (4)
|
122
|
+
|
123
|
+
pipeline.execute()
|
124
|
+
|
125
|
+
return pipeline
|
126
|
+
|
127
|
+
|
128
|
+
if __name__ == "__main__":
|
129
|
+
# main()
|
130
|
+
runnable_pipeline()
|
131
|
+
|
132
|
+
```
|
133
|
+
|
134
|
+
|
135
|
+
1. Return two serialized objects X and Y.
|
136
|
+
2. Store the file `iris_logistic.png` for future reference.
|
137
|
+
3. Define the sequence of tasks.
|
138
|
+
4. Define a pipeline with the tasks
|
139
|
+
|
140
|
+
The difference between native driver and runnable orchestration:
|
141
|
+
|
142
|
+
!!! tip inline end "Notebooks and Shell scripts"
|
143
|
+
|
144
|
+
You can execute notebooks and shell scripts too!!
|
145
|
+
|
146
|
+
They can be written just as you would want them, *plain old notebooks and scripts*.
|
147
|
+
|
148
|
+
|
149
|
+
|
150
|
+
|
151
|
+
<div class="annotate" markdown>
|
152
|
+
|
153
|
+
```diff
|
154
|
+
|
155
|
+
- X, Y = load_data()
|
156
|
+
+load_data_task = PythonTask(
|
157
|
+
+ function=load_data,
|
158
|
+
+ name="load_data",
|
159
|
+
+ returns=[pickled("X"), pickled("Y")], (1)
|
160
|
+
+ )
|
161
|
+
|
162
|
+
-logreg = model_fit(X, Y, C=1.0)
|
163
|
+
+model_fit_task = PythonTask(
|
164
|
+
+ function=model_fit,
|
165
|
+
+ name="model_fit",
|
166
|
+
+ returns=[pickled("logreg")],
|
167
|
+
+ )
|
168
|
+
|
169
|
+
-generate_plots(X, Y, logreg)
|
170
|
+
+generate_plots_task = PythonTask(
|
171
|
+
+ function=generate_plots,
|
172
|
+
+ name="generate_plots",
|
173
|
+
+ terminate_with_success=True,
|
174
|
+
+ catalog=Catalog(put=["iris_logistic.png"]), (2)
|
175
|
+
+ )
|
176
|
+
|
177
|
+
|
178
|
+
+pipeline = Pipeline(
|
179
|
+
+ steps=[load_data_task, model_fit_task, generate_plots_task], (3)
|
180
|
+
|
181
|
+
```
|
182
|
+
</div>
|
183
|
+
|
184
|
+
|
185
|
+
---
|
186
|
+
|
187
|
+
- [x] ```Domain``` code remains completely independent of ```driver``` code.
|
188
|
+
- [x] The ```driver``` function has an equivalent and intuitive runnable expression
|
189
|
+
- [x] Reproducible by default, runnable stores metadata about code/data/config for every execution.
|
190
|
+
- [x] The pipeline is `runnable` in any environment.
|
191
|
+
|
192
|
+
|
193
|
+
## Documentation
|
194
|
+
|
195
|
+
[More details about the project and how to use it available here](https://astrazeneca.github.io/runnable/).
|
196
|
+
|
197
|
+
<hr style="border:2px dotted orange">
|
198
|
+
|
199
|
+
## Installation
|
200
|
+
|
201
|
+
The minimum python version that runnable supports is 3.8
|
202
|
+
|
203
|
+
```shell
|
204
|
+
pip install runnable
|
205
|
+
```
|
206
|
+
|
207
|
+
Please look at the [installation guide](https://astrazeneca.github.io/runnable-core/usage)
|
208
|
+
for more information.
|
209
|
+
|
210
|
+
|
211
|
+
## Pipelines can be:
|
212
|
+
|
213
|
+
### Linear
|
214
|
+
|
215
|
+
A simple linear pipeline with tasks either
|
216
|
+
[python functions](https://astrazeneca.github.io/runnable-core/concepts/task/#python_functions),
|
217
|
+
[notebooks](https://astrazeneca.github.io/runnable-core/concepts/task/#notebooks), or [shell scripts](https://astrazeneca.github.io/runnable-core/concepts/task/#shell)
|
218
|
+
|
219
|
+
[](https://mermaid.live/edit#pako:eNpl0bFuwyAQBuBXQVdZTqTESpxMDJ0ytkszhgwnOCcoNo4OaFVZfvcSx20tGSQ4fn0wHB3o1hBIyLJOWGeDFJ3Iq7r90lfkkA9HHfmTUpnX1hFyLvrHzDLl_qB4-1BOOZGGD3TfSikvTDSNFqdj2sT2vBTr9euQlXNWjqycsN2c7UZWFMUE7udwP0L3y6JenNKiyfvz8t8_b-gavT9QJYY0PcDtjeTLptrAChriBq1JzeoeWkG4UkMKZCoN8k2Bcn1yGEN7_HYaZOBIK4h3g4EOFi-MDcgKa59SMja0_P7s_vAJ_Q_YOH6o)
|
220
|
+
|
221
|
+
### [Parallel branches](https://astrazeneca.github.io/runnable-core/concepts/parallel)
|
222
|
+
|
223
|
+
Execute branches in parallel
|
224
|
+
|
225
|
+
[](https://mermaid.live/edit#pako:eNp9k01rwzAMhv-K8S4ZtJCzDzuMLmWwwkh2KMQ7eImShiZ2sB1KKf3vs52PpsWNT7LySHqlyBeciRwwwUUtTtmBSY2-YsopR8MpQUfAdCdBBekWNBpvv6-EkFICzGAtWcUTDW3wYy20M7lr5QGBK2j-anBAkH4M1z6grnjpy17xAiTwDII07jj6HK8-VnVZBspITnpjztyoVkLLJOy3Qfrdm6gQEu2370Io7WLORo84PbRoA_oOl9BBg4UHbHR58UkMWq_fxjrOnhLRx1nH0SgkjlBjh7ekxNKGc0NelDLknhePI8qf7MVNr_31nm1wwNTeM2Ao6pmf-3y3Mp7WlqA7twOnXfKs17zt-6azmim1gQL1A0NKS3EE8hKZE4Yezm3chIVFiFe4AdmwKjdv7mIjKNYHaIBiYsycySPFlF8NxzotkjPPMNGygxXu2pxp2FSslKzBpGC1Ml7IKy3krn_E7i1f_wEayTcn)
|
226
|
+
|
227
|
+
### [loops or map](https://astrazeneca.github.io/runnable-core/concepts/map)
|
228
|
+
|
229
|
+
Execute a pipeline over an iterable parameter.
|
230
|
+
|
231
|
+
[](https://mermaid.live/edit#pako:eNqVlF1rwjAUhv9KyG4qKNR-3AS2m8nuBgN3Z0Sy5tQG20SSdE7E_76kVVEr2CY3Ied9Tx6Sk3PAmeKACc5LtcsKpi36nlGZFbXciHwfLN79CuWiBLMcEULWGkBSaeosA2OCxbxdXMd89Get2bZASsLiSyuvQE2mJZXIjW27t2rOmQZ3Gp9rD6UjatWnwy7q6zPPukd50WTydmemEiS_QbQ79RwxGoQY9UaMuojRA8TCXexzyHgQZNwbMu5Cxl3IXNX6OWMyiDHpzZh0GZMHjOK3xz2mgxjT3oxplzG9MPp5_nVOhwJjteDwOg3HyFj3L1dCcvh7DUc-iftX18n6Waet1xX8cG908vpKHO6OW7cvkeHm5GR2b3drdvaSGTODHLW37mxabYC8fLgRhlfxpjNdwmEets-Dx7gCXTHBXQc8-D2KbQEVUEzckjO9oZjKo9Ox2qr5XmaYWF3DGNdbzizMBHOVVWGSs9K4XeDCKv3ZttSmsx7_AYa341E)
|
232
|
+
|
233
|
+
### [Arbitrary nesting](https://astrazeneca.github.io/runnable-core/concepts/nesting/)
|
234
|
+
Any nesting of parallel within map and so on.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "runnable"
|
3
|
-
version = "0.12.
|
3
|
+
version = "0.12.3"
|
4
4
|
description = "A Compute agnostic pipelining software"
|
5
5
|
authors = ["Vijay Vammi <mesanthu@gmail.com>"]
|
6
6
|
license = "Apache-2.0"
|
@@ -25,43 +25,12 @@ mlflow-skinny = { version = "*", optional = true }
|
|
25
25
|
ploomber-engine = "^0.0.31"
|
26
26
|
dill = "^0.3.8"
|
27
27
|
|
28
|
-
[tool.poetry.group.docs.dependencies]
|
29
|
-
mkdocs = "*"
|
30
|
-
mkdocs-material = "*"
|
31
|
-
mkdocs-section-index = "^0.3.5"
|
32
|
-
mkdocstrings = { extras = ["python"], version = "^0.24.0" }
|
33
|
-
nbconvert = "^7.13.1"
|
34
|
-
mkdocs-click = "^0.8.1"
|
35
|
-
tensorflow = "^2.16.1"
|
36
|
-
|
37
|
-
[tool.poetry.group.binary.dependencies]
|
38
|
-
pyinstaller = "^5.13.2"
|
39
|
-
|
40
|
-
[tool.poetry.group.perf.dependencies]
|
41
|
-
# Run the performace tests poetry run python -m pyflame -p ./flamegraph.pl runnable/entrypoints.py
|
42
|
-
pyflame = "^0.3.1"
|
43
|
-
|
44
|
-
|
45
|
-
[tool.poetry.group.tutorial.dependencies]
|
46
|
-
pandas = "^2.2.1"
|
47
|
-
numpy = "^1.26.4"
|
48
|
-
scikit-learn = "^1.4.1.post1"
|
49
|
-
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" }
|
50
|
-
matplotlib = "^3.8.3"
|
51
|
-
|
52
|
-
|
53
|
-
[tool.poetry.group.release.dependencies]
|
54
|
-
python-semantic-release = "^9.4.2"
|
55
|
-
|
56
|
-
|
57
|
-
[tool.poetry.group.examples.dependencies]
|
58
|
-
pandas = "^2.2.2"
|
59
|
-
|
60
28
|
[tool.poetry.extras]
|
61
29
|
docker = ['docker']
|
62
30
|
notebook = ['ploomber-engine']
|
63
31
|
database = ["sqlalchemy"]
|
64
32
|
|
33
|
+
|
65
34
|
[tool.poetry.group.dev.dependencies]
|
66
35
|
pytest = "*"
|
67
36
|
pytest-cov = "*"
|
@@ -73,13 +42,44 @@ ruff = "^0.0.259"
|
|
73
42
|
commit-linter = "^1.0.2"
|
74
43
|
black = "^23.3.0"
|
75
44
|
gitlint = "^0.19.1"
|
76
|
-
pandas = "^2.2.2"
|
45
|
+
pandas = "^2.2.2" # for testing examples
|
77
46
|
|
47
|
+
[tool.poetry.group.release.dependencies]
|
48
|
+
python-semantic-release = "^9.4.2"
|
49
|
+
|
50
|
+
[tool.poetry.group.docs.dependencies]
|
51
|
+
mkdocs = "*"
|
52
|
+
mkdocs-material = "*"
|
53
|
+
mkdocs-section-index = "^0.3.5"
|
54
|
+
mkdocstrings = { extras = ["python"], version = "^0.24.0" }
|
55
|
+
nbconvert = "^7.13.1"
|
56
|
+
mkdocs-click = "^0.8.1"
|
57
|
+
|
58
|
+
[tool.poetry.group.tutorial.dependencies]
|
59
|
+
pandas = "^2.2.1"
|
60
|
+
numpy = "^1.26.4"
|
61
|
+
scikit-learn = "^1.4.1.post1"
|
62
|
+
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" }
|
63
|
+
matplotlib = "^3.8.3"
|
64
|
+
|
65
|
+
|
66
|
+
[tool.poetry.group.compare.dependencies]
|
67
|
+
torch = "^2.3.0"
|
68
|
+
torchvision = "^0.18.0"
|
69
|
+
tensorflow = "^2.16.1"
|
78
70
|
|
79
71
|
[tool.poetry.scripts]
|
80
72
|
runnable = 'runnable.cli:cli'
|
81
73
|
|
82
74
|
|
75
|
+
[tool.poetry.group.binary.dependencies]
|
76
|
+
pyinstaller = "^5.13.2"
|
77
|
+
|
78
|
+
[tool.poetry.group.perf.dependencies]
|
79
|
+
# Run the performace tests poetry run python -m pyflame -p ./flamegraph.pl runnable/entrypoints.py
|
80
|
+
pyflame = "^0.3.1"
|
81
|
+
|
82
|
+
|
83
83
|
# Plugins for Executors
|
84
84
|
[tool.poetry.plugins."executor"]
|
85
85
|
"local" = "runnable.extensions.executor.local.implementation:LocalExecutor"
|