runnable 0.12.3__py3-none-any.whl → 0.14.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. runnable/__init__.py +0 -11
  2. runnable/catalog.py +27 -5
  3. runnable/cli.py +122 -26
  4. runnable/datastore.py +71 -35
  5. runnable/defaults.py +0 -1
  6. runnable/entrypoints.py +107 -32
  7. runnable/exceptions.py +6 -2
  8. runnable/executor.py +28 -9
  9. runnable/graph.py +37 -12
  10. runnable/integration.py +7 -2
  11. runnable/nodes.py +15 -17
  12. runnable/parameters.py +27 -8
  13. runnable/pickler.py +1 -1
  14. runnable/sdk.py +101 -33
  15. runnable/secrets.py +3 -1
  16. runnable/tasks.py +246 -34
  17. runnable/utils.py +41 -13
  18. {runnable-0.12.3.dist-info → runnable-0.14.0.dist-info}/METADATA +25 -31
  19. runnable-0.14.0.dist-info/RECORD +24 -0
  20. {runnable-0.12.3.dist-info → runnable-0.14.0.dist-info}/WHEEL +1 -1
  21. runnable-0.14.0.dist-info/entry_points.txt +40 -0
  22. runnable/extensions/__init__.py +0 -0
  23. runnable/extensions/catalog/__init__.py +0 -21
  24. runnable/extensions/catalog/file_system/__init__.py +0 -0
  25. runnable/extensions/catalog/file_system/implementation.py +0 -234
  26. runnable/extensions/catalog/k8s_pvc/__init__.py +0 -0
  27. runnable/extensions/catalog/k8s_pvc/implementation.py +0 -16
  28. runnable/extensions/catalog/k8s_pvc/integration.py +0 -59
  29. runnable/extensions/executor/__init__.py +0 -649
  30. runnable/extensions/executor/argo/__init__.py +0 -0
  31. runnable/extensions/executor/argo/implementation.py +0 -1194
  32. runnable/extensions/executor/argo/specification.yaml +0 -51
  33. runnable/extensions/executor/k8s_job/__init__.py +0 -0
  34. runnable/extensions/executor/k8s_job/implementation_FF.py +0 -259
  35. runnable/extensions/executor/k8s_job/integration_FF.py +0 -69
  36. runnable/extensions/executor/local/__init__.py +0 -0
  37. runnable/extensions/executor/local/implementation.py +0 -71
  38. runnable/extensions/executor/local_container/__init__.py +0 -0
  39. runnable/extensions/executor/local_container/implementation.py +0 -446
  40. runnable/extensions/executor/mocked/__init__.py +0 -0
  41. runnable/extensions/executor/mocked/implementation.py +0 -154
  42. runnable/extensions/executor/retry/__init__.py +0 -0
  43. runnable/extensions/executor/retry/implementation.py +0 -168
  44. runnable/extensions/nodes.py +0 -855
  45. runnable/extensions/run_log_store/__init__.py +0 -0
  46. runnable/extensions/run_log_store/chunked_file_system/__init__.py +0 -0
  47. runnable/extensions/run_log_store/chunked_file_system/implementation.py +0 -111
  48. runnable/extensions/run_log_store/chunked_k8s_pvc/__init__.py +0 -0
  49. runnable/extensions/run_log_store/chunked_k8s_pvc/implementation.py +0 -21
  50. runnable/extensions/run_log_store/chunked_k8s_pvc/integration.py +0 -61
  51. runnable/extensions/run_log_store/db/implementation_FF.py +0 -157
  52. runnable/extensions/run_log_store/db/integration_FF.py +0 -0
  53. runnable/extensions/run_log_store/file_system/__init__.py +0 -0
  54. runnable/extensions/run_log_store/file_system/implementation.py +0 -140
  55. runnable/extensions/run_log_store/generic_chunked.py +0 -557
  56. runnable/extensions/run_log_store/k8s_pvc/__init__.py +0 -0
  57. runnable/extensions/run_log_store/k8s_pvc/implementation.py +0 -21
  58. runnable/extensions/run_log_store/k8s_pvc/integration.py +0 -56
  59. runnable/extensions/secrets/__init__.py +0 -0
  60. runnable/extensions/secrets/dotenv/__init__.py +0 -0
  61. runnable/extensions/secrets/dotenv/implementation.py +0 -100
  62. runnable-0.12.3.dist-info/RECORD +0 -64
  63. runnable-0.12.3.dist-info/entry_points.txt +0 -41
  64. {runnable-0.12.3.dist-info → runnable-0.14.0.dist-info/licenses}/LICENSE +0 -0
runnable/entrypoints.py CHANGED
@@ -35,6 +35,7 @@ def prepare_configurations(
35
35
  force_local_executor: bool = False,
36
36
  ) -> context.Context:
37
37
  """
38
+ Sets up everything needed
38
39
  Replace the placeholders in the dag/config against the variables file.
39
40
 
40
41
  Attach the secrets_handler, run_log_store, catalog_handler to the executor and return it.
@@ -53,11 +54,17 @@ def prepare_configurations(
53
54
  variables = utils.gather_variables()
54
55
 
55
56
  templated_configuration = {}
56
- configuration_file = os.environ.get("RUNNABLE_CONFIGURATION_FILE", configuration_file)
57
+ configuration_file = os.environ.get(
58
+ "RUNNABLE_CONFIGURATION_FILE", configuration_file
59
+ )
57
60
 
58
61
  if configuration_file:
59
62
  templated_configuration = utils.load_yaml(configuration_file) or {}
60
63
 
64
+ # Since all the services (run_log_store, catalog, secrets, executor) are
65
+ # dynamically loaded via stevedore, we cannot validate the configuration
66
+ # before they are passed to the service.
67
+
61
68
  configuration: RunnableConfig = cast(RunnableConfig, templated_configuration)
62
69
 
63
70
  logger.info(f"Resolved configurations: {configuration}")
@@ -65,23 +72,32 @@ def prepare_configurations(
65
72
  # Run log settings, configuration over-rides everything
66
73
  run_log_config: Optional[ServiceConfig] = configuration.get("run_log_store", None)
67
74
  if not run_log_config:
68
- run_log_config = cast(ServiceConfig, runnable_defaults.get("run_log_store", defaults.DEFAULT_RUN_LOG_STORE))
75
+ run_log_config = cast(
76
+ ServiceConfig,
77
+ runnable_defaults.get("run_log_store", defaults.DEFAULT_RUN_LOG_STORE),
78
+ )
69
79
  run_log_store = utils.get_provider_by_name_and_type("run_log_store", run_log_config)
70
80
 
71
81
  # Catalog handler settings, configuration over-rides everything
72
82
  catalog_config: Optional[ServiceConfig] = configuration.get("catalog", None)
73
83
  if not catalog_config:
74
- catalog_config = cast(ServiceConfig, runnable_defaults.get("catalog", defaults.DEFAULT_CATALOG))
84
+ catalog_config = cast(
85
+ ServiceConfig, runnable_defaults.get("catalog", defaults.DEFAULT_CATALOG)
86
+ )
75
87
  catalog_handler = utils.get_provider_by_name_and_type("catalog", catalog_config)
76
88
 
77
89
  # Secret handler settings, configuration over-rides everything
78
90
  secrets_config: Optional[ServiceConfig] = configuration.get("secrets", None)
79
91
  if not secrets_config:
80
- secrets_config = cast(ServiceConfig, runnable_defaults.get("secrets", defaults.DEFAULT_SECRETS))
92
+ secrets_config = cast(
93
+ ServiceConfig, runnable_defaults.get("secrets", defaults.DEFAULT_SECRETS)
94
+ )
81
95
  secrets_handler = utils.get_provider_by_name_and_type("secrets", secrets_config)
82
96
 
83
97
  # pickler
84
- pickler_config = cast(ServiceConfig, runnable_defaults.get("pickler", defaults.DEFAULT_PICKLER))
98
+ pickler_config = cast(
99
+ ServiceConfig, runnable_defaults.get("pickler", defaults.DEFAULT_PICKLER)
100
+ )
85
101
  pickler_handler = utils.get_provider_by_name_and_type("pickler", pickler_config)
86
102
 
87
103
  # executor configurations, configuration over rides everything
@@ -90,8 +106,12 @@ def prepare_configurations(
90
106
  executor_config = ServiceConfig(type="local", config={})
91
107
 
92
108
  if not executor_config:
93
- executor_config = cast(ServiceConfig, runnable_defaults.get("executor", defaults.DEFAULT_EXECUTOR))
94
- configured_executor = utils.get_provider_by_name_and_type("executor", executor_config)
109
+ executor_config = cast(
110
+ ServiceConfig, runnable_defaults.get("executor", defaults.DEFAULT_EXECUTOR)
111
+ )
112
+ configured_executor = utils.get_provider_by_name_and_type(
113
+ "executor", executor_config
114
+ )
95
115
 
96
116
  # Construct the context
97
117
  run_context = context.Context(
@@ -174,20 +194,26 @@ def execute(
174
194
 
175
195
  run_context.execution_plan = defaults.EXECUTION_PLAN.CHAINED.value
176
196
 
177
- utils.set_runnable_environment_variables(run_id=run_id, configuration_file=configuration_file, tag=tag)
197
+ utils.set_runnable_environment_variables(
198
+ run_id=run_id, configuration_file=configuration_file, tag=tag
199
+ )
178
200
 
179
201
  # Prepare for graph execution
180
202
  executor.prepare_for_graph_execution()
181
203
 
182
204
  logger.info(f"Executing the graph: {run_context.dag}")
183
205
  with Progress(
184
- TextColumn("[progress.description]{task.description}", table_column=Column(ratio=2)),
206
+ TextColumn(
207
+ "[progress.description]{task.description}", table_column=Column(ratio=2)
208
+ ),
185
209
  BarColumn(table_column=Column(ratio=1), style="dark_orange"),
186
210
  TimeElapsedColumn(table_column=Column(ratio=1)),
187
211
  console=console,
188
212
  expand=True,
189
213
  ) as progress:
190
- pipeline_execution_task = progress.add_task("[dark_orange] Starting execution .. ", total=1)
214
+ pipeline_execution_task = progress.add_task(
215
+ "[dark_orange] Starting execution .. ", total=1
216
+ )
191
217
  try:
192
218
  run_context.progress = progress
193
219
  executor.execute_graph(dag=run_context.dag) # type: ignore
@@ -197,16 +223,30 @@ def execute(
197
223
  executor.send_return_code(stage="traversal")
198
224
  return
199
225
 
200
- run_log = run_context.run_log_store.get_run_log_by_id(run_id=run_context.run_id, full=False)
226
+ run_log = run_context.run_log_store.get_run_log_by_id(
227
+ run_id=run_context.run_id, full=False
228
+ )
201
229
 
202
230
  if run_log.status == defaults.SUCCESS:
203
- progress.update(pipeline_execution_task, description="[green] Success", completed=True)
231
+ progress.update(
232
+ pipeline_execution_task,
233
+ description="[green] Success",
234
+ completed=True,
235
+ )
204
236
  else:
205
- progress.update(pipeline_execution_task, description="[red] Failed", completed=True)
237
+ progress.update(
238
+ pipeline_execution_task, description="[red] Failed", completed=True
239
+ )
206
240
  except Exception as e: # noqa: E722
207
241
  console.print(e, style=defaults.error_style)
208
- progress.update(pipeline_execution_task, description="[red] Errored execution", completed=True)
209
- run_log = run_context.run_log_store.get_run_log_by_id(run_id=run_context.run_id, full=False)
242
+ progress.update(
243
+ pipeline_execution_task,
244
+ description="[red] Errored execution",
245
+ completed=True,
246
+ )
247
+ run_log = run_context.run_log_store.get_run_log_by_id(
248
+ run_id=run_context.run_id, full=False
249
+ )
210
250
  run_log.status = defaults.FAIL
211
251
  run_context.run_log_store.add_branch_log(run_log, run_context.run_id)
212
252
  raise e
@@ -240,9 +280,13 @@ def execute_single_node(
240
280
  """
