nextpipe 0.1.0.dev1__tar.gz → 0.1.0.dev3__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.
Files changed (34) hide show
  1. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/PKG-INFO +2 -2
  2. nextpipe-0.1.0.dev3/examples/pipeline-chain/README.md +21 -0
  3. nextpipe-0.1.0.dev3/examples/pipeline-chain/app.yaml +7 -0
  4. nextpipe-0.1.0.dev3/examples/pipeline-chain/main.py +50 -0
  5. nextpipe-0.1.0.dev3/examples/pipeline-chain/requirements.txt +1 -0
  6. nextpipe-0.1.0.dev3/examples/pipeline-complex/README.md +37 -0
  7. nextpipe-0.1.0.dev3/examples/pipeline-complex/app.yaml +7 -0
  8. nextpipe-0.1.0.dev3/examples/pipeline-complex/main.py +75 -0
  9. nextpipe-0.1.0.dev3/examples/pipeline-complex/requirements.txt +1 -0
  10. nextpipe-0.1.0.dev3/examples/pipeline-ensemble/README.md +29 -0
  11. nextpipe-0.1.0.dev3/examples/pipeline-ensemble/app.yaml +7 -0
  12. nextpipe-0.1.0.dev3/examples/pipeline-ensemble/main.py +49 -0
  13. nextpipe-0.1.0.dev3/examples/pipeline-ensemble/requirements.txt +1 -0
  14. nextpipe-0.1.0.dev3/examples/pipeline-preprocess/README.md +39 -0
  15. nextpipe-0.1.0.dev3/examples/pipeline-preprocess/app.yaml +7 -0
  16. nextpipe-0.1.0.dev3/examples/pipeline-preprocess/main.py +106 -0
  17. nextpipe-0.1.0.dev3/examples/pipeline-preprocess/requirements.txt +1 -0
  18. nextpipe-0.1.0.dev3/nextpipe/__about__.py +1 -0
  19. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/pyproject.toml +1 -1
  20. nextpipe-0.1.0.dev1/nextpipe/__about__.py +0 -1
  21. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/.github/workflows/publish.yml +0 -0
  22. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/.github/workflows/python-lint.yml +0 -0
  23. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/.github/workflows/python-test.yml +0 -0
  24. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/.gitignore +0 -0
  25. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/.prettierrc.yml +0 -0
  26. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/LICENSE.md +0 -0
  27. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/README.md +0 -0
  28. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/nextpipe/__init__.py +0 -0
  29. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/nextpipe/decorators.py +0 -0
  30. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/nextpipe/flow.py +0 -0
  31. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/nextpipe/utils.py +0 -0
  32. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/nextpipe.code-workspace +0 -0
  33. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/tests/__init__.py +0 -0
  34. {nextpipe-0.1.0.dev1 → nextpipe-0.1.0.dev3}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nextpipe
3
- Version: 0.1.0.dev1
3
+ Version: 0.1.0.dev3
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
@@ -104,7 +104,7 @@ Classifier: Programming Language :: Python :: 3.10
104
104
  Classifier: Programming Language :: Python :: 3.11
105
105
  Classifier: Programming Language :: Python :: 3.12
106
106
  Requires-Python: >=3.8
107
- Requires-Dist: nextmv>=0.12.0
107
+ Requires-Dist: nextmv>=0.12.1.dev2
108
108
  Requires-Dist: pathos>=0.3.2
109
109
  Requires-Dist: requests>=2.31.0
110
110
  Provides-Extra: dev
