runnable 0.23.0__py3-none-any.whl → 0.25.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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,,