runnable 0.13.0__py3-none-any.whl → 0.16.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 +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