nextpipe 0.6.2.dev1__py3-none-any.whl → 0.6.2.dev3__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.6.2-dev.1"
1
+ __version__ = "v0.6.2-dev.3"
nextpipe/constants.py ADDED
@@ -0,0 +1,28 @@
1
+ """
2
+ Constants for nextpipe.
3
+
4
+ This module provides constants used across the nextpipe package.
5
+
6
+ Functions
7
+ --------
8
+ _get_run_info
9
+ Retrieves information about the run from environment variables.
10
+ """
11
+
12
+ import os
13
+
14
+ ENV_APP_ID = "NEXTMV_APP_ID"
15
+ """Environment variable name for the application ID."""
16
+
17
+ ENV_RUN_ID = "NEXTMV_RUN_ID"
18
+ """Environment variable name for the run ID."""
19
+
20
+
21
+ def _get_run_info():
22
+ """
23
+ Retrieves information about the run from environment variables.
24
+ If the environment variables are not set, it returns None for both values.
25
+ """
26
+ app_id = os.environ.get(ENV_APP_ID)
27
+ run_id = os.environ.get(ENV_RUN_ID)
28
+ return app_id, run_id
nextpipe/flow.py CHANGED
@@ -40,6 +40,8 @@ from typing import Any
40
40
  import nextmv
41
41
  from nextmv.cloud import Application, Client
42
42
 
43
+ from nextpipe.constants import _get_run_info
44
+
43
45
  from . import config, decorators, graph, schema, threads, uplink, utils
44
46
  from .__about__ import __version__
45
47
 
