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,546 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from functools import wraps
|
|
4
|
+
|
|
5
|
+
from metaflow._vendor import click
|
|
6
|
+
|
|
7
|
+
from .. import decorators, namespace, parameters, tracing
|
|
8
|
+
from ..exception import CommandException
|
|
9
|
+
from ..graph import FlowGraph
|
|
10
|
+
from ..metaflow_current import current
|
|
11
|
+
from ..metaflow_config import (
|
|
12
|
+
DEFAULT_DECOSPECS,
|
|
13
|
+
FEAT_ALWAYS_UPLOAD_CODE_PACKAGE,
|
|
14
|
+
SPIN_PERSIST,
|
|
15
|
+
)
|
|
16
|
+
from ..metaflow_profile import from_start
|
|
17
|
+
from ..package import MetaflowPackage
|
|
18
|
+
from ..runtime import NativeRuntime, SpinRuntime
|
|
19
|
+
from ..system import _system_logger
|
|
20
|
+
|
|
21
|
+
# from ..client.core import Run
|
|
22
|
+
|
|
23
|
+
from ..tagging_util import validate_tags
|
|
24
|
+
from ..util import get_latest_run_id, write_latest_run_id, parse_spin_pathspec
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def before_run(obj, tags, decospecs, skip_decorators=False):
|
|
28
|
+
validate_tags(tags)
|
|
29
|
+
|
|
30
|
+
# There's a --with option both at the top-level and for the run/resume/spin
|
|
31
|
+
# subcommand. Why?
|
|
32
|
+
#
|
|
33
|
+
# "run --with shoes" looks so much better than "--with shoes run".
|
|
34
|
+
# This is a very common use case of --with.
|
|
35
|
+
#
|
|
36
|
+
# A downside is that we need to have the following decorators handling
|
|
37
|
+
# in two places in this module and make sure _init_step_decorators
|
|
38
|
+
# doesn't get called twice.
|
|
39
|
+
|
|
40
|
+
# We want the order to be the following:
|
|
41
|
+
# - run level decospecs
|
|
42
|
+
# - top level decospecs
|
|
43
|
+
# - environment decospecs
|
|
44
|
+
from_start(
|
|
45
|
+
f"Inside before_run, skip_decorators={skip_decorators}, is_spin={obj.is_spin}"
|
|
46
|
+
)
|
|
47
|
+
if not skip_decorators:
|
|
48
|
+
all_decospecs = (
|
|
49
|
+
list(decospecs or [])
|
|
50
|
+
+ obj.tl_decospecs
|
|
51
|
+
+ list(obj.environment.decospecs() or [])
|
|
52
|
+
)
|
|
53
|
+
if all_decospecs:
|
|
54
|
+
# These decospecs are the ones from run/resume/spin PLUS the ones from the
|
|
55
|
+
# environment (for example the @conda)
|
|
56
|
+
decorators._attach_decorators(obj.flow, all_decospecs)
|
|
57
|
+
decorators._init(obj.flow)
|
|
58
|
+
# Regenerate graph if we attached more decorators
|
|
59
|
+
obj.flow.__class__._init_graph()
|
|
60
|
+
obj.graph = obj.flow._graph
|
|
61
|
+
|
|
62
|
+
obj.check(obj.graph, obj.flow, obj.environment, pylint=obj.pylint)
|
|
63
|
+
# obj.environment.init_environment(obj.logger)
|
|
64
|
+
|
|
65
|
+
decorators._init_step_decorators(
|
|
66
|
+
obj.flow,
|
|
67
|
+
obj.graph,
|
|
68
|
+
obj.environment,
|
|
69
|
+
obj.flow_datastore,
|
|
70
|
+
obj.logger,
|
|
71
|
+
obj.is_spin,
|
|
72
|
+
skip_decorators,
|
|
73
|
+
)
|
|
74
|
+
# Re-read graph since it may have been modified by mutators
|
|
75
|
+
obj.graph = obj.flow._graph
|
|
76
|
+
|
|
77
|
+
obj.metadata.add_sticky_tags(tags=tags)
|
|
78
|
+
|
|
79
|
+
# Package working directory only once per run.
|
|
80
|
+
# We explicitly avoid doing this in `start` since it is invoked for every
|
|
81
|
+
# step in the run.
|
|
82
|
+
obj.package = MetaflowPackage(
|
|
83
|
+
obj.flow,
|
|
84
|
+
obj.environment,
|
|
85
|
+
obj.echo,
|
|
86
|
+
suffixes=obj.package_suffixes,
|
|
87
|
+
flow_datastore=obj.flow_datastore if FEAT_ALWAYS_UPLOAD_CODE_PACKAGE else None,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def common_runner_options(func):
|
|
92
|
+
@click.option(
|
|
93
|
+
"--run-id-file",
|
|
94
|
+
default=None,
|
|
95
|
+
show_default=True,
|
|
96
|
+
type=str,
|
|
97
|
+
help="Write the ID of this run to the file specified.",
|
|
98
|
+
)
|
|
99
|
+
@click.option(
|
|
100
|
+
"--runner-attribute-file",
|
|
101
|
+
default=None,
|
|
102
|
+
show_default=True,
|
|
103
|
+
type=str,
|
|
104
|
+
help="Write the metadata and pathspec of this run to the file specified. Used internally "
|
|
105
|
+
"for Metaflow's Runner API.",
|
|
106
|
+
)
|
|
107
|
+
@wraps(func)
|
|
108
|
+
def wrapper(*args, **kwargs):
|
|
109
|
+
return func(*args, **kwargs)
|
|
110
|
+
|
|
111
|
+
return wrapper
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def write_file(file_path, content):
|
|
115
|
+
if file_path is not None:
|
|
116
|
+
with open(file_path, "w", encoding="utf-8") as f:
|
|
117
|
+
f.write(str(content))
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def config_callback(ctx, param, value):
|
|
121
|
+
# Callback to:
|
|
122
|
+
# - read the Click auto_envvar variable from both the
|
|
123
|
+
# environment AND the configuration
|
|
124
|
+
# - merge that value with the value passed in the command line (value)
|
|
125
|
+
# - return the value as a tuple
|
|
126
|
+
# Note that this function gets called even if there is no option passed on the
|
|
127
|
+
# command line.
|
|
128
|
+
# NOTE: Assumes that ctx.auto_envvar_prefix is set to METAFLOW (same as in
|
|
129
|
+
# from_conf)
|
|
130
|
+
|
|
131
|
+
# Read decospecs options from the environment (METAFLOW_DEFAULT_DECOSPECS=...)
|
|
132
|
+
# and merge them with the one provided as --with.
|
|
133
|
+
splits = DEFAULT_DECOSPECS.split()
|
|
134
|
+
return tuple(list(value) + splits)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def common_run_options(func):
|
|
138
|
+
@click.option(
|
|
139
|
+
"--tag",
|
|
140
|
+
"tags",
|
|
141
|
+
multiple=True,
|
|
142
|
+
default=None,
|
|
143
|
+
help="Annotate this run with the given tag. You can specify "
|
|
144
|
+
"this option multiple times to attach multiple tags in "
|
|
145
|
+
"the run.",
|
|
146
|
+
)
|
|
147
|
+
@click.option(
|
|
148
|
+
"--max-workers",
|
|
149
|
+
default=16,
|
|
150
|
+
show_default=True,
|
|
151
|
+
help="Maximum number of parallel processes.",
|
|
152
|
+
)
|
|
153
|
+
@click.option(
|
|
154
|
+
"--max-num-splits",
|
|
155
|
+
default=100,
|
|
156
|
+
show_default=True,
|
|
157
|
+
help="Maximum number of splits allowed in a foreach. This "
|
|
158
|
+
"is a safety check preventing bugs from triggering "
|
|
159
|
+
"thousands of steps inadvertently.",
|
|
160
|
+
)
|
|
161
|
+
@click.option(
|
|
162
|
+
"--max-log-size",
|
|
163
|
+
default=10,
|
|
164
|
+
show_default=True,
|
|
165
|
+
help="Maximum size of stdout and stderr captured in "
|
|
166
|
+
"megabytes. If a step outputs more than this to "
|
|
167
|
+
"stdout/stderr, its output will be truncated.",
|
|
168
|
+
)
|
|
169
|
+
@click.option(
|
|
170
|
+
"--with",
|
|
171
|
+
"decospecs",
|
|
172
|
+
multiple=True,
|
|
173
|
+
help="Add a decorator to all steps. You can specify this "
|
|
174
|
+
"option multiple times to attach multiple decorators "
|
|
175
|
+
"in steps.",
|
|
176
|
+
callback=config_callback,
|
|
177
|
+
)
|
|
178
|
+
@wraps(func)
|
|
179
|
+
def wrapper(*args, **kwargs):
|
|
180
|
+
return func(*args, **kwargs)
|
|
181
|
+
|
|
182
|
+
return wrapper
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@click.option(
|
|
186
|
+
"--origin-run-id",
|
|
187
|
+
default=None,
|
|
188
|
+
help="ID of the run that should be resumed. By default, the "
|
|
189
|
+
"last run executed locally.",
|
|
190
|
+
)
|
|
191
|
+
@click.option(
|
|
192
|
+
"--run-id",
|
|
193
|
+
default=None,
|
|
194
|
+
help="Run ID for the new run. By default, a new run-id will be generated",
|
|
195
|
+
hidden=True,
|
|
196
|
+
)
|
|
197
|
+
@click.option(
|
|
198
|
+
"--clone-only/--no-clone-only",
|
|
199
|
+
default=False,
|
|
200
|
+
show_default=True,
|
|
201
|
+
help="Only clone tasks without continuing execution",
|
|
202
|
+
hidden=True,
|
|
203
|
+
)
|
|
204
|
+
@click.option(
|
|
205
|
+
"--reentrant/--no-reentrant",
|
|
206
|
+
default=False,
|
|
207
|
+
show_default=True,
|
|
208
|
+
hidden=True,
|
|
209
|
+
help="If specified, allows this call to be called in parallel",
|
|
210
|
+
)
|
|
211
|
+
@click.option(
|
|
212
|
+
"--resume-identifier",
|
|
213
|
+
default=None,
|
|
214
|
+
show_default=True,
|
|
215
|
+
hidden=True,
|
|
216
|
+
help="If specified, it identifies the task that started this resume call. It is in the form of {step_name}-{task_id}",
|
|
217
|
+
)
|
|
218
|
+
@click.argument("step-to-rerun", required=False)
|
|
219
|
+
@click.command(help="Resume execution of a previous run of this flow.")
|
|
220
|
+
@tracing.cli("cli/resume")
|
|
221
|
+
@common_run_options
|
|
222
|
+
@common_runner_options
|
|
223
|
+
@click.pass_obj
|
|
224
|
+
def resume(
|
|
225
|
+
obj,
|
|
226
|
+
tags=None,
|
|
227
|
+
step_to_rerun=None,
|
|
228
|
+
origin_run_id=None,
|
|
229
|
+
run_id=None,
|
|
230
|
+
clone_only=False,
|
|
231
|
+
reentrant=False,
|
|
232
|
+
max_workers=None,
|
|
233
|
+
max_num_splits=None,
|
|
234
|
+
max_log_size=None,
|
|
235
|
+
decospecs=None,
|
|
236
|
+
run_id_file=None,
|
|
237
|
+
resume_identifier=None,
|
|
238
|
+
runner_attribute_file=None,
|
|
239
|
+
):
|
|
240
|
+
before_run(obj, tags, decospecs)
|
|
241
|
+
|
|
242
|
+
if origin_run_id is None:
|
|
243
|
+
origin_run_id = get_latest_run_id(obj.echo, obj.flow.name)
|
|
244
|
+
if origin_run_id is None:
|
|
245
|
+
raise CommandException(
|
|
246
|
+
"A previous run id was not found. Specify --origin-run-id."
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
if step_to_rerun is None:
|
|
250
|
+
steps_to_rerun = set()
|
|
251
|
+
else:
|
|
252
|
+
# validate step name
|
|
253
|
+
if step_to_rerun not in obj.graph.nodes:
|
|
254
|
+
raise CommandException(
|
|
255
|
+
"invalid step name {0} specified, must be step present in "
|
|
256
|
+
"current form of execution graph. Valid step names include: {1}".format(
|
|
257
|
+
step_to_rerun, ",".join(list(obj.graph.nodes.keys()))
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
## TODO: instead of checking execution path here, can add a warning later
|
|
262
|
+
## instead of throwing an error. This is for resuming a step which was not
|
|
263
|
+
## taken inside a branch i.e. not present in the execution path.
|
|
264
|
+
|
|
265
|
+
# origin_run = Run(f"{obj.flow.name}/{origin_run_id}", _namespace_check=False)
|
|
266
|
+
# executed_steps = {step.path_components[-1] for step in origin_run}
|
|
267
|
+
# if step_to_rerun not in executed_steps:
|
|
268
|
+
# raise CommandException(
|
|
269
|
+
# f"Cannot resume from step '{step_to_rerun}'. This step was not "
|
|
270
|
+
# f"part of the original execution path for run '{origin_run_id}'."
|
|
271
|
+
# )
|
|
272
|
+
|
|
273
|
+
steps_to_rerun = {step_to_rerun}
|
|
274
|
+
|
|
275
|
+
if run_id:
|
|
276
|
+
# Run-ids that are provided by the metadata service are always integers.
|
|
277
|
+
# External providers or run-ids (like external schedulers) always need to
|
|
278
|
+
# be non-integers to avoid any clashes. This condition ensures this.
|
|
279
|
+
try:
|
|
280
|
+
int(run_id)
|
|
281
|
+
except:
|
|
282
|
+
pass
|
|
283
|
+
else:
|
|
284
|
+
raise CommandException("run-id %s cannot be an integer" % run_id)
|
|
285
|
+
|
|
286
|
+
runtime = NativeRuntime(
|
|
287
|
+
obj.flow,
|
|
288
|
+
obj.graph,
|
|
289
|
+
obj.flow_datastore,
|
|
290
|
+
obj.metadata,
|
|
291
|
+
obj.environment,
|
|
292
|
+
obj.package,
|
|
293
|
+
obj.logger,
|
|
294
|
+
obj.entrypoint,
|
|
295
|
+
obj.event_logger,
|
|
296
|
+
obj.monitor,
|
|
297
|
+
run_id=run_id,
|
|
298
|
+
clone_run_id=origin_run_id,
|
|
299
|
+
clone_only=clone_only,
|
|
300
|
+
reentrant=reentrant,
|
|
301
|
+
steps_to_rerun=steps_to_rerun,
|
|
302
|
+
max_workers=max_workers,
|
|
303
|
+
max_num_splits=max_num_splits,
|
|
304
|
+
max_log_size=max_log_size * 1024 * 1024,
|
|
305
|
+
resume_identifier=resume_identifier,
|
|
306
|
+
)
|
|
307
|
+
write_file(run_id_file, runtime.run_id)
|
|
308
|
+
runtime.print_workflow_info()
|
|
309
|
+
|
|
310
|
+
runtime.persist_constants()
|
|
311
|
+
|
|
312
|
+
if runner_attribute_file:
|
|
313
|
+
with open(runner_attribute_file, "w", encoding="utf-8") as f:
|
|
314
|
+
json.dump(
|
|
315
|
+
{
|
|
316
|
+
"run_id": runtime.run_id,
|
|
317
|
+
"flow_name": obj.flow.name,
|
|
318
|
+
"metadata": obj.metadata.metadata_str(),
|
|
319
|
+
},
|
|
320
|
+
f,
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
# We may skip clone-only resume if this is not a resume leader,
|
|
324
|
+
# and clone is already complete.
|
|
325
|
+
if runtime.should_skip_clone_only_execution():
|
|
326
|
+
return
|
|
327
|
+
|
|
328
|
+
current._update_env(
|
|
329
|
+
{
|
|
330
|
+
"run_id": runtime.run_id,
|
|
331
|
+
}
|
|
332
|
+
)
|
|
333
|
+
_system_logger.log_event(
|
|
334
|
+
level="info",
|
|
335
|
+
module="metaflow.resume",
|
|
336
|
+
name="start",
|
|
337
|
+
payload={
|
|
338
|
+
"msg": "Resuming run",
|
|
339
|
+
},
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
with runtime.run_heartbeat():
|
|
343
|
+
if clone_only:
|
|
344
|
+
runtime.clone_original_run()
|
|
345
|
+
else:
|
|
346
|
+
runtime.clone_original_run(generate_task_obj=True, verbose=False)
|
|
347
|
+
runtime.execute()
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
@parameters.add_custom_parameters(deploy_mode=True)
|
|
351
|
+
@click.command(help="Run the workflow locally.")
|
|
352
|
+
@tracing.cli("cli/run")
|
|
353
|
+
@common_run_options
|
|
354
|
+
@common_runner_options
|
|
355
|
+
@click.option(
|
|
356
|
+
"--namespace",
|
|
357
|
+
"user_namespace",
|
|
358
|
+
default=None,
|
|
359
|
+
help="Change namespace from the default (your username) to "
|
|
360
|
+
"the specified tag. Note that this option does not alter "
|
|
361
|
+
"tags assigned to the objects produced by this run, just "
|
|
362
|
+
"what existing objects are visible in the client API. You "
|
|
363
|
+
"can enable the global namespace with an empty string."
|
|
364
|
+
"--namespace=",
|
|
365
|
+
)
|
|
366
|
+
@click.pass_obj
|
|
367
|
+
def run(
|
|
368
|
+
obj,
|
|
369
|
+
tags=None,
|
|
370
|
+
max_workers=None,
|
|
371
|
+
max_num_splits=None,
|
|
372
|
+
max_log_size=None,
|
|
373
|
+
decospecs=None,
|
|
374
|
+
run_id_file=None,
|
|
375
|
+
runner_attribute_file=None,
|
|
376
|
+
user_namespace=None,
|
|
377
|
+
**kwargs,
|
|
378
|
+
):
|
|
379
|
+
if user_namespace is not None:
|
|
380
|
+
namespace(user_namespace or None)
|
|
381
|
+
before_run(obj, tags, decospecs)
|
|
382
|
+
|
|
383
|
+
runtime = NativeRuntime(
|
|
384
|
+
obj.flow,
|
|
385
|
+
obj.graph,
|
|
386
|
+
obj.flow_datastore,
|
|
387
|
+
obj.metadata,
|
|
388
|
+
obj.environment,
|
|
389
|
+
obj.package,
|
|
390
|
+
obj.logger,
|
|
391
|
+
obj.entrypoint,
|
|
392
|
+
obj.event_logger,
|
|
393
|
+
obj.monitor,
|
|
394
|
+
max_workers=max_workers,
|
|
395
|
+
max_num_splits=max_num_splits,
|
|
396
|
+
max_log_size=max_log_size * 1024 * 1024,
|
|
397
|
+
)
|
|
398
|
+
write_latest_run_id(obj, runtime.run_id)
|
|
399
|
+
write_file(run_id_file, runtime.run_id)
|
|
400
|
+
|
|
401
|
+
obj.flow._set_constants(obj.graph, kwargs, obj.config_options)
|
|
402
|
+
current._update_env(
|
|
403
|
+
{
|
|
404
|
+
"run_id": runtime.run_id,
|
|
405
|
+
}
|
|
406
|
+
)
|
|
407
|
+
_system_logger.log_event(
|
|
408
|
+
level="info",
|
|
409
|
+
module="metaflow.run",
|
|
410
|
+
name="start",
|
|
411
|
+
payload={
|
|
412
|
+
"msg": "Starting run",
|
|
413
|
+
},
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
runtime.print_workflow_info()
|
|
417
|
+
runtime.persist_constants()
|
|
418
|
+
if runner_attribute_file:
|
|
419
|
+
with open(runner_attribute_file, "w", encoding="utf-8") as f:
|
|
420
|
+
json.dump(
|
|
421
|
+
{
|
|
422
|
+
"run_id": runtime.run_id,
|
|
423
|
+
"flow_name": obj.flow.name,
|
|
424
|
+
"metadata": obj.metadata.metadata_str(),
|
|
425
|
+
},
|
|
426
|
+
f,
|
|
427
|
+
)
|
|
428
|
+
with runtime.run_heartbeat():
|
|
429
|
+
runtime.execute()
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
# @parameters.add_custom_parameters(deploy_mode=True)
|
|
433
|
+
@click.command(help="Spins up a task for a given step from a previous run locally.")
|
|
434
|
+
@tracing.cli("cli/spin")
|
|
435
|
+
@click.argument("pathspec")
|
|
436
|
+
@click.option(
|
|
437
|
+
"--skip-decorators/--no-skip-decorators",
|
|
438
|
+
is_flag=True,
|
|
439
|
+
# Default False matches the saved_args check in cli.py for spin steps - skip_decorators
|
|
440
|
+
# only becomes True when explicitly passed, otherwise decorators are applied by default
|
|
441
|
+
default=False,
|
|
442
|
+
show_default=True,
|
|
443
|
+
help="Skip decorators attached to the step or flow.",
|
|
444
|
+
)
|
|
445
|
+
@click.option(
|
|
446
|
+
"--artifacts-module",
|
|
447
|
+
default=None,
|
|
448
|
+
show_default=True,
|
|
449
|
+
help="Path to a module that contains artifacts to be used in the spun step. "
|
|
450
|
+
"The artifacts should be defined as a dictionary called ARTIFACTS with keys as "
|
|
451
|
+
"the artifact names and values as the artifact values. The artifact values will "
|
|
452
|
+
"overwrite the default values of the artifacts used in the spun step.",
|
|
453
|
+
)
|
|
454
|
+
@click.option(
|
|
455
|
+
"--persist/--no-persist",
|
|
456
|
+
"persist",
|
|
457
|
+
default=SPIN_PERSIST,
|
|
458
|
+
show_default=True,
|
|
459
|
+
help="Whether to persist the artifacts in the spun step. If set to False, "
|
|
460
|
+
"the artifacts will not be persisted and will not be available in the spun step's "
|
|
461
|
+
"datastore.",
|
|
462
|
+
)
|
|
463
|
+
@click.option(
|
|
464
|
+
"--max-log-size",
|
|
465
|
+
default=10,
|
|
466
|
+
show_default=True,
|
|
467
|
+
help="Maximum size of stdout and stderr captured in "
|
|
468
|
+
"megabytes. If a step outputs more than this to "
|
|
469
|
+
"stdout/stderr, its output will be truncated.",
|
|
470
|
+
)
|
|
471
|
+
@common_runner_options
|
|
472
|
+
@click.pass_obj
|
|
473
|
+
def spin(
|
|
474
|
+
obj,
|
|
475
|
+
pathspec,
|
|
476
|
+
persist=True,
|
|
477
|
+
artifacts_module=None,
|
|
478
|
+
skip_decorators=False,
|
|
479
|
+
max_log_size=None,
|
|
480
|
+
run_id_file=None,
|
|
481
|
+
runner_attribute_file=None,
|
|
482
|
+
**kwargs,
|
|
483
|
+
):
|
|
484
|
+
# Parse the pathspec argument to extract step name and full pathspec
|
|
485
|
+
step_name, parsed_pathspec = parse_spin_pathspec(pathspec, obj.flow.name)
|
|
486
|
+
|
|
487
|
+
before_run(obj, [], [], skip_decorators)
|
|
488
|
+
obj.echo(f"Spinning up step *{step_name}* locally for flow *{obj.flow.name}*")
|
|
489
|
+
# For spin, flow parameters come from the original run, but _set_constants
|
|
490
|
+
# requires them in kwargs. Use parameter defaults as placeholders - they'll be
|
|
491
|
+
# overwritten when the spin step loads artifacts from the original run.
|
|
492
|
+
flow_param_defaults = {}
|
|
493
|
+
for var, param in obj.flow._get_parameters():
|
|
494
|
+
if not param.IS_CONFIG_PARAMETER:
|
|
495
|
+
default_value = param.kwargs.get("default")
|
|
496
|
+
# Use None for required parameters without defaults
|
|
497
|
+
flow_param_defaults[param.name.replace("-", "_").lower()] = default_value
|
|
498
|
+
obj.flow._set_constants(obj.graph, flow_param_defaults, obj.config_options)
|
|
499
|
+
step_func = getattr(obj.flow, step_name, None)
|
|
500
|
+
if step_func is None:
|
|
501
|
+
raise CommandException(
|
|
502
|
+
f"Step '{step_name}' not found in flow '{obj.flow.name}'. "
|
|
503
|
+
"Please provide a valid step name."
|
|
504
|
+
)
|
|
505
|
+
from_start("Spin: before spin runtime init")
|
|
506
|
+
spin_runtime = SpinRuntime(
|
|
507
|
+
obj.flow,
|
|
508
|
+
obj.graph,
|
|
509
|
+
obj.flow_datastore,
|
|
510
|
+
obj.metadata,
|
|
511
|
+
obj.environment,
|
|
512
|
+
obj.package,
|
|
513
|
+
obj.logger,
|
|
514
|
+
obj.entrypoint,
|
|
515
|
+
obj.event_logger,
|
|
516
|
+
obj.monitor,
|
|
517
|
+
step_func,
|
|
518
|
+
step_name,
|
|
519
|
+
parsed_pathspec,
|
|
520
|
+
skip_decorators,
|
|
521
|
+
artifacts_module,
|
|
522
|
+
persist,
|
|
523
|
+
max_log_size * 1024 * 1024,
|
|
524
|
+
)
|
|
525
|
+
write_latest_run_id(obj, spin_runtime.run_id)
|
|
526
|
+
write_file(run_id_file, spin_runtime.run_id)
|
|
527
|
+
# We only need the root for the metadata, i.e. the portion before DATASTORE_LOCAL_DIR
|
|
528
|
+
datastore_root = spin_runtime._flow_datastore._storage_impl.datastore_root
|
|
529
|
+
orig_task_metadata_root = datastore_root.rsplit("/", 1)[0]
|
|
530
|
+
from_start("Spin: going to execute")
|
|
531
|
+
spin_runtime.execute()
|
|
532
|
+
from_start("Spin: after spin runtime execute")
|
|
533
|
+
|
|
534
|
+
if runner_attribute_file:
|
|
535
|
+
with open(runner_attribute_file, "w") as f:
|
|
536
|
+
json.dump(
|
|
537
|
+
{
|
|
538
|
+
"task_id": spin_runtime.task.task_id,
|
|
539
|
+
"step_name": step_name,
|
|
540
|
+
"run_id": spin_runtime.run_id,
|
|
541
|
+
"flow_name": obj.flow.name,
|
|
542
|
+
# Store metadata in a format that can be used by the Runner API
|
|
543
|
+
"metadata": f"{obj.metadata.__class__.TYPE}@{orig_task_metadata_root}",
|
|
544
|
+
},
|
|
545
|
+
f,
|
|
546
|
+
)
|