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
metaflow/runner/utils.py
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import ast
|
|
3
|
+
import time
|
|
4
|
+
import asyncio
|
|
5
|
+
import tempfile
|
|
6
|
+
import select
|
|
7
|
+
import fcntl
|
|
8
|
+
from contextlib import contextmanager
|
|
9
|
+
from subprocess import CalledProcessError
|
|
10
|
+
from typing import Any, Dict, TYPE_CHECKING, ContextManager, Tuple
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
import tempfile
|
|
14
|
+
import metaflow.runner.subprocess_manager
|
|
15
|
+
import metaflow.runner.click_api
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_current_cell(ipython):
|
|
19
|
+
if ipython:
|
|
20
|
+
return ipython.history_manager.input_hist_raw[-1]
|
|
21
|
+
return None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def format_flowfile(cell):
|
|
25
|
+
"""
|
|
26
|
+
Formats the given cell content to create a valid Python script that can be
|
|
27
|
+
executed as a Metaflow flow.
|
|
28
|
+
"""
|
|
29
|
+
flowspec = [
|
|
30
|
+
x
|
|
31
|
+
for x in ast.parse(cell).body
|
|
32
|
+
if isinstance(x, ast.ClassDef) and any(b.id == "FlowSpec" for b in x.bases)
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
if not flowspec:
|
|
36
|
+
raise ModuleNotFoundError(
|
|
37
|
+
"The cell doesn't contain any class that inherits from 'FlowSpec'"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
lines = cell.splitlines()[: flowspec[0].end_lineno]
|
|
41
|
+
lines += ["if __name__ == '__main__':", f" {flowspec[0].name}()"]
|
|
42
|
+
return "\n".join(lines)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def check_process_exited(
|
|
46
|
+
command_obj: "metaflow.runner.subprocess_manager.CommandManager",
|
|
47
|
+
) -> bool:
|
|
48
|
+
if isinstance(command_obj.process, asyncio.subprocess.Process):
|
|
49
|
+
return command_obj.process.returncode is not None
|
|
50
|
+
else:
|
|
51
|
+
return command_obj.process.poll() is not None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@contextmanager
|
|
55
|
+
def temporary_fifo() -> ContextManager[Tuple[str, int]]:
|
|
56
|
+
"""
|
|
57
|
+
Create and open the read side of a temporary FIFO in a non-blocking mode.
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
str
|
|
62
|
+
Path to the temporary FIFO.
|
|
63
|
+
int
|
|
64
|
+
File descriptor of the temporary FIFO.
|
|
65
|
+
"""
|
|
66
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
67
|
+
path = os.path.join(temp_dir, "fifo")
|
|
68
|
+
os.mkfifo(path)
|
|
69
|
+
# Blocks until the write side is opened unless in non-blocking mode
|
|
70
|
+
fd = os.open(path, os.O_RDONLY | os.O_NONBLOCK)
|
|
71
|
+
try:
|
|
72
|
+
yield path, fd
|
|
73
|
+
finally:
|
|
74
|
+
os.close(fd)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def read_from_fifo_when_ready(
|
|
78
|
+
fifo_fd: int,
|
|
79
|
+
command_obj: "metaflow.runner.subprocess_manager.CommandManager",
|
|
80
|
+
encoding: str = "utf-8",
|
|
81
|
+
timeout: int = 3600,
|
|
82
|
+
) -> str:
|
|
83
|
+
"""
|
|
84
|
+
Read the content from the FIFO file descriptor when it is ready.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
fifo_fd : int
|
|
89
|
+
File descriptor of the FIFO.
|
|
90
|
+
command_obj : CommandManager
|
|
91
|
+
Command manager object that handles the write side of the FIFO.
|
|
92
|
+
encoding : str, optional
|
|
93
|
+
Encoding to use while reading the file, by default "utf-8".
|
|
94
|
+
timeout : int, optional
|
|
95
|
+
Timeout for reading the file in seconds, by default 3600.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
str
|
|
100
|
+
Content read from the FIFO.
|
|
101
|
+
|
|
102
|
+
Raises
|
|
103
|
+
------
|
|
104
|
+
TimeoutError
|
|
105
|
+
If no event occurs on the FIFO within the timeout.
|
|
106
|
+
CalledProcessError
|
|
107
|
+
If the process managed by `command_obj` has exited without writing any
|
|
108
|
+
content to the FIFO.
|
|
109
|
+
"""
|
|
110
|
+
content = bytearray()
|
|
111
|
+
poll = select.poll()
|
|
112
|
+
poll.register(fifo_fd, select.POLLIN)
|
|
113
|
+
while True:
|
|
114
|
+
if check_process_exited(command_obj) and command_obj.process.returncode != 0:
|
|
115
|
+
raise CalledProcessError(
|
|
116
|
+
command_obj.process.returncode, command_obj.command
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if timeout < 0:
|
|
120
|
+
raise TimeoutError("Timeout while waiting for the file content")
|
|
121
|
+
|
|
122
|
+
poll_begin = time.time()
|
|
123
|
+
# We poll for a very short time to be also able to check if the file was closed
|
|
124
|
+
# If the file is closed, we assume that we only have one writer so if we have
|
|
125
|
+
# data, we break out. This is to work around issues in macos
|
|
126
|
+
events = poll.poll(min(10, timeout * 1000))
|
|
127
|
+
timeout -= time.time() - poll_begin
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
data = os.read(fifo_fd, 8192)
|
|
131
|
+
if data:
|
|
132
|
+
content += data
|
|
133
|
+
# We got data! Now switch to blocking mode for guaranteed complete reads.
|
|
134
|
+
# In blocking mode, read() won't return 0 until writer closes AND all
|
|
135
|
+
# kernel buffers are drained - this is POSIX guaranteed.
|
|
136
|
+
flags = fcntl.fcntl(fifo_fd, fcntl.F_GETFL)
|
|
137
|
+
fcntl.fcntl(fifo_fd, fcntl.F_SETFL, flags & ~os.O_NONBLOCK)
|
|
138
|
+
|
|
139
|
+
# Now do blocking reads until true EOF
|
|
140
|
+
while True:
|
|
141
|
+
chunk = os.read(fifo_fd, 8192)
|
|
142
|
+
if not chunk:
|
|
143
|
+
# True EOF - all data drained
|
|
144
|
+
break
|
|
145
|
+
content += chunk
|
|
146
|
+
# All data read, exit main loop
|
|
147
|
+
break
|
|
148
|
+
else:
|
|
149
|
+
if len(events):
|
|
150
|
+
# We read an EOF -- consider the file done
|
|
151
|
+
break
|
|
152
|
+
else:
|
|
153
|
+
# We had no events (just a timeout) and the read didn't return
|
|
154
|
+
# an exception so the file is still open; we continue waiting for data
|
|
155
|
+
pass
|
|
156
|
+
except BlockingIOError:
|
|
157
|
+
# File not ready yet, continue waiting
|
|
158
|
+
pass
|
|
159
|
+
|
|
160
|
+
if not content and check_process_exited(command_obj):
|
|
161
|
+
raise CalledProcessError(command_obj.process.returncode, command_obj.command)
|
|
162
|
+
|
|
163
|
+
return content.decode(encoding)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
async def async_read_from_fifo_when_ready(
|
|
167
|
+
fifo_fd: int,
|
|
168
|
+
command_obj: "metaflow.runner.subprocess_manager.CommandManager",
|
|
169
|
+
encoding: str = "utf-8",
|
|
170
|
+
timeout: int = 3600,
|
|
171
|
+
) -> str:
|
|
172
|
+
"""
|
|
173
|
+
Read the content from the FIFO file descriptor when it is ready.
|
|
174
|
+
|
|
175
|
+
Parameters
|
|
176
|
+
----------
|
|
177
|
+
fifo_fd : int
|
|
178
|
+
File descriptor of the FIFO.
|
|
179
|
+
command_obj : CommandManager
|
|
180
|
+
Command manager object that handles the write side of the FIFO.
|
|
181
|
+
encoding : str, optional
|
|
182
|
+
Encoding to use while reading the file, by default "utf-8".
|
|
183
|
+
timeout : int, optional
|
|
184
|
+
Timeout for reading the file in seconds, by default 3600.
|
|
185
|
+
|
|
186
|
+
Returns
|
|
187
|
+
-------
|
|
188
|
+
str
|
|
189
|
+
Content read from the FIFO.
|
|
190
|
+
|
|
191
|
+
Raises
|
|
192
|
+
------
|
|
193
|
+
TimeoutError
|
|
194
|
+
If no event occurs on the FIFO within the timeout.
|
|
195
|
+
CalledProcessError
|
|
196
|
+
If the process managed by `command_obj` has exited without writing any
|
|
197
|
+
content to the FIFO.
|
|
198
|
+
"""
|
|
199
|
+
return await asyncio.to_thread(
|
|
200
|
+
read_from_fifo_when_ready, fifo_fd, command_obj, encoding, timeout
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def make_process_error_message(
|
|
205
|
+
command_obj: "metaflow.runner.subprocess_manager.CommandManager",
|
|
206
|
+
):
|
|
207
|
+
stdout_log = open(command_obj.log_files["stdout"], encoding="utf-8").read()
|
|
208
|
+
stderr_log = open(command_obj.log_files["stderr"], encoding="utf-8").read()
|
|
209
|
+
command = " ".join(command_obj.command)
|
|
210
|
+
error_message = "Error executing: '%s':\n" % command
|
|
211
|
+
if stdout_log.strip():
|
|
212
|
+
error_message += "\nStdout:\n%s\n" % stdout_log
|
|
213
|
+
if stderr_log.strip():
|
|
214
|
+
error_message += "\nStderr:\n%s\n" % stderr_log
|
|
215
|
+
return error_message
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def handle_timeout(
|
|
219
|
+
attribute_file_fd: int,
|
|
220
|
+
command_obj: "metaflow.runner.subprocess_manager.CommandManager",
|
|
221
|
+
file_read_timeout: int,
|
|
222
|
+
):
|
|
223
|
+
"""
|
|
224
|
+
Handle the timeout for a running subprocess command that reads a file
|
|
225
|
+
and raises an error with appropriate logs if a TimeoutError occurs.
|
|
226
|
+
|
|
227
|
+
Parameters
|
|
228
|
+
----------
|
|
229
|
+
attribute_file_fd : int
|
|
230
|
+
File descriptor belonging to the FIFO containing the attribute data.
|
|
231
|
+
command_obj : CommandManager
|
|
232
|
+
Command manager object that encapsulates the running command details.
|
|
233
|
+
file_read_timeout : int
|
|
234
|
+
Timeout for reading the file, in seconds
|
|
235
|
+
|
|
236
|
+
Returns
|
|
237
|
+
-------
|
|
238
|
+
str
|
|
239
|
+
Content read from the temporary file.
|
|
240
|
+
|
|
241
|
+
Raises
|
|
242
|
+
------
|
|
243
|
+
RuntimeError
|
|
244
|
+
If a TimeoutError occurs, it raises a RuntimeError with the command's
|
|
245
|
+
stdout and stderr logs.
|
|
246
|
+
"""
|
|
247
|
+
try:
|
|
248
|
+
return read_from_fifo_when_ready(
|
|
249
|
+
attribute_file_fd, command_obj=command_obj, timeout=file_read_timeout
|
|
250
|
+
)
|
|
251
|
+
except (CalledProcessError, TimeoutError) as e:
|
|
252
|
+
raise RuntimeError(make_process_error_message(command_obj)) from e
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
async def async_handle_timeout(
|
|
256
|
+
attribute_file_fd: "int",
|
|
257
|
+
command_obj: "metaflow.runner.subprocess_manager.CommandManager",
|
|
258
|
+
file_read_timeout: int,
|
|
259
|
+
):
|
|
260
|
+
"""
|
|
261
|
+
Handle the timeout for a running subprocess command that reads a file
|
|
262
|
+
and raises an error with appropriate logs if a TimeoutError occurs.
|
|
263
|
+
|
|
264
|
+
Parameters
|
|
265
|
+
----------
|
|
266
|
+
attribute_file_fd : int
|
|
267
|
+
File descriptor belonging to the FIFO containing the attribute data.
|
|
268
|
+
command_obj : CommandManager
|
|
269
|
+
Command manager object that encapsulates the running command details.
|
|
270
|
+
file_read_timeout : int
|
|
271
|
+
Timeout for reading the file, in seconds
|
|
272
|
+
|
|
273
|
+
Returns
|
|
274
|
+
-------
|
|
275
|
+
str
|
|
276
|
+
Content read from the temporary file.
|
|
277
|
+
|
|
278
|
+
Raises
|
|
279
|
+
------
|
|
280
|
+
RuntimeError
|
|
281
|
+
If a TimeoutError occurs, it raises a RuntimeError with the command's
|
|
282
|
+
stdout and stderr logs.
|
|
283
|
+
"""
|
|
284
|
+
try:
|
|
285
|
+
return await async_read_from_fifo_when_ready(
|
|
286
|
+
attribute_file_fd, command_obj=command_obj, timeout=file_read_timeout
|
|
287
|
+
)
|
|
288
|
+
except (CalledProcessError, TimeoutError) as e:
|
|
289
|
+
raise RuntimeError(make_process_error_message(command_obj)) from e
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def get_lower_level_group(
|
|
293
|
+
api: "metaflow.runner.click_api.MetaflowAPI",
|
|
294
|
+
top_level_kwargs: Dict[str, Any],
|
|
295
|
+
sub_command: str,
|
|
296
|
+
sub_command_kwargs: Dict[str, Any],
|
|
297
|
+
) -> "metaflow.runner.click_api.MetaflowAPI":
|
|
298
|
+
"""
|
|
299
|
+
Retrieve a lower-level group from the API based on the type and provided arguments.
|
|
300
|
+
|
|
301
|
+
Parameters
|
|
302
|
+
----------
|
|
303
|
+
api : MetaflowAPI
|
|
304
|
+
Metaflow API instance.
|
|
305
|
+
top_level_kwargs : Dict[str, Any]
|
|
306
|
+
Top-level keyword arguments to pass to the API.
|
|
307
|
+
sub_command : str
|
|
308
|
+
Sub-command of API to get the API for
|
|
309
|
+
sub_command_kwargs : Dict[str, Any]
|
|
310
|
+
Sub-command arguments
|
|
311
|
+
|
|
312
|
+
Returns
|
|
313
|
+
-------
|
|
314
|
+
MetaflowAPI
|
|
315
|
+
The lower-level group object retrieved from the API.
|
|
316
|
+
|
|
317
|
+
Raises
|
|
318
|
+
------
|
|
319
|
+
ValueError
|
|
320
|
+
If the `_type` is None.
|
|
321
|
+
"""
|
|
322
|
+
sub_command_obj = getattr(api(**top_level_kwargs), sub_command)
|
|
323
|
+
|
|
324
|
+
if sub_command_obj is None:
|
|
325
|
+
raise ValueError(f"Sub-command '{sub_command}' not found in API '{api.name}'")
|
|
326
|
+
|
|
327
|
+
return sub_command_obj(**sub_command_kwargs)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
@contextmanager
|
|
331
|
+
def with_dir(new_dir):
|
|
332
|
+
current_dir = os.getcwd()
|
|
333
|
+
os.chdir(new_dir)
|
|
334
|
+
yield new_dir
|
|
335
|
+
os.chdir(current_dir)
|