nextpipe 0.7.0.dev0__py3-none-any.whl → 0.7.3.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.7.0-dev.0"
1
+ __version__ = "v0.7.3-dev.0"
nextpipe/decorators.py CHANGED
@@ -798,12 +798,16 @@ class App:
798
798
  The ID of the Nextmv Application to run.
799
799
  instance_id : str, optional
800
800
  The ID of the instance to run. Default is defined by the app on Platform.
801
+ A predecessor step may override this per run by returning an `AppRunConfig`
802
+ carrying its own `instance_id`.
801
803
  options : dict[str, Any], optional
802
804
  The options to pass to the application, by default None.
803
805
  full_result : bool, optional
804
806
  Whether to return the full result including metadata, by default False.
805
807
  run_configuration : nextmv.RunConfiguration, optional
806
- The configuration to apply when running the app, by default None.
808
+ The configuration to apply when running the app, by default None. A
809
+ predecessor step may override this per run by returning an
810
+ `AppRunConfig` carrying its own `run_configuration`.
807
811
  polling_options : Optional[nextmv.PollingOptions], optional
808
812
  Options for polling for the results of the app run, by default _DEFAULT_POLLING_OPTIONS.
809
813
  bypass_result : typing.Any, optional
@@ -884,7 +888,9 @@ def app(
884
888
  app_id : str
885
889
  The ID of the application to run.
886
890
  instance_id : str
887
- The ID of the instance to run. Default is defined by the app on Platform.
891
+ The ID of the instance to run. Default is defined by the app on Platform. A
892
+ predecessor step may override this per run by returning an `AppRunConfig`
893
+ carrying its own `instance_id`.
888
894
  options : dict[str, Any]
889
895
  The options to pass to the application. This is a dictionary of
890
896
  parameter names and values. The values must be JSON serializable.
@@ -894,7 +900,10 @@ def app(
894
900
  this is set to `False`, only the output of the application will be
895
901
  returned.
896
902
  run_configuration : nextmv.RunConfiguration
897
- The configuration to apply when running the app.
903
+ The configuration to apply when running the app. A predecessor step may
904
+ override this per run by returning an `AppRunConfig` carrying its own
905
+ `run_configuration`. In that case, the configuration of the `AppRunConfig`
906
+ replaces this one as a whole, i.e., no fields are inherited from it.
898
907
  polling_options : Optional[nextmv.PollingOptions]
899
908
  Options for polling for the results of the app run. This is used to
900
909
  configure the polling behavior, such as the timeout and backoff
nextpipe/flow.py CHANGED
@@ -901,14 +901,15 @@ class Runner:
901
901
  node: FlowNode,
902
902
  inputs: list[object],
903
903
  app_step: decorators.App,
904
- ) -> tuple[dict[str, Any], nextmv.PollingOptions, bool]:
904
+ ) -> tuple[dict[str, Any], nextmv.PollingOptions, bool, str]:
905
905
  """
906
906
  Prepare arguments for running an app step.
907
907
 
908
908
  Returns
909
909
  -------
910
- tuple[dict[str, Any], nextmv.PollingOptions, bool]
911
- A tuple of run kwargs, polling options, and whether the input is dir mode.
910
+ tuple[dict[str, Any], nextmv.PollingOptions, bool, str]
911
+ A tuple of run kwargs, polling options, whether the input is dir mode, and
912
+ the ID of the instance to run.
912
913
  """
913
914
 
914
915
  app_run_name, app_run_description = Runner.__determine_sub_run_info(app_step.app_id, node.id)
@@ -920,6 +921,9 @@ class Runner:
920
921
  if len(inputs) > 1:
921
922
  raise Exception(f"App steps cannot have more than one predecessor, but {node.id} has {len(inputs)}")
922
923
 
924
+ run_configuration = app_step.run_configuration
925
+ instance_id = app_step.instance_id
926
+
923
927
  if isinstance(inputs[0], schema.AppRunConfig):
