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,470 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from typing import ClassVar, Dict, Optional, TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from metaflow.exception import MetaflowNotFound
|
|
8
|
+
from metaflow.metaflow_config import DEFAULT_FROM_DEPLOYMENT_IMPL
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def generate_fake_flow_file_contents(
|
|
12
|
+
flow_name: str, param_info: dict, project_name: Optional[str] = None
|
|
13
|
+
):
|
|
14
|
+
params_code = ""
|
|
15
|
+
for _, param_details in param_info.items():
|
|
16
|
+
param_python_var_name = param_details.get(
|
|
17
|
+
"python_var_name", param_details["name"]
|
|
18
|
+
)
|
|
19
|
+
param_name = param_details["name"]
|
|
20
|
+
param_type = param_details["type"]
|
|
21
|
+
param_help = param_details["description"]
|
|
22
|
+
param_required = param_details["is_required"]
|
|
23
|
+
|
|
24
|
+
if param_type == "JSON":
|
|
25
|
+
params_code += (
|
|
26
|
+
f" {param_python_var_name} = Parameter('{param_name}', "
|
|
27
|
+
f"type=JSONType, help='''{param_help}''', required={param_required})\n"
|
|
28
|
+
)
|
|
29
|
+
elif param_type == "FilePath":
|
|
30
|
+
is_text = param_details.get("is_text", True)
|
|
31
|
+
encoding = param_details.get("encoding", "utf-8")
|
|
32
|
+
params_code += (
|
|
33
|
+
f" {param_python_var_name} = IncludeFile('{param_name}', "
|
|
34
|
+
f"is_text={is_text}, encoding='{encoding}', help='''{param_help}''', "
|
|
35
|
+
f"required={param_required})\n"
|
|
36
|
+
)
|
|
37
|
+
else:
|
|
38
|
+
params_code += (
|
|
39
|
+
f" {param_python_var_name} = Parameter('{param_name}', "
|
|
40
|
+
f"type={param_type}, help='''{param_help}''', required={param_required})\n"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
project_decorator = f"@project(name='{project_name}')\n" if project_name else ""
|
|
44
|
+
|
|
45
|
+
contents = f"""\
|
|
46
|
+
from metaflow import FlowSpec, Parameter, IncludeFile, JSONType, step, project
|
|
47
|
+
{project_decorator}class {flow_name}(FlowSpec):
|
|
48
|
+
{params_code}
|
|
49
|
+
@step
|
|
50
|
+
def start(self):
|
|
51
|
+
self.next(self.end)
|
|
52
|
+
@step
|
|
53
|
+
def end(self):
|
|
54
|
+
pass
|
|
55
|
+
if __name__ == '__main__':
|
|
56
|
+
{flow_name}()
|
|
57
|
+
"""
|
|
58
|
+
return contents
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
if TYPE_CHECKING:
|
|
62
|
+
import metaflow
|
|
63
|
+
import metaflow.runner.deployer_impl
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class DeployerMeta(type):
|
|
67
|
+
def __new__(mcs, name, bases, dct):
|
|
68
|
+
cls = super().__new__(mcs, name, bases, dct)
|
|
69
|
+
|
|
70
|
+
from metaflow.plugins import DEPLOYER_IMPL_PROVIDERS
|
|
71
|
+
|
|
72
|
+
def _injected_method(method_name, deployer_class):
|
|
73
|
+
def f(self, **deployer_kwargs):
|
|
74
|
+
return deployer_class(
|
|
75
|
+
deployer_kwargs=deployer_kwargs,
|
|
76
|
+
flow_file=self.flow_file,
|
|
77
|
+
show_output=self.show_output,
|
|
78
|
+
profile=self.profile,
|
|
79
|
+
env=self.env,
|
|
80
|
+
cwd=self.cwd,
|
|
81
|
+
file_read_timeout=self.file_read_timeout,
|
|
82
|
+
**self.top_level_kwargs,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
f.__doc__ = provider_class.__doc__ or ""
|
|
86
|
+
f.__name__ = method_name
|
|
87
|
+
return f
|
|
88
|
+
|
|
89
|
+
for provider_class in DEPLOYER_IMPL_PROVIDERS:
|
|
90
|
+
# TYPE is the name of the CLI groups i.e.
|
|
91
|
+
# `argo-workflows` instead of `argo_workflows`
|
|
92
|
+
# The injected method names replace '-' by '_' though.
|
|
93
|
+
method_name = provider_class.TYPE.replace("-", "_")
|
|
94
|
+
setattr(cls, method_name, _injected_method(method_name, provider_class))
|
|
95
|
+
|
|
96
|
+
return cls
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class Deployer(metaclass=DeployerMeta):
|
|
100
|
+
"""
|
|
101
|
+
Use the `Deployer` class to configure and access one of the production
|
|
102
|
+
orchestrators supported by Metaflow.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
flow_file : str
|
|
107
|
+
Path to the flow file to deploy, relative to current directory.
|
|
108
|
+
show_output : bool, default True
|
|
109
|
+
Show the 'stdout' and 'stderr' to the console by default.
|
|
110
|
+
profile : Optional[str], default None
|
|
111
|
+
Metaflow profile to use for the deployment. If not specified, the default
|
|
112
|
+
profile is used.
|
|
113
|
+
env : Optional[Dict[str, str]], default None
|
|
114
|
+
Additional environment variables to set for the deployment.
|
|
115
|
+
cwd : Optional[str], default None
|
|
116
|
+
The directory to run the subprocess in; if not specified, the current
|
|
117
|
+
directory is used.
|
|
118
|
+
file_read_timeout : int, default 3600
|
|
119
|
+
The timeout until which we try to read the deployer attribute file (in seconds).
|
|
120
|
+
**kwargs : Any
|
|
121
|
+
Additional arguments that you would pass to `python myflow.py` before
|
|
122
|
+
the deployment command.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
def __init__(
|
|
126
|
+
self,
|
|
127
|
+
flow_file: str,
|
|
128
|
+
show_output: bool = True,
|
|
129
|
+
profile: Optional[str] = None,
|
|
130
|
+
env: Optional[Dict] = None,
|
|
131
|
+
cwd: Optional[str] = None,
|
|
132
|
+
file_read_timeout: int = 3600,
|
|
133
|
+
**kwargs,
|
|
134
|
+
):
|
|
135
|
+
# Convert flow_file to absolute path if it's relative
|
|
136
|
+
if not os.path.isabs(flow_file):
|
|
137
|
+
self.flow_file = os.path.abspath(flow_file)
|
|
138
|
+
else:
|
|
139
|
+
self.flow_file = flow_file
|
|
140
|
+
|
|
141
|
+
self.show_output = show_output
|
|
142
|
+
self.profile = profile
|
|
143
|
+
self.env = env
|
|
144
|
+
self.cwd = cwd
|
|
145
|
+
self.file_read_timeout = file_read_timeout
|
|
146
|
+
self.top_level_kwargs = kwargs
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class TriggeredRun(object):
|
|
150
|
+
"""
|
|
151
|
+
TriggeredRun class represents a run that has been triggered on a
|
|
152
|
+
production orchestrator.
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
def __init__(
|
|
156
|
+
self,
|
|
157
|
+
deployer: "metaflow.runner.deployer_impl.DeployerImpl",
|
|
158
|
+
content: str,
|
|
159
|
+
):
|
|
160
|
+
self.deployer = deployer
|
|
161
|
+
content_json = json.loads(content)
|
|
162
|
+
self.metadata_for_flow = content_json.get("metadata")
|
|
163
|
+
self.pathspec = content_json.get("pathspec")
|
|
164
|
+
self.name = content_json.get("name")
|
|
165
|
+
|
|
166
|
+
def wait_for_run(self, check_interval: int = 5, timeout: Optional[int] = None):
|
|
167
|
+
"""
|
|
168
|
+
Wait for the `run` property to become available.
|
|
169
|
+
|
|
170
|
+
The `run` property becomes available only after the `start` task of the triggered
|
|
171
|
+
flow starts running.
|
|
172
|
+
|
|
173
|
+
Parameters
|
|
174
|
+
----------
|
|
175
|
+
check_interval: int, default: 5
|
|
176
|
+
Frequency of checking for the `run` to become available, in seconds.
|
|
177
|
+
timeout : int, optional, default None
|
|
178
|
+
Maximum time to wait for the `run` to become available, in seconds. If
|
|
179
|
+
None, wait indefinitely.
|
|
180
|
+
|
|
181
|
+
Raises
|
|
182
|
+
------
|
|
183
|
+
TimeoutError
|
|
184
|
+
If the `run` is not available within the specified timeout.
|
|
185
|
+
"""
|
|
186
|
+
start_time = time.time()
|
|
187
|
+
while True:
|
|
188
|
+
if self.run is not None:
|
|
189
|
+
return self.run
|
|
190
|
+
|
|
191
|
+
if timeout is not None and (time.time() - start_time) > timeout:
|
|
192
|
+
raise TimeoutError(
|
|
193
|
+
"Timed out waiting for the run object to become available."
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
time.sleep(check_interval)
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def run(self) -> Optional["metaflow.Run"]:
|
|
200
|
+
"""
|
|
201
|
+
Retrieve the `Run` object for the triggered run.
|
|
202
|
+
|
|
203
|
+
Note that Metaflow `Run` becomes available only when the `start` task
|
|
204
|
+
has started executing.
|
|
205
|
+
|
|
206
|
+
Returns
|
|
207
|
+
-------
|
|
208
|
+
Run, optional
|
|
209
|
+
Metaflow Run object if the `start` step has started executing, otherwise None.
|
|
210
|
+
"""
|
|
211
|
+
from metaflow import Run
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
return Run(self.pathspec, _namespace_check=False)
|
|
215
|
+
except MetaflowNotFound:
|
|
216
|
+
return None
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class DeployedFlowMeta(type):
|
|
220
|
+
def __new__(mcs, name, bases, dct):
|
|
221
|
+
cls = super().__new__(mcs, name, bases, dct)
|
|
222
|
+
if not bases:
|
|
223
|
+
# Inject methods only in DeployedFlow and not any of its
|
|
224
|
+
# subclasses
|
|
225
|
+
from metaflow.plugins import DEPLOYER_IMPL_PROVIDERS
|
|
226
|
+
|
|
227
|
+
allowed_providers = dict(
|
|
228
|
+
{
|
|
229
|
+
provider.TYPE.replace("-", "_"): provider
|
|
230
|
+
for provider in DEPLOYER_IMPL_PROVIDERS
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
def _get_triggered_run_injected_method():
|
|
235
|
+
def f(
|
|
236
|
+
cls,
|
|
237
|
+
identifier: str,
|
|
238
|
+
run_id: str,
|
|
239
|
+
metadata: Optional[str] = None,
|
|
240
|
+
impl: str = DEFAULT_FROM_DEPLOYMENT_IMPL.replace("-", "_"),
|
|
241
|
+
) -> "TriggeredRun":
|
|
242
|
+
"""
|
|
243
|
+
Retrieves a `TriggeredRun` object from an identifier, a run id and optional
|
|
244
|
+
metadata. The `impl` parameter specifies the deployer implementation
|
|
245
|
+
to use (like `argo-workflows`).
|
|
246
|
+
|
|
247
|
+
Parameters
|
|
248
|
+
----------
|
|
249
|
+
identifier : str
|
|
250
|
+
Deployer specific identifier for the workflow to retrieve
|
|
251
|
+
run_id : str
|
|
252
|
+
Run ID for the which to fetch the triggered run object
|
|
253
|
+
metadata : str, optional, default None
|
|
254
|
+
Optional deployer specific metadata.
|
|
255
|
+
impl : str, optional, default given by METAFLOW_DEFAULT_FROM_DEPLOYMENT_IMPL
|
|
256
|
+
The default implementation to use if not specified
|
|
257
|
+
|
|
258
|
+
Returns
|
|
259
|
+
-------
|
|
260
|
+
TriggeredRun
|
|
261
|
+
A `TriggeredRun` object representing the triggered run corresponding
|
|
262
|
+
to the identifier and the run id.
|
|
263
|
+
"""
|
|
264
|
+
if impl in allowed_providers:
|
|
265
|
+
return (
|
|
266
|
+
allowed_providers[impl]
|
|
267
|
+
.deployed_flow_type()
|
|
268
|
+
.get_triggered_run(identifier, run_id, metadata)
|
|
269
|
+
)
|
|
270
|
+
else:
|
|
271
|
+
raise ValueError(
|
|
272
|
+
f"No deployer '{impl}' exists; valid deployers are: "
|
|
273
|
+
f"{list(allowed_providers.keys())}"
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
f.__name__ = "get_triggered_run"
|
|
277
|
+
return f
|
|
278
|
+
|
|
279
|
+
def _per_type_get_triggered_run_injected_method(method_name, impl):
|
|
280
|
+
def f(
|
|
281
|
+
cls,
|
|
282
|
+
identifier: str,
|
|
283
|
+
run_id: str,
|
|
284
|
+
metadata: Optional[str] = None,
|
|
285
|
+
):
|
|
286
|
+
return (
|
|
287
|
+
allowed_providers[impl]
|
|
288
|
+
.deployed_flow_type()
|
|
289
|
+
.get_triggered_run(identifier, run_id, metadata)
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
f.__name__ = method_name
|
|
293
|
+
return f
|
|
294
|
+
|
|
295
|
+
def _from_deployment_injected_method():
|
|
296
|
+
def f(
|
|
297
|
+
cls,
|
|
298
|
+
identifier: str,
|
|
299
|
+
metadata: Optional[str] = None,
|
|
300
|
+
impl: str = DEFAULT_FROM_DEPLOYMENT_IMPL.replace("-", "_"),
|
|
301
|
+
) -> "DeployedFlow":
|
|
302
|
+
"""
|
|
303
|
+
Retrieves a `DeployedFlow` object from an identifier and optional
|
|
304
|
+
metadata. The `impl` parameter specifies the deployer implementation
|
|
305
|
+
to use (like `argo-workflows`).
|
|
306
|
+
|
|
307
|
+
Parameters
|
|
308
|
+
----------
|
|
309
|
+
identifier : str
|
|
310
|
+
Deployer specific identifier for the workflow to retrieve
|
|
311
|
+
metadata : str, optional, default None
|
|
312
|
+
Optional deployer specific metadata.
|
|
313
|
+
impl : str, optional, default given by METAFLOW_DEFAULT_FROM_DEPLOYMENT_IMPL
|
|
314
|
+
The default implementation to use if not specified
|
|
315
|
+
|
|
316
|
+
Returns
|
|
317
|
+
-------
|
|
318
|
+
DeployedFlow
|
|
319
|
+
A `DeployedFlow` object representing the deployed flow corresponding
|
|
320
|
+
to the identifier
|
|
321
|
+
"""
|
|
322
|
+
if impl in allowed_providers:
|
|
323
|
+
return (
|
|
324
|
+
allowed_providers[impl]
|
|
325
|
+
.deployed_flow_type()
|
|
326
|
+
.from_deployment(identifier, metadata)
|
|
327
|
+
)
|
|
328
|
+
else:
|
|
329
|
+
raise ValueError(
|
|
330
|
+
f"No deployer '{impl}' exists; valid deployers are: "
|
|
331
|
+
f"{list(allowed_providers.keys())}"
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
f.__name__ = "from_deployment"
|
|
335
|
+
return f
|
|
336
|
+
|
|
337
|
+
def _per_type_from_deployment_injected_method(method_name, impl):
|
|
338
|
+
def f(
|
|
339
|
+
cls,
|
|
340
|
+
identifier: str,
|
|
341
|
+
metadata: Optional[str] = None,
|
|
342
|
+
):
|
|
343
|
+
return (
|
|
344
|
+
allowed_providers[impl]
|
|
345
|
+
.deployed_flow_type()
|
|
346
|
+
.from_deployment(identifier, metadata)
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
f.__name__ = method_name
|
|
350
|
+
return f
|
|
351
|
+
|
|
352
|
+
def _list_deployed_flows_injected_method():
|
|
353
|
+
def f(
|
|
354
|
+
cls,
|
|
355
|
+
flow_name: Optional[str] = None,
|
|
356
|
+
impl: str = DEFAULT_FROM_DEPLOYMENT_IMPL.replace("-", "_"),
|
|
357
|
+
):
|
|
358
|
+
"""
|
|
359
|
+
List all deployed flows for the specified implementation.
|
|
360
|
+
|
|
361
|
+
Parameters
|
|
362
|
+
----------
|
|
363
|
+
flow_name : str, optional, default None
|
|
364
|
+
If specified, only list deployed flows for this specific flow name.
|
|
365
|
+
If None, list all deployed flows.
|
|
366
|
+
impl : str, optional, default given by METAFLOW_DEFAULT_FROM_DEPLOYMENT_IMPL
|
|
367
|
+
The default implementation to use if not specified
|
|
368
|
+
|
|
369
|
+
Yields
|
|
370
|
+
------
|
|
371
|
+
DeployedFlow
|
|
372
|
+
`DeployedFlow` objects representing deployed flows.
|
|
373
|
+
"""
|
|
374
|
+
if impl in allowed_providers:
|
|
375
|
+
return (
|
|
376
|
+
allowed_providers[impl]
|
|
377
|
+
.deployed_flow_type()
|
|
378
|
+
.list_deployed_flows(flow_name)
|
|
379
|
+
)
|
|
380
|
+
else:
|
|
381
|
+
raise ValueError(
|
|
382
|
+
f"No deployer '{impl}' exists; valid deployers are: "
|
|
383
|
+
f"{list(allowed_providers.keys())}"
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
f.__name__ = "list_deployed_flows"
|
|
387
|
+
return f
|
|
388
|
+
|
|
389
|
+
def _per_type_list_deployed_flows_injected_method(method_name, impl):
|
|
390
|
+
def f(
|
|
391
|
+
cls,
|
|
392
|
+
flow_name: Optional[str] = None,
|
|
393
|
+
):
|
|
394
|
+
return (
|
|
395
|
+
allowed_providers[impl]
|
|
396
|
+
.deployed_flow_type()
|
|
397
|
+
.list_deployed_flows(flow_name)
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
f.__name__ = method_name
|
|
401
|
+
return f
|
|
402
|
+
|
|
403
|
+
setattr(
|
|
404
|
+
cls, "from_deployment", classmethod(_from_deployment_injected_method())
|
|
405
|
+
)
|
|
406
|
+
setattr(
|
|
407
|
+
cls,
|
|
408
|
+
"list_deployed_flows",
|
|
409
|
+
classmethod(_list_deployed_flows_injected_method()),
|
|
410
|
+
)
|
|
411
|
+
setattr(
|
|
412
|
+
cls,
|
|
413
|
+
"get_triggered_run",
|
|
414
|
+
classmethod(_get_triggered_run_injected_method()),
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
for impl in allowed_providers:
|
|
418
|
+
from_deployment_method_name = f"from_{impl}"
|
|
419
|
+
list_deployed_flows_method_name = f"list_{impl}"
|
|
420
|
+
get_triggered_run_method_name = f"get_triggered_{impl}_run"
|
|
421
|
+
|
|
422
|
+
setattr(
|
|
423
|
+
cls,
|
|
424
|
+
from_deployment_method_name,
|
|
425
|
+
classmethod(
|
|
426
|
+
_per_type_from_deployment_injected_method(
|
|
427
|
+
from_deployment_method_name, impl
|
|
428
|
+
)
|
|
429
|
+
),
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
setattr(
|
|
433
|
+
cls,
|
|
434
|
+
list_deployed_flows_method_name,
|
|
435
|
+
classmethod(
|
|
436
|
+
_per_type_list_deployed_flows_injected_method(
|
|
437
|
+
list_deployed_flows_method_name, impl
|
|
438
|
+
)
|
|
439
|
+
),
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
setattr(
|
|
443
|
+
cls,
|
|
444
|
+
get_triggered_run_method_name,
|
|
445
|
+
classmethod(
|
|
446
|
+
_per_type_get_triggered_run_injected_method(
|
|
447
|
+
get_triggered_run_method_name, impl
|
|
448
|
+
)
|
|
449
|
+
),
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
return cls
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
class DeployedFlow(metaclass=DeployedFlowMeta):
|
|
456
|
+
"""
|
|
457
|
+
DeployedFlow class represents a flow that has been deployed.
|
|
458
|
+
|
|
459
|
+
This class is not meant to be instantiated directly. Instead, it is returned from
|
|
460
|
+
methods of `Deployer`.
|
|
461
|
+
"""
|
|
462
|
+
|
|
463
|
+
# This should match the TYPE value in DeployerImpl for proper stub generation
|
|
464
|
+
TYPE: ClassVar[Optional[str]] = None
|
|
465
|
+
|
|
466
|
+
def __init__(self, deployer: "metaflow.runner.deployer_impl.DeployerImpl"):
|
|
467
|
+
self.deployer = deployer
|
|
468
|
+
self.name = self.deployer.name
|
|
469
|
+
self.flow_name = self.deployer.flow_name
|
|
470
|
+
self.metadata = self.deployer.metadata
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from typing import Any, ClassVar, Dict, Optional, TYPE_CHECKING, Type, List
|
|
7
|
+
|
|
8
|
+
from metaflow.metaflow_config import CLICK_API_PROCESS_CONFIG
|
|
9
|
+
|
|
10
|
+
from .subprocess_manager import SubprocessManager
|
|
11
|
+
from .utils import get_lower_level_group, handle_timeout, temporary_fifo, with_dir
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
import metaflow.runner.deployer
|
|
15
|
+
|
|
16
|
+
# NOTE: This file is separate from the deployer.py file to prevent circular imports.
|
|
17
|
+
# This file is needed in any of the DeployerImpl implementations
|
|
18
|
+
# (like argo_workflows_deployer.py) which is in turn needed to create the Deployer
|
|
19
|
+
# class (ie: it uses ArgoWorkflowsDeployer to create the Deployer class).
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DeployerImpl(object):
|
|
23
|
+
"""
|
|
24
|
+
Base class for deployer implementations. Each implementation should define a TYPE
|
|
25
|
+
class variable that matches the name of the CLI group.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
flow_file : str
|
|
30
|
+
Path to the flow file to deploy, relative to current directory.
|
|
31
|
+
show_output : bool, default True
|
|
32
|
+
Show the 'stdout' and 'stderr' to the console by default.
|
|
33
|
+
profile : Optional[str], default None
|
|
34
|
+
Metaflow profile to use for the deployment. If not specified, the default
|
|
35
|
+
profile is used.
|
|
36
|
+
env : Optional[Dict], default None
|
|
37
|
+
Additional environment variables to set for the deployment.
|
|
38
|
+
cwd : Optional[str], default None
|
|
39
|
+
The directory to run the subprocess in; if not specified, the current
|
|
40
|
+
directory is used.
|
|
41
|
+
file_read_timeout : int, default 3600
|
|
42
|
+
The timeout until which we try to read the deployer attribute file (in seconds).
|
|
43
|
+
**kwargs : Any
|
|
44
|
+
Additional arguments that you would pass to `python myflow.py` before
|
|
45
|
+
the deployment command.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
TYPE: ClassVar[Optional[str]] = None
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
flow_file: str,
|
|
53
|
+
show_output: bool = True,
|
|
54
|
+
profile: Optional[str] = None,
|
|
55
|
+
env: Optional[Dict] = None,
|
|
56
|
+
cwd: Optional[str] = None,
|
|
57
|
+
file_read_timeout: int = 3600,
|
|
58
|
+
**kwargs
|
|
59
|
+
):
|
|
60
|
+
if self.TYPE is None:
|
|
61
|
+
raise ValueError(
|
|
62
|
+
"DeployerImpl doesn't have a 'TYPE' to target. Please use a sub-class "
|
|
63
|
+
"of DeployerImpl."
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
from metaflow.parameters import flow_context
|
|
67
|
+
|
|
68
|
+
# Reload the CLI with an "empty" flow -- this will remove any configuration
|
|
69
|
+
# and parameter options. They are re-added in from_cli (called below).
|
|
70
|
+
with flow_context(None):
|
|
71
|
+
[
|
|
72
|
+
importlib.reload(sys.modules[module])
|
|
73
|
+
for module in self.to_reload
|
|
74
|
+
if module in sys.modules
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
from metaflow.cli import start
|
|
78
|
+
from metaflow.runner.click_api import MetaflowAPI
|
|
79
|
+
|
|
80
|
+
# Convert flow_file to absolute path if it's relative
|
|
81
|
+
if not os.path.isabs(flow_file):
|
|
82
|
+
self.flow_file = os.path.abspath(flow_file)
|
|
83
|
+
else:
|
|
84
|
+
self.flow_file = flow_file
|
|
85
|
+
self.show_output = show_output
|
|
86
|
+
self.profile = profile
|
|
87
|
+
self.env = env
|
|
88
|
+
self.cwd = cwd or os.getcwd()
|
|
89
|
+
self.file_read_timeout = file_read_timeout
|
|
90
|
+
|
|
91
|
+
self.env_vars = os.environ.copy()
|
|
92
|
+
self.env_vars.update(self.env or {})
|
|
93
|
+
if self.profile:
|
|
94
|
+
self.env_vars["METAFLOW_PROFILE"] = profile
|
|
95
|
+
|
|
96
|
+
self.spm = SubprocessManager()
|
|
97
|
+
self.top_level_kwargs = kwargs
|
|
98
|
+
self.api = MetaflowAPI.from_cli(self.flow_file, start)
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def to_reload(self) -> List[str]:
|
|
102
|
+
"""
|
|
103
|
+
List of modules to reload when the deployer is initialized.
|
|
104
|
+
This is used to ensure that the CLI is in a clean state before
|
|
105
|
+
deploying the flow.
|
|
106
|
+
"""
|
|
107
|
+
return [
|
|
108
|
+
"metaflow.cli",
|
|
109
|
+
"metaflow.cli_components.run_cmds",
|
|
110
|
+
"metaflow.cli_components.init_cmd",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def deployer_kwargs(self) -> Dict[str, Any]:
|
|
115
|
+
raise NotImplementedError
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def deployed_flow_type() -> Type["metaflow.runner.deployer.DeployedFlow"]:
|
|
119
|
+
raise NotImplementedError
|
|
120
|
+
|
|
121
|
+
def __enter__(self) -> "DeployerImpl":
|
|
122
|
+
return self
|
|
123
|
+
|
|
124
|
+
def create(self, **kwargs) -> "metaflow.runner.deployer.DeployedFlow":
|
|
125
|
+
"""
|
|
126
|
+
Create a sub-class of a `DeployedFlow` depending on the deployer implementation.
|
|
127
|
+
|
|
128
|
+
Parameters
|
|
129
|
+
----------
|
|
130
|
+
**kwargs : Any
|
|
131
|
+
Additional arguments to pass to `create` corresponding to the
|
|
132
|
+
command line arguments of `create`
|
|
133
|
+
|
|
134
|
+
Returns
|
|
135
|
+
-------
|
|
136
|
+
DeployedFlow
|
|
137
|
+
DeployedFlow object representing the deployed flow.
|
|
138
|
+
|
|
139
|
+
Raises
|
|
140
|
+
------
|
|
141
|
+
Exception
|
|
142
|
+
If there is an error during deployment.
|
|
143
|
+
"""
|
|
144
|
+
# Sub-classes should implement this by simply calling _create and pass the
|
|
145
|
+
# proper class as the DeployedFlow to return.
|
|
146
|
+
raise NotImplementedError
|
|
147
|
+
|
|
148
|
+
def _create(
|
|
149
|
+
self, create_class: Type["metaflow.runner.deployer.DeployedFlow"], **kwargs
|
|
150
|
+
) -> "metaflow.runner.deployer.DeployedFlow":
|
|
151
|
+
with temporary_fifo() as (attribute_file_path, attribute_file_fd):
|
|
152
|
+
# every subclass needs to have `self.deployer_kwargs`
|
|
153
|
+
# TODO: Get rid of CLICK_API_PROCESS_CONFIG in the near future
|
|
154
|
+
if CLICK_API_PROCESS_CONFIG:
|
|
155
|
+
# We need to run this in the cwd because configs depend on files
|
|
156
|
+
# that may be located in paths relative to the directory the user
|
|
157
|
+
# wants to run in
|
|
158
|
+
with with_dir(self.cwd):
|
|
159
|
+
command = get_lower_level_group(
|
|
160
|
+
self.api, self.top_level_kwargs, self.TYPE, self.deployer_kwargs
|
|
161
|
+
).create(deployer_attribute_file=attribute_file_path, **kwargs)
|
|
162
|
+
else:
|
|
163
|
+
command = get_lower_level_group(
|
|
164
|
+
self.api, self.top_level_kwargs, self.TYPE, self.deployer_kwargs
|
|
165
|
+
).create(deployer_attribute_file=attribute_file_path, **kwargs)
|
|
166
|
+
|
|
167
|
+
pid = self.spm.run_command(
|
|
168
|
+
[sys.executable, *command],
|
|
169
|
+
env=self.env_vars,
|
|
170
|
+
cwd=self.cwd,
|
|
171
|
+
show_output=self.show_output,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
command_obj = self.spm.get(pid)
|
|
175
|
+
content = handle_timeout(
|
|
176
|
+
attribute_file_fd, command_obj, self.file_read_timeout
|
|
177
|
+
)
|
|
178
|
+
content = json.loads(content)
|
|
179
|
+
self.name = content.get("name")
|
|
180
|
+
self.flow_name = content.get("flow_name")
|
|
181
|
+
self.metadata = content.get("metadata")
|
|
182
|
+
# Additional info is used to pass additional deployer specific information.
|
|
183
|
+
# It is used in non-OSS deployers (extensions).
|
|
184
|
+
self.additional_info = content.get("additional_info", {})
|
|
185
|
+
command_obj.sync_wait()
|
|
186
|
+
if command_obj.process.returncode == 0:
|
|
187
|
+
return create_class(deployer=self)
|
|
188
|
+
|
|
189
|
+
raise RuntimeError("Error deploying %s to %s" % (self.flow_file, self.TYPE))
|
|
190
|
+
|
|
191
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
192
|
+
"""
|
|
193
|
+
Cleanup resources on exit.
|
|
194
|
+
"""
|
|
195
|
+
self.cleanup()
|
|
196
|
+
|
|
197
|
+
def cleanup(self):
|
|
198
|
+
"""
|
|
199
|
+
Cleanup resources.
|
|
200
|
+
"""
|
|
201
|
+
self.spm.cleanup()
|