nextpipe 0.3.5.dev0__py3-none-any.whl → 0.4.0.dev0__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.
- nextpipe/__about__.py +1 -1
- nextpipe/decorators.py +24 -8
- nextpipe/flow.py +53 -13
- nextpipe/schema.py +8 -4
- {nextpipe-0.3.5.dev0.dist-info → nextpipe-0.4.0.dev0.dist-info}/METADATA +2 -2
- nextpipe-0.4.0.dev0.dist-info/RECORD +14 -0
- nextpipe-0.3.5.dev0.dist-info/RECORD +0 -14
- {nextpipe-0.3.5.dev0.dist-info → nextpipe-0.4.0.dev0.dist-info}/WHEEL +0 -0
- {nextpipe-0.3.5.dev0.dist-info → nextpipe-0.4.0.dev0.dist-info}/licenses/LICENSE.md +0 -0
nextpipe/__about__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "v0.
|
|
1
|
+
__version__ = "v0.4.0.dev.0"
|
nextpipe/decorators.py
CHANGED
|
@@ -50,6 +50,7 @@ from collections.abc import Callable
|
|
|
50
50
|
from enum import Enum
|
|
51
51
|
from functools import wraps
|
|
52
52
|
|
|
53
|
+
import nextmv
|
|
53
54
|
from nextmv import cloud
|
|
54
55
|
from nextmv.deprecated import deprecated
|
|
55
56
|
|
|
@@ -772,10 +773,10 @@ class App:
|
|
|
772
773
|
The ID of the instance to run.
|
|
773
774
|
options : dict[str, Any]
|
|
774
775
|
The options to pass to the application.
|
|
775
|
-
input_type : InputType
|
|
776
|
-
The type of input to pass to the application (JSON or FILES).
|
|
777
776
|
full_result : bool
|
|
778
777
|
Whether to return the full result including metadata.
|
|
778
|
+
run_configuration : nextmv.RunConfiguration
|
|
779
|
+
The configuration to apply when running the app.
|
|
779
780
|
polling_options : Optional[cloud.PollingOptions]
|
|
780
781
|
Options for polling for the results of the app run.
|
|
781
782
|
"""
|
|
@@ -788,6 +789,7 @@ class App:
|
|
|
788
789
|
parameters: dict[str, typing.Any] = None,
|
|
789
790
|
options: dict[str, typing.Any] = None,
|
|
790
791
|
full_result: bool = False,
|
|
792
|
+
run_configuration: nextmv.RunConfiguration = None,
|
|
791
793
|
polling_options: typing.Optional[cloud.PollingOptions] = _DEFAULT_POLLING_OPTIONS,
|
|
792
794
|
):
|
|
793
795
|
"""
|
|
@@ -799,16 +801,22 @@ class App:
|
|
|
799
801
|
The ID of the Nextmv Application to run.
|
|
800
802
|
instance_id : str, optional
|
|
801
803
|
The ID of the instance to run. Default is defined by the app on Platform.
|
|
802
|
-
input_type : InputType, optional
|
|
803
|
-
The type of input to pass to the application, by default InputType.JSON.
|
|
804
804
|
options : dict[str, Any], optional
|
|
805
805
|
The options to pass to the application, by default None.
|
|
806
806
|
full_result : bool, optional
|
|
807
807
|
Whether to return the full result including metadata, by default False.
|
|
808
|
+
run_configuration : nextmv.RunConfiguration, optional
|
|
809
|
+
The configuration to apply when running the app, by default None.
|
|
808
810
|
polling_options : Optional[cloud.PollingOptions], optional
|
|
809
811
|
Options for polling for the results of the app run, by default _DEFAULT_POLLING_OPTIONS.
|
|
810
812
|
"""
|
|
811
813
|
|
|
814
|
+
if input_type:
|
|
815
|
+
deprecated(
|
|
816
|
+
"input_type",
|
|
817
|
+
"The 'input_type' argument is deprecated and will be removed in a future release.",
|
|
818
|
+
)
|
|
819
|
+
|
|
812
820
|
# Make sure only one of options or parameters is used.
|
|
813
821
|
if parameters and options:
|
|
814
822
|
raise ValueError("You can only use either 'parameters' or 'options', not both.")
|
|
@@ -824,6 +832,7 @@ class App:
|
|
|
824
832
|
self.options = options if options else {}
|
|
825
833
|
self.input_type = input_type
|
|
826
834
|
self.full_result = full_result
|
|
835
|
+
self.run_configuration = run_configuration
|
|
827
836
|
self.polling_options = polling_options
|
|
828
837
|
|
|
829
838
|
def __repr__(self):
|
|
@@ -835,7 +844,7 @@ class App:
|
|
|
835
844
|
A string representation of the app.
|
|
836
845
|
"""
|
|
837
846
|
|
|
838
|
-
return f"StepRun({self.app_id}, {self.instance_id}, {self.options}, {self.
|
|
847
|
+
return f"StepRun({self.app_id}, {self.instance_id}, {self.options}, {self.full_result})"
|
|
839
848
|
|
|
840
849
|
|
|
841
850
|
def app(
|
|
@@ -845,6 +854,7 @@ def app(
|
|
|
845
854
|
options: dict[str, typing.Any] = None,
|
|
846
855
|
input_type: InputType = InputType.JSON,
|
|
847
856
|
full_result: bool = False,
|
|
857
|
+
run_configuration: nextmv.RunConfiguration = None,
|
|
848
858
|
polling_options: typing.Optional[cloud.PollingOptions] = _DEFAULT_POLLING_OPTIONS,
|
|
849
859
|
):
|
|
850
860
|
"""
|
|
@@ -871,14 +881,13 @@ def app(
|
|
|
871
881
|
options : dict[str, Any]
|
|
872
882
|
The options to pass to the application. This is a dictionary of
|
|
873
883
|
parameter names and values. The values must be JSON serializable.
|
|
874
|
-
input_type : InputType
|
|
875
|
-
The type of input to pass to the application. This can be either
|
|
876
|
-
JSON or FILES. Default is JSON.
|
|
877
884
|
full_result : bool
|
|
878
885
|
Whether to return the full result of the application run. If this is
|
|
879
886
|
set to `True`, the full result (with metadata) will be returned. If
|
|
880
887
|
this is set to `False`, only the output of the application will be
|
|
881
888
|
returned.
|
|
889
|
+
run_configuration : nextmv.RunConfiguration
|
|
890
|
+
The configuration to apply when running the app.
|
|
882
891
|
polling_options : Optional[cloud.PollingOptions]
|
|
883
892
|
Options for polling for the results of the app run. This is used to
|
|
884
893
|
configure the polling behavior, such as the timeout and backoff
|
|
@@ -924,6 +933,12 @@ def app(
|
|
|
924
933
|
```
|
|
925
934
|
"""
|
|
926
935
|
|
|
936
|
+
if input_type:
|
|
937
|
+
deprecated(
|
|
938
|
+
"input_type",
|
|
939
|
+
"The 'input_type' argument is deprecated and will be removed in a future release.",
|
|
940
|
+
)
|
|
941
|
+
|
|
927
942
|
# Make sure only one of options or parameters is used.
|
|
928
943
|
if parameters and options:
|
|
929
944
|
raise ValueError("You can only use either 'parameters' or 'options', not both.")
|
|
@@ -950,6 +965,7 @@ def app(
|
|
|
950
965
|
options=converted_options,
|
|
951
966
|
input_type=input_type,
|
|
952
967
|
full_result=full_result,
|
|
968
|
+
run_configuration=run_configuration,
|
|
953
969
|
polling_options=polling_options,
|
|
954
970
|
)
|
|
955
971
|
wrapper.step.type = StepType.APP
|
nextpipe/flow.py
CHANGED
|
@@ -27,14 +27,16 @@ import base64
|
|
|
27
27
|
import copy
|
|
28
28
|
import inspect
|
|
29
29
|
import io
|
|
30
|
+
import os
|
|
30
31
|
import random
|
|
32
|
+
import tempfile
|
|
31
33
|
import threading
|
|
32
34
|
import time
|
|
33
35
|
from importlib.metadata import version
|
|
34
36
|
from itertools import product
|
|
35
37
|
from typing import Any, Optional, Union
|
|
36
38
|
|
|
37
|
-
from nextmv.cloud import Application, Client
|
|
39
|
+
from nextmv.cloud import Application, Client, RunResult
|
|
38
40
|
|
|
39
41
|
from . import config, decorators, graph, schema, threads, uplink, utils
|
|
40
42
|
from .__about__ import __version__
|
|
@@ -907,6 +909,7 @@ class Runner:
|
|
|
907
909
|
# Run the step
|
|
908
910
|
if node.parent.definition.is_app():
|
|
909
911
|
app_step: decorators.App = node.parent.definition.app
|
|
912
|
+
|
|
910
913
|
# Prepare the input for the app
|
|
911
914
|
# TODO: We only support one predecessor for app steps for now. This may
|
|
912
915
|
# change in the future. We may want to support multiple predecessors for
|
|
@@ -923,12 +926,23 @@ class Runner:
|
|
|
923
926
|
# Merge the options from the app decorator with the options from the
|
|
924
927
|
# AppRunConfig. AppRunConfig options take precedence.
|
|
925
928
|
options = app_step.options | app_run_options
|
|
929
|
+
elif isinstance(inputs[0], RunResult):
|
|
930
|
+
# If the input is a RunResult, we use its output as input.
|
|
931
|
+
run_result: RunResult = inputs[0]
|
|
932
|
+
input = run_result.output
|
|
933
|
+
options = app_step.options
|
|
934
|
+
name = node.id
|
|
926
935
|
else:
|
|
927
936
|
# If the input is not AppRunConfig, we use it directly.
|
|
928
937
|
input = inputs[0]
|
|
929
938
|
options = app_step.options
|
|
930
939
|
name = node.id
|
|
931
940
|
|
|
941
|
+
# Detect dir mode / multi-file direct input
|
|
942
|
+
is_dir_mode = False
|
|
943
|
+
if isinstance(input, str) and os.path.isdir(input):
|
|
944
|
+
is_dir_mode = True
|
|
945
|
+
|
|
932
946
|
# Modify the polling options set for the step (by default or by the
|
|
933
947
|
# user) so that the initial delay is randomized and the stopping
|
|
934
948
|
# callback is configured as the node being cancelled if the user
|
|
@@ -942,13 +956,22 @@ class Runner:
|
|
|
942
956
|
run_args = (
|
|
943
957
|
[], # No nameless arguments
|
|
944
958
|
{ # We use the named arguments to pass the user arguments to the run function
|
|
945
|
-
"
|
|
946
|
-
"run_options": options,
|
|
947
|
-
"polling_options": polling_options,
|
|
959
|
+
"options": options,
|
|
948
960
|
"name": name,
|
|
949
961
|
},
|
|
950
962
|
)
|
|
951
963
|
|
|
964
|
+
# Prepare input argument. We need to use 'input_dir_path' when dealing with a
|
|
965
|
+
# directory input (e.g., multi-file input).
|
|
966
|
+
if is_dir_mode:
|
|
967
|
+
run_args[1]["input_dir_path"] = input
|
|
968
|
+
else:
|
|
969
|
+
run_args[1]["input"] = input
|
|
970
|
+
|
|
971
|
+
# Apply run configuration if given.
|
|
972
|
+
if app_step.run_configuration is not None:
|
|
973
|
+
run_args[1]["configuration"] = app_step.run_configuration
|
|
974
|
+
|
|
952
975
|
# Prepare the application itself.
|
|
953
976
|
app = Application(
|
|
954
977
|
client=client,
|
|
@@ -957,18 +980,35 @@ class Runner:
|
|
|
957
980
|
if app_step.instance_id is not None and app_step.instance_id != "":
|
|
958
981
|
app.default_instance_id = app_step.instance_id
|
|
959
982
|
|
|
960
|
-
#
|
|
961
|
-
|
|
962
|
-
*run_args[0],
|
|
963
|
-
**run_args[1],
|
|
964
|
-
)
|
|
965
|
-
run_id = result.id
|
|
966
|
-
node.run_id = run_id
|
|
967
|
-
utils.log_internal(f"Finished app step {node.id} run, find it at {result.console_url}")
|
|
983
|
+
# We always supply an output directory path in case of implicit multi-file output
|
|
984
|
+
temp_dir = tempfile.mkdtemp(prefix="nextpipe_output_")
|
|
968
985
|
|
|
969
|
-
#
|
|
986
|
+
# Run the application
|
|
987
|
+
try:
|
|
988
|
+
run_id = app.new_run(*run_args[0], **run_args[1])
|
|
989
|
+
console_url = f"{client.console_url}/app/{app_step.app_id}/run/{run_id}?view=details"
|
|
990
|
+
utils.log_internal(f"Started app step {node.id} run, find it at {console_url}")
|
|
991
|
+
result = app.run_result_with_polling(
|
|
992
|
+
run_id=run_id, polling_options=polling_options, output_dir_path=temp_dir
|
|
993
|
+
)
|
|
994
|
+
node.run_id = run_id
|
|
995
|
+
finally: # Make sure we clean up temp dir on failure too
|
|
996
|
+
# If the temp dir is empty, remove it
|
|
997
|
+
dir_result = False
|
|
998
|
+
if not os.listdir(temp_dir):
|
|
999
|
+
os.rmdir(temp_dir)
|
|
1000
|
+
else:
|
|
1001
|
+
dir_result = True
|
|
1002
|
+
|
|
1003
|
+
# Return result
|
|
1004
|
+
# - Do not unwrap if full result is requested
|
|
1005
|
+
# - If the output came in a directory, return the directory path
|
|
970
1006
|
if app_step.full_result:
|
|
1007
|
+
if dir_result:
|
|
1008
|
+
result.output = temp_dir
|
|
971
1009
|
return result
|
|
1010
|
+
if dir_result:
|
|
1011
|
+
return temp_dir
|
|
972
1012
|
return result.output
|
|
973
1013
|
|
|
974
1014
|
else:
|
nextpipe/schema.py
CHANGED
|
@@ -70,8 +70,10 @@ class AppRunConfig:
|
|
|
70
70
|
|
|
71
71
|
Parameters
|
|
72
72
|
----------
|
|
73
|
-
input : dict[str, Any],
|
|
74
|
-
Input data for the app,
|
|
73
|
+
input : Union[dict[str, Any], str, Any]
|
|
74
|
+
Input data for the app. A JSON app can take a dictionary, multi-file apps can take
|
|
75
|
+
a directory path as a string. Other types will be passed to the underlying Python
|
|
76
|
+
SDK as-is (e.g., nextmv.Input).
|
|
75
77
|
options : Union[list[AppOption], dict[str, Any]], optional
|
|
76
78
|
Options for running the app, by default empty. These can be provided as a list of
|
|
77
79
|
`AppOption` instances, or, simply as a dictionary of key-value pairs.
|
|
@@ -88,8 +90,10 @@ class AppRunConfig:
|
|
|
88
90
|
... )
|
|
89
91
|
"""
|
|
90
92
|
|
|
91
|
-
input: dict[str, Any]
|
|
92
|
-
"""Input for the app.
|
|
93
|
+
input: Union[dict[str, Any], str, Any]
|
|
94
|
+
"""Input for the app. A JSON app can take a dictionary, multi-file apps can take a
|
|
95
|
+
directory path as a string. Other types will be passed to the underlying Python SDK
|
|
96
|
+
as-is (e.g., nextmv.Input)."""
|
|
93
97
|
options: Union[list[AppOption], dict[str, Any]] = field(default_factory=list)
|
|
94
98
|
"""Options for running the app."""
|
|
95
99
|
name: Optional[str] = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nextpipe
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0.dev0
|
|
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://nextpipe.docs.nextmv.io/en/latest/
|
|
@@ -108,7 +108,7 @@ Requires-Dist: dataclasses-json>=0.6.7
|
|
|
108
108
|
Requires-Dist: nextmv>=0.29.4
|
|
109
109
|
Requires-Dist: requests>=2.31.0
|
|
110
110
|
Provides-Extra: dev
|
|
111
|
-
Requires-Dist: goldie>=0.1.
|
|
111
|
+
Requires-Dist: goldie>=0.1.8; extra == 'dev'
|
|
112
112
|
Requires-Dist: ruff>=0.11.6; extra == 'dev'
|
|
113
113
|
Description-Content-Type: text/markdown
|
|
114
114
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
nextpipe/__about__.py,sha256=mdzuNb93MdHDpJbMl-whjJJUbZi4Yyfl7Nv47quBabA,29
|
|
2
|
+
nextpipe/__init__.py,sha256=SzRhi2z33zmvskfgqoRHwaKvRnt8G1_JJR1M7BXlda0,694
|
|
3
|
+
nextpipe/config.py,sha256=JSShEaK3fnqieGofalQysKxEJUkyrWIRbwhdyH9yYZM,1659
|
|
4
|
+
nextpipe/decorators.py,sha256=-fbmwDVi0pnEZnJ8xThCd_Hmm8O1pErG0m2nTudw-2M,25568
|
|
5
|
+
nextpipe/flow.py,sha256=37AnTFWJxQJGj-eGzuOvGMzPvwxSkpdT5O3s31d3uV0,38933
|
|
6
|
+
nextpipe/graph.py,sha256=Oi8HQ4fgvBYxpRK6xBoLtoxftGb-gCOb09BqFwzrwWs,2867
|
|
7
|
+
nextpipe/schema.py,sha256=gzWcaDwt65OMDnciU2T8--Eb4u77J8w3sUN1iXlxNgc,3224
|
|
8
|
+
nextpipe/threads.py,sha256=yxyoRj3aknVMeGZzlVM1HcXhL-iXsCovaTE5OfFM4TI,9052
|
|
9
|
+
nextpipe/uplink.py,sha256=j4k7Msa1Il7uxrQeXd1yoCMWWd9KmkbQb72EZy4zMSs,11646
|
|
10
|
+
nextpipe/utils.py,sha256=JTirVzh3npkjikMg3-fbtuLeIeG1zI7Rxu-1xREu2LY,7916
|
|
11
|
+
nextpipe-0.4.0.dev0.dist-info/METADATA,sha256=IZcLKWIOYZ_t56pCGFm2iGQCc4TgnJqSr8vz8WKSBr0,8765
|
|
12
|
+
nextpipe-0.4.0.dev0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
+
nextpipe-0.4.0.dev0.dist-info/licenses/LICENSE.md,sha256=FpVScuRcgdbeBNVsMzoPyBbKL2eCB1vFor1vfNNFEj4,4106
|
|
14
|
+
nextpipe-0.4.0.dev0.dist-info/RECORD,,
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
nextpipe/__about__.py,sha256=LF9FBcRfZAKRmyrREOND-uQQeSAcbb_afE2DUHOhT6A,29
|
|
2
|
-
nextpipe/__init__.py,sha256=SzRhi2z33zmvskfgqoRHwaKvRnt8G1_JJR1M7BXlda0,694
|
|
3
|
-
nextpipe/config.py,sha256=JSShEaK3fnqieGofalQysKxEJUkyrWIRbwhdyH9yYZM,1659
|
|
4
|
-
nextpipe/decorators.py,sha256=1pndK9ej5JQJjtYFugzidlEeyyqPxWi0zvCaeDQfAro,25008
|
|
5
|
-
nextpipe/flow.py,sha256=wIXeCqxuWgZuDty4pScEOv1d1m-9SkPZ2qo_55u4nkg,37150
|
|
6
|
-
nextpipe/graph.py,sha256=Oi8HQ4fgvBYxpRK6xBoLtoxftGb-gCOb09BqFwzrwWs,2867
|
|
7
|
-
nextpipe/schema.py,sha256=jnyXimHepzWPGCEpSyyObLtza8Cb8RSVpCP9sS9vWWI,2854
|
|
8
|
-
nextpipe/threads.py,sha256=yxyoRj3aknVMeGZzlVM1HcXhL-iXsCovaTE5OfFM4TI,9052
|
|
9
|
-
nextpipe/uplink.py,sha256=j4k7Msa1Il7uxrQeXd1yoCMWWd9KmkbQb72EZy4zMSs,11646
|
|
10
|
-
nextpipe/utils.py,sha256=JTirVzh3npkjikMg3-fbtuLeIeG1zI7Rxu-1xREu2LY,7916
|
|
11
|
-
nextpipe-0.3.5.dev0.dist-info/METADATA,sha256=eQM8CjG4xcy4zQ4O_6dBU3dWTtzVflHDFDv7IPfI2LU,8765
|
|
12
|
-
nextpipe-0.3.5.dev0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
-
nextpipe-0.3.5.dev0.dist-info/licenses/LICENSE.md,sha256=FpVScuRcgdbeBNVsMzoPyBbKL2eCB1vFor1vfNNFEj4,4106
|
|
14
|
-
nextpipe-0.3.5.dev0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|