runnable 0.23.0__py3-none-any.whl → 0.25.0__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.
extensions/nodes/nodes.py CHANGED
@@ -661,6 +661,10 @@ class MapNode(CompositeNode):
661
661
 
662
662
  self._context.run_log_store.add_step_log(step_log, self._context.run_id)
663
663
 
664
+ # If we failed, we return without any collection
665
+ if not step_log.status == defaults.SUCCESS:
666
+ return
667
+
664
668
  # Apply the reduce function and reduce the returns of the task nodes.
665
669
  # The final value of the parameter is the result of the reduce function.
666
670
  reducer_f = self.get_reducer_function()
runnable/cli.py CHANGED
@@ -64,8 +64,9 @@ def execute(
64
64
  tag: Annotated[str, typer.Option(help="A tag attached to the run")] = "",
65
65
  run_id: Annotated[
66
66
  str,
67
- typer.Option(
68
- help="An optional run_id, one would be generated if its not provided"
67
+ typer.Argument(
68
+ envvar=defaults.ENV_RUN_ID,
69
+ help="An optional run_id, one would be generated if its not provided",
69
70
  ),
70
71
  ] = "",
71
72
  ):
@@ -282,8 +283,11 @@ def execute_job(
282
283
  ],
283
284
  run_id: Annotated[
284
285
  str,
285
- typer.Argument(help="An run_id, one would be generated if its not provided"),
286
- ],
286
+ typer.Argument(
287
+ envvar="RUNNABLE_RUN_ID",
288
+ help="An optional run_id, one would be generated if its not provided",
289
+ ),
290
+ ] = "",
287
291
  config_file: Annotated[
288
292
  str,
289
293
  typer.Option(
runnable/graph.py CHANGED
@@ -76,7 +76,6 @@ class Graph(BaseModel):
76
76
  for _, value in self.nodes.items():
77
77
  if value.internal_name == internal_name:
78
78
  return value
79
- print("graph", internal_name)
80
79
  raise exceptions.NodeNotFoundError(internal_name)
81
80
 
82
81
  def __str__(self): # pragma: no cover
runnable/tasks.py CHANGED
@@ -31,7 +31,26 @@ logger = logging.getLogger(defaults.LOGGER_NAME)
31
31
  logging.getLogger("stevedore").setLevel(logging.CRITICAL)
32
32
 
33
33
 
34
- # TODO: This has to be an extension
34
+ class TeeIO(io.StringIO):
35
+ """
36
+ A custom class to write to the buffer and the output stream at the same time.
37
+ """
38
+
39
+ def __init__(self, output_stream=sys.stdout):
40
+ super().__init__()
41
+ self.output_stream = output_stream
42
+
43
+ def write(self, s):
44
+ super().write(s) # Write to the buffer
45
+ self.output_stream.write(s) # Write to the output stream
46
+
47
+ def flush(self):
48
+ super().flush()
49
+ self.output_stream.flush()
50
+
51
+
52
+ buffer = TeeIO()
53
+ sys.stdout = buffer
35
54
 
36
55
 
37
56
  class TaskReturns(BaseModel):
@@ -152,6 +171,7 @@ class BaseTaskType(BaseModel):
152
171
  key: value
153
172
  for key, value in params.items()
154
173
  if isinstance(value, JsonParameter)
174
+ or isinstance(value, MetricParameter)
155
175
  }
156
176
 
157
177
  parameters_in = copy.deepcopy(params)
@@ -274,7 +294,7 @@ class PythonTaskType(BaseTaskType): # pylint: disable=too-few-public-methods
274
294
  f"Calling {func} from {module} with {filtered_parameters}"
275
295
  )
276
296
 
277
- out_file = io.StringIO()
297
+ out_file = TeeIO()
278
298
  with contextlib.redirect_stdout(out_file):