924
928
  app_run_config: schema.AppRunConfig = inputs[0]
925
929
  input_data = app_run_config.input
@@ -929,6 +933,12 @@ class Runner:
929
933
  app_run_description = app_run_config.description
930
934
  # AppRunConfig options take precedence over decorator options.
931
935
  options = app_step.options | app_run_config.get_options()
936
+ # An AppRunConfig run configuration replaces the decorator one as a whole.
937
+ if app_run_config.run_configuration is not None:
938
+ run_configuration = app_run_config.run_configuration
939
+ # Same for the instance to run on.
940
+ if app_run_config.instance_id:
941
+ instance_id = app_run_config.instance_id
932
942
  elif isinstance(inputs[0], nextmv.RunResult):
933
943
  run_result: nextmv.RunResult = inputs[0]
934
944
  input_data = run_result.output
@@ -953,10 +963,10 @@ class Runner:
953
963
  run_kwargs["input_dir_path"] = input_data
954
964
  else:
955
965
  run_kwargs["input"] = input_data
956
- if app_step.run_configuration is not None:
957
- run_kwargs["configuration"] = app_step.run_configuration
966
+ if run_configuration is not None:
967
+ run_kwargs["configuration"] = run_configuration
958
968
 
959
- return run_kwargs, polling_options, is_dir_mode
969
+ return run_kwargs, polling_options, is_dir_mode, instance_id
960
970
 
961
971
  @staticmethod
962
972
  def __execute_app_run(
@@ -969,6 +979,7 @@ class Runner:
969
979
  polling_options: nextmv.PollingOptions,
970
980
  is_dir_mode: bool,
971
981
  temp_dir: str,
982
+ instance_id: str,
972
983
  ) -> nextmv.RunResult:
