ob-metaflow 2.11.13.1__py2.py3-none-any.whl → 2.19.7.1rc0__py2.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.
- metaflow/R.py +10 -7
- metaflow/__init__.py +40 -25
- metaflow/_vendor/imghdr/__init__.py +186 -0
- metaflow/_vendor/importlib_metadata/__init__.py +1063 -0
- metaflow/_vendor/importlib_metadata/_adapters.py +68 -0
- metaflow/_vendor/importlib_metadata/_collections.py +30 -0
- metaflow/_vendor/importlib_metadata/_compat.py +71 -0
- metaflow/_vendor/importlib_metadata/_functools.py +104 -0
- metaflow/_vendor/importlib_metadata/_itertools.py +73 -0
- metaflow/_vendor/importlib_metadata/_meta.py +48 -0
- metaflow/_vendor/importlib_metadata/_text.py +99 -0
- metaflow/_vendor/importlib_metadata/py.typed +0 -0
- metaflow/_vendor/typeguard/__init__.py +48 -0
- metaflow/_vendor/typeguard/_checkers.py +1070 -0
- metaflow/_vendor/typeguard/_config.py +108 -0
- metaflow/_vendor/typeguard/_decorators.py +233 -0
- metaflow/_vendor/typeguard/_exceptions.py +42 -0
- metaflow/_vendor/typeguard/_functions.py +308 -0
- metaflow/_vendor/typeguard/_importhook.py +213 -0
- metaflow/_vendor/typeguard/_memo.py +48 -0
- metaflow/_vendor/typeguard/_pytest_plugin.py +127 -0
- metaflow/_vendor/typeguard/_suppression.py +86 -0
- metaflow/_vendor/typeguard/_transformer.py +1229 -0
- metaflow/_vendor/typeguard/_union_transformer.py +55 -0
- metaflow/_vendor/typeguard/_utils.py +173 -0
- metaflow/_vendor/typeguard/py.typed +0 -0
- metaflow/_vendor/typing_extensions.py +3641 -0
- metaflow/_vendor/v3_7/importlib_metadata/__init__.py +1063 -0
- metaflow/_vendor/v3_7/importlib_metadata/_adapters.py +68 -0
- metaflow/_vendor/v3_7/importlib_metadata/_collections.py +30 -0
- metaflow/_vendor/v3_7/importlib_metadata/_compat.py +71 -0
- metaflow/_vendor/v3_7/importlib_metadata/_functools.py +104 -0
- metaflow/_vendor/v3_7/importlib_metadata/_itertools.py +73 -0
- metaflow/_vendor/v3_7/importlib_metadata/_meta.py +48 -0
- metaflow/_vendor/v3_7/importlib_metadata/_text.py +99 -0
- metaflow/_vendor/v3_7/importlib_metadata/py.typed +0 -0
- metaflow/_vendor/v3_7/typeguard/__init__.py +48 -0
- metaflow/_vendor/v3_7/typeguard/_checkers.py +906 -0
- metaflow/_vendor/v3_7/typeguard/_config.py +108 -0
- metaflow/_vendor/v3_7/typeguard/_decorators.py +237 -0
- metaflow/_vendor/v3_7/typeguard/_exceptions.py +42 -0
- metaflow/_vendor/v3_7/typeguard/_functions.py +310 -0
- metaflow/_vendor/v3_7/typeguard/_importhook.py +213 -0
- metaflow/_vendor/v3_7/typeguard/_memo.py +48 -0
- metaflow/_vendor/v3_7/typeguard/_pytest_plugin.py +100 -0
- metaflow/_vendor/v3_7/typeguard/_suppression.py +88 -0
- metaflow/_vendor/v3_7/typeguard/_transformer.py +1207 -0
- metaflow/_vendor/v3_7/typeguard/_union_transformer.py +54 -0
- metaflow/_vendor/v3_7/typeguard/_utils.py +169 -0
- metaflow/_vendor/v3_7/typeguard/py.typed +0 -0
- metaflow/_vendor/v3_7/typing_extensions.py +3072 -0
- metaflow/_vendor/yaml/__init__.py +427 -0
- metaflow/_vendor/yaml/composer.py +139 -0
- metaflow/_vendor/yaml/constructor.py +748 -0
- metaflow/_vendor/yaml/cyaml.py +101 -0
- metaflow/_vendor/yaml/dumper.py +62 -0
- metaflow/_vendor/yaml/emitter.py +1137 -0
- metaflow/_vendor/yaml/error.py +75 -0
- metaflow/_vendor/yaml/events.py +86 -0
- metaflow/_vendor/yaml/loader.py +63 -0
- metaflow/_vendor/yaml/nodes.py +49 -0
- metaflow/_vendor/yaml/parser.py +589 -0
- metaflow/_vendor/yaml/reader.py +185 -0
- metaflow/_vendor/yaml/representer.py +389 -0
- metaflow/_vendor/yaml/resolver.py +227 -0
- metaflow/_vendor/yaml/scanner.py +1435 -0
- metaflow/_vendor/yaml/serializer.py +111 -0
- metaflow/_vendor/yaml/tokens.py +104 -0
- metaflow/cards.py +5 -0
- metaflow/cli.py +331 -785
- metaflow/cli_args.py +17 -0
- metaflow/cli_components/__init__.py +0 -0
- metaflow/cli_components/dump_cmd.py +96 -0
- metaflow/cli_components/init_cmd.py +52 -0
- metaflow/cli_components/run_cmds.py +546 -0
- metaflow/cli_components/step_cmd.py +334 -0
- metaflow/cli_components/utils.py +140 -0
- metaflow/client/__init__.py +1 -0
- metaflow/client/core.py +467 -73
- metaflow/client/filecache.py +75 -35
- metaflow/clone_util.py +7 -1
- metaflow/cmd/code/__init__.py +231 -0
- metaflow/cmd/develop/stub_generator.py +756 -288
- metaflow/cmd/develop/stubs.py +12 -28
- metaflow/cmd/main_cli.py +6 -4
- metaflow/cmd/make_wrapper.py +78 -0
- metaflow/datastore/__init__.py +1 -0
- metaflow/datastore/content_addressed_store.py +41 -10
- metaflow/datastore/datastore_set.py +11 -2
- metaflow/datastore/flow_datastore.py +156 -10
- metaflow/datastore/spin_datastore.py +91 -0
- metaflow/datastore/task_datastore.py +154 -39
- metaflow/debug.py +5 -0
- metaflow/decorators.py +404 -78
- metaflow/exception.py +8 -2
- metaflow/extension_support/__init__.py +527 -376
- metaflow/extension_support/_empty_file.py +2 -2
- metaflow/extension_support/plugins.py +49 -31
- metaflow/flowspec.py +482 -33
- metaflow/graph.py +210 -42
- metaflow/includefile.py +84 -40
- metaflow/lint.py +141 -22
- metaflow/meta_files.py +13 -0
- metaflow/{metadata → metadata_provider}/heartbeat.py +24 -8
- metaflow/{metadata → metadata_provider}/metadata.py +86 -1
- metaflow/metaflow_config.py +175 -28
- metaflow/metaflow_config_funcs.py +51 -3
- metaflow/metaflow_current.py +4 -10
- metaflow/metaflow_environment.py +139 -53
- metaflow/metaflow_git.py +115 -0
- metaflow/metaflow_profile.py +18 -0
- metaflow/metaflow_version.py +150 -66
- metaflow/mflog/__init__.py +4 -3
- metaflow/mflog/save_logs.py +2 -2
- metaflow/multicore_utils.py +31 -14
- metaflow/package/__init__.py +673 -0
- metaflow/packaging_sys/__init__.py +880 -0
- metaflow/packaging_sys/backend.py +128 -0
- metaflow/packaging_sys/distribution_support.py +153 -0
- metaflow/packaging_sys/tar_backend.py +99 -0
- metaflow/packaging_sys/utils.py +54 -0
- metaflow/packaging_sys/v1.py +527 -0
- metaflow/parameters.py +149 -28
- metaflow/plugins/__init__.py +74 -5
- metaflow/plugins/airflow/airflow.py +40 -25
- metaflow/plugins/airflow/airflow_cli.py +22 -5
- metaflow/plugins/airflow/airflow_decorator.py +1 -1
- metaflow/plugins/airflow/airflow_utils.py +5 -3
- metaflow/plugins/airflow/sensors/base_sensor.py +4 -4
- metaflow/plugins/airflow/sensors/external_task_sensor.py +2 -2
- metaflow/plugins/airflow/sensors/s3_sensor.py +2 -2
- metaflow/plugins/argo/argo_client.py +78 -33
- metaflow/plugins/argo/argo_events.py +6 -6
- metaflow/plugins/argo/argo_workflows.py +2410 -527
- metaflow/plugins/argo/argo_workflows_cli.py +571 -121
- metaflow/plugins/argo/argo_workflows_decorator.py +43 -12
- metaflow/plugins/argo/argo_workflows_deployer.py +106 -0
- metaflow/plugins/argo/argo_workflows_deployer_objects.py +453 -0
- metaflow/plugins/argo/capture_error.py +73 -0
- metaflow/plugins/argo/conditional_input_paths.py +35 -0
- metaflow/plugins/argo/exit_hooks.py +209 -0
- metaflow/plugins/argo/jobset_input_paths.py +15 -0
- metaflow/plugins/argo/param_val.py +19 -0
- metaflow/plugins/aws/aws_client.py +10 -3
- metaflow/plugins/aws/aws_utils.py +55 -2
- metaflow/plugins/aws/batch/batch.py +72 -5
- metaflow/plugins/aws/batch/batch_cli.py +33 -10
- metaflow/plugins/aws/batch/batch_client.py +4 -3
- metaflow/plugins/aws/batch/batch_decorator.py +102 -35
- metaflow/plugins/aws/secrets_manager/aws_secrets_manager_secrets_provider.py +13 -10
- metaflow/plugins/aws/step_functions/dynamo_db_client.py +0 -3
- metaflow/plugins/aws/step_functions/production_token.py +1 -1
- metaflow/plugins/aws/step_functions/step_functions.py +65 -8
- metaflow/plugins/aws/step_functions/step_functions_cli.py +101 -7
- metaflow/plugins/aws/step_functions/step_functions_decorator.py +1 -2
- metaflow/plugins/aws/step_functions/step_functions_deployer.py +97 -0
- metaflow/plugins/aws/step_functions/step_functions_deployer_objects.py +264 -0
- metaflow/plugins/azure/azure_exceptions.py +1 -1
- metaflow/plugins/azure/azure_secret_manager_secrets_provider.py +240 -0
- metaflow/plugins/azure/azure_tail.py +1 -1
- metaflow/plugins/azure/includefile_support.py +2 -0
- metaflow/plugins/cards/card_cli.py +66 -30
- metaflow/plugins/cards/card_creator.py +25 -1
- metaflow/plugins/cards/card_datastore.py +21 -49
- metaflow/plugins/cards/card_decorator.py +132 -8
- metaflow/plugins/cards/card_modules/basic.py +112 -17
- metaflow/plugins/cards/card_modules/bundle.css +1 -1
- metaflow/plugins/cards/card_modules/card.py +16 -1
- metaflow/plugins/cards/card_modules/chevron/renderer.py +1 -1
- metaflow/plugins/cards/card_modules/components.py +665 -28
- metaflow/plugins/cards/card_modules/convert_to_native_type.py +36 -7
- metaflow/plugins/cards/card_modules/json_viewer.py +232 -0
- metaflow/plugins/cards/card_modules/main.css +1 -0
- metaflow/plugins/cards/card_modules/main.js +68 -49
- metaflow/plugins/cards/card_modules/renderer_tools.py +1 -0
- metaflow/plugins/cards/card_modules/test_cards.py +26 -12
- metaflow/plugins/cards/card_server.py +39 -14
- metaflow/plugins/cards/component_serializer.py +2 -9
- metaflow/plugins/cards/metadata.py +22 -0
- metaflow/plugins/catch_decorator.py +9 -0
- metaflow/plugins/datastores/azure_storage.py +10 -1
- metaflow/plugins/datastores/gs_storage.py +6 -2
- metaflow/plugins/datastores/local_storage.py +12 -6
- metaflow/plugins/datastores/spin_storage.py +12 -0
- metaflow/plugins/datatools/local.py +2 -0
- metaflow/plugins/datatools/s3/s3.py +126 -75
- metaflow/plugins/datatools/s3/s3op.py +254 -121
- metaflow/plugins/env_escape/__init__.py +3 -3
- metaflow/plugins/env_escape/client_modules.py +102 -72
- metaflow/plugins/env_escape/server.py +7 -0
- metaflow/plugins/env_escape/stub.py +24 -5
- metaflow/plugins/events_decorator.py +343 -185
- metaflow/plugins/exit_hook/__init__.py +0 -0
- metaflow/plugins/exit_hook/exit_hook_decorator.py +46 -0
- metaflow/plugins/exit_hook/exit_hook_script.py +52 -0
- metaflow/plugins/gcp/__init__.py +1 -1
- metaflow/plugins/gcp/gcp_secret_manager_secrets_provider.py +11 -6
- metaflow/plugins/gcp/gs_tail.py +10 -6
- metaflow/plugins/gcp/includefile_support.py +3 -0
- metaflow/plugins/kubernetes/kube_utils.py +108 -0
- metaflow/plugins/kubernetes/kubernetes.py +411 -130
- metaflow/plugins/kubernetes/kubernetes_cli.py +168 -36
- metaflow/plugins/kubernetes/kubernetes_client.py +104 -2
- metaflow/plugins/kubernetes/kubernetes_decorator.py +246 -88
- metaflow/plugins/kubernetes/kubernetes_job.py +253 -581
- metaflow/plugins/kubernetes/kubernetes_jobsets.py +1071 -0
- metaflow/plugins/kubernetes/spot_metadata_cli.py +69 -0
- metaflow/plugins/kubernetes/spot_monitor_sidecar.py +109 -0
- metaflow/plugins/logs_cli.py +359 -0
- metaflow/plugins/{metadata → metadata_providers}/local.py +144 -84
- metaflow/plugins/{metadata → metadata_providers}/service.py +103 -26
- metaflow/plugins/metadata_providers/spin.py +16 -0
- metaflow/plugins/package_cli.py +36 -24
- metaflow/plugins/parallel_decorator.py +128 -11
- metaflow/plugins/parsers.py +16 -0
- metaflow/plugins/project_decorator.py +51 -5
- metaflow/plugins/pypi/bootstrap.py +357 -105
- metaflow/plugins/pypi/conda_decorator.py +82 -81
- metaflow/plugins/pypi/conda_environment.py +187 -52
- metaflow/plugins/pypi/micromamba.py +157 -47
- metaflow/plugins/pypi/parsers.py +268 -0
- metaflow/plugins/pypi/pip.py +88 -13
- metaflow/plugins/pypi/pypi_decorator.py +37 -1
- metaflow/plugins/pypi/utils.py +48 -2
- metaflow/plugins/resources_decorator.py +2 -2
- metaflow/plugins/secrets/__init__.py +3 -0
- metaflow/plugins/secrets/secrets_decorator.py +26 -181
- metaflow/plugins/secrets/secrets_func.py +49 -0
- metaflow/plugins/secrets/secrets_spec.py +101 -0
- metaflow/plugins/secrets/utils.py +74 -0
- metaflow/plugins/tag_cli.py +4 -7
- metaflow/plugins/test_unbounded_foreach_decorator.py +41 -6
- metaflow/plugins/timeout_decorator.py +3 -3
- metaflow/plugins/uv/__init__.py +0 -0
- metaflow/plugins/uv/bootstrap.py +128 -0
- metaflow/plugins/uv/uv_environment.py +72 -0
- metaflow/procpoll.py +1 -1
- metaflow/pylint_wrapper.py +5 -1
- metaflow/runner/__init__.py +0 -0
- metaflow/runner/click_api.py +717 -0
- metaflow/runner/deployer.py +470 -0
- metaflow/runner/deployer_impl.py +201 -0
- metaflow/runner/metaflow_runner.py +714 -0
- metaflow/runner/nbdeploy.py +132 -0
- metaflow/runner/nbrun.py +225 -0
- metaflow/runner/subprocess_manager.py +650 -0
- metaflow/runner/utils.py +335 -0
- metaflow/runtime.py +1078 -260
- metaflow/sidecar/sidecar_worker.py +1 -1
- metaflow/system/__init__.py +5 -0
- metaflow/system/system_logger.py +85 -0
- metaflow/system/system_monitor.py +108 -0
- metaflow/system/system_utils.py +19 -0
- metaflow/task.py +521 -225
- metaflow/tracing/__init__.py +7 -7
- metaflow/tracing/span_exporter.py +31 -38
- metaflow/tracing/tracing_modules.py +38 -43
- metaflow/tuple_util.py +27 -0
- metaflow/user_configs/__init__.py +0 -0
- metaflow/user_configs/config_options.py +563 -0
- metaflow/user_configs/config_parameters.py +598 -0
- metaflow/user_decorators/__init__.py +0 -0
- metaflow/user_decorators/common.py +144 -0
- metaflow/user_decorators/mutable_flow.py +512 -0
- metaflow/user_decorators/mutable_step.py +424 -0
- metaflow/user_decorators/user_flow_decorator.py +264 -0
- metaflow/user_decorators/user_step_decorator.py +749 -0
- metaflow/util.py +243 -27
- metaflow/vendor.py +23 -7
- metaflow/version.py +1 -1
- ob_metaflow-2.19.7.1rc0.data/data/share/metaflow/devtools/Makefile +355 -0
- ob_metaflow-2.19.7.1rc0.data/data/share/metaflow/devtools/Tiltfile +726 -0
- ob_metaflow-2.19.7.1rc0.data/data/share/metaflow/devtools/pick_services.sh +105 -0
- ob_metaflow-2.19.7.1rc0.dist-info/METADATA +87 -0
- ob_metaflow-2.19.7.1rc0.dist-info/RECORD +445 -0
- {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/WHEEL +1 -1
- {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/entry_points.txt +1 -0
- metaflow/_vendor/v3_5/__init__.py +0 -1
- metaflow/_vendor/v3_5/importlib_metadata/__init__.py +0 -644
- metaflow/_vendor/v3_5/importlib_metadata/_compat.py +0 -152
- metaflow/package.py +0 -188
- ob_metaflow-2.11.13.1.dist-info/METADATA +0 -85
- ob_metaflow-2.11.13.1.dist-info/RECORD +0 -308
- /metaflow/_vendor/{v3_5/zipp.py → zipp.py} +0 -0
- /metaflow/{metadata → metadata_provider}/__init__.py +0 -0
- /metaflow/{metadata → metadata_provider}/util.py +0 -0
- /metaflow/plugins/{metadata → metadata_providers}/__init__.py +0 -0
- {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info/licenses}/LICENSE +0 -0
- {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import inspect
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
from typing import Dict, Iterator, Optional, Tuple
|
|
8
|
+
|
|
9
|
+
from metaflow import Run, Task
|
|
10
|
+
|
|
11
|
+
from metaflow.metaflow_config import CLICK_API_PROCESS_CONFIG
|
|
12
|
+
|
|
13
|
+
from metaflow.plugins import get_runner_cli
|
|
14
|
+
|
|
15
|
+
from .utils import (
|
|
16
|
+
temporary_fifo,
|
|
17
|
+
handle_timeout,
|
|
18
|
+
async_handle_timeout,
|
|
19
|
+
with_dir,
|
|
20
|
+
)
|
|
21
|
+
from .subprocess_manager import CommandManager, SubprocessManager
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ExecutingProcess(object):
|
|
25
|
+
"""
|
|
26
|
+
This is a base class for `ExecutingRun` and `ExecutingTask` classes.
|
|
27
|
+
The `ExecutingRun` and `ExecutingTask` classes are returned by methods
|
|
28
|
+
in `Runner` and `NBRunner`, and they are subclasses of this class.
|
|
29
|
+
|
|
30
|
+
The `ExecutingRun` class for instance contains a reference to a `metaflow.Run`
|
|
31
|
+
object representing the currently executing or finished run, as well as the metadata
|
|
32
|
+
related to the process.
|
|
33
|
+
|
|
34
|
+
Similarly, the `ExecutingTask` class contains a reference to a `metaflow.Task`
|
|
35
|
+
object representing the currently executing or finished task, as well as the metadata
|
|
36
|
+
related to the process.
|
|
37
|
+
|
|
38
|
+
This class or its subclasses are not meant to be instantiated directly. The class
|
|
39
|
+
works as a context manager, allowing you to use a pattern like:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
with Runner(...).run() as running:
|
|
43
|
+
...
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Note that you should use either this object as the context manager or `Runner`, not both
|
|
47
|
+
in a nested manner.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(self, runner: "Runner", command_obj: CommandManager) -> None:
|
|
51
|
+
"""
|
|
52
|
+
Create a new ExecutingRun -- this should not be done by the user directly but
|
|
53
|
+
instead use Runner.run()
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
runner : Runner
|
|
58
|
+
Parent runner for this run.
|
|
59
|
+
command_obj : CommandManager
|
|
60
|
+
CommandManager containing the subprocess executing this run.
|
|
61
|
+
run_obj : Run
|
|
62
|
+
Run object corresponding to this run.
|
|
63
|
+
"""
|
|
64
|
+
self.runner = runner
|
|
65
|
+
self.command_obj = command_obj
|
|
66
|
+
|
|
67
|
+
def __enter__(self) -> "ExecutingProcess":
|
|
68
|
+
return self
|
|
69
|
+
|
|
70
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
71
|
+
self.runner.__exit__(exc_type, exc_value, traceback)
|
|
72
|
+
|
|
73
|
+
async def wait(
|
|
74
|
+
self, timeout: Optional[float] = None, stream: Optional[str] = None
|
|
75
|
+
) -> "ExecutingProcess":
|
|
76
|
+
"""
|
|
77
|
+
Wait for this run to finish, optionally with a timeout
|
|
78
|
+
and optionally streaming its output.
|
|
79
|
+
|
|
80
|
+
Note that this method is asynchronous and needs to be `await`ed.
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
timeout : float, optional, default None
|
|
85
|
+
The maximum time, in seconds, to wait for the run to finish.
|
|
86
|
+
If the timeout is reached, the run is terminated. If not specified, wait
|
|
87
|
+
forever.
|
|
88
|
+
stream : str, optional, default None
|
|
89
|
+
If specified, the specified stream is printed to stdout. `stream` can
|
|
90
|
+
be one of `stdout` or `stderr`.
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
ExecutingProcess
|
|
95
|
+
This object, allowing you to chain calls.
|
|
96
|
+
"""
|
|
97
|
+
await self.command_obj.wait(timeout, stream)
|
|
98
|
+
return self
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def returncode(self) -> Optional[int]:
|
|
102
|
+
"""
|
|
103
|
+
Gets the return code of the underlying subprocess. A non-zero
|
|
104
|
+
code indicates a failure, `None` a currently executing run.
|
|
105
|
+
|
|
106
|
+
Returns
|
|
107
|
+
-------
|
|
108
|
+
Optional[int]
|
|
109
|
+
The return code of the underlying subprocess.
|
|
110
|
+
"""
|
|
111
|
+
return self.command_obj.process.returncode
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def status(self) -> str:
|
|
115
|
+
"""
|
|
116
|
+
Returns the status of the underlying subprocess that is responsible
|
|
117
|
+
for executing the run.
|
|
118
|
+
|
|
119
|
+
The return value is one of the following strings:
|
|
120
|
+
- `timeout` indicates that the run timed out.
|
|
121
|
+
- `running` indicates a currently executing run.
|
|
122
|
+
- `failed` indicates a failed run.
|
|
123
|
+
- `successful` indicates a successful run.
|
|
124
|
+
|
|
125
|
+
Returns
|
|
126
|
+
-------
|
|
127
|
+
str
|
|
128
|
+
The current status of the run.
|
|
129
|
+
"""
|
|
130
|
+
if self.command_obj.timeout:
|
|
131
|
+
return "timeout"
|
|
132
|
+
elif self.command_obj.process.returncode is None:
|
|
133
|
+
return "running"
|
|
134
|
+
elif self.command_obj.process.returncode != 0:
|
|
135
|
+
return "failed"
|
|
136
|
+
else:
|
|
137
|
+
return "successful"
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def stdout(self) -> str:
|
|
141
|
+
"""
|
|
142
|
+
Returns the current stdout of the run. If the run is finished, this will
|
|
143
|
+
contain the entire stdout output. Otherwise, it will contain the
|
|
144
|
+
stdout up until this point.
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
str
|
|
149
|
+
The current snapshot of stdout.
|
|
150
|
+
"""
|
|
151
|
+
with open(
|
|
152
|
+
self.command_obj.log_files.get("stdout"), "r", encoding="utf-8"
|
|
153
|
+
) as fp:
|
|
154
|
+
return fp.read()
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def stderr(self) -> str:
|
|
158
|
+
"""
|
|
159
|
+
Returns the current stderr of the run. If the run is finished, this will
|
|
160
|
+
contain the entire stderr output. Otherwise, it will contain the
|
|
161
|
+
stderr up until this point.
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
str
|
|
166
|
+
The current snapshot of stderr.
|
|
167
|
+
"""
|
|
168
|
+
with open(
|
|
169
|
+
self.command_obj.log_files.get("stderr"), "r", encoding="utf-8"
|
|
170
|
+
) as fp:
|
|
171
|
+
return fp.read()
|
|
172
|
+
|
|
173
|
+
async def stream_log(
|
|
174
|
+
self, stream: str, position: Optional[int] = None
|
|
175
|
+
) -> Iterator[Tuple[int, str]]:
|
|
176
|
+
"""
|
|
177
|
+
Asynchronous iterator to stream logs from the subprocess line by line.
|
|
178
|
+
|
|
179
|
+
Note that this method is asynchronous and needs to be `await`ed.
|
|
180
|
+
|
|
181
|
+
Parameters
|
|
182
|
+
----------
|
|
183
|
+
stream : str
|
|
184
|
+
The stream to stream logs from. Can be one of `stdout` or `stderr`.
|
|
185
|
+
position : int, optional, default None
|
|
186
|
+
The position in the log file to start streaming from. If None, it starts
|
|
187
|
+
from the beginning of the log file. This allows resuming streaming from
|
|
188
|
+
a previously known position
|
|
189
|
+
|
|
190
|
+
Yields
|
|
191
|
+
------
|
|
192
|
+
Tuple[int, str]
|
|
193
|
+
A tuple containing the position in the log file and the line read. The
|
|
194
|
+
position returned can be used to feed into another `stream_logs` call
|
|
195
|
+
for example.
|
|
196
|
+
"""
|
|
197
|
+
async for position, line in self.command_obj.stream_log(stream, position):
|
|
198
|
+
yield position, line
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class ExecutingTask(ExecutingProcess):
|
|
202
|
+
"""
|
|
203
|
+
This class contains a reference to a `metaflow.Task` object representing
|
|
204
|
+
the currently executing or finished task, as well as metadata related
|
|
205
|
+
to the process.
|
|
206
|
+
`ExecutingTask` is returned by methods in `Runner` and `NBRunner`. It is not
|
|
207
|
+
meant to be instantiated directly.
|
|
208
|
+
This class works as a context manager, allowing you to use a pattern like
|
|
209
|
+
```python
|
|
210
|
+
with Runner(...).spin() as running:
|
|
211
|
+
...
|
|
212
|
+
```
|
|
213
|
+
Note that you should use either this object as the context manager or
|
|
214
|
+
`Runner`, not both in a nested manner.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
def __init__(
|
|
218
|
+
self, runner: "Runner", command_obj: CommandManager, task_obj: Task
|
|
219
|
+
) -> None:
|
|
220
|
+
"""
|
|
221
|
+
Create a new ExecutingTask -- this should not be done by the user directly but
|
|
222
|
+
instead use Runner.spin()
|
|
223
|
+
Parameters
|
|
224
|
+
----------
|
|
225
|
+
runner : Runner
|
|
226
|
+
Parent runner for this task.
|
|
227
|
+
command_obj : CommandManager
|
|
228
|
+
CommandManager containing the subprocess executing this task.
|
|
229
|
+
task_obj : Task
|
|
230
|
+
Task object corresponding to this task.
|
|
231
|
+
"""
|
|
232
|
+
super().__init__(runner, command_obj)
|
|
233
|
+
self.task = task_obj
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class ExecutingRun(ExecutingProcess):
|
|
237
|
+
"""
|
|
238
|
+
This class contains a reference to a `metaflow.Run` object representing
|
|
239
|
+
the currently executing or finished run, as well as metadata related
|
|
240
|
+
to the process.
|
|
241
|
+
`ExecutingRun` is returned by methods in `Runner` and `NBRunner`. It is not
|
|
242
|
+
meant to be instantiated directly.
|
|
243
|
+
This class works as a context manager, allowing you to use a pattern like
|
|
244
|
+
```python
|
|
245
|
+
with Runner(...).run() as running:
|
|
246
|
+
...
|
|
247
|
+
```
|
|
248
|
+
Note that you should use either this object as the context manager or
|
|
249
|
+
`Runner`, not both in a nested manner.
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
def __init__(
|
|
253
|
+
self, runner: "Runner", command_obj: CommandManager, run_obj: Run
|
|
254
|
+
) -> None:
|
|
255
|
+
"""
|
|
256
|
+
Create a new ExecutingRun -- this should not be done by the user directly but
|
|
257
|
+
instead use Runner.run()
|
|
258
|
+
Parameters
|
|
259
|
+
----------
|
|
260
|
+
runner : Runner
|
|
261
|
+
Parent runner for this run.
|
|
262
|
+
command_obj : CommandManager
|
|
263
|
+
CommandManager containing the subprocess executing this run.
|
|
264
|
+
run_obj : Run
|
|
265
|
+
Run object corresponding to this run.
|
|
266
|
+
"""
|
|
267
|
+
super().__init__(runner, command_obj)
|
|
268
|
+
self.run = run_obj
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class RunnerMeta(type):
|
|
272
|
+
def __new__(mcs, name, bases, dct):
|
|
273
|
+
cls = super().__new__(mcs, name, bases, dct)
|
|
274
|
+
|
|
275
|
+
def _injected_method(subcommand_name, runner_subcommand):
|
|
276
|
+
def f(self, *args, **kwargs):
|
|
277
|
+
return runner_subcommand(self, *args, **kwargs)
|
|
278
|
+
|
|
279
|
+
f.__doc__ = runner_subcommand.__init__.__doc__ or ""
|
|
280
|
+
f.__name__ = subcommand_name
|
|
281
|
+
sig = inspect.signature(runner_subcommand)
|
|
282
|
+
# We take all the same parameters except replace the first with
|
|
283
|
+
# simple "self"
|
|
284
|
+
new_parameters = {}
|
|
285
|
+
for name, param in sig.parameters.items():
|
|
286
|
+
if new_parameters:
|
|
287
|
+
new_parameters[name] = param
|
|
288
|
+
else:
|
|
289
|
+
new_parameters["self"] = inspect.Parameter(
|
|
290
|
+
"self", inspect.Parameter.POSITIONAL_OR_KEYWORD
|
|
291
|
+
)
|
|
292
|
+
f.__signature__ = inspect.Signature(
|
|
293
|
+
list(new_parameters.values()), return_annotation=runner_subcommand
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
return f
|
|
297
|
+
|
|
298
|
+
for runner_subcommand in get_runner_cli():
|
|
299
|
+
method_name = runner_subcommand.name.replace("-", "_")
|
|
300
|
+
setattr(cls, method_name, _injected_method(method_name, runner_subcommand))
|
|
301
|
+
|
|
302
|
+
return cls
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class Runner(metaclass=RunnerMeta):
|
|
306
|
+
"""
|
|
307
|
+
Metaflow's Runner API that presents a programmatic interface
|
|
308
|
+
to run flows and perform other operations either synchronously or asynchronously.
|
|
309
|
+
The class expects a path to the flow file along with optional arguments
|
|
310
|
+
that match top-level options on the command-line.
|
|
311
|
+
|
|
312
|
+
This class works as a context manager, calling `cleanup()` to remove
|
|
313
|
+
temporary files at exit.
|
|
314
|
+
|
|
315
|
+
Example:
|
|
316
|
+
```python
|
|
317
|
+
with Runner('slowflow.py', pylint=False) as runner:
|
|
318
|
+
result = runner.run(alpha=5, tags=["abc", "def"], max_workers=5)
|
|
319
|
+
print(result.run.finished)
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Parameters
|
|
323
|
+
----------
|
|
324
|
+
flow_file : str
|
|
325
|
+
Path to the flow file to run, relative to current directory.
|
|
326
|
+
show_output : bool, default True
|
|
327
|
+
Show the 'stdout' and 'stderr' to the console by default,
|
|
328
|
+
Only applicable for synchronous 'run' and 'resume' functions.
|
|
329
|
+
profile : str, optional, default None
|
|
330
|
+
Metaflow profile to use to run this run. If not specified, the default
|
|
331
|
+
profile is used (or the one already set using `METAFLOW_PROFILE`)
|
|
332
|
+
env : Dict[str, str], optional, default None
|
|
333
|
+
Additional environment variables to set for the Run. This overrides the
|
|
334
|
+
environment set for this process.
|
|
335
|
+
cwd : str, optional, default None
|
|
336
|
+
The directory to run the subprocess in; if not specified, the current
|
|
337
|
+
directory is used.
|
|
338
|
+
file_read_timeout : int, default 3600
|
|
339
|
+
The timeout until which we try to read the runner attribute file (in seconds).
|
|
340
|
+
**kwargs : Any
|
|
341
|
+
Additional arguments that you would pass to `python myflow.py` before
|
|
342
|
+
the `run` command.
|
|
343
|
+
"""
|
|
344
|
+
|
|
345
|
+
def __init__(
|
|
346
|
+
self,
|
|
347
|
+
flow_file: str,
|
|
348
|
+
show_output: bool = True,
|
|
349
|
+
profile: Optional[str] = None,
|
|
350
|
+
env: Optional[Dict[str, str]] = None,
|
|
351
|
+
cwd: Optional[str] = None,
|
|
352
|
+
file_read_timeout: int = 3600,
|
|
353
|
+
**kwargs,
|
|
354
|
+
):
|
|
355
|
+
# these imports are required here and not at the top
|
|
356
|
+
# since they interfere with the user defined Parameters
|
|
357
|
+
# in the flow file, this is related to the ability of
|
|
358
|
+
# importing 'Runner' directly i.e.
|
|
359
|
+
# from metaflow import Runner
|
|
360
|
+
# This ability is made possible by the statement:
|
|
361
|
+
# 'from .metaflow_runner import Runner' in '__init__.py'
|
|
362
|
+
|
|
363
|
+
from metaflow.parameters import flow_context
|
|
364
|
+
|
|
365
|
+
# Reload the CLI with an "empty" flow -- this will remove any configuration
|
|
366
|
+
# and parameter options. They are re-added in from_cli (called below).
|
|
367
|
+
to_reload = [
|
|
368
|
+
"metaflow.cli",
|
|
369
|
+
"metaflow.cli_components.run_cmds",
|
|
370
|
+
"metaflow.cli_components.init_cmd",
|
|
371
|
+
]
|
|
372
|
+
with flow_context(None):
|
|
373
|
+
[
|
|
374
|
+
importlib.reload(sys.modules[module])
|
|
375
|
+
for module in to_reload
|
|
376
|
+
if module in sys.modules
|
|
377
|
+
]
|
|
378
|
+
|
|
379
|
+
from metaflow.cli import start
|
|
380
|
+
from metaflow.runner.click_api import MetaflowAPI
|
|
381
|
+
|
|
382
|
+
# Convert flow_file to absolute path if it's relative
|
|
383
|
+
if not os.path.isabs(flow_file):
|
|
384
|
+
self.flow_file = os.path.abspath(flow_file)
|
|
385
|
+
else:
|
|
386
|
+
self.flow_file = flow_file
|
|
387
|
+
|
|
388
|
+
self.show_output = show_output
|
|
389
|
+
|
|
390
|
+
self.env_vars = os.environ.copy()
|
|
391
|
+
self.env_vars.update(env or {})
|
|
392
|
+
if profile:
|
|
393
|
+
self.env_vars["METAFLOW_PROFILE"] = profile
|
|
394
|
+
|
|
395
|
+
self.cwd = cwd or os.getcwd()
|
|
396
|
+
self.file_read_timeout = file_read_timeout
|
|
397
|
+
self.spm = SubprocessManager()
|
|
398
|
+
self.top_level_kwargs = kwargs
|
|
399
|
+
self.api = MetaflowAPI.from_cli(self.flow_file, start)
|
|
400
|
+
|
|
401
|
+
def __enter__(self) -> "Runner":
|
|
402
|
+
return self
|
|
403
|
+
|
|
404
|
+
async def __aenter__(self) -> "Runner":
|
|
405
|
+
return self
|
|
406
|
+
|
|
407
|
+
def __get_executing_run(self, attribute_file_fd, command_obj):
|
|
408
|
+
content = handle_timeout(attribute_file_fd, command_obj, self.file_read_timeout)
|
|
409
|
+
|
|
410
|
+
command_obj.sync_wait()
|
|
411
|
+
|
|
412
|
+
content = json.loads(content)
|
|
413
|
+
pathspec = "%s/%s" % (content.get("flow_name"), content.get("run_id"))
|
|
414
|
+
|
|
415
|
+
# Set the correct metadata from the runner_attribute file corresponding to this run.
|
|
416
|
+
metadata_for_flow = content.get("metadata")
|
|
417
|
+
|
|
418
|
+
run_object = Run(
|
|
419
|
+
pathspec, _namespace_check=False, _current_metadata=metadata_for_flow
|
|
420
|
+
)
|
|
421
|
+
return ExecutingRun(self, command_obj, run_object)
|
|
422
|
+
|
|
423
|
+
async def __async_get_executing_run(self, attribute_file_fd, command_obj):
|
|
424
|
+
content = await async_handle_timeout(
|
|
425
|
+
attribute_file_fd, command_obj, self.file_read_timeout
|
|
426
|
+
)
|
|
427
|
+
content = json.loads(content)
|
|
428
|
+
pathspec = "%s/%s" % (content.get("flow_name"), content.get("run_id"))
|
|
429
|
+
|
|
430
|
+
# Set the correct metadata from the runner_attribute file corresponding to this run.
|
|
431
|
+
metadata_for_flow = content.get("metadata")
|
|
432
|
+
|
|
433
|
+
run_object = Run(
|
|
434
|
+
pathspec, _namespace_check=False, _current_metadata=metadata_for_flow
|
|
435
|
+
)
|
|
436
|
+
return ExecutingRun(self, command_obj, run_object)
|
|
437
|
+
|
|
438
|
+
def run(self, **kwargs) -> ExecutingRun:
|
|
439
|
+
"""
|
|
440
|
+
Blocking execution of the run. This method will wait until
|
|
441
|
+
the run has completed execution.
|
|
442
|
+
|
|
443
|
+
Parameters
|
|
444
|
+
----------
|
|
445
|
+
**kwargs : Any
|
|
446
|
+
Additional arguments that you would pass to `python myflow.py` after
|
|
447
|
+
the `run` command, in particular, any parameters accepted by the flow.
|
|
448
|
+
|
|
449
|
+
Returns
|
|
450
|
+
-------
|
|
451
|
+
ExecutingRun
|
|
452
|
+
ExecutingRun containing the results of the run.
|
|
453
|
+
"""
|
|
454
|
+
with temporary_fifo() as (attribute_file_path, attribute_file_fd):
|
|
455
|
+
if CLICK_API_PROCESS_CONFIG:
|
|
456
|
+
with with_dir(self.cwd):
|
|
457
|
+
command = self.api(**self.top_level_kwargs).run(
|
|
458
|
+
runner_attribute_file=attribute_file_path, **kwargs
|
|
459
|
+
)
|
|
460
|
+
else:
|
|
461
|
+
command = self.api(**self.top_level_kwargs).run(
|
|
462
|
+
runner_attribute_file=attribute_file_path, **kwargs
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
pid = self.spm.run_command(
|
|
466
|
+
[sys.executable, *command],
|
|
467
|
+
env=self.env_vars,
|
|
468
|
+
cwd=self.cwd,
|
|
469
|
+
show_output=self.show_output,
|
|
470
|
+
)
|
|
471
|
+
command_obj = self.spm.get(pid)
|
|
472
|
+
|
|
473
|
+
return self.__get_executing_run(attribute_file_fd, command_obj)
|
|
474
|
+
|
|
475
|
+
def __get_executing_task(self, attribute_file_fd, command_obj):
|
|
476
|
+
content = handle_timeout(attribute_file_fd, command_obj, self.file_read_timeout)
|
|
477
|
+
|
|
478
|
+
command_obj.sync_wait()
|
|
479
|
+
|
|
480
|
+
content = json.loads(content)
|
|
481
|
+
pathspec = f"{content.get('flow_name')}/{content.get('run_id')}/{content.get('step_name')}/{content.get('task_id')}"
|
|
482
|
+
|
|
483
|
+
# Set the correct metadata from the runner_attribute file corresponding to this run.
|
|
484
|
+
metadata_for_flow = content.get("metadata")
|
|
485
|
+
|
|
486
|
+
task_object = Task(
|
|
487
|
+
pathspec, _namespace_check=False, _current_metadata=metadata_for_flow
|
|
488
|
+
)
|
|
489
|
+
return ExecutingTask(self, command_obj, task_object)
|
|
490
|
+
|
|
491
|
+
async def __async_get_executing_task(self, attribute_file_fd, command_obj):
|
|
492
|
+
content = await async_handle_timeout(
|
|
493
|
+
attribute_file_fd, command_obj, self.file_read_timeout
|
|
494
|
+
)
|
|
495
|
+
content = json.loads(content)
|
|
496
|
+
pathspec = f"{content.get('flow_name')}/{content.get('run_id')}/{content.get('step_name')}/{content.get('task_id')}"
|
|
497
|
+
|
|
498
|
+
# Set the correct metadata from the runner_attribute file corresponding to this run.
|
|
499
|
+
metadata_for_flow = content.get("metadata")
|
|
500
|
+
|
|
501
|
+
task_object = Task(
|
|
502
|
+
pathspec, _namespace_check=False, _current_metadata=metadata_for_flow
|
|
503
|
+
)
|
|
504
|
+
return ExecutingTask(self, command_obj, task_object)
|
|
505
|
+
|
|
506
|
+
def spin(self, pathspec, **kwargs) -> ExecutingTask:
|
|
507
|
+
"""
|
|
508
|
+
Blocking spin execution of the run.
|
|
509
|
+
This method will wait until the spun run has completed execution.
|
|
510
|
+
Parameters
|
|
511
|
+
----------
|
|
512
|
+
pathspec : str
|
|
513
|
+
The pathspec of the step/task to spin.
|
|
514
|
+
**kwargs : Any
|
|
515
|
+
Additional arguments that you would pass to `python ./myflow.py` after
|
|
516
|
+
the `spin` command.
|
|
517
|
+
Returns
|
|
518
|
+
-------
|
|
519
|
+
ExecutingTask
|
|
520
|
+
ExecutingTask containing the results of the spun task.
|
|
521
|
+
"""
|
|
522
|
+
with temporary_fifo() as (attribute_file_path, attribute_file_fd):
|
|
523
|
+
if CLICK_API_PROCESS_CONFIG:
|
|
524
|
+
with with_dir(self.cwd):
|
|
525
|
+
command = self.api(**self.top_level_kwargs).spin(
|
|
526
|
+
pathspec=pathspec,
|
|
527
|
+
runner_attribute_file=attribute_file_path,
|
|
528
|
+
**kwargs,
|
|
529
|
+
)
|
|
530
|
+
else:
|
|
531
|
+
command = self.api(**self.top_level_kwargs).spin(
|
|
532
|
+
pathspec=pathspec,
|
|
533
|
+
runner_attribute_file=attribute_file_path,
|
|
534
|
+
**kwargs,
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
pid = self.spm.run_command(
|
|
538
|
+
[sys.executable, *command],
|
|
539
|
+
env=self.env_vars,
|
|
540
|
+
cwd=self.cwd,
|
|
541
|
+
show_output=self.show_output,
|
|
542
|
+
)
|
|
543
|
+
command_obj = self.spm.get(pid)
|
|
544
|
+
|
|
545
|
+
return self.__get_executing_task(attribute_file_fd, command_obj)
|
|
546
|
+
|
|
547
|
+
def resume(self, **kwargs) -> ExecutingRun:
|
|
548
|
+
"""
|
|
549
|
+
Blocking resume execution of the run.
|
|
550
|
+
This method will wait until the resumed run has completed execution.
|
|
551
|
+
|
|
552
|
+
Parameters
|
|
553
|
+
----------
|
|
554
|
+
**kwargs : Any
|
|
555
|
+
Additional arguments that you would pass to `python ./myflow.py` after
|
|
556
|
+
the `resume` command.
|
|
557
|
+
|
|
558
|
+
Returns
|
|
559
|
+
-------
|
|
560
|
+
ExecutingRun
|
|
561
|
+
ExecutingRun containing the results of the resumed run.
|
|
562
|
+
"""
|
|
563
|
+
with temporary_fifo() as (attribute_file_path, attribute_file_fd):
|
|
564
|
+
if CLICK_API_PROCESS_CONFIG:
|
|
565
|
+
with with_dir(self.cwd):
|
|
566
|
+
command = self.api(**self.top_level_kwargs).resume(
|
|
567
|
+
runner_attribute_file=attribute_file_path, **kwargs
|
|
568
|
+
)
|
|
569
|
+
else:
|
|
570
|
+
command = self.api(**self.top_level_kwargs).resume(
|
|
571
|
+
runner_attribute_file=attribute_file_path, **kwargs
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
pid = self.spm.run_command(
|
|
575
|
+
[sys.executable, *command],
|
|
576
|
+
env=self.env_vars,
|
|
577
|
+
cwd=self.cwd,
|
|
578
|
+
show_output=self.show_output,
|
|
579
|
+
)
|
|
580
|
+
command_obj = self.spm.get(pid)
|
|
581
|
+
|
|
582
|
+
return self.__get_executing_run(attribute_file_fd, command_obj)
|
|
583
|
+
|
|
584
|
+
async def async_run(self, **kwargs) -> ExecutingRun:
|
|
585
|
+
"""
|
|
586
|
+
Non-blocking execution of the run. This method will return as soon as the
|
|
587
|
+
run has launched.
|
|
588
|
+
|
|
589
|
+
Note that this method is asynchronous and needs to be `await`ed.
|
|
590
|
+
|
|
591
|
+
Parameters
|
|
592
|
+
----------
|
|
593
|
+
**kwargs : Any
|
|
594
|
+
Additional arguments that you would pass to `python myflow.py` after
|
|
595
|
+
the `run` command, in particular, any parameters accepted by the flow.
|
|
596
|
+
|
|
597
|
+
Returns
|
|
598
|
+
-------
|
|
599
|
+
ExecutingRun
|
|
600
|
+
ExecutingRun representing the run that was started.
|
|
601
|
+
"""
|
|
602
|
+
with temporary_fifo() as (attribute_file_path, attribute_file_fd):
|
|
603
|
+
if CLICK_API_PROCESS_CONFIG:
|
|
604
|
+
with with_dir(self.cwd):
|
|
605
|
+
command = self.api(**self.top_level_kwargs).run(
|
|
606
|
+
runner_attribute_file=attribute_file_path, **kwargs
|
|
607
|
+
)
|
|
608
|
+
else:
|
|
609
|
+
command = self.api(**self.top_level_kwargs).run(
|
|
610
|
+
runner_attribute_file=attribute_file_path, **kwargs
|
|
611
|
+
)
|
|
612
|
+
|
|
613
|
+
pid = await self.spm.async_run_command(
|
|
614
|
+
[sys.executable, *command],
|
|
615
|
+
env=self.env_vars,
|
|
616
|
+
cwd=self.cwd,
|
|
617
|
+
)
|
|
618
|
+
command_obj = self.spm.get(pid)
|
|
619
|
+
|
|
620
|
+
return await self.__async_get_executing_run(attribute_file_fd, command_obj)
|
|
621
|
+
|
|
622
|
+
async def async_resume(self, **kwargs) -> ExecutingRun:
|
|
623
|
+
"""
|
|
624
|
+
Non-blocking resume execution of the run.
|
|
625
|
+
This method will return as soon as the resume has launched.
|
|
626
|
+
|
|
627
|
+
Note that this method is asynchronous and needs to be `await`ed.
|
|
628
|
+
|
|
629
|
+
Parameters
|
|
630
|
+
----------
|
|
631
|
+
**kwargs : Any
|
|
632
|
+
Additional arguments that you would pass to `python myflow.py` after
|
|
633
|
+
the `resume` command.
|
|
634
|
+
|
|
635
|
+
Returns
|
|
636
|
+
-------
|
|
637
|
+
ExecutingRun
|
|
638
|
+
ExecutingRun representing the resumed run that was started.
|
|
639
|
+
"""
|
|
640
|
+
with temporary_fifo() as (attribute_file_path, attribute_file_fd):
|
|
641
|
+
if CLICK_API_PROCESS_CONFIG:
|
|
642
|
+
with with_dir(self.cwd):
|
|
643
|
+
command = self.api(**self.top_level_kwargs).resume(
|
|
644
|
+
runner_attribute_file=attribute_file_path, **kwargs
|
|
645
|
+
)
|
|
646
|
+
else:
|
|
647
|
+
command = self.api(**self.top_level_kwargs).resume(
|
|
648
|
+
runner_attribute_file=attribute_file_path, **kwargs
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
pid = await self.spm.async_run_command(
|
|
652
|
+
[sys.executable, *command],
|
|
653
|
+
env=self.env_vars,
|
|
654
|
+
cwd=self.cwd,
|
|
655
|
+
)
|
|
656
|
+
command_obj = self.spm.get(pid)
|
|
657
|
+
|
|
658
|
+
return await self.__async_get_executing_run(attribute_file_fd, command_obj)
|
|
659
|
+
|
|
660
|
+
async def async_spin(self, pathspec, **kwargs) -> ExecutingTask:
|
|
661
|
+
"""
|
|
662
|
+
Non-blocking spin execution of the run.
|
|
663
|
+
This method will return as soon as the spun task has launched.
|
|
664
|
+
|
|
665
|
+
Note that this method is asynchronous and needs to be `await`ed.
|
|
666
|
+
|
|
667
|
+
Parameters
|
|
668
|
+
----------
|
|
669
|
+
pathspec : str
|
|
670
|
+
The pathspec of the step/task to spin.
|
|
671
|
+
**kwargs : Any
|
|
672
|
+
Additional arguments that you would pass to `python ./myflow.py` after
|
|
673
|
+
the `spin` command.
|
|
674
|
+
|
|
675
|
+
Returns
|
|
676
|
+
-------
|
|
677
|
+
ExecutingTask
|
|
678
|
+
ExecutingTask representing the spun task that was started.
|
|
679
|
+
"""
|
|
680
|
+
with temporary_fifo() as (attribute_file_path, attribute_file_fd):
|
|
681
|
+
if CLICK_API_PROCESS_CONFIG:
|
|
682
|
+
with with_dir(self.cwd):
|
|
683
|
+
command = self.api(**self.top_level_kwargs).spin(
|
|
684
|
+
pathspec=pathspec,
|
|
685
|
+
runner_attribute_file=attribute_file_path,
|
|
686
|
+
**kwargs,
|
|
687
|
+
)
|
|
688
|
+
else:
|
|
689
|
+
command = self.api(**self.top_level_kwargs).spin(
|
|
690
|
+
pathspec=pathspec,
|
|
691
|
+
runner_attribute_file=attribute_file_path,
|
|
692
|
+
**kwargs,
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
pid = await self.spm.async_run_command(
|
|
696
|
+
[sys.executable, *command],
|
|
697
|
+
env=self.env_vars,
|
|
698
|
+
cwd=self.cwd,
|
|
699
|
+
)
|
|
700
|
+
command_obj = self.spm.get(pid)
|
|
701
|
+
|
|
702
|
+
return await self.__async_get_executing_task(attribute_file_fd, command_obj)
|
|
703
|
+
|
|
704
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
705
|
+
self.spm.cleanup()
|
|
706
|
+
|
|
707
|
+
async def __aexit__(self, exc_type, exc_value, traceback):
|
|
708
|
+
self.spm.cleanup()
|
|
709
|
+
|
|
710
|
+
def cleanup(self):
|
|
711
|
+
"""
|
|
712
|
+
Delete any temporary files created during execution.
|
|
713
|
+
"""
|
|
714
|
+
self.spm.cleanup()
|