279
299
  user_set_parameters = f(
280
300
  **filtered_parameters
@@ -284,16 +304,15 @@ class PythonTaskType(BaseTaskType): # pylint: disable=too-few-public-methods
284
304
  raise exceptions.CommandCallError(
285
305
  f"Function call: {self.command} did not succeed.\n"
286
306
  ) from e
287
-
288
- attempt_log.input_parameters = params.copy()
289
-
290
- if map_variable:
291
- attempt_log.input_parameters.update(
292
- {
293
- k: JsonParameter(value=v, kind="json")
294
- for k, v in map_variable.items()
295
- }
296
- )
307
+ finally:
308
+ attempt_log.input_parameters = params.copy()
309
+ if map_variable:
310
+ attempt_log.input_parameters.update(
311
+ {
312
+ k: JsonParameter(value=v, kind="json")
313
+ for k, v in map_variable.items()
314
+ }
315
+ )
297
316
 
298
317
  if self.returns:
299
318
  if not isinstance(user_set_parameters, tuple): # make it a tuple
@@ -448,6 +467,7 @@ class NotebookTaskType(BaseTaskType):
448
467
  ) as params,
449
468
  self.expose_secrets() as _,
450
469
  ):
470
+ attempt_log.input_parameters = params.copy()
451
471
  copy_params = copy.deepcopy(params)
452
472
 
453
473
  if map_variable:
@@ -476,7 +496,7 @@ class NotebookTaskType(BaseTaskType):
476
496
  }
477
497
  kwds.update(ploomber_optional_args)
478
498
 
479
- out_file = io.StringIO()
499
+ out_file = TeeIO()
480
500
  with contextlib.redirect_stdout(out_file):
481
501
  pm.execute_notebook(**kwds)
482
502
  task_console.print(out_file.getvalue())
@@ -635,6 +655,7 @@ class ShellTaskType(BaseTaskType):
635
655
  ) as params:
636
656
  subprocess_env.update({k: v.get_value() for k, v in params.items()})
637
657
 
658
+ attempt_log.input_parameters = params.copy()
638
659
  # Json dumps all runnable environment variables
639
660
  for key, value in subprocess_env.items():
640
661
  if isinstance(value, str):
runnable/utils.py CHANGED
@@ -77,7 +77,11 @@ def generate_run_id(run_id: str = "") -> str:
77
77
  Returns:
78
78
  str: A generated run_id