973
984
  """
974
985
  Execute an app run or return bypass output wrapped as a run result.
@@ -1000,7 +1011,7 @@ class Runner:
1000
1011
  user_email="unavailable",
1001
1012
  metadata=nextmv.Metadata(
1002
1013
  application_id=app_step.app_id or "unavailable",
1003
- application_instance_id=app_step.instance_id or "unavailable",
1014
+ application_instance_id=instance_id or "unavailable",
1004
1015
  application_version_id="unavailable",
1005
1016
  created_at=datetime.datetime.now(),
1006
1017
  duration=0.0,
@@ -1067,15 +1078,17 @@ class Runner:
1067
1078
  if node.parent.definition.is_app():
1068
1079
  app_step: decorators.App = node.parent.definition.app
1069
1080
 
1070
- run_kwargs, polling_options, is_dir_mode = Runner.__prepare_app_run_args(node, inputs, app_step)
1081
+ run_kwargs, polling_options, is_dir_mode, instance_id = Runner.__prepare_app_run_args(
1082
+ node, inputs, app_step
1083
+ )
1071
1084
 
1072
1085
  # Prepare the application itself.
1073
1086
  app = Application(
1074
1087
  client=client,
1075
1088
  id=app_step.app_id,
1076
1089
  )
1077
- if app_step.instance_id is not None and app_step.instance_id != "":
1078
- app.default_instance_id = app_step.instance_id
1090
+ if instance_id is not None and instance_id != "":
1091
+ app.default_instance_id = instance_id
1079
1092
 
1080
1093
  # We always supply an output directory path in case of implicit multi-file output
1081
1094
  temp_dir = tempfile.mkdtemp(prefix="nextpipe_output_")
@@ -1092,6 +1105,7 @@ class Runner:
1092
1105
  polling_options=polling_options,
1093
1106
  is_dir_mode=is_dir_mode,
1094
1107
  temp_dir=temp_dir,
1108
+ instance_id=instance_id,
1095
1109
  )
1096
1110
 
1097
1111
  finally: # Make sure we clean up temp dir on failure too
nextpipe/schema.py CHANGED
@@ -14,11 +14,31 @@ AppRunConfig
14
14
  from dataclasses import dataclass, field
15
15
  from typing import Any
16
16
 
17
- from dataclasses_json import dataclass_json
17
+ import nextmv
18
+ from dataclasses_json import config, dataclass_json
18
19
 
19
20
  from . import utils
20
21
 
21
22
 
23
+ def _encode_run_configuration(
24
+ run_configuration: nextmv.RunConfiguration | None,
25
+ ) -> dict[str, Any] | None:
26
+ """Encode a run configuration for JSON serialization."""
27
+
28
+ return run_configuration.to_dict() if run_configuration is not None else None
29
+
30
+
31
+ def _decode_run_configuration(
32
+ run_configuration: dict[str, Any] | nextmv.RunConfiguration | None,
33
+ ) -> nextmv.RunConfiguration | None:
34
+ """Decode a run configuration from its JSON representation."""
35
+
36
+ if run_configuration is None or isinstance(run_configuration, nextmv.RunConfiguration):
37
+ return run_configuration
38
+
39
+ return nextmv.RunConfiguration.from_dict(run_configuration)
40
+
41
+
22
42
  @dataclass_json
23
43
  @dataclass
24
44
  class AppOption:
@@ -79,6 +99,16 @@ class AppRunConfig:
79
99
  `AppOption` instances, or, simply as a dictionary of key-value pairs.
80
100
  name : str, optional
81
101
  Name for the run, by default None.
102
+ description : str, optional
103
+ Description for the run, by default None.
104
+ run_configuration : nextmv.RunConfiguration, optional
105
+ The configuration to apply when running the app, by default None. If given, it
106
+ replaces the `run_configuration` of the `app` decorator for this run. Note that
107
+ it replaces it as a whole, i.e., no fields are inherited from the decorator's
108
+ configuration.
109
+ instance_id : str, optional
110
+ The ID of the instance to run, by default None. If given, it replaces the
111
+ `instance_id` of the `app` decorator for this run.
82
112
 
83
113
  Examples
84
114
  --------
@@ -88,6 +118,17 @@ class AppRunConfig:
88
118
  ... options={"threads": 4},
89
119
  ... name="my-run"
90
120
  ... )
121
+
122
+ The run configuration and instance can be chosen per run, e.g., to pick an
123
+ execution class based on the size of the scenario at hand.
124
+
125
+ >>> import nextmv
126
+ >>> from nextpipe import AppRunConfig
127
+ >>> config = AppRunConfig(
128
+ ... input={"data": [1, 2, 3]},
129
+ ... run_configuration=nextmv.RunConfiguration(execution_class="8c16gb12h"),
130
+ ... instance_id="tuned-for-large",
131
+ ... )
91
132
  """
92
133
 
93
134
  input: dict[str, Any] | str | Any
@@ -100,6 +141,18 @@ class AppRunConfig:
100
141
  """Name for the run."""
101
142
  description: str | None = None
102
143
  """Description for the run."""
144
+ run_configuration: nextmv.RunConfiguration | None = field(
145
+ default=None,
146
+ metadata=config(
147
+ encoder=_encode_run_configuration,
148
+ decoder=_decode_run_configuration,
149
+ ),
150
+ )
151
+ """The configuration to apply when running the app. Replaces the `run_configuration`
152
+ of the `app` decorator as a whole, if given."""
153
+ instance_id: str | None = None
154
+ """The ID of the instance to run. Replaces the `instance_id` of the `app` decorator,
155
+ if given."""
103
156
 
104
157
  def get_options(self) -> dict[str, Any]:
