runnable 0.13.0__py3-none-any.whl → 0.16.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.
Files changed (64) hide show
  1. runnable/__init__.py +1 -12
  2. runnable/catalog.py +29 -5
  3. runnable/cli.py +268 -215
  4. runnable/context.py +10 -3
  5. runnable/datastore.py +212 -53
  6. runnable/defaults.py +13 -55
  7. runnable/entrypoints.py +270 -183
  8. runnable/exceptions.py +28 -2
  9. runnable/executor.py +133 -86
  10. runnable/graph.py +37 -13
  11. runnable/nodes.py +50 -22
  12. runnable/parameters.py +27 -8
  13. runnable/pickler.py +1 -1
  14. runnable/sdk.py +230 -66
  15. runnable/secrets.py +3 -1
  16. runnable/tasks.py +99 -41
  17. runnable/utils.py +59 -39
  18. {runnable-0.13.0.dist-info → runnable-0.16.0.dist-info}/METADATA +28 -31
  19. runnable-0.16.0.dist-info/RECORD +23 -0
  20. {runnable-0.13.0.dist-info → runnable-0.16.0.dist-info}/WHEEL +1 -1
  21. runnable-0.16.0.dist-info/entry_points.txt +45 -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.py +0 -69
  37. runnable/extensions/executor/local_container/__init__.py +0 -0
  38. runnable/extensions/executor/local_container/implementation.py +0 -446
  39. runnable/extensions/executor/mocked/__init__.py +0 -0
  40. runnable/extensions/executor/mocked/implementation.py +0 -154
  41. runnable/extensions/executor/retry/__init__.py +0 -0
  42. runnable/extensions/executor/retry/implementation.py +0 -168
  43. runnable/extensions/nodes.py +0 -870
  44. runnable/extensions/run_log_store/__init__.py +0 -0
  45. runnable/extensions/run_log_store/chunked_file_system/__init__.py +0 -0
  46. runnable/extensions/run_log_store/chunked_file_system/implementation.py +0 -111
  47. runnable/extensions/run_log_store/chunked_k8s_pvc/__init__.py +0 -0
  48. runnable/extensions/run_log_store/chunked_k8s_pvc/implementation.py +0 -21
  49. runnable/extensions/run_log_store/chunked_k8s_pvc/integration.py +0 -61
  50. runnable/extensions/run_log_store/db/implementation_FF.py +0 -157
  51. runnable/extensions/run_log_store/db/integration_FF.py +0 -0
  52. runnable/extensions/run_log_store/file_system/__init__.py +0 -0
  53. runnable/extensions/run_log_store/file_system/implementation.py +0 -140
  54. runnable/extensions/run_log_store/generic_chunked.py +0 -557
  55. runnable/extensions/run_log_store/k8s_pvc/__init__.py +0 -0
  56. runnable/extensions/run_log_store/k8s_pvc/implementation.py +0 -21
  57. runnable/extensions/run_log_store/k8s_pvc/integration.py +0 -56
  58. runnable/extensions/secrets/__init__.py +0 -0
  59. runnable/extensions/secrets/dotenv/__init__.py +0 -0
  60. runnable/extensions/secrets/dotenv/implementation.py +0 -100
  61. runnable/integration.py +0 -192
  62. runnable-0.13.0.dist-info/RECORD +0 -63
  63. runnable-0.13.0.dist-info/entry_points.txt +0 -41
  64. {runnable-0.13.0.dist-info → runnable-0.16.0.dist-info/licenses}/LICENSE +0 -0
runnable/__init__.py CHANGED
@@ -1,6 +1,5 @@
1
1
  # ruff: noqa
2
2
 
3
- # TODO: Might need to add Rich to pyinstaller part
4
3
  import logging
5
4
  import os
6
5
  from logging.config import dictConfig