241
281
  from runnable import nodes
242
282
 
243
- task_console.print(f"Executing the single node: {step_name} with map variable: {map_variable}")
283
+ task_console.print(
284
+ f"Executing the single node: {step_name} with map variable: {map_variable}"
285
+ )
244
286
 
245
- configuration_file = os.environ.get("RUNNABLE_CONFIGURATION_FILE", configuration_file)
287
+ configuration_file = os.environ.get(
288
+ "RUNNABLE_CONFIGURATION_FILE", configuration_file
289
+ )
246
290
 
247
291
  run_context = prepare_configurations(
248
292
  configuration_file=configuration_file,
@@ -257,7 +301,9 @@ def execute_single_node(
257
301
 
258
302
  executor = run_context.executor
259
303
  run_context.execution_plan = defaults.EXECUTION_PLAN.CHAINED.value
260
- utils.set_runnable_environment_variables(run_id=run_id, configuration_file=configuration_file, tag=tag)
304
+ utils.set_runnable_environment_variables(
305
+ run_id=run_id, configuration_file=configuration_file, tag=tag
306
+ )
261
307
 
262
308
  executor.prepare_for_node_execution()
263
309
 
@@ -271,7 +317,9 @@ def execute_single_node(
271
317
  map_variable_dict = utils.json_to_ordered_dict(map_variable)
272
318
 
273
319
  step_internal_name = nodes.BaseNode._get_internal_name_from_command_name(step_name)
274
- node_to_execute, _ = graph.search_node_by_internal_name(run_context.dag, step_internal_name)
320
+ node_to_execute, _ = graph.search_node_by_internal_name(
321
+ run_context.dag, step_internal_name
322
+ )
275
323
 
276
324
  logger.info("Executing the single node of : %s", node_to_execute)
277
325
  ## This step is where we save the log file
@@ -316,7 +364,9 @@ def execute_notebook(
316
364
 
317
365
  executor = run_context.executor
318
366
  run_context.execution_plan = defaults.EXECUTION_PLAN.UNCHAINED.value
319
- utils.set_runnable_environment_variables(run_id=run_id, configuration_file=configuration_file, tag=tag)
367
+ utils.set_runnable_environment_variables(
368
+ run_id=run_id, configuration_file=configuration_file, tag=tag
369
+ )
320
370
 
321
371
  console.print("Working with context:")
322
372
  console.print(run_context)
@@ -336,17 +386,25 @@ def execute_notebook(
336
386
  # Prepare for graph execution
337
387
  executor.prepare_for_graph_execution()
338
388
 
339
- logger.info("Executing the job from the user. We are still in the caller's compute environment")
389
+ logger.info(
390
+ "Executing the job from the user. We are still in the caller's compute environment"
391
+ )
340
392
  executor.execute_job(node=node)
341
393
 
342
394
  elif entrypoint == defaults.ENTRYPOINT.SYSTEM.value:
343
395
  executor.prepare_for_node_execution()
344
- logger.info("Executing the job from the system. We are in the config's compute environment")
396
+ logger.info(
397
+ "Executing the job from the system. We are in the config's compute environment"
398
+ )
345
399
  executor.execute_node(node=node)
346
400
 
347
401
  # Update the status of the run log
348
- step_log = run_context.run_log_store.get_step_log(node._get_step_log_name(), run_id)
349
- run_context.run_log_store.update_run_log_status(run_id=run_id, status=step_log.status)
402
+ step_log = run_context.run_log_store.get_step_log(
403
+ node._get_step_log_name(), run_id
404
+ )
405
+ run_context.run_log_store.update_run_log_status(
406
+ run_id=run_id, status=step_log.status
407
+ )
350
408
 
351
409
  else:
352
410
  raise ValueError(f"Invalid entrypoint {entrypoint}")
@@ -379,7 +437,9 @@ def execute_function(
379
437
  executor = run_context.executor
380
438
 
381
439
  run_context.execution_plan = defaults.EXECUTION_PLAN.UNCHAINED.value
382
- utils.set_runnable_environment_variables(run_id=run_id, configuration_file=configuration_file, tag=tag)
440
+ utils.set_runnable_environment_variables(
441
+ run_id=run_id, configuration_file=configuration_file, tag=tag
442
+ )
383
443
 
384
444
  console.print("Working with context:")
385
445
  console.print(run_context)
@@ -399,17 +459,25 @@ def execute_function(
399
459
  # Prepare for graph execution
400
460
  executor.prepare_for_graph_execution()
401
461
 
402
- logger.info("Executing the job from the user. We are still in the caller's compute environment")
462
+ logger.info(
463
+ "Executing the job from the user. We are still in the caller's compute environment"
464
+ )
403
465
  executor.execute_job(node=node)
404
466
 
405
467
  elif entrypoint == defaults.ENTRYPOINT.SYSTEM.value:
406
468
  executor.prepare_for_node_execution()
407
- logger.info("Executing the job from the system. We are in the config's compute environment")
469
+ logger.info(
470
+ "Executing the job from the system. We are in the config's compute environment"
471
+ )
408
472
  executor.execute_node(node=node)
409
473
 
410
474
  # Update the status of the run log
411
- step_log = run_context.run_log_store.get_step_log(node._get_step_log_name(), run_id)
412
- run_context.run_log_store.update_run_log_status(run_id=run_id, status=step_log.status)
475
+ step_log = run_context.run_log_store.get_step_log(
476
+ node._get_step_log_name(), run_id
477
+ )
478
+ run_context.run_log_store.update_run_log_status(
479
+ run_id=run_id, status=step_log.status
480
+ )
413
481
 
414
482
  else:
415
483
  raise ValueError(f"Invalid entrypoint {entrypoint}")
@@ -444,7 +512,9 @@ def fan(
444
512
  """
445
513
  from runnable import nodes
446
514
 
447
- configuration_file = os.environ.get("RUNNABLE_CONFIGURATION_FILE", configuration_file)
515
+ configuration_file = os.environ.get(
516
+ "RUNNABLE_CONFIGURATION_FILE", configuration_file
517
+ )
448
518
 
449
519
  run_context = prepare_configurations(
450
520
  configuration_file=configuration_file,
@@ -459,12 +529,17 @@ def fan(
459
529
 
460
530
  executor = run_context.executor
461
531
  run_context.execution_plan = defaults.EXECUTION_PLAN.CHAINED.value
462
- utils.set_runnable_environment_variables(run_id=run_id, configuration_file=configuration_file, tag=tag)
532
+ utils.set_runnable_environment_variables(
533
+ run_id=run_id, configuration_file=configuration_file, tag=tag
534
+ )
463
535
 
464
536
  executor.prepare_for_node_execution()
465
537
 
466
538
  step_internal_name = nodes.BaseNode._get_internal_name_from_command_name(step_name)
467
- node_to_execute, _ = graph.search_node_by_internal_name(run_context.dag, step_internal_name) # type: ignore
539
+ node_to_execute, _ = graph.search_node_by_internal_name(
540
+ run_context.dag, # type: ignore
541
+ step_internal_name,
542
+ )
468
543
 
469
544
  map_variable_dict = utils.json_to_ordered_dict(map_variable)
470
545
 
runnable/exceptions.py CHANGED
@@ -31,7 +31,9 @@ class StepLogNotFoundError(Exception): # pragma: no cover
31
31
 
32
32
  def __init__(self, run_id, name):
33
33
  super().__init__()
34
- self.message = f"Step log for {name} is not found in the datastore for Run id: {run_id}"
34
+ self.message = (
35
+ f"Step log for {name} is not found in the datastore for Run id: {run_id}"
36
+ )
35
37
 
36
38
 
37
39
  class BranchLogNotFoundError(Exception): # pragma: no cover
@@ -43,7 +45,9 @@ class BranchLogNotFoundError(Exception): # pragma: no cover
43
45
 
44
46
  def __init__(self, run_id, name):
45
47
  super().__init__()
46
- self.message = f"Branch log for {name} is not found in the datastore for Run id: {run_id}"
48
+ self.message = (
49
+ f"Branch log for {name} is not found in the datastore for Run id: {run_id}"
50
+ )
47
51
 
48
52
 
49
53
  class NodeNotFoundError(Exception): # pragma: no cover
runnable/executor.py CHANGED
@@ -14,7 +14,7 @@ from runnable.defaults import TypeMapVariable
14
14
  from runnable.graph import Graph
15
15
 
16
16
  if TYPE_CHECKING: # pragma: no cover
17
- from runnable.extensions.nodes import TaskNode
17
+ from extensions.nodes.nodes import TaskNode
18
18
  from runnable.nodes import BaseNode
19
19
 
20
20
  logger = logging.getLogger(defaults.LOGGER_NAME)
@@ -36,9 +36,12 @@ class BaseExecutor(ABC, BaseModel):
36
36
 
37
37
  overrides: dict = {}
38
38
 
39
- _local: bool = False # This is a flag to indicate whether the executor is local or not.
39
+ _local: bool = (
40
+ False # This is a flag to indicate whether the executor is local or not.
41
+ )
40
42
 
41
- _context_node = None # type: BaseNode
43
+ # TODO: Change this to _is_local
44
+ _context_node: Optional[BaseNode] = None
42
45
  model_config = ConfigDict(extra="forbid")
43
46
 
44
47
  @property
@@ -90,7 +93,9 @@ class BaseExecutor(ABC, BaseModel):
90
93
  ...
91
94
 
92
95
  @abstractmethod
93
- def _sync_catalog(self, stage: str, synced_catalogs=None) -> Optional[List[DataCatalog]]:
96
+ def _sync_catalog(
97
+ self, stage: str, synced_catalogs=None
98
+ ) -> Optional[List[DataCatalog]]:
94
99
  """
95
100
  1). Identify the catalog settings by over-riding node settings with the global settings.
96
101
  2). For stage = get:
@@ -141,7 +146,13 @@ class BaseExecutor(ABC, BaseModel):
141
146
  return int(os.environ.get(defaults.ATTEMPT_NUMBER, 1))
142
147
 
143
148
  @abstractmethod
144
- def _execute_node(self, node: BaseNode, map_variable: TypeMapVariable = None, mock: bool = False, **kwargs):
149
+ def _execute_node(
150
+ self,
151
+ node: BaseNode,
152
+ map_variable: TypeMapVariable = None,
153
+ mock: bool = False,
154
+ **kwargs,
155
+ ):
145
156
  """
146
157
  This is the entry point when we do the actual execution of the function.
147
158
 
@@ -163,7 +174,9 @@ class BaseExecutor(ABC, BaseModel):
163
174
  ...
164
175
 
165
176
  @abstractmethod
166
- def execute_node(self, node: BaseNode, map_variable: TypeMapVariable = None, **kwargs):
177
+ def execute_node(
178
+ self, node: BaseNode, map_variable: TypeMapVariable = None, **kwargs
179
+ ):
167
180
  """
168
181
  The entry point for all executors apart from local.
169
182
  We have already prepared for node execution.
@@ -191,7 +204,9 @@ class BaseExecutor(ABC, BaseModel):
191
204
  ...
192
205
 
193
206
  @abstractmethod
194
- def execute_from_graph(self, node: BaseNode, map_variable: TypeMapVariable = None, **kwargs):
207
+ def execute_from_graph(
208
+ self, node: BaseNode, map_variable: TypeMapVariable = None, **kwargs
209
+ ):
195
210
  """
196
211
  This is the entry point to from the graph execution.
197
212
 
@@ -219,7 +234,9 @@ class BaseExecutor(ABC, BaseModel):
219
234
  ...
220
235
 
221
236
  @abstractmethod
222
- def trigger_job(self, node: BaseNode, map_variable: TypeMapVariable = None, **kwargs):
237
+ def trigger_job(
238
+ self, node: BaseNode, map_variable: TypeMapVariable = None, **kwargs
239
+ ):
223
240
  """
224
241
  Executor specific way of triggering jobs when runnable does both traversal and execution
225
242
 
@@ -236,7 +253,9 @@ class BaseExecutor(ABC, BaseModel):
236
253
  ...
237
254
 
238
255
  @abstractmethod
239
- def _get_status_and_next_node_name(self, current_node: BaseNode, dag: Graph, map_variable: TypeMapVariable = None):
256
+ def _get_status_and_next_node_name(
257
+ self, current_node: BaseNode, dag: Graph, map_variable: TypeMapVariable = None
258
+ ):
240
259
  """
241
260
  Given the current node and the graph, returns the name of the next node to execute.
242
261
 
runnable/graph.py CHANGED
@@ -24,7 +24,9 @@ class Graph(BaseModel):
24
24
  name: str = ""
25
25
  description: Optional[str] = ""
26
26
  internal_branch_name: str = Field(default="", exclude=True)
27
- nodes: SerializeAsAny[Dict[str, "BaseNode"]] = Field(default_factory=dict, serialization_alias="steps")
27
+ nodes: SerializeAsAny[Dict[str, "BaseNode"]] = Field(
28
+ default_factory=dict, serialization_alias="steps"
29
+ )
28
30
 
29
31
  def get_summary(self) -> Dict[str, Any]:
30
32
  """
@@ -229,7 +231,9 @@ class Graph(BaseModel):
229
231
  return False
230
232
  return True
231
233
 
232
- def is_cyclic_util(self, node: "BaseNode", visited: Dict[str, bool], recstack: Dict[str, bool]) -> bool:
234
+ def is_cyclic_util(
235
+ self, node: "BaseNode", visited: Dict[str, bool], recstack: Dict[str, bool]
236
+ ) -> bool:
233
237
  """
234
238
  Recursive utility that determines if a node and neighbors has a cycle. Is used in is_dag method.
235
239
 
@@ -327,7 +331,9 @@ def create_graph(dag_config: Dict[str, Any], internal_branch_name: str = "") ->
327
331
  Graph: The created graph object
328
332
  """
329
333
  description: str = dag_config.get("description", None)
330
- start_at: str = cast(str, dag_config.get("start_at")) # Let the start_at be relative to the graph
334
+ start_at: str = cast(
335
+ str, dag_config.get("start_at")
336
+ ) # Let the start_at be relative to the graph
331
337
 
332
338
  graph = Graph(
333
339
  start_at=start_at,
@@ -339,7 +345,9 @@ def create_graph(dag_config: Dict[str, Any], internal_branch_name: str = "") ->
339
345
  for name, step_config in dag_config.get("steps", {}).items():
340
346
  logger.info(f"Adding node {name} with :{step_config}")
341
347
 
342
- node = create_node(name, step_config=step_config, internal_branch_name=internal_branch_name)
348
+ node = create_node(
349
+ name, step_config=step_config, internal_branch_name=internal_branch_name
350
+ )
343
351
  graph.add_node(node)
344
352
 
345
353
  graph.add_terminal_nodes(internal_branch_name=internal_branch_name)
@@ -369,8 +377,12 @@ def create_node(name: str, step_config: dict, internal_branch_name: Optional[str
369
377
  internal_name = internal_branch_name + "." + name
370
378
 
371
379
  try:
372
- node_type = step_config.pop("type") # Remove the type as it is not used in node creation.
373
- node_mgr: BaseNode = driver.DriverManager(namespace="nodes", name=node_type).driver
380
+ node_type = step_config.pop(
381
+ "type"
382
+ ) # Remove the type as it is not used in node creation.
383
+ node_mgr: BaseNode = driver.DriverManager(
384
+ namespace="nodes", name=node_type
385
+ ).driver
374
386
 
375
387
  next_node = step_config.pop("next", None)
376
388
 
@@ -424,11 +436,18 @@ def search_node_by_internal_name(dag: Graph, internal_name: str):
424
436
  for i in range(len(dot_path)):
425
437
  if i % 2:
426
438
  # Its odd, so we are in brach name
427
- current_branch = current_node._get_branch_by_name(".".join(dot_path[: i + 1])) # type: ignore
428
- logger.debug(f"Finding step for {internal_name} in branch: {current_branch}")
439
+
440
+ current_branch = current_node._get_branch_by_name( # type: ignore
441
+ ".".join(dot_path[: i + 1])
442
+ )
443
+ logger.debug(
444
+ f"Finding step for {internal_name} in branch: {current_branch}"
445
+ )
429
446
  else:
430
447
  # Its even, so we are in Step, we start here!
431
- current_node = current_branch.get_node_by_internal_name(".".join(dot_path[: i + 1]))
448
+ current_node = current_branch.get_node_by_internal_name(
449
+ ".".join(dot_path[: i + 1])
450
+ )
432
451
  logger.debug(f"Finding {internal_name} in node: {current_node}")
433
452
 
434
453
  logger.debug(f"current branch : {current_branch}, current step {current_node}")
@@ -463,12 +482,18 @@ def search_branch_by_internal_name(dag: Graph, internal_name: str):
463
482
  for i in range(len(dot_path)):
464
483
  if i % 2:
465
484
  # Its odd, so we are in brach name
466
- current_branch = current_node._get_branch_by_name(".".join(dot_path[: i + 1])) # type: ignore
467
- logger.debug(f"Finding step for {internal_name} in branch: {current_branch}")
485
+ current_branch = current_node._get_branch_by_name( # type: ignore
486
+ ".".join(dot_path[: i + 1])
487
+ )
488
+ logger.debug(
489
+ f"Finding step for {internal_name} in branch: {current_branch}"
490
+ )
468
491
 
469
492
  else:
470
493
  # Its even, so we are in Step, we start here!
471
- current_node = current_branch.get_node_by_internal_name(".".join(dot_path[: i + 1]))
494
+ current_node = current_branch.get_node_by_internal_name(
495
+ ".".join(dot_path[: i + 1])
496
+ )
472
497
  logger.debug(f"Finding {internal_name} in node: {current_node}")
473
498
 
474
499
  logger.debug(f"current branch : {current_branch}, current step {current_node}")
runnable/integration.py CHANGED
@@ -49,7 +49,9 @@ class BaseIntegration:
49
49
  # --8<-- [end:docs]
50
50
 
51
51
 
52
- def get_integration_handler(executor: "BaseExecutor", service: object) -> BaseIntegration:
52
+ def get_integration_handler(
53
+ executor: "BaseExecutor", service: object
54
+ ) -> BaseIntegration:
53
55
  """
54
56
  Return the integration handler between executor and the service.
55
57
 
@@ -147,6 +149,7 @@ def configure_for_execution(executor: "BaseExecutor", service: object, **kwargs)
147
149
  integration_handler.configure_for_execution(**kwargs)
148
150
 
149
151
 
152
+ # TODO: Move all of these to the proper locations
150
153
  class BufferedRunLogStore(BaseIntegration):
151
154
  """
152
155
  Integration between any executor and buffered run log store
@@ -157,7 +160,9 @@ class BufferedRunLogStore(BaseIntegration):
157
160
 
158
161
  def validate(self, **kwargs):
159
162
  if not self.executor.service_name == "local":
160
- raise Exception("Buffered run log store is only supported for local executor")
163
+ raise Exception(
164
+ "Buffered run log store is only supported for local executor"
165
+ )
161
166
 
162
167
  msg = (
163
168
  "Run log generated by buffered run log store are not persisted. "
runnable/nodes.py CHANGED
@@ -51,7 +51,9 @@ class BaseNode(ABC, BaseModel):
51
51
  raise ValueError("Node names cannot have . or '%' in them")
52
52
  return name
53
53
 
54
- def _command_friendly_name(self, replace_with=defaults.COMMAND_FRIENDLY_CHARACTER) -> str:
54
+ def _command_friendly_name(
55
+ self, replace_with=defaults.COMMAND_FRIENDLY_CHARACTER
56
+ ) -> str:
55
57
  """
56
58
  Replace spaces with special character for spaces.
57
59
  Spaces in the naming of the node is convenient for the user but causes issues when used programmatically.
@@ -76,7 +78,9 @@ class BaseNode(ABC, BaseModel):
76
78
  return command_name.replace(defaults.COMMAND_FRIENDLY_CHARACTER, " ")
77
79
 
78
80
  @classmethod
79
- def _resolve_map_placeholders(cls, name: str, map_variable: TypeMapVariable = None) -> str:
81
+ def _resolve_map_placeholders(
82
+ cls, name: str, map_variable: TypeMapVariable = None
83
+ ) -> str:
80
84
  """
81
85
  If there is no map step used, then we just return the name as we find it.
82
86
 
@@ -141,7 +145,9 @@ class BaseNode(ABC, BaseModel):
141
145
  Returns:
142
146
  str: The dot path name of the step log name
143
147
  """
144
- return self._resolve_map_placeholders(self.internal_name, map_variable=map_variable)
148
+ return self._resolve_map_placeholders(
149
+ self.internal_name, map_variable=map_variable
150
+ )
145
151
 
146
152
  def _get_branch_log_name(self, map_variable: TypeMapVariable = None) -> str:
147
153
  """
@@ -158,7 +164,9 @@ class BaseNode(ABC, BaseModel):
158
164
  Returns:
159
165
  str: The dot path name of the branch log
160
166
  """
161
- return self._resolve_map_placeholders(self.internal_branch_name, map_variable=map_variable)
167
+ return self._resolve_map_placeholders(
168
+ self.internal_branch_name, map_variable=map_variable
169
+ )
162
170
 
163
171
  def __str__(self) -> str: # pragma: no cover
164
172
  """
@@ -180,7 +188,6 @@ class BaseNode(ABC, BaseModel):
180
188
  str: The on_failure node defined by the dag or ''
181
189
  This is a base implementation which the BaseNode does not satisfy
182
190
  """
183
- ...
184
191
 
185
192
  @abstractmethod
186
193
  def _get_next_node(self) -> str:
@@ -190,7 +197,6 @@ class BaseNode(ABC, BaseModel):
190
197
  Returns:
191
198
  str: The node name, relative to the dag, as defined by the config
192
199
  """
193
- ...
194
200
 
195
201
  @abstractmethod
196
202
  def _is_terminal_node(self) -> bool:
@@ -200,7 +206,6 @@ class BaseNode(ABC, BaseModel):
200
206
  Returns:
201
207
  bool: True or False of whether there is next node.
202
208
  """
203
- ...
204
209
 
205
210
  @abstractmethod
206
211
  def _get_catalog_settings(self) -> Dict[str, Any]:
@@ -210,7 +215,6 @@ class BaseNode(ABC, BaseModel):
210
215
  Returns:
211
216
  dict: catalog settings defined as per the node or None
212
217
  """
213
- ...
214
218
 
215
219
  @abstractmethod
216
220
  def _get_branch_by_name(self, branch_name: str):
@@ -225,7 +229,6 @@ class BaseNode(ABC, BaseModel):
225
229
  Raises:
226
230
  Exception: [description]
227
231
  """
228
- ...
229
232
 
230
233
  def _get_neighbors(self) -> List[str]:
231
234
  """
@@ -261,7 +264,6 @@ class BaseNode(ABC, BaseModel):
261
264
  Returns:
262
265
  dict: The executor config, if defined or an empty dict
263
266
  """
264
- ...
265
267
 
266
268
  @abstractmethod
267
269
  def _get_max_attempts(self) -> int:
@@ -271,7 +273,6 @@ class BaseNode(ABC, BaseModel):
271
273
  Returns:
272
274
  int: The number of maximum retries as defined by the config or 1.
273
275
  """
274
- ...
275
276
 
276
277
  @abstractmethod
277
278
  def execute(
@@ -296,7 +297,6 @@ class BaseNode(ABC, BaseModel):
296
297
  Raises:
297
298
  NotImplementedError: Base class, hence not implemented.
298
299
  """
299
- ...
300
300
 
301
301
  @abstractmethod
302
302
  def execute_as_graph(self, map_variable: TypeMapVariable = None, **kwargs):
@@ -312,7 +312,6 @@ class BaseNode(ABC, BaseModel):
312
312
  Raises:
313
313
  NotImplementedError: Base class, hence not implemented.
314
314
  """
315
- ...
316
315
 
317
316
  @abstractmethod
318
317
  def fan_out(self, map_variable: TypeMapVariable = None, **kwargs):
@@ -329,7 +328,6 @@ class BaseNode(ABC, BaseModel):
329
328
  Raises:
330
329
  Exception: If the node is not a composite node.
331
330
  """
332
- ...
333
331
 
334
332
  @abstractmethod
335
333
  def fan_in(self, map_variable: TypeMapVariable = None, **kwargs):
@@ -346,7 +344,6 @@ class BaseNode(ABC, BaseModel):
346
344
  Raises:
347
345
  Exception: If the node is not a composite node.
348
346
  """
349
- ...
350
347
 
351
348
  @classmethod
352
349
  @abstractmethod
@@ -360,7 +357,6 @@ class BaseNode(ABC, BaseModel):
360
357
  Returns:
361
358
  BaseNode: The corresponding node.
362
359
  """
363
- ...
364
360
 
365
361
  @abstractmethod
366
362
  def get_summary(self) -> Dict[str, Any]:
@@ -471,7 +467,9 @@ class CompositeNode(TraversalNode):
471
467
  attempt_number: int = 1,
472
468
  **kwargs,
473
469
  ) -> StepLog:
474
- raise Exception("This is a composite node and does not have an execute function")
470
+ raise Exception(
471
+ "This is a composite node and does not have an execute function"
472
+ )
475
473
 
476
474
 
477
475
  class TerminalNode(BaseNode):