@@ -0,0 +1,21 @@
1
+ # Chain example
2
+
3
+ A simple chain pipeline.
4
+
5
+ ## Graph
6
+
7
+ ```mermaid
8
+ graph TD
9
+ prepare(prepare)
10
+ prepare --> solve
11
+ solve(solve)
12
+ solve --> enhance
13
+ enhance(enhance)
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ```bash
19
+ nextmv app push -a <app-id>
20
+ echo '{"hello": "world!"}' | nextmv app run -a <app-id> -e "8c16gb12h"
21
+ ```
@@ -0,0 +1,7 @@
1
+ type: python
2
+ runtime: ghcr.io/nextmv-io/runtime/python:3.11
3
+ files:
4
+ - main.py
5
+ - key.json
6
+ python:
7
+ pip-requirements: requirements.txt
@@ -0,0 +1,50 @@
1
+ import json
2
+ import os
3
+
4
+ import nextmv
5
+
6
+ from nextpipe import FlowSpec, app, needs, step
7
+
8
+
9
+ # >>> Workflow definition
10
+ class Flow(FlowSpec):
11
+ @step
12
+ def prepare(input: dict):
13
+ """Prepares the data."""
14
+ input["prepared"] = True
15
+ return input
16
+
17
+ @app(app_id="echo")
18
+ @needs(predecessors=[prepare])
19
+ @step
20
+ def solve():
21
+ """Runs the model."""
22
+ pass
23
+
24
+ @needs(predecessors=[solve])
25
+ @step
26
+ def enhance(result: dict):
27
+ """Enhances the result."""
28
+ output = result["solution"] # Unwrap the solution
29
+ output["echo"]["enhanced"] = True
30
+ return output
31
+
32
+
33
+ def main():
34
+ # Read API key from file (until secrets management support)
35
+ with open("key.json") as f:
36
+ os.environ["NEXTMV_API_KEY"] = json.load(f)["nextmv_api_key"]
37
+
38
+ # Load input data
39
+ input = nextmv.load_local()
40
+
41
+ # Run workflow
42
+ flow = Flow("DecisionFlow", input.data)
43
+ flow.run()
44
+
45
+ # Write out the result
46
+ print(json.dumps(flow.get_result(flow.enhance)))
47
+
48
+
49
+ if __name__ == "__main__":
50
+ main()
@@ -0,0 +1 @@
1
+ nextpipe==0.1.0.dev2
@@ -0,0 +1,37 @@
1
+ # Complex example
2
+
3
+ A more complex pipeline combining some concepts.
4
+
5
+ ## Graph
6
+
7
+ ```mermaid
8
+ graph TD
9
+ fetch_data(fetch_data)
10
+ fetch_data --> run_nextroute
11
+ fetch_data --> run_ortools
12
+ fetch_data --> run_pyvroom
13
+ run_nextroute{ }
14
+ run_nextroute_join{ }
15
+ run_nextroute_0(run_nextroute_0)
16
+ run_nextroute --> run_nextroute_0
17
+ run_nextroute_0 --> run_nextroute_join
18
+ run_nextroute_1(run_nextroute_1)
19
+ run_nextroute --> run_nextroute_1
20
+ run_nextroute_1 --> run_nextroute_join
21
+ run_nextroute_2(run_nextroute_2)
22
+ run_nextroute --> run_nextroute_2
23
+ run_nextroute_2 --> run_nextroute_join
24
+ run_nextroute_join --> pick_best
25
+ run_ortools(run_ortools)
26
+ run_ortools --> pick_best
27
+ run_pyvroom(run_pyvroom)
28
+ run_pyvroom --> pick_best
29
+ pick_best(pick_best)
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ```bash
35
+ nextmv app push -a <app-id>
36
+ echo '{}' | nextmv app run -a <app-id> -e "8c16gb12h"
37
+ ```
@@ -0,0 +1,7 @@
1
+ type: python
2
+ runtime: ghcr.io/nextmv-io/runtime/python:3.11
3
+ files:
4
+ - main.py
5
+ - key.json
6
+ python:
7
+ pip-requirements: requirements.txt
@@ -0,0 +1,75 @@
1
+ import json
2
+ import os
3
+
4
+ import nextmv
5
+ import requests
6
+
7
+ from nextpipe import FlowSpec, app, needs, repeat, step
8
+
9
+
10
+ # >>> Workflow definition
11
+ class Flow(FlowSpec):
12
+ @step
13
+ def fetch_data(_):
14
+ """Fetches data from the database."""
15
+ file_url = "https://gist.githubusercontent.com/merschformann/a90959b87d1360b604e4a9f6457340ca/raw/661e631376bdf78a07548a3cd136c1fc6e47c639/muenster.json"
16
+ response = requests.get(file_url)
17
+ return response.json()
18
+
19
+ @repeat(repetitions=3)
20
+ @app(app_id="routing-nextroute")
21
+ @needs(predecessors=[fetch_data])
22
+ @step
23
+ def run_nextroute():
24
+ """Runs the model."""
25
+ pass
26
+
27
+ @app(app_id="routing-ortools")
28
+ @needs(predecessors=[fetch_data])
29
+ @step
30
+ def run_ortools():
31
+ """Runs the model."""
32
+ pass
33
+
34
+ @app(app_id="routing-pyvroom")
35
+ @needs(predecessors=[fetch_data])
36
+ @step
37
+ def run_pyvroom():
38
+ """Runs the model."""
39
+ pass
40
+
41
+ @needs(predecessors=[run_nextroute, run_ortools, run_pyvroom])
42
+ @step
43
+ def pick_best(
44
+ results_nextroute: list[dict],
45
+ result_ortools: dict,
46
+ result_pyvroom: dict,
47
+ ):
48
+ """Aggregates the results."""
49
+ results = results_nextroute + [result_ortools, result_pyvroom]
50
+ best_solution_idx = min(
51
+ range(len(results)),
52
+ key=lambda i: results[i]["statistics"]["result"]["value"],
53
+ )
54
+
55
+ values = [result["statistics"]["result"]["value"] for result in results]
56
+ values.sort()
57
+ nextmv.log(f"Values: {values}")
58
+
59
+ return results[best_solution_idx]
60
+
61
+
62
+ def main():
63
+ # Read API key from file (until secrets management support)
64
+ with open("key.json") as f:
65
+ os.environ["NEXTMV_API_KEY"] = json.load(f)["nextmv_api_key"]
66
+
67
+ # Run workflow
68
+ flow = Flow("DecisionFlow", None)
69
+ flow.run()
70
+ result = flow.get_result(flow.pick_best)
71
+ print(json.dumps(result))
72
+
73
+
74
+ if __name__ == "__main__":
75
+ main()
@@ -0,0 +1 @@
1
+ nextpipe==0.1.0.dev2
@@ -0,0 +1,29 @@
1
+ # Ensemble example
2
+
3
+ A basic ensemble pipeline.
4
+
5
+ ## Graph
6
+
7
+ ```mermaid
8
+ graph TD
9
+ run_nextroute{ }
10
+ run_nextroute_join{ }
11
+ run_nextroute_0(run_nextroute_0)
12
+ run_nextroute --> run_nextroute_0
13
+ run_nextroute_0 --> run_nextroute_join
14
+ run_nextroute_1(run_nextroute_1)
15
+ run_nextroute --> run_nextroute_1
16
+ run_nextroute_1 --> run_nextroute_join
17
+ run_nextroute_2(run_nextroute_2)
18
+ run_nextroute --> run_nextroute_2
19
+ run_nextroute_2 --> run_nextroute_join
20
+ run_nextroute_join --> pick_best
21
+ pick_best(pick_best)
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```bash
27
+ nextmv app push -a <app-id>
28
+ cat /path/to/routing/input.json | nextmv app run -a <app-id> -e "8c16gb12h"
29
+ ```
@@ -0,0 +1,7 @@
1
+ type: python
2
+ runtime: ghcr.io/nextmv-io/runtime/python:3.11
3
+ files:
4
+ - main.py
5
+ - key.json
6
+ python:
7
+ pip-requirements: requirements.txt
@@ -0,0 +1,49 @@
1
+ import json
2
+ import os
3
+
4
+ import nextmv
5
+
6
+ from nextpipe import FlowSpec, app, needs, repeat, step
7
+
8
+
9
+ # >>> Workflow definition
10
+ class Flow(FlowSpec):
11
+ @app(
12
+ app_id="routing-nextroute",
13
+ instance_id="v171-5s",
14
+ parameters={"model.constraints.enable.cluster": True},
15
+ )
16
+ @repeat(repetitions=3)
17
+ @step
18
+ def run_nextroute():
19
+ """Runs the model."""
20
+ pass
21
+
22
+ @needs(predecessors=[run_nextroute])
23
+ @step
24
+ def pick_best(results: list[dict]):
25
+ """Aggregates the results."""
26
+ best_solution_idx = min(
27
+ range(len(results)),
28
+ key=lambda i: results[i]["statistics"]["result"]["value"],
29
+ )
30
+ return results[best_solution_idx]
31
+
32
+
33
+ def main():
34
+ # Read API key from file (until secrets management support)
35
+ with open("key.json") as f:
36
+ os.environ["NEXTMV_API_KEY"] = json.load(f)["nextmv_api_key"]
37
+
38
+ # Load input data
39
+ input = nextmv.load_local()
40
+
41
+ # Run workflow
42
+ flow = Flow("DecisionFlow", input.data)
43
+ flow.run()
44
+ result = flow.get_result(flow.pick_best)
45
+ print(json.dumps(result))
46
+
47
+
48
+ if __name__ == "__main__":
49
+ main()
@@ -0,0 +1 @@
1
+ nextpipe==0.1.0.dev2
@@ -0,0 +1,39 @@
1
+ # CSV to JSON multi-solver ensemble example
2
+
3
+ An example of a pipeline fetching CSV data, converting it to JSON, ensembling across multiple solvers and repetitions and picking the best result.
4
+
5
+ ## Graph
6
+
7
+ ```mermaid
8
+ graph TD
9
+ fetch(fetch)
10
+ fetch --> convert
11
+ convert(convert)
12
+ convert --> solve_nextroute
13
+ convert --> solve_vroom
14
+ convert --> solve_ortools
15
+ solve_nextroute{ }
16
+ solve_nextroute_join{ }
17
+ solve_nextroute_0(solve_nextroute_0)
18
+ solve_nextroute --> solve_nextroute_0
19
+ solve_nextroute_0 --> solve_nextroute_join
20
+ solve_nextroute_1(solve_nextroute_1)
21
+ solve_nextroute --> solve_nextroute_1
22
+ solve_nextroute_1 --> solve_nextroute_join
23
+ solve_nextroute_2(solve_nextroute_2)
24
+ solve_nextroute --> solve_nextroute_2
25
+ solve_nextroute_2 --> solve_nextroute_join
26
+ solve_nextroute_join --> pick_best
27
+ solve_vroom(solve_vroom)
28
+ solve_vroom --> pick_best
29
+ solve_ortools(solve_ortools)
30
+ solve_ortools --> pick_best
31
+ pick_best(pick_best)
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ```bash
37
+ nextmv app push -a <app-id>
38
+ echo '{}' | nextmv app run -a <app-id> -e "8c16gb12h"
39
+ ```
@@ -0,0 +1,7 @@
1
+ type: python
2
+ runtime: ghcr.io/nextmv-io/runtime/python:3.11
3
+ files:
4
+ - main.py
5
+ - key.json
6
+ python:
7
+ pip-requirements: requirements.txt
@@ -0,0 +1,106 @@
1
+ import csv
2
+ import json
3
+ import os
4
+
5
+ import requests
6
+ from nextmv.logger import log
7
+
8
+ from nextpipe import FlowSpec, app, needs, repeat, step
9
+
10
+
11
+ # >>> Workflow definition
12
+ class Flow(FlowSpec):
13
+ # >>> Fetch CSV data from external source
14
+ @step
15
+ def fetch(_: dict):
16
+ file_url = "https://gist.githubusercontent.com/merschformann/5dc2d06b246f924f8c65e93dd3c646e2/raw/fca52de5b7b9a1396e8d9525f8006488ac3467c9/muenster-stops.csv"
17
+ response = requests.get(file_url)
18
+ return response.text
19
+
20
+ # >>> Convert CSV data to JSON
21
+ @needs(predecessors=[fetch])
22
+ @step
23
+ def convert(input_csv: str):
24
+ reader = csv.reader(input_csv.splitlines())
25
+ next(reader) # skip header
26
+ return json.dumps(
27
+ {
28
+ "vehicles": [
29
+ {
30
+ "id": f"vehicle-{i}",
31
+ "start_location": {"lon": 7.62558, "lat": 51.96223},
32
+ "end_location": {"lon": 7.62558, "lat": 51.96223},
33
+ "start_time": "2024-09-04T11:00:00+00:00",
34
+ "speed": 10,
35
+ "capacity": 27,
36
+ }
37
+ for i in range(20)
38
+ ],
39
+ "stops": [
40
+ {
41
+ "id": row[0],
42
+ "location": {"lon": float(row[1]), "lat": float(row[2])},
43
+ "quantity": -1,
44
+ "unplanned_penalty": 2000000000,
45
+ }
46
+ for row in reader
47
+ ],
48
+ }
49
+ )
50
+
51
+ # >>> Solve the problem using different solvers
52
+ @app(
53
+ app_id="routing-nextroute",
54
+ parameters={"solve.duration": "30s"},
55
+ )
56
+ @repeat(repetitions=3)
57
+ @needs(predecessors=[convert])
58
+ @step
59
+ def solve_nextroute():
60
+ pass
61
+
62
+ @app(app_id="routing-pyvroom")
63
+ @needs(predecessors=[convert])
64
+ @step
65
+ def solve_vroom():
66
+ pass
67
+
68
+ @app(app_id="routing-ortools")
69
+ @needs(predecessors=[convert])
70
+ @step
71
+ def solve_ortools():
72
+ pass
73
+
74
+ # >>> Pick the best solution
75
+ @needs(predecessors=[solve_nextroute, solve_vroom, solve_ortools])
76
+ @step
77
+ def pick_best(
78
+ nextroute_results: list[dict],
79
+ vroom_result: dict,
80
+ ortools_result: dict,
81
+ ):
82
+ results = nextroute_results + [vroom_result, ortools_result]
83
+ best_solution_idx = min(
84
+ range(len(results)),
85
+ key=lambda i: results[i]["statistics"]["result"]["value"],
86
+ )
87
+ for result in results:
88
+ log(f"{result['statistics']['run']['custom']['solver']}: " + f"{result['statistics']['result']['value']}")
89
+ return results[best_solution_idx]
90
+
91
+
92
+ def main():
93
+ # Read API key from file (until secrets management support)
94
+ with open("key.json") as f:
95
+ os.environ["NEXTMV_API_KEY"] = json.load(f)["nextmv_api_key"]
96
+
97
+ # Run workflow
98
+ flow = Flow("DecisionFlow", None)
99
+ flow.run()
100
+
101
+ # Write out the result
102
+ print(json.dumps(flow.get_result(flow.pick_best)))
103
+
104
+
105
+ if __name__ == "__main__":
106
+ main()
@@ -0,0 +1 @@
1
+ nextpipe==0.1.0.dev2
@@ -0,0 +1 @@
1
+ __version__ = "v0.1.0.dev3"
@@ -18,7 +18,7 @@ classifiers = [
18
18
  dependencies = [
19
19
  "requests>=2.31.0",
20
20
  "pathos>=0.3.2",
21
- "nextmv>=0.12.0",
21
+ "nextmv>=0.12.1.dev2",
22
22
  ]
23
23
  description = "Framework for Decision Pipeline modeling and execution"
24
24
  dynamic = [
@@ -1 +0,0 @@
1
- __version__ = "v0.1.0.dev1"
File without changes
File without changes
File without changes