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 CHANGED
@@ -1 +1 @@
1
- __version__ = "v0.3.5-dev.0"
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.input_type}, {self.full_result})"
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
- "input": input,
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
- # Run the application
961
- result = app.new_run_with_result(
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
- # Return result (do not unwrap if full result is requested)
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], optional
74
- Input data for the app, by default None.
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] = None
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.5.dev0
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.7; extra == 'dev'
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,,