79
79
  """
80
- # If we are not provided with a run_id, generate one
80
+ # If we are not provided with a run_id, check env var
81
+ if not run_id:
82
+ run_id = os.environ.get(defaults.ENV_RUN_ID, "")
83
+
84
+ # If both are not given, generate one
81
85
  if not run_id:
82
86
  now = datetime.now()
83
87
  run_id = f"{names.get_random_name()}-{now.hour:02}{now.minute:02}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runnable
3
- Version: 0.23.0
3
+ Version: 0.25.0
4
4
  Summary: Add your description here
5
5
  Author-email: "Vammi, Vijay" <vijay.vammi@astrazeneca.com>
6
6
  License-File: LICENSE
@@ -11,7 +11,7 @@ extensions/job_executor/local.py,sha256=FvxTk0vyxdrbLOAyNkLyjvmmowypabWOSITQBK_f
11
11
  extensions/job_executor/local_container.py,sha256=hyFnpicCp3_87mZsW64P6KSVbz7XMLjwJUWVjeCJ0_I,6627
12
12
  extensions/job_executor/pyproject.toml,sha256=UIEgiCYHTXcRWSByNMFuKJFKgxTBpQqTqyUecIsb_Vc,286
13
13
  extensions/nodes/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- extensions/nodes/nodes.py,sha256=ib68QE737ihGLIVp3V2wea13u7lmMZdRvK80bgUkRtA,34645
14
+ extensions/nodes/nodes.py,sha256=WdOmep4uxmY2mTOtsuVZ5QhYl96jqJprkG6jkIg7BVg,34774
15
15
  extensions/nodes/pyproject.toml,sha256=YTu-ETN3JNFSkMzzWeOwn4m-O2nbRH-PmiPBALDCUw4,278
16
16
  extensions/pipeline_executor/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  extensions/pipeline_executor/__init__.py,sha256=bobyC4BWmDKCnMQsuyj9buQX7tZOFxuwU3Coq9-QgR0,25568
@@ -34,24 +34,24 @@ extensions/secrets/dotenv.py,sha256=FbYYd_pVuJuVuIDIvXbzKuSSQ9GPq7xJXTDbJMTQbhM,
34
34
  extensions/secrets/pyproject.toml,sha256=mLJNImNcBlbLKHh-0ugVWT9V83R4RibyyYDtBCSqVF4,282
35
35
  runnable/__init__.py,sha256=n14AnTUUEYxXlTJ6-YLT0tMmeFb7Co_3kNldV6pgKSs,662
36
36
  runnable/catalog.py,sha256=b9N40kTv1IBidzlWjkHcBGyYhq6qIDHZfBuFenzjsMI,4924
37
- runnable/cli.py,sha256=xHb2VSC16z9IT45SnhUYHuXUrzPqF_pK-jyWiTnz5sM,8670
37
+ runnable/cli.py,sha256=3BiKSj95h2Drn__YlchMPZ5rBMafuRb2OGIsVpbsO5Y,8788
38
38
  runnable/context.py,sha256=by5uepmuCP0dmM9BmsliXihSes5QEFejwAsmekcqylE,1388
39
39
  runnable/datastore.py,sha256=9y5enzn6AXLHLdwvgkdjGPrBkVlrcjfbaAHsst-lJzg,32466
40
40
  runnable/defaults.py,sha256=3o9IVGryyCE6PoQTOoaIaHHTbJGEzmdXMcwzOhwAYoI,3518
41
41
  runnable/entrypoints.py,sha256=xkUa568-7x9xALz13qW14DxS1nnLDKwLwdIBJZG-vM0,18982
42
42
  runnable/exceptions.py,sha256=LFbp0-Qxg2PAMLEVt7w2whhBxSG-5pzUEv5qN-Rc4_c,3003
43
43
  runnable/executor.py,sha256=ne-iRQqGuEmmuApnkBDz1_hokVcjFrbe7BvWqXCG1Ys,15684
44
- runnable/graph.py,sha256=jVjikRLR-so3b2ufmNKpEQ_Ny68qN4bcGDAdXBRKiCY,16574
44
+ runnable/graph.py,sha256=poQz5zcvq89ju_u5sYlunQLPbHnXTaUmjcvstPwvT4U,16536
45
45
  runnable/names.py,sha256=vn92Kv9ANROYSZX6Z4z1v_WA3WiEdIYmG6KEStBFZug,8134
46
46
  runnable/nodes.py,sha256=YU9u7r1ESzui1uVtJ1dgwdv1ozyJnF2k-MCFieT8CLI,17519
47
47
  runnable/parameters.py,sha256=LyQb1d0SaFeI4PJ_yDYt9wArm9ThSPASWb36TwIdDUs,5213
48
48
  runnable/pickler.py,sha256=ydJ_eti_U1F4l-YacFp7BWm6g5vTn04UXye25S1HVok,2684
49
49
  runnable/sdk.py,sha256=T1nqDpLN9fULvvU9L-oY0EHqYdKUI9qk7oekLynm02Y,33568
50
50
  runnable/secrets.py,sha256=PXcEJw-4WPzeWRLfsatcPPyr1zkqgHzdRWRcS9vvpvM,2354
51
- runnable/tasks.py,sha256=YVKpKxSpsRZWcU3MOqoBoqxeo1XSqv5crkOu6kyu63o,28520
52
- runnable/utils.py,sha256=6yIqPO8TrUMwOj9pid37I2qg6LD6ILDz9acdO3rQ1zo,19702
53
- runnable-0.23.0.dist-info/METADATA,sha256=8wQhNRz6xtLWKcxRE4qFT3liU157UedYYw5cSdg0LdA,9945
54
- runnable-0.23.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
55
- runnable-0.23.0.dist-info/entry_points.txt,sha256=seek5WVGvwYALm8lZ0TfPXwG5NaCeUKjU8urF8k3gvY,1621
56
- runnable-0.23.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
57
- runnable-0.23.0.dist-info/RECORD,,
51
+ runnable/tasks.py,sha256=SYy9eZOs1iCwu1IX5O9WyXk6DMpVsqaruQtMX-YX0bY,29207
52
+ runnable/utils.py,sha256=hJUfRmIgU20weWPmBOHF22F6svBU0A_0nqifRMuXKs0,19822
53
+ runnable-0.25.0.dist-info/METADATA,sha256=bpDSeecHPHb9qCHycgxbAtPFpuEx73t1bO_OAal8dN8,9945
54
+ runnable-0.25.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
55
+ runnable-0.25.0.dist-info/entry_points.txt,sha256=seek5WVGvwYALm8lZ0TfPXwG5NaCeUKjU8urF8k3gvY,1621
56
+ runnable-0.25.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
57
+ runnable-0.25.0.dist-info/RECORD,,