nextpipe 0.1.0.dev5__tar.gz → 0.1.0.dev6__tar.gz
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.
- nextpipe-0.1.0.dev5/.github/workflows/python-lint.yml → nextpipe-0.1.0.dev6/.github/workflows/lint.yml +3 -3
- nextpipe-0.1.0.dev5/.github/workflows/python-test.yml → nextpipe-0.1.0.dev6/.github/workflows/test.yml +5 -3
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/PKG-INFO +88 -4
- nextpipe-0.1.0.dev6/README.md +90 -0
- nextpipe-0.1.0.dev6/examples/README.md +18 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/apps/echo/main.py +7 -1
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-chain/README.md +2 -2
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-complex/README.md +2 -2
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-ensemble/README.md +2 -2
- nextpipe-0.1.0.dev6/examples/pipeline-foreach/README.md +26 -0
- nextpipe-0.1.0.dev6/examples/pipeline-foreach/main.py +56 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-preprocess/README.md +2 -2
- nextpipe-0.1.0.dev6/examples/pipeline-preprocess/app.yaml +7 -0
- nextpipe-0.1.0.dev6/examples/pipeline-preprocess/requirements.txt +1 -0
- nextpipe-0.1.0.dev6/nextpipe/__about__.py +1 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/nextpipe/__init__.py +4 -0
- nextpipe-0.1.0.dev6/nextpipe/config.py +22 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/nextpipe/decorators.py +94 -50
- nextpipe-0.1.0.dev6/nextpipe/flow.py +455 -0
- nextpipe-0.1.0.dev6/nextpipe/graph.py +44 -0
- nextpipe-0.1.0.dev6/nextpipe/schema.py +25 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/nextpipe/threads.py +32 -19
- nextpipe-0.1.0.dev6/nextpipe/uplink.py +206 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/nextpipe/utils.py +7 -8
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/pyproject.toml +7 -4
- nextpipe-0.1.0.dev6/tests/.gitignore +3 -0
- nextpipe-0.1.0.dev6/tests/README.md +52 -0
- nextpipe-0.1.0.dev6/tests/apps/echo/.gitignore +1 -0
- nextpipe-0.1.0.dev6/tests/apps/echo/README.md +19 -0
- nextpipe-0.1.0.dev6/tests/apps/echo/app.yaml +6 -0
- nextpipe-0.1.0.dev6/tests/apps/echo/main.py +17 -0
- nextpipe-0.1.0.dev6/tests/apps/echo/requirements.txt +1 -0
- nextpipe-0.1.0.dev6/tests/deploy/app.yaml +7 -0
- nextpipe-0.1.0.dev6/tests/deploy/main.py +50 -0
- nextpipe-0.1.0.dev6/tests/deploy/requirements.txt +2 -0
- nextpipe-0.1.0.dev6/tests/pipelines/chain.json +3 -0
- nextpipe-0.1.0.dev6/tests/pipelines/chain.json.golden +10 -0
- nextpipe-0.1.0.dev6/tests/pipelines/chain.py +50 -0
- nextpipe-0.1.0.dev6/tests/pipelines/complex.json +20 -0
- nextpipe-0.1.0.dev6/tests/pipelines/complex.json.golden +72 -0
- nextpipe-0.1.0.dev6/tests/pipelines/complex.py +77 -0
- nextpipe-0.1.0.dev6/tests/pipelines/fail.py +36 -0
- nextpipe-0.1.0.dev6/tests/test_graph.py +40 -0
- nextpipe-0.1.0.dev6/tests/test_integration.py +113 -0
- nextpipe-0.1.0.dev6/tests/test_threads.py +52 -0
- nextpipe-0.1.0.dev6/tests/test_uplink.py +99 -0
- nextpipe-0.1.0.dev5/README.md +0 -7
- nextpipe-0.1.0.dev5/examples/README.md +0 -3
- nextpipe-0.1.0.dev5/nextpipe/__about__.py +0 -1
- nextpipe-0.1.0.dev5/nextpipe/flow.py +0 -315
- nextpipe-0.1.0.dev5/nextpipe/schema.py +0 -50
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/.github/workflows/release.yml +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/.gitignore +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/.prettierrc.yml +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/LICENSE.md +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/apps/echo/.gitignore +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/apps/echo/README.md +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/apps/echo/app.yaml +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/apps/echo/requirements.txt +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-chain/app.yaml +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-chain/main.py +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-chain/requirements.txt +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-complex/app.yaml +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-complex/main.py +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-complex/requirements.txt +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-ensemble/app.yaml +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-ensemble/main.py +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-ensemble/requirements.txt +0 -0
- {nextpipe-0.1.0.dev5/examples/pipeline-preprocess → nextpipe-0.1.0.dev6/examples/pipeline-foreach}/app.yaml +0 -0
- {nextpipe-0.1.0.dev5/examples/pipeline-preprocess → nextpipe-0.1.0.dev6/examples/pipeline-foreach}/requirements.txt +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/examples/pipeline-preprocess/main.py +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/nextpipe.code-workspace +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/tests/__init__.py +0 -0
- {nextpipe-0.1.0.dev5 → nextpipe-0.1.0.dev6}/tests/test_version.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: lint
|
|
2
2
|
on: [push]
|
|
3
3
|
jobs:
|
|
4
|
-
|
|
4
|
+
lint:
|
|
5
5
|
runs-on: ubuntu-latest
|
|
6
6
|
strategy:
|
|
7
7
|
matrix:
|
|
8
|
-
python-version: ["3.
|
|
8
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
9
9
|
steps:
|
|
10
10
|
- name: git clone
|
|
11
11
|
uses: actions/checkout@v4
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: test
|
|
2
2
|
on: [push]
|
|
3
3
|
jobs:
|
|
4
|
-
|
|
4
|
+
test:
|
|
5
5
|
runs-on: ubuntu-latest
|
|
6
6
|
strategy:
|
|
7
7
|
matrix:
|
|
8
|
-
python-version: ["3.
|
|
8
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
9
9
|
steps:
|
|
10
10
|
- name: git clone
|
|
11
11
|
uses: actions/checkout@v4
|
|
@@ -21,4 +21,6 @@ jobs:
|
|
|
21
21
|
pip install .[dev]
|
|
22
22
|
|
|
23
23
|
- name: unit tests
|
|
24
|
+
env:
|
|
25
|
+
NEXTMV_API_KEY_NEXTPIPE: ${{ secrets.NEXTMV_API_KEY_NEXTPIPE }}
|
|
24
26
|
run: python -m unittest
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nextpipe
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev6
|
|
4
4
|
Summary: Framework for Decision Pipeline modeling and execution
|
|
5
5
|
Project-URL: Homepage, https://www.nextmv.io
|
|
6
6
|
Project-URL: Documentation, https://www.nextmv.io/docs
|
|
@@ -98,17 +98,18 @@ License-File: LICENSE.md
|
|
|
98
98
|
Keywords: decision automation,decision engineering,decision pipelines,decision science,decision workflows,decisions,nextmv,operations research,optimization,pipelines,workflows
|
|
99
99
|
Classifier: Operating System :: OS Independent
|
|
100
100
|
Classifier: Programming Language :: Python :: 3
|
|
101
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
102
101
|
Classifier: Programming Language :: Python :: 3.9
|
|
103
102
|
Classifier: Programming Language :: Python :: 3.10
|
|
104
103
|
Classifier: Programming Language :: Python :: 3.11
|
|
105
104
|
Classifier: Programming Language :: Python :: 3.12
|
|
106
|
-
|
|
105
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
106
|
+
Requires-Python: >=3.9
|
|
107
107
|
Requires-Dist: dataclasses-json>=0.6.7
|
|
108
108
|
Requires-Dist: nextmv>=0.13.1
|
|
109
109
|
Requires-Dist: pathos>=0.3.2
|
|
110
110
|
Requires-Dist: requests>=2.31.0
|
|
111
111
|
Provides-Extra: dev
|
|
112
|
+
Requires-Dist: goldie>=0.1.6; extra == 'dev'
|
|
112
113
|
Requires-Dist: ruff>=0.6.4; extra == 'dev'
|
|
113
114
|
Description-Content-Type: text/markdown
|
|
114
115
|
|
|
@@ -116,6 +117,89 @@ Description-Content-Type: text/markdown
|
|
|
116
117
|
|
|
117
118
|
Framework for Decision Pipeline modeling and execution.
|
|
118
119
|
|
|
120
|
+
## Installation
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pip install nextpipe
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Preview
|
|
127
|
+
|
|
128
|
+
Example of a pipeline utilizing multiple routing solvers, and picking the best result.
|
|
129
|
+
|
|
130
|
+
```mermaid
|
|
131
|
+
graph LR
|
|
132
|
+
fetch_data(prepare_data)
|
|
133
|
+
fetch_data --> run_nextroute
|
|
134
|
+
fetch_data --> run_ortools
|
|
135
|
+
fetch_data --> run_pyvroom
|
|
136
|
+
run_nextroute{ }
|
|
137
|
+
run_nextroute_join{ }
|
|
138
|
+
run_nextroute_0(run_nextroute_0)
|
|
139
|
+
run_nextroute --> run_nextroute_0
|
|
140
|
+
run_nextroute_0 --> run_nextroute_join
|
|
141
|
+
run_nextroute_1(run_nextroute_1)
|
|
142
|
+
run_nextroute --> run_nextroute_1
|
|
143
|
+
run_nextroute_1 --> run_nextroute_join
|
|
144
|
+
run_nextroute_2(run_nextroute_2)
|
|
145
|
+
run_nextroute --> run_nextroute_2
|
|
146
|
+
run_nextroute_2 --> run_nextroute_join
|
|
147
|
+
run_nextroute_join --> pick_best
|
|
148
|
+
run_ortools(run_ortools)
|
|
149
|
+
run_ortools --> pick_best
|
|
150
|
+
run_pyvroom(run_pyvroom)
|
|
151
|
+
run_pyvroom --> pick_best
|
|
152
|
+
pick_best(pick_best)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Modeling
|
|
156
|
+
|
|
157
|
+
Pipeline modeling is done by defining a flow as steps and decorating them.
|
|
158
|
+
The following example demonstrates a 3 step pipeline that makes use of dynamic fanout and joining of results.
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
from nextpipe import AppOption, AppRunConfig, FlowSpec, app, foreach, join, needs, step
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class Flow(FlowSpec):
|
|
165
|
+
@foreach() # Run the successor step for each item in the result list of this step
|
|
166
|
+
@step
|
|
167
|
+
def prepare(data: dict):
|
|
168
|
+
"""
|
|
169
|
+
Creates 3 copies of the input and configures them for 3 different app parameters.
|
|
170
|
+
"""
|
|
171
|
+
inputs = [copy.deepcopy(data) for _ in range(3)]
|
|
172
|
+
run_configs = [AppRunConfig(input, [AppOption("param", i)]) for i, input in enumerate(inputs)]
|
|
173
|
+
return run_configs
|
|
174
|
+
|
|
175
|
+
@app(app_id="echo")
|
|
176
|
+
@needs(predecessors=[prepare])
|
|
177
|
+
@step
|
|
178
|
+
def solve():
|
|
179
|
+
"""
|
|
180
|
+
Imitates a solver app.
|
|
181
|
+
"""
|
|
182
|
+
pass
|
|
183
|
+
|
|
184
|
+
@needs(predecessors=[solve])
|
|
185
|
+
@join() # Collect the results from the previous 'foreach' step and combine them into a list passed as the arg
|
|
186
|
+
@step
|
|
187
|
+
def merge(results: list[dict]):
|
|
188
|
+
"""Merges the results."""
|
|
189
|
+
return results
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The pipeline can simply be executed from the main func of the app.
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
# Run workflow
|
|
196
|
+
flow = Flow("DecisionFlow", input.data)
|
|
197
|
+
flow.run()
|
|
198
|
+
|
|
199
|
+
# Write out the result
|
|
200
|
+
print(json.dumps(flow.get_result(flow.merge)))
|
|
201
|
+
```
|
|
202
|
+
|
|
119
203
|
## Examples
|
|
120
204
|
|
|
121
|
-
You can find examples of how to use `nextpipe` in the [examples](./examples) directory.
|
|
205
|
+
You can find further examples of how to use `nextpipe` in the [examples](./examples) directory.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# nextpipe
|
|
2
|
+
|
|
3
|
+
Framework for Decision Pipeline modeling and execution.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install nextpipe
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Preview
|
|
12
|
+
|
|
13
|
+
Example of a pipeline utilizing multiple routing solvers, and picking the best result.
|
|
14
|
+
|
|
15
|
+
```mermaid
|
|
16
|
+
graph LR
|
|
17
|
+
fetch_data(prepare_data)
|
|
18
|
+
fetch_data --> run_nextroute
|
|
19
|
+
fetch_data --> run_ortools
|
|
20
|
+
fetch_data --> run_pyvroom
|
|
21
|
+
run_nextroute{ }
|
|
22
|
+
run_nextroute_join{ }
|
|
23
|
+
run_nextroute_0(run_nextroute_0)
|
|
24
|
+
run_nextroute --> run_nextroute_0
|
|
25
|
+
run_nextroute_0 --> run_nextroute_join
|
|
26
|
+
run_nextroute_1(run_nextroute_1)
|
|
27
|
+
run_nextroute --> run_nextroute_1
|
|
28
|
+
run_nextroute_1 --> run_nextroute_join
|
|
29
|
+
run_nextroute_2(run_nextroute_2)
|
|
30
|
+
run_nextroute --> run_nextroute_2
|
|
31
|
+
run_nextroute_2 --> run_nextroute_join
|
|
32
|
+
run_nextroute_join --> pick_best
|
|
33
|
+
run_ortools(run_ortools)
|
|
34
|
+
run_ortools --> pick_best
|
|
35
|
+
run_pyvroom(run_pyvroom)
|
|
36
|
+
run_pyvroom --> pick_best
|
|
37
|
+
pick_best(pick_best)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Modeling
|
|
41
|
+
|
|
42
|
+
Pipeline modeling is done by defining a flow as steps and decorating them.
|
|
43
|
+
The following example demonstrates a 3 step pipeline that makes use of dynamic fanout and joining of results.
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from nextpipe import AppOption, AppRunConfig, FlowSpec, app, foreach, join, needs, step
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class Flow(FlowSpec):
|
|
50
|
+
@foreach() # Run the successor step for each item in the result list of this step
|
|
51
|
+
@step
|
|
52
|
+
def prepare(data: dict):
|
|
53
|
+
"""
|
|
54
|
+
Creates 3 copies of the input and configures them for 3 different app parameters.
|
|
55
|
+
"""
|
|
56
|
+
inputs = [copy.deepcopy(data) for _ in range(3)]
|
|
57
|
+
run_configs = [AppRunConfig(input, [AppOption("param", i)]) for i, input in enumerate(inputs)]
|
|
58
|
+
return run_configs
|
|
59
|
+
|
|
60
|
+
@app(app_id="echo")
|
|
61
|
+
@needs(predecessors=[prepare])
|
|
62
|
+
@step
|
|
63
|
+
def solve():
|
|
64
|
+
"""
|
|
65
|
+
Imitates a solver app.
|
|
66
|
+
"""
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
@needs(predecessors=[solve])
|
|
70
|
+
@join() # Collect the results from the previous 'foreach' step and combine them into a list passed as the arg
|
|
71
|
+
@step
|
|
72
|
+
def merge(results: list[dict]):
|
|
73
|
+
"""Merges the results."""
|
|
74
|
+
return results
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The pipeline can simply be executed from the main func of the app.
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# Run workflow
|
|
81
|
+
flow = Flow("DecisionFlow", input.data)
|
|
82
|
+
flow.run()
|
|
83
|
+
|
|
84
|
+
# Write out the result
|
|
85
|
+
print(json.dumps(flow.get_result(flow.merge)))
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Examples
|
|
89
|
+
|
|
90
|
+
You can find further examples of how to use `nextpipe` in the [examples](./examples) directory.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
This directory contains examples of how to use `nextpipe`.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Create and push all necessary apps in your account (check the README of the example and look for `@app` in the pipeline definition).
|
|
8
|
+
- Some simple apps are available in the `./apps` directory. Push them as described in their READMEs.
|
|
9
|
+
- Some examples make use of marketplace apps. Follow instructions in the example READMEs to subscribe to them.
|
|
10
|
+
- Alternative, you can use the `nextmv community clone -a <app-id>` command to clone the app from the community apps repository.
|
|
11
|
+
|
|
12
|
+
## Table of contents
|
|
13
|
+
|
|
14
|
+
- [pipeline-chain](./pipeline-chain): Example of a simple pipeline with a chain of steps.
|
|
15
|
+
- [pipeline-foreach](./pipeline-foreach): Example of a pipeline with a fanout step (`@foreach`) that runs the same input through a solve step with different app options.
|
|
16
|
+
- [pipeline-complex](./pipeline-complex): A more complex pipeline combining some concepts and multiple solvers.
|
|
17
|
+
- [pipeline-ensemble](./pipeline-ensemble): Example of a pipeline ensembling the results of multiple solvers.
|
|
18
|
+
- [pipeline-preprocess](./pipeline-preprocess): Example of a pipeline doing some preprocessing before running a solver.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import sys
|
|
1
2
|
import time
|
|
2
3
|
|
|
3
4
|
import nextmv
|
|
@@ -5,7 +6,12 @@ import nextmv
|
|
|
5
6
|
before = time.time()
|
|
6
7
|
input = nextmv.load_local()
|
|
7
8
|
output = nextmv.Output(
|
|
8
|
-
solution={
|
|
9
|
+
solution={
|
|
10
|
+
"echo": {
|
|
11
|
+
"data": input.data,
|
|
12
|
+
"args": sys.argv[1:],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
9
15
|
statistics={"run": {"duration": time.time() - before}},
|
|
10
16
|
)
|
|
11
17
|
nextmv.write_local(output)
|
|
@@ -5,7 +5,7 @@ A simple chain pipeline.
|
|
|
5
5
|
## Graph
|
|
6
6
|
|
|
7
7
|
```mermaid
|
|
8
|
-
graph
|
|
8
|
+
graph LR
|
|
9
9
|
prepare(prepare)
|
|
10
10
|
prepare --> solve
|
|
11
11
|
solve(solve)
|
|
@@ -21,5 +21,5 @@ graph TD
|
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
23
|
nextmv app push -a <app-id>
|
|
24
|
-
echo '{"hello": "world!"}' | nextmv app run -a <app-id>
|
|
24
|
+
echo '{"hello": "world!"}' | nextmv app run -a <app-id>
|
|
25
25
|
```
|
|
@@ -5,7 +5,7 @@ A more complex pipeline combining some concepts.
|
|
|
5
5
|
## Graph
|
|
6
6
|
|
|
7
7
|
```mermaid
|
|
8
|
-
graph
|
|
8
|
+
graph LR
|
|
9
9
|
fetch_data(fetch_data)
|
|
10
10
|
fetch_data --> run_nextroute
|
|
11
11
|
fetch_data --> run_ortools
|
|
@@ -40,5 +40,5 @@ graph TD
|
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
nextmv app push -a <app-id>
|
|
43
|
-
echo '{}' | nextmv app run -a <app-id>
|
|
43
|
+
echo '{}' | nextmv app run -a <app-id>
|
|
44
44
|
```
|
|
@@ -5,7 +5,7 @@ A basic ensemble pipeline.
|
|
|
5
5
|
## Graph
|
|
6
6
|
|
|
7
7
|
```mermaid
|
|
8
|
-
graph
|
|
8
|
+
graph LR
|
|
9
9
|
run_nextroute{ }
|
|
10
10
|
run_nextroute_join{ }
|
|
11
11
|
run_nextroute_0(run_nextroute_0)
|
|
@@ -30,5 +30,5 @@ graph TD
|
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
32
|
nextmv app push -a <app-id>
|
|
33
|
-
cat /path/to/routing/input.json | nextmv app run -a <app-id> -
|
|
33
|
+
cat /path/to/routing/input.json | nextmv app run -a <app-id> -o 'instance=v171-5s'
|
|
34
34
|
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Foreach fanout example
|
|
2
|
+
|
|
3
|
+
Example of a pipeline with a fanout step (`@foreach`) that runs the same input through a solve step with different app options.
|
|
4
|
+
|
|
5
|
+
## Graph
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
graph LR
|
|
9
|
+
prepare{ }
|
|
10
|
+
prepare(prepare)
|
|
11
|
+
prepare -- foreach --> solve
|
|
12
|
+
solve(solve)
|
|
13
|
+
solve -- join --> enhance
|
|
14
|
+
enhance(enhance)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Pre-requisites
|
|
18
|
+
|
|
19
|
+
- Push the echo app as described in the [echo app README](../apps/echo/README.md)`
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
nextmv app push -a <app-id>
|
|
25
|
+
echo '{}' | nextmv app run -a <app-id>
|
|
26
|
+
```
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import nextmv
|
|
6
|
+
import nextmv.cloud
|
|
7
|
+
|
|
8
|
+
from nextpipe import AppOption, AppRunConfig, FlowSpec, app, foreach, join, needs, step
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Flow(FlowSpec):
|
|
12
|
+
@foreach() # Run the successor step for each item in the result list of this step
|
|
13
|
+
@step
|
|
14
|
+
def prepare(data: dict):
|
|
15
|
+
"""
|
|
16
|
+
Creates 3 copies of the input and configures them for 3 different app parameters.
|
|
17
|
+
"""
|
|
18
|
+
inputs = [copy.deepcopy(data) for _ in range(3)]
|
|
19
|
+
run_configs = [AppRunConfig(input, [AppOption("param", i)]) for i, input in enumerate(inputs)]
|
|
20
|
+
return run_configs
|
|
21
|
+
|
|
22
|
+
@app(app_id="echo")
|
|
23
|
+
@needs(predecessors=[prepare])
|
|
24
|
+
@step
|
|
25
|
+
def solve():
|
|
26
|
+
"""
|
|
27
|
+
Runs the model.
|
|
28
|
+
"""
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@needs(predecessors=[solve])
|
|
32
|
+
@join() # Collect the results from the previous 'foreach' step and combine them into a list passed as the arg
|
|
33
|
+
@step
|
|
34
|
+
def merge(results: list[dict]):
|
|
35
|
+
"""Merges the results."""
|
|
36
|
+
return results
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main():
|
|
40
|
+
# Read API key from file (until secrets management support)
|
|
41
|
+
with open("key.json") as f:
|
|
42
|
+
os.environ["NEXTMV_API_KEY"] = json.load(f)["nextmv_api_key"]
|
|
43
|
+
|
|
44
|
+
# Load input data
|
|
45
|
+
input = nextmv.load_local()
|
|
46
|
+
|
|
47
|
+
# Run workflow
|
|
48
|
+
flow = Flow("DecisionFlow", input.data)
|
|
49
|
+
flow.run()
|
|
50
|
+
|
|
51
|
+
# Write out the result
|
|
52
|
+
print(json.dumps(flow.get_result(flow.merge)))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
if __name__ == "__main__":
|
|
56
|
+
main()
|
|
@@ -5,7 +5,7 @@ An example of a pipeline fetching CSV data, converting it to JSON, ensembling ac
|
|
|
5
5
|
## Graph
|
|
6
6
|
|
|
7
7
|
```mermaid
|
|
8
|
-
graph
|
|
8
|
+
graph LR
|
|
9
9
|
fetch(fetch)
|
|
10
10
|
fetch --> convert
|
|
11
11
|
convert(convert)
|
|
@@ -42,5 +42,5 @@ graph TD
|
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
44
|
nextmv app push -a <app-id>
|
|
45
|
-
echo '{}' | nextmv app run -a <app-id>
|
|
45
|
+
echo '{}' | nextmv app run -a <app-id>
|
|
46
46
|
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nextpipe==0.1.0.dev3
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "v0.1.0.dev6"
|
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
from .__about__ import __version__
|
|
4
4
|
from .decorators import app as app
|
|
5
|
+
from .decorators import foreach as foreach
|
|
6
|
+
from .decorators import join as join
|
|
5
7
|
from .decorators import needs as needs
|
|
6
8
|
from .decorators import optional as optional
|
|
7
9
|
from .decorators import repeat as repeat
|
|
8
10
|
from .decorators import step as step
|
|
9
11
|
from .flow import FlowGraph as FlowGraph
|
|
10
12
|
from .flow import FlowSpec as FlowSpec
|
|
13
|
+
from .schema import AppOption as AppOption
|
|
14
|
+
from .schema import AppRunConfig as AppRunConfig
|
|
11
15
|
|
|
12
16
|
VERSION = __version__
|
|
13
17
|
"""The version of the nextpipe package."""
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from dataclasses_json import dataclass_json
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass_json
|
|
7
|
+
@dataclass
|
|
8
|
+
class Configuration:
|
|
9
|
+
"""Configuration for the pipeline."""
|
|
10
|
+
|
|
11
|
+
thread_count: int = 0
|
|
12
|
+
"""
|
|
13
|
+
Number of threads to use for parallel processing.
|
|
14
|
+
If 0, the number of threads is set to the number of available CPUs.
|
|
15
|
+
"""
|
|
16
|
+
max_step_inputs: int = 50
|
|
17
|
+
"""
|
|
18
|
+
Maximum number of inputs to a step.
|
|
19
|
+
This is used to avoid accidental combinatorial explosions due to the Cartesian product
|
|
20
|
+
of inputs used when a step has multiple predecessors which are themselves repeated or
|
|
21
|
+
foreach steps.
|
|
22
|
+
"""
|