105
158
  """
@@ -1,9 +1,9 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: nextpipe
3
- Version: 0.7.0.dev0
3
+ Version: 0.7.3-dev.0
4
4
  Summary: Framework for Decision Pipeline modeling and execution
5
5
  Project-URL: Homepage, https://www.nextmv.io
6
- Project-URL: Documentation, https://nextpipe.docs.nextmv.io/en/latest/
6
+ Project-URL: Documentation, https://docs.nextmv.io/nextpipe
7
7
  Project-URL: Repository, https://github.com/nextmv-io/nextpipe
8
8
  Author-email: Nextmv <tech@nextmv.io>
9
9
  Maintainer-email: Nextmv <tech@nextmv.io>
@@ -105,17 +105,12 @@ Classifier: Programming Language :: Python :: 3.13
105
105
  Classifier: Programming Language :: Python :: 3.14
106
106
  Requires-Python: >=3.10
107
107
  Requires-Dist: dataclasses-json>=0.6.7
108
- Requires-Dist: nextmv>=1.2.2
108
+ Requires-Dist: nextmv>=1.10.3
109
109
  Requires-Dist: requests>=2.31.0
110
- Provides-Extra: dev
111
- Requires-Dist: goldie>=0.1.8; extra == 'dev'
112
- Requires-Dist: ruff>=0.11.6; extra == 'dev'
113
110
  Description-Content-Type: text/markdown
114
111
 
115
112
  # Nextpipe
116
113
 
117
- <!-- markdownlint-disable MD033 MD013 -->
118
-
119
114
  <p align="center">
120
115
  <a href="https://nextmv.io"><img src="https://cdn.prod.website-files.com/60dee0fad10d14c8ab66dd74/65c66addcd07eed09be35114_blog-banner-what-is-cicd-for-decision-science-p-2000.jpeg" alt="Nextmv" width="45%"></a>
121
116
  </p>
@@ -137,8 +132,6 @@ Description-Content-Type: text/markdown
137
132
  </a>
138
133
  </p>
139
134
 
140
- <!-- markdownlint-enable MD033 MD013 -->
141
-
142
135
  Nextpipe is a Python package that provides a framework for Decision Workflows
143
136
  modeling and execution. It provides first-class support for Workflows in the
144
137
  [Nextmv Platform][nextmv].
@@ -152,13 +145,26 @@ modeling and execution. It provides first-class support for Workflows in the
152
145
 
153
146
  ## Installation
154
147
 
155
- The package is hosted on [PyPI][nextpipe-pypi]. Python `>=3.10` is required.
148
+ The package is hosted on [PyPI][nextpipe-pypi]. Requires Python `>=3.10`.
149
+ Install using the Python package manager of your choice:
156
150
 
157
- Install via `pip`:
151
+ * `uv`
158
152
 
159
- ```bash
160
- pip install nextpipe
161
- ```
153
+ ```bash
154
+ uv add nextpipe
155
+ ```
156
+
157
+ * `pip`
158
+
159
+ ```bash
160
+ pip install nextpipe
161
+ ```
162
+
163
+ * `pipx`
164
+
165
+ ```bash
166
+ pipx install nextpipe
167
+ ```
162
168
 
163
169
  ## Preview
164
170
 
@@ -192,4 +198,4 @@ graph LR
192
198
 
193
199
  [nextpipe-pypi]: https://pypi.org/project/nextpipe/
194
200
  [nextmv]: https://nextmv.io
195
- [docs]: https://nextpipe.docs.nextmv.io/en/latest/
201
+ [docs]: https://docs.nextmv.io/nextpipe
@@ -0,0 +1,15 @@
1
+ nextpipe/__about__.py,sha256=xiTWpIpDzKX9oSh5wKsno5zZTDGZZ38j18p-3yb4I0I,29
2
+ nextpipe/__init__.py,sha256=SzRhi2z33zmvskfgqoRHwaKvRnt8G1_JJR1M7BXlda0,694
3
+ nextpipe/config.py,sha256=JSShEaK3fnqieGofalQysKxEJUkyrWIRbwhdyH9yYZM,1659
4
+ nextpipe/constants.py,sha256=ws1_khUbZFau_kShi6nweLhg24_2fjPWyXY6VPVAH7E,667
5
+ nextpipe/decorators.py,sha256=2X3pmHQQi5eEirGQmpRzRo26TB9m7cDpwJ3guTDsIdc,27194
6
+ nextpipe/flow.py,sha256=LODA9eJKe8bkokxqLfKI4jANZbKtFEZGvWLGkJVwGBo,43000
7
+ nextpipe/graph.py,sha256=Oi8HQ4fgvBYxpRK6xBoLtoxftGb-gCOb09BqFwzrwWs,2867
8
+ nextpipe/schema.py,sha256=9k33I73NIIh2dDUWFfwE5-A7hcUif7eHqT0RLG9f1Uw,5460
9
+ nextpipe/threads.py,sha256=5s7jF-hgVF_Eqfxgf6hsF6dhXsRSfqTsq5F0JBy4hNw,9039
10
+ nextpipe/uplink.py,sha256=oW8rIt6byUqKhex5-Nk0KwTOBuPvRAMtuDfP-fmM6_E,11475
11
+ nextpipe/utils.py,sha256=jAeWautNhUZsjuF00K7BVaU5grLRWlBmtLkcNnPYnXg,8279
12
+ nextpipe-0.7.3.dev0.dist-info/METADATA,sha256=lpaVQ7gEAip30nuRc8VDalAdqzs8_a4EntDYmte5ZX8,8706
13
+ nextpipe-0.7.3.dev0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
14
+ nextpipe-0.7.3.dev0.dist-info/licenses/LICENSE.md,sha256=FpVScuRcgdbeBNVsMzoPyBbKL2eCB1vFor1vfNNFEj4,4106
15
+ nextpipe-0.7.3.dev0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.29.0
2
+ Generator: hatchling 1.32.4
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,15 +0,0 @@
1
- nextpipe/__about__.py,sha256=voAqpvLYyNpIqOhLs1vs_n50MuzBlS-4YA9FW80GWY8,29
2
- nextpipe/__init__.py,sha256=SzRhi2z33zmvskfgqoRHwaKvRnt8G1_JJR1M7BXlda0,694
3
- nextpipe/config.py,sha256=JSShEaK3fnqieGofalQysKxEJUkyrWIRbwhdyH9yYZM,1659
4
- nextpipe/constants.py,sha256=ws1_khUbZFau_kShi6nweLhg24_2fjPWyXY6VPVAH7E,667
5
- nextpipe/decorators.py,sha256=kLYOVYqx0QWtTbVkgw6US8ZZSa0YijZ5qzMX0mRiO7k,26539
6
- nextpipe/flow.py,sha256=Qt8nHk1RT9i6SMIGan5C3aU_a6ZS056SNt3YwrlHYD0,42411
7
- nextpipe/graph.py,sha256=Oi8HQ4fgvBYxpRK6xBoLtoxftGb-gCOb09BqFwzrwWs,2867
8
- nextpipe/schema.py,sha256=HsJnzpYhemXUa8IZvFEChPB-_5YXTCbkYSPf5zpPqo8,3263
9
- nextpipe/threads.py,sha256=5s7jF-hgVF_Eqfxgf6hsF6dhXsRSfqTsq5F0JBy4hNw,9039
10
- nextpipe/uplink.py,sha256=oW8rIt6byUqKhex5-Nk0KwTOBuPvRAMtuDfP-fmM6_E,11475
11
- nextpipe/utils.py,sha256=jAeWautNhUZsjuF00K7BVaU5grLRWlBmtLkcNnPYnXg,8279
12
- nextpipe-0.7.0.dev0.dist-info/METADATA,sha256=HUa8RpPfBoOWbobkJBPGE_IpeVQ3z7gFvObVkRlII8I,8759
13
- nextpipe-0.7.0.dev0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
14
- nextpipe-0.7.0.dev0.dist-info/licenses/LICENSE.md,sha256=FpVScuRcgdbeBNVsMzoPyBbKL2eCB1vFor1vfNNFEj4,4106
15
- nextpipe-0.7.0.dev0.dist-info/RECORD,,