@@ -20,6 +19,7 @@ task_console = Console(record=True)
20
19
  from runnable.sdk import ( # noqa
21
20
  Catalog,
22
21
  Fail,
22
+ Job,
23
23
  Map,
24
24
  NotebookTask,
25
25
  Parallel,
@@ -34,14 +34,3 @@ from runnable.sdk import ( # noqa
34
34
 
35
35
  # Needed to disable ploomber telemetry
36
36
  os.environ["PLOOMBER_STATS_ENABLED"] = "false"
37
-
38
- ## TODO: Summary should be a bit better for catalog.
39
- ## If the execution fails, hint them about the retry executor.
40
- # Make the retry executor loose!
41
-
42
- # TODO: Think of model registry as a central place to store models.
43
- # TODO: Implement Sagemaker pipelines as a executor.
44
-
45
-
46
- # TODO: Think of way of generating dag hash without executor configuration
47
- # Try to get a release
runnable/catalog.py CHANGED
@@ -10,6 +10,28 @@ from runnable.datastore import DataCatalog
10
10
 
11
11
  logger = logging.getLogger(defaults.LOGGER_NAME)
12
12
 
13
+ # TODO: Should ** be allowed as glob pattern as it can potentially copy everything to catalog
14
+
15
+
16
+ def is_catalog_out_of_sync(
17
+ catalog, synced_catalogs=Optional[List[DataCatalog]]
18
+ ) -> bool:
19
+ """
20
+ Check if the catalog items are out of sync from already cataloged objects.
21
+ If they are, return False.
22
+ If the object does not exist or synced catalog does not exist, return True
23
+ """
24
+ if not synced_catalogs:
25
+ return True # If nothing has been synced in the past
26
+
27
+ for synced_catalog in synced_catalogs:
28
+ if synced_catalog.catalog_relative_path == catalog.catalog_relative_path:
29
+ if synced_catalog.data_hash == catalog.data_hash:
30
+ return False
31
+ return True
32
+
33
+ return True # The object does not exist, sync it
34
+
13
35
 
14
36
  # --8<-- [start:docs]
15
37
 
@@ -26,8 +48,7 @@ class BaseCatalog(ABC, BaseModel):
26
48
  model_config = ConfigDict(extra="forbid")
27
49
 
28
50
  @abstractmethod
29
- def get_summary(self) -> Dict[str, Any]:
30
- ...
51
+ def get_summary(self) -> Dict[str, Any]: ...
31
52
 
32
53
  @property
33
54
  def _context(self):
@@ -38,7 +59,9 @@ class BaseCatalog(ABC, BaseModel):
38
59
  return defaults.COMPUTE_DATA_FOLDER
39
60
 
40
61
  @abstractmethod
41
- def get(self, name: str, run_id: str, compute_data_folder: str = "", **kwargs) -> List[DataCatalog]:
62
+ def get(
63
+ self, name: str, run_id: str, compute_data_folder: str = "", **kwargs
64
+ ) -> List[DataCatalog]:
42
65
  """
43
66
  Get the catalog item by 'name' for the 'run id' and store it in compute data folder.
44
67
 
@@ -119,7 +142,9 @@ class DoNothingCatalog(BaseCatalog):
119
142
  def get_summary(self) -> Dict[str, Any]:
120
143
  return {}
121
144
 
122
- def get(self, name: str, run_id: str, compute_data_folder: str = "", **kwargs) -> List[DataCatalog]:
145
+ def get(
146
+ self, name: str, run_id: str, compute_data_folder: str = "", **kwargs
147
+ ) -> List[DataCatalog]:
123
148
  """
124
149
  Does nothing
125
150
  """
@@ -145,4 +170,3 @@ class DoNothingCatalog(BaseCatalog):
145
170
  Does nothing
146
171
  """
147
172
  logger.info("Using a do-nothing catalog, doing nothing while sync between runs")
148
- ...
runnable/cli.py CHANGED
@@ -1,112 +1,154 @@
1
- # A dummy to trigger the PR
2
1
  import logging
2
+ from enum import Enum
3
+ from typing import Annotated
3
4
 
4
- import click
5
- from click_plugins import with_plugins
6
- from pkg_resources import iter_entry_points
5
+ import typer
7
6
 
8
7
  from runnable import defaults, entrypoints
9
8
 
10
9
  logger = logging.getLogger(defaults.LOGGER_NAME)
11
10
 
12
11
 
13
- @with_plugins(iter_entry_points("runnable.cli_plugins"))
14
- @click.group()
15
- @click.version_option()
16
- def cli():
17
- """
18
- Welcome to runnable. Please provide the command that you want to use.
19
- All commands have options that you can see by runnable <command> --help
20
- """
21
- pass
12
+ app = typer.Typer(
13
+ help=(
14
+ "Welcome to runnable. Please provide the command that you want to use."
15
+ "All commands have options that you can see by runnable <command> --help"
16
+ ),
17
+ )
22
18
 
23
19
 
24
- @cli.command("execute", short_help="Execute/translate a pipeline")
25
- @click.option("-f", "--file", default="pipeline.yaml", help="The pipeline definition file", show_default=True)
26
- @click.option(
27
- "-c", "--config-file", default=None, help="config file, in yaml, to be used for the run", show_default=True
28
- )
29
- @click.option(
30
- "-p",
31
- "--parameters-file",
32
- default=None,
33
- help="Parameters, in yaml, accessible by the application",
34
- show_default=True,
35
- )
36
- @click.option(
37
- "--log-level",
38
- default=defaults.LOG_LEVEL,
39
- help="The log level",
40
- show_default=True,
41
- type=click.Choice(["INFO", "DEBUG", "WARNING", "ERROR", "FATAL"]),
42
- )
43
- @click.option("--tag", default="", help="A tag attached to the run")
44
- @click.option("--run-id", help="An optional run_id, one would be generated if not provided")
45
- def execute(file, config_file, parameters_file, log_level, tag, run_id): # pragma: no cover
20
+ class LogLevel(str, Enum):
21
+ INFO = "INFO"
22
+ DEBUG = "DEBUG"
23
+ WARNING = "WARNING"
24
+ ERROR = "ERROR"
25
+ FATAL = "FATAL"
26
+
27
+
28
+ class ExecutionMode(str, Enum):
29
+ YAML = "yaml"
30
+ PYTHON = "python"
31
+
32
+
33
+ class FanMode(str, Enum):
34
+ IN = "in"
35
+ OUT = "out"
36
+
37
+
38
+ @app.command()
39
+ def execute(
40
+ yaml_file: Annotated[str, typer.Argument(help="The pipeline definition file")],
41
+ config_file: Annotated[
42
+ str,
43
+ typer.Option(
44
+ "--config", "-c", help="The configuration file specifying the services"
45
+ ),
46
+ ] = "",
47
+ parameters_file: Annotated[
48
+ str,
49
+ typer.Option(
50
+ "--parameters",
51
+ "-p",
52
+ help="Parameters, in yaml, accessible by the application",
53
+ ),
54
+ ] = "",
55
+ log_level: Annotated[
56
+ LogLevel,
57
+ typer.Option(
58
+ "--log-level",
59
+ help="The log level",
60
+ show_default=True,
61
+ case_sensitive=False,
62
+ ),
63
+ ] = LogLevel.WARNING,
64
+ tag: Annotated[str, typer.Option(help="A tag attached to the run")] = "",
65
+ run_id: Annotated[
66
+ str,
67
+ typer.Option(
68
+ help="An optional run_id, one would be generated if its not provided"
69
+ ),
70
+ ] = "",
71
+ ):
46
72
  """
47
- Execute a pipeline
73
+ Execute a pipeline defined by yaml file.
74
+
75
+ The executor is defined by executor block of the configuration file.
76
+
77
+ The behavior of this command depends on the executor type:
48
78
 
49
- Usage: runnable execute [OPTIONS]
79
+ -- For local executors (local, local-container), the pipeline is executed in the current environment.
50
80
 
51
- Options:
52
- -f, --file TEXT The pipeline definition file [default: pipeline.yaml]
53
- -c, --config-file TEXT config file, in yaml, to be used for the run [default: None]
54
- -p, --parameters-file TEXT Parameters, in yaml, accessible by the application [default: None]
55
- --log-level One of [INFO|DEBUG|WARNING|ERROR|FATAL]
56
- The log level
57
- [default: INFO]
58
- --tag TEXT A tag attached to the run
59
- [default: ]
60
- --run-id TEXT An optional run_id, one would be generated if not
61
- provided
81
+ -- For remote executors (argo, airflow), the pipeline translated to the specification.
62
82
  """
63
- logger.setLevel(log_level)
83
+ logger.setLevel(log_level.value)
64
84
 
65
- entrypoints.execute(
85
+ entrypoints.execute_pipeline_yaml_spec(
66
86
  configuration_file=config_file,
67
- pipeline_file=file,
87
+ pipeline_file=yaml_file,
68
88
  tag=tag,
69
89
  run_id=run_id,
70
90
  parameters_file=parameters_file,
71
91
  )
72
92
 
73
93
 
74
- @cli.command("execute_single_node", short_help="Internal entry point to execute a single node", hidden=True)
75
- @click.argument("run_id")
76
- @click.argument("step_name")
77
- @click.option("--map-variable", default="", help="The map variable dictionary in str", show_default=True)
78
- @click.option("-f", "--file", default="", help="The pipeline definition file", show_default=True)
79
- @click.option(
80
- "-c", "--config-file", default=None, help="config file, in yaml, to be used for the run", show_default=True
81
- )
82
- @click.option(
83
- "-p",
84
- "--parameters-file",
85
- default=None,
86
- help="Parameters, in yaml, accessible by the application",
87
- show_default=True,
88
- )
89
- @click.option(
90
- "--log-level",
91
- default=defaults.LOG_LEVEL,
92
- help="The log level",
93
- show_default=True,
94
- type=click.Choice(["INFO", "DEBUG", "WARNING", "ERROR", "FATAL"]),
95
- )
96
- @click.option("--tag", default="", help="A tag attached to the run")
97
- def execute_single_node(run_id, step_name, map_variable, file, config_file, parameters_file, log_level, tag):
98
- """
99
- Internal entrypoint for runnable to execute a single node.
100
-
101
- Other than local executor, every other executor uses this entry point to execute a step in the context of runnable.
102
- Only chained executions should use this method. Unchained executions should use execute_
103
- """
104
- logger.setLevel(log_level)
105
-
106
- # Execute the node as part of the graph execution.
94
+ @app.command(hidden=True)
95
+ def execute_single_node(
96
+ run_id: Annotated[
97
+ str,
98
+ typer.Argument(
99
+ help="An optional run_id, one would be generated if its not provided"
100
+ ),
101
+ ],
102
+ yaml_or_python_file: Annotated[
103
+ str, typer.Argument(help="The pipeline definition file")
104
+ ],
105
+ step_name: Annotated[str, typer.Argument(help="The step name to execute")],
106
+ config_file: Annotated[
107
+ str,
108
+ typer.Option(
109
+ "--config", "-c", help="The configuration file specifying the services"
110
+ ),
111
+ ] = "",
112
+ parameters_file: Annotated[
113
+ str,
114
+ typer.Option(
115
+ "--parameters-file",
116
+ "-p",
117
+ help="Parameters, in yaml, accessible by the application",
118
+ ),
119
+ ] = "",
120
+ log_level: Annotated[
121
+ LogLevel,
122
+ typer.Option(
123
+ "--log-level",
124
+ help="The log level",
125
+ show_default=True,
126
+ case_sensitive=False,
127
+ ),
128
+ ] = LogLevel.INFO,
129
+ tag: Annotated[str, typer.Option(help="A tag attached to the run")] = "",
130
+ mode: Annotated[
131
+ ExecutionMode,
132
+ typer.Option(
133
+ "--mode",
134
+ "-m",
135
+ help="spec in yaml or python sdk",
136
+ ),
137
+ ] = ExecutionMode.YAML,
138
+ map_variable: Annotated[
139
+ str,
140
+ typer.Option(
141
+ "--map-variable",
142
+ help="The map variable dictionary in str",
143
+ show_default=True,
144
+ ),
145
+ ] = "",
146
+ ):
147
+ logger.setLevel(log_level.value)
107
148
  entrypoints.execute_single_node(
108
149
  configuration_file=config_file,
109
- pipeline_file=file,
150
+ pipeline_file=yaml_or_python_file,
151
+ mode=mode,
110
152
  step_name=step_name,
111
153
  map_variable=map_variable,
112
154
  run_id=run_id,
@@ -115,157 +157,168 @@ def execute_single_node(run_id, step_name, map_variable, file, config_file, para
115
157
  )
116
158
 
117
159
 
118
- @cli.command("execute_notebook", short_help="Entry point to execute a notebook")
119
- @click.argument("filename")
120
- @click.option("--entrypoint", default=defaults.ENTRYPOINT.USER.value, hidden=True)
121
- @click.option(
122
- "-c", "--config-file", default=None, help="config file, in yaml, to be used for the run", show_default=True
123
- )
124
- @click.option(
125
- "-p",
126
- "--parameters-file",
127
- default=None,
128
- help="Parameters, in yaml, accessible by the application",
129
- show_default=True,
130
- )
131
- @click.option(
132
- "--log-level",
133
- default=defaults.LOG_LEVEL,
134
- help="The log level",
135
- show_default=True,
136
- type=click.Choice(["INFO", "DEBUG", "WARNING", "ERROR", "FATAL"]),
137
- )
138
- @click.option("--data-folder", "-d", default="data/", help="The catalog data folder")
139
- @click.option("--put-in-catalog", "-put", default=None, multiple=True, help="The data to put from the catalog")
140
- @click.option("--notebook-output-path", default="", help="The output path for the notebook")
141
- @click.option("--tag", help="A tag attached to the run")
142
- @click.option("--run-id", help="An optional run_id, one would be generated if not provided")
143
- def execute_notebook(
144
- filename,
145
- entrypoint,
146
- config_file,
147
- parameters_file,
148
- log_level,
149
- data_folder,
150
- put_in_catalog,
151
- notebook_output_path,
152
- tag,
153
- run_id,
160
+ @app.command(hidden=True)
161
+ def fan(
162
+ run_id: Annotated[str, typer.Argument(help="The run id")],
163
+ step_name: Annotated[str, typer.Argument(help="The step name")],
164
+ python_or_yaml_file: Annotated[
165
+ str, typer.Argument(help="The pipeline definition file")
166
+ ],
167
+ mode: Annotated[FanMode, typer.Option(help="fan in or fan out")],
168
+ map_variable: Annotated[
169
+ str,
170
+ typer.Option(
171
+ "--map-variable",
172
+ help="The map variable dictionary in str",
173
+ show_default=True,
174
+ ),
175
+ ],
176
+ config_file: Annotated[
177
+ str,
178
+ typer.Option(
179
+ "--config-file", "-c", help="The configuration file specifying the services"
180
+ ),
181
+ ] = "",
182
+ parameters_file: Annotated[
183
+ str,
184
+ typer.Option(
185
+ "--parameters-file",
186
+ "-p",
187
+ help="Parameters, in yaml, accessible by the application",
188
+ ),
189
+ ] = "",
190
+ log_level: Annotated[
191
+ LogLevel,
192
+ typer.Option(
193
+ "--log-level",
194
+ help="The log level",
195
+ show_default=True,
196
+ case_sensitive=False,
197
+ ),
198
+ ] = LogLevel.INFO,
199
+ tag: Annotated[str, typer.Option(help="A tag attached to the run")] = "",
154
200
  ):
155
- """
156
- External entry point to execute a Jupyter notebook in isolation.
157
-
158
- The notebook would be executed in the environment defined by the config file or default if none.
159
- The execution plan is unchained.
160
- """
161
- logger.setLevel(log_level)
162
- catalog_config = {"compute_data_folder": data_folder, "put": list(put_in_catalog) if put_in_catalog else None}
163
- if not filename.endswith(".ipynb"):
164
- raise Exception("A notebook should always have ipynb as the extension")
201
+ logger.setLevel(log_level.value)
165
202
 
166
- entrypoints.execute_notebook(
167
- entrypoint=entrypoint,
168
- notebook_file=filename,
169
- catalog_config=catalog_config,
203
+ # Fan in or out
204
+ entrypoints.fan(
170
205
  configuration_file=config_file,
171
- parameters_file=parameters_file,
172
- notebook_output_path=notebook_output_path,
173
- tag=tag,
206
+ pipeline_file=python_or_yaml_file,
207
+ step_name=step_name,
208
+ mode=mode,
209
+ map_variable=map_variable,
174
210
  run_id=run_id,
211
+ tag=tag,
212
+ parameters_file=parameters_file,
175
213
  )
176
214
 
177
215
 
178
- @cli.command("execute_function", short_help="Entry point to execute a python function")
179
- @click.argument("command")
180
- @click.option("--entrypoint", default=defaults.ENTRYPOINT.USER.value, hidden=True)
181
- @click.option(
182
- "-c", "--config-file", default=None, help="config file, in yaml, to be used for the run", show_default=True
183
- )
184
- @click.option(
185
- "-p",
186
- "--parameters-file",
187
- default=None,
188
- help="Parameters, in yaml, accessible by the application",
189
- show_default=True,
190
- )
191
- @click.option(
192
- "--log-level",
193
- default=defaults.LOG_LEVEL,
194
- help="The log level",
195
- show_default=True,
196
- type=click.Choice(["INFO", "DEBUG", "WARNING", "ERROR", "FATAL"]),
197
- )
198
- @click.option("--data-folder", "-d", default="data/", help="The catalog data folder")
199
- @click.option("--put-in-catalog", "-put", default=None, multiple=True, help="The data to put from the catalog")
200
- @click.option("--tag", help="A tag attached to the run")
201
- @click.option("--run-id", help="An optional run_id, one would be generated if not provided")
202
- def execute_function(
203
- command, entrypoint, config_file, parameters_file, log_level, data_folder, put_in_catalog, tag, run_id
216
+ @app.command()
217
+ def submit_job(
218
+ job_definition_file: Annotated[
219
+ str,
220
+ typer.Argument(
221
+ help=("The yaml file containing the job definition"),
222
+ ),
223
+ ],
224
+ config_file: Annotated[
225
+ str,
226
+ typer.Option(
227
+ "--config", "-c", help="The configuration file specifying the services"
228
+ ),
229
+ ] = "",
230
+ parameters_file: Annotated[
231
+ str,
232
+ typer.Option(
233
+ "--parameters",
234
+ "-p",
235
+ help="Parameters, in yaml, accessible by the application",
236
+ ),
237
+ ] = "",
238
+ log_level: Annotated[
239
+ LogLevel,
240
+ typer.Option(
241
+ "--log-level",
242
+ help="The log level",
243
+ show_default=True,
244
+ case_sensitive=False,
245
+ ),
246
+ ] = LogLevel.WARNING,
247
+ tag: Annotated[str, typer.Option(help="A tag attached to the run")] = "",
248
+ run_id: Annotated[
249
+ str,
250
+ typer.Option(
251
+ help="An optional run_id, one would be generated if its not provided"
252
+ ),
253
+ ] = "",
204
254
  ):
205
- """
206
- External entry point to execute a python function in isolation.
255
+ logger.setLevel(log_level.value)
207
256
 
208
- The function would be executed in the environment defined by the config file or default if none.
209
- The execution plan is unchained.
210
- """
211
- logger.setLevel(log_level)
212
- catalog_config = {"compute_data_folder": data_folder, "put": list(put_in_catalog) if put_in_catalog else None}
213
- entrypoints.execute_function(
214
- entrypoint=entrypoint,
215
- command=command,
216
- catalog_config=catalog_config,
257
+ entrypoints.execute_job_yaml_spec(
217
258
  configuration_file=config_file,
218
- parameters_file=parameters_file,
259
+ job_definition_file=job_definition_file,
219
260
  tag=tag,
220
261
  run_id=run_id,
262
+ parameters_file=parameters_file,
221
263
  )
222
264
 
223
265
 
224
- @cli.command("fan", short_help="Internal entry point to fan in or out a composite node", hidden=True)
225
- @click.argument("run_id")
226
- @click.argument("step_name")
227
- @click.option("-m", "--mode", help="fan in or fan out", required=True, type=click.Choice(["in", "out"]))
228
- @click.option("--map-variable", default="", help="The map variable dictionary in str", show_default=True)
229
- @click.option("-f", "--file", default="", help="The pipeline definition file", show_default=True)
230
- @click.option(
231
- "-c", "--config-file", default=None, help="config file, in yaml, to be used for the run", show_default=True
232
- )
233
- @click.option(
234
- "-p",
235
- "--parameters-file",
236
- default=None,
237
- help="Parameters, in yaml, accessible by the application",
238
- show_default=True,
239
- )
240
- @click.option(
241
- "--log-level",
242
- default=defaults.LOG_LEVEL,
243
- help="The log level",
244
- show_default=True,
245
- type=click.Choice(["INFO", "DEBUG", "WARNING", "ERROR", "FATAL"]),
246
- )
247
- @click.option("--tag", default="", help="A tag attached to the run")
248
- def fan(run_id, step_name, mode, map_variable, file, config_file, parameters_file, log_level, tag):
249
- """
250
- Internal entrypoint for runnable to fan in or out a composite node.
251
-
252
- Only 3rd party orchestrators should use this entry point.
253
- """
254
- logger.setLevel(log_level)
266
+ @app.command(hidden=True)
267
+ def execute_job(
268
+ job_definition_file: Annotated[
269
+ str,
270
+ typer.Argument(
271
+ help=("The yaml file containing the job definition"),
272
+ ),
273
+ ],
274
+ run_id: Annotated[
275
+ str,
276
+ typer.Argument(help="An run_id, one would be generated if its not provided"),
277
+ ],
278
+ config_file: Annotated[
279
+ str,
280
+ typer.Option(
281
+ "--config", "-c", help="The configuration file specifying the services"
282
+ ),
283
+ ] = "",
284
+ parameters_file: Annotated[
285
+ str,
286
+ typer.Option(
287
+ "--parameters",
288
+ "-p",
289
+ help="Parameters, in yaml, accessible by the application",
290
+ ),
291
+ ] = "",
292
+ mode: Annotated[
293
+ ExecutionMode,
294
+ typer.Option(
295
+ "--mode",
296
+ "-m",
297
+ help="spec in yaml or python sdk",
298
+ ),
299
+ ] = ExecutionMode.YAML,
300
+ log_level: Annotated[
301
+ LogLevel,
302
+ typer.Option(
303
+ "--log-level",
304
+ help="The log level",
305
+ show_default=True,
306
+ case_sensitive=False,
307
+ ),
308
+ ] = LogLevel.WARNING,
309
+ tag: Annotated[str, typer.Option(help="A tag attached to the run")] = "",
310
+ ):
311
+ logger.setLevel(log_level.value)
255
312
 
256
- # Fan in or out
257
- entrypoints.fan(
313
+ entrypoints.execute_job_non_local(
258
314
  configuration_file=config_file,
259
- pipeline_file=file,
260
- step_name=step_name,
315
+ job_definition_file=job_definition_file,
261
316
  mode=mode,
262
- map_variable=map_variable,
263
- run_id=run_id,
264
317
  tag=tag,
318
+ run_id=run_id,
265
319
  parameters_file=parameters_file,
266
320
  )
267
321
 
268
322
 
269
- # Needed for the binary creation
270
323
  if __name__ == "__main__":
271
- cli()
324
+ app()
runnable/context.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import Dict, Optional
1
+ from typing import Dict, List, Optional
2
2
 
3
3
  from pydantic import BaseModel, ConfigDict, Field, SerializeAsAny
4
4
  from rich.progress import Progress
@@ -9,6 +9,7 @@ from runnable.executor import BaseExecutor
9
9
  from runnable.graph import Graph
10
10
  from runnable.pickler import BasePickler
11
11
  from runnable.secrets import BaseSecrets
12
+ from runnable.tasks import BaseTaskType
12
13
 
13
14
 
14
15
  class Context(BaseModel):
@@ -22,15 +23,21 @@ class Context(BaseModel):
22
23
  model_config = ConfigDict(arbitrary_types_allowed=True)
23
24
 
24
25
  pipeline_file: Optional[str] = ""
26
+ job_definition_file: Optional[str] = ""
25
27
  parameters_file: Optional[str] = ""
26
28
  configuration_file: Optional[str] = ""
29
+ from_sdk: bool = False
27
30
 
28
- tag: str = ""
29
31
  run_id: str = ""
32
+
33
+ tag: str = ""
30
34
  variables: Dict[str, str] = {}
35
+
31
36
  dag: Optional[Graph] = None
32
37
  dag_hash: str = ""
33
- execution_plan: str = ""
38
+
39
+ job: Optional[BaseTaskType] = None
40
+ job_catalog_settings: Optional[List[str]] = []
34
41
 
35
42
 
36
43
  run_context = None # type: Context # type: ignore