@@ -862,9 +864,9 @@ class Runner:
862
864
  """
863
865
 
864
866
  reference: FlowNode = job.reference
865
- reference.status = STATUS_SUCCEEDED if job.error is None else STATUS_FAILED
867
+ failed = job.error is not None or reference.error is not None
868
+ reference.status = STATUS_SUCCEEDED if not failed else STATUS_FAILED
866
869
  reference.result = job.result
867
- reference.error = job.error
868
870
  # Check if the job failed and mark the flow as failed if it did
869
871
  with self.lock_fail:
870
872
  if job.error is not None and not self.fail:
@@ -878,6 +880,20 @@ class Runner:
878
880
  # Inform the platform about the node update
879
881
  self.uplink.submit_update(self.graph._to_uplink_dto())
880
882
 
883
+ @staticmethod
884
+ def __determine_sub_run_info(app_step_id: str, step_name: str) -> tuple[str, str]:
885
+ """
886
+ Determine name and description to use for sub-runs.
887
+ """
888
+ wf_app_id, wf_run_id = _get_run_info()
889
+ wf_app_id = wf_app_id or app_step_id # Fallback if dynamic detection fails
890
+ wf_run_id = wf_run_id or "local" # Use "local" for non-platform runs
891
+ step_name = step_name[:50] # Truncate step name to 50 chars to keep overall name within limits
892
+ name = f"Nextpipe step {step_name} ({wf_app_id}/{wf_run_id})"
893
+ name = name[:128] # Truncate to 128 chars to comply with platform limits
894
+ description = f"This run was started by the nextpipe parent: {wf_app_id} (run-id: {wf_run_id})"
895
+ return name, description
896
+
881
897
  @staticmethod
882
898
  def __run_step(
883
899
  node: FlowNode,
@@ -917,6 +933,9 @@ class Runner:
917
933
  if node.parent.definition.is_app():
918
934
  app_step: decorators.App = node.parent.definition.app
919
935
 
936
+ # Try to detect platform run context.
937
+ app_run_name, app_run_description = Runner.__determine_sub_run_info(app_step.app_id, node.id)
938
+
920
939
  # Prepare the input for the app
921
940
  # TODO: We only support one predecessor for app steps for now. This may
922
941
  # change in the future. We may want to support multiple predecessors for
@@ -928,7 +947,10 @@ class Runner:
928
947
  # If the input is AppRunConfig, unwrap it.
929
948
  app_run_config: schema.AppRunConfig = inputs[0]
930
949
  input = app_run_config.input
931
- name = app_run_config.name if app_run_config.name else node.id
950
+ if app_run_config.name:
951
+ app_run_name = app_run_config.name
952
+ if app_run_config.description:
953
+ app_run_description = app_run_config.description
932
954
  app_run_options = app_run_config.get_options()
933
955
  # Merge the options from the app decorator with the options from the
934
956
  # AppRunConfig. AppRunConfig options take precedence.
@@ -938,12 +960,10 @@ class Runner:
938
960
  run_result: nextmv.RunResult = inputs[0]
939
961
  input = run_result.output
940
962
  options = app_step.options
941
- name = node.id
942
963
  else:
943
964
  # If the input is not AppRunConfig, we use it directly.
944
965
  input = inputs[0]
945
966
  options = app_step.options
946
- name = node.id
947
967
 
948
968
  # Detect dir mode / multi-file direct input
949
969
  is_dir_mode = False
@@ -964,7 +984,8 @@ class Runner:
964
984
  [], # No nameless arguments
965
985
  { # We use the named arguments to pass the user arguments to the run function
966
986
  "options": options,
967
- "name": name,
987
+ "name": app_run_name,
988
+ "description": app_run_description,
968
989
  },
969
990
  )
970
991
 
@@ -1003,38 +1024,36 @@ class Runner:
1003
1024
  )
1004
1025
  else:
1005
1026
  utils.log_internal(f"Bypassing app step {node.id} run, using bypass result")
1027
+ # We wrap the bypass result in a dummy RunResult to ensure consistent behavior.
1028
+ result = nextmv.RunResult(
1029
+ id="bypassed-run",
1030
+ name="bypassed-run",
1031
+ description="This run was bypassed using a user-supplied result.",
1032
+ user_email="unavailable",
1033
+ metadata=nextmv.Metadata(
1034
+ application_id="unavailable",
1035
+ application_instance_id="unavailable",
1036
+ application_version_id="unavailable",
1037
+ created_at="unavailable",
1038
+ duration="unavailable",
1039
+ error="unavailable",
1040
+ input_size=0.0,
1041
+ output_size=0.0,
1042
+ format=nextmv.Format(
1043
+ format_input=nextmv.FormatInput(
1044
+ input_type=nextmv.InputFormat.MULTI_FILE
1045
+ if is_dir_mode
1046
+ else nextmv.InputFormat.JSON,
1047
+ ),
1048
+ ),
1049
+ status_v2=nextmv.StatusV2.succeeded,
1050
+ ),
1051
+ output=app_step.bypass_result,
1052
+ )
1006
1053
  # If the user supplied a bypass result, we need to write it to the temp dir if it's in dir mode
1007
1054
  if isinstance(app_step.bypass_result, str) and os.path.isdir(app_step.bypass_result):
1008
- # If the bypass result is a directory, we copy its contents to the temp dir
1009
1055
  for filename in os.listdir(app_step.bypass_result):
1010
1056
  shutil.copy(os.path.join(app_step.bypass_result, filename), temp_dir)
1011
- else:
1012
- # We wrap the bypass result in a dummy RunResult to ensure consistent behavior.
1013
- result = nextmv.RunResult(
1014
- id="bypassed_run",
1015
- name="bypassed_run",
1016
- description="This run was bypassed using a user-supplied result.",
1017
- user_email="unavailable",
1018
- metadata=nextmv.Metadata(
1019
- application_id="unavailable",
1020
- application_instance_id="unavailable",
1021
- application_version_id="unavailable",
1022
- created_at="unavailable",
1023
- duration="unavailable",
1024
- error="unavailable",
1025
- input_size=0.0,
1026
- output_size=0.0,
1027
- format=nextmv.Format(
1028
- format_input=nextmv.FormatInput(
1029
- input_type=nextmv.InputFormat.MULTI_FILE
1030
- if is_dir_mode
1031
- else nextmv.InputFormat.JSON,
1032
- ),
1033
- ),
1034
- status_v2=nextmv.StatusV2.succeeded,
1035
- ),
1036
- output=app_step.bypass_result,
1037
- )
1038
1057
  finally: # Make sure we clean up temp dir on failure too
1039
1058
  # If the temp dir is empty, remove it
1040
1059
  dir_result = False
@@ -1043,6 +1062,9 @@ class Runner:
1043
1062
  else:
1044
1063
  dir_result = True
1045
1064
 
1065
+ # Emit result status to DAG
1066
+ node.error = result.metadata.error
1067
+
1046
1068
  # Return result
1047
1069
  # - Do not unwrap if full result is requested
1048
1070
  # - If the output came in a directory, return the directory path
nextpipe/schema.py CHANGED
@@ -98,6 +98,8 @@ class AppRunConfig:
98
98
  """Options for running the app."""
99
99
  name: str | None = None
100
100
  """Name for the run."""
101
+ description: str | None = None
102
+ """Description for the run."""
101
103
 
102
104
  def get_options(self) -> dict[str, Any]:
103
105
  """
nextpipe/uplink.py CHANGED
@@ -27,7 +27,6 @@ ExcludeIfNone
27
27
  """
28
28
 
29
29
  import datetime
30
- import os
31
30
  import threading
32
31
  import time
33
32
  from dataclasses import dataclass, field
@@ -35,6 +34,7 @@ from dataclasses import dataclass, field
35
34
  from dataclasses_json import config, dataclass_json
36
35
  from nextmv.cloud import Client
37
36
 
37
+ from nextpipe.constants import _get_run_info
38
38
  from nextpipe.utils import log_internal
39
39
 
40
40
  FAILED_UPDATES_THRESHOLD = 10
@@ -46,12 +46,6 @@ UPDATE_INTERVAL = 5
46
46
  MAX_DOCS_LENGTH = 1000
47
47
  """Maximum length for documentation strings sent to the platform."""
48
48
 
49
- ENV_APP_ID = "NEXTMV_APP_ID"
50
- """Environment variable name for the application ID."""
51
-
52
- ENV_RUN_ID = "NEXTMV_RUN_ID"
53
- """Environment variable name for the run ID."""
54
-
55
49
 
56
50
  def ExcludeIfNone(value):
57
51
  """
@@ -278,10 +272,8 @@ class UplinkClient:
278
272
 
279
273
  if config is None:
280
274
  # Load config from environment
281
- config = UplinkConfig(
282
- application_id=os.environ.get(ENV_APP_ID),
283
- run_id=os.environ.get(ENV_RUN_ID),
284
- )
275
+ app_id, run_id = _get_run_info()
276
+ config = UplinkConfig(application_id=app_id, run_id=run_id)
285
277
  self.config = config
286
278
  self.inactive = False
287
279
  if not self.config.application_id or not self.config.run_id:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextpipe
3
- Version: 0.6.2.dev1
3
+ Version: 0.6.2.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://nextpipe.docs.nextmv.io/en/latest/
@@ -0,0 +1,15 @@
1
+ nextpipe/__about__.py,sha256=8AMrE0_anvG9euAOawmj8RKxbYUQPQvpyH3k78xhWFM,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=MLTwuTONn30-esVaF7q3hNdOp8AnJ5ksNswQHpFrGlE,25727
6
+ nextpipe/flow.py,sha256=zQsv3OOOaoCl3x3jL-f31fqaL5cB19yvhj1VxloOWMM,42472
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=-ni6Em1QfatgVMh95hYSPVCdTboozB8vRKkakti3gls,8063
12
+ nextpipe-0.6.2.dev3.dist-info/METADATA,sha256=MtCbj3EDrUBwU7Hz3Dh0b_qlUnpJe3-qLSN-SiNPDcU,8760
13
+ nextpipe-0.6.2.dev3.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
14
+ nextpipe-0.6.2.dev3.dist-info/licenses/LICENSE.md,sha256=FpVScuRcgdbeBNVsMzoPyBbKL2eCB1vFor1vfNNFEj4,4106
15
+ nextpipe-0.6.2.dev3.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- nextpipe/__about__.py,sha256=CGD3tElYa8glEEiSIpPFwQvA47zpDglHVEx0rp1LNNM,29
2
- nextpipe/__init__.py,sha256=SzRhi2z33zmvskfgqoRHwaKvRnt8G1_JJR1M7BXlda0,694
3
- nextpipe/config.py,sha256=JSShEaK3fnqieGofalQysKxEJUkyrWIRbwhdyH9yYZM,1659
4
- nextpipe/decorators.py,sha256=MLTwuTONn30-esVaF7q3hNdOp8AnJ5ksNswQHpFrGlE,25727
5
- nextpipe/flow.py,sha256=p9M2lHUJOlwWew-cEWy8Le6amm-XJunbz8IoSAS9QkQ,41458
6
- nextpipe/graph.py,sha256=Oi8HQ4fgvBYxpRK6xBoLtoxftGb-gCOb09BqFwzrwWs,2867
7
- nextpipe/schema.py,sha256=wZ61Tlu0k8b36OnCNwu6EHpXiIB_H5g9WSDdJxG6Uc4,3193
8
- nextpipe/threads.py,sha256=5s7jF-hgVF_Eqfxgf6hsF6dhXsRSfqTsq5F0JBy4hNw,9039
9
- nextpipe/uplink.py,sha256=j4k7Msa1Il7uxrQeXd1yoCMWWd9KmkbQb72EZy4zMSs,11646
10
- nextpipe/utils.py,sha256=-ni6Em1QfatgVMh95hYSPVCdTboozB8vRKkakti3gls,8063
11
- nextpipe-0.6.2.dev1.dist-info/METADATA,sha256=wm6N1tsLyzEAhLFB42hcGwynytiMSmehOANvkzg89xQ,8760
12
- nextpipe-0.6.2.dev1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
13
- nextpipe-0.6.2.dev1.dist-info/licenses/LICENSE.md,sha256=FpVScuRcgdbeBNVsMzoPyBbKL2eCB1vFor1vfNNFEj4,4106
14
- nextpipe-0.6.2.dev1.dist-info/RECORD,,