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
|
@@ -2,20 +2,30 @@ import collections
|
|
|
2
2
|
import glob
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
|
+
import re
|
|
5
6
|
import random
|
|
6
7
|
import tempfile
|
|
7
8
|
import time
|
|
8
9
|
from collections import namedtuple
|
|
10
|
+
from typing import List
|
|
9
11
|
|
|
10
12
|
from metaflow.exception import MetaflowInternalError, MetaflowTaggingError
|
|
11
|
-
from metaflow.
|
|
13
|
+
from metaflow.metadata_provider.metadata import ObjectOrder
|
|
12
14
|
from metaflow.metaflow_config import DATASTORE_LOCAL_DIR
|
|
13
|
-
from metaflow.
|
|
15
|
+
from metaflow.metadata_provider import MetadataProvider
|
|
14
16
|
from metaflow.tagging_util import MAX_USER_TAG_SET_SIZE, validate_tags
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
class LocalMetadataProvider(MetadataProvider):
|
|
18
20
|
TYPE = "local"
|
|
21
|
+
DATASTORE_DIR = DATASTORE_LOCAL_DIR # ".metaflow"
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def _get_storage_class(cls):
|
|
25
|
+
# This method is meant to be overridden
|
|
26
|
+
from metaflow.plugins.datastores.local_storage import LocalStorage
|
|
27
|
+
|
|
28
|
+
return LocalStorage
|
|
19
29
|
|
|
20
30
|
def __init__(self, environment, flow, event_logger, monitor):
|
|
21
31
|
super(LocalMetadataProvider, self).__init__(
|
|
@@ -24,30 +34,28 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
24
34
|
|
|
25
35
|
@classmethod
|
|
26
36
|
def compute_info(cls, val):
|
|
27
|
-
|
|
37
|
+
storage_class = cls._get_storage_class()
|
|
28
38
|
|
|
29
|
-
v = os.path.realpath(os.path.join(val,
|
|
39
|
+
v = os.path.realpath(os.path.join(val, cls.DATASTORE_DIR))
|
|
30
40
|
if os.path.isdir(v):
|
|
31
|
-
|
|
41
|
+
storage_class.datastore_root = v
|
|
32
42
|
return val
|
|
33
43
|
raise ValueError(
|
|
34
|
-
"Could not find directory %s in directory %s" % (
|
|
44
|
+
"Could not find directory %s in directory %s" % (cls.DATASTORE_DIR, val)
|
|
35
45
|
)
|
|
36
46
|
|
|
37
47
|
@classmethod
|
|
38
48
|
def default_info(cls):
|
|
39
|
-
|
|
49
|
+
storage_class = cls._get_storage_class()
|
|
40
50
|
|
|
41
51
|
def print_clean(line, **kwargs):
|
|
42
52
|
print(line)
|
|
43
53
|
|
|
44
|
-
v =
|
|
54
|
+
v = storage_class.get_datastore_root_from_config(
|
|
45
55
|
print_clean, create_on_absent=False
|
|
46
56
|
)
|
|
47
57
|
if v is None:
|
|
48
|
-
return
|
|
49
|
-
"<No %s directory found in current working tree>" % DATASTORE_LOCAL_DIR
|
|
50
|
-
)
|
|
58
|
+
return "<No %s directory found in current working tree>" % cls.DATASTORE_DIR
|
|
51
59
|
return os.path.dirname(v)
|
|
52
60
|
|
|
53
61
|
def version(self):
|
|
@@ -100,7 +108,7 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
100
108
|
def register_data_artifacts(
|
|
101
109
|
self, run_id, step_name, task_id, attempt_id, artifacts
|
|
102
110
|
):
|
|
103
|
-
meta_dir = self._create_and_get_metadir(
|
|
111
|
+
meta_dir = self.__class__._create_and_get_metadir(
|
|
104
112
|
self._flow_name, run_id, step_name, task_id
|
|
105
113
|
)
|
|
106
114
|
artlist = self._artifacts_to_json(
|
|
@@ -110,7 +118,7 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
110
118
|
self._save_meta(meta_dir, artdict)
|
|
111
119
|
|
|
112
120
|
def register_metadata(self, run_id, step_name, task_id, metadata):
|
|
113
|
-
meta_dir = self._create_and_get_metadir(
|
|
121
|
+
meta_dir = self.__class__._create_and_get_metadir(
|
|
114
122
|
self._flow_name, run_id, step_name, task_id
|
|
115
123
|
)
|
|
116
124
|
metalist = self._metadata_to_json(run_id, step_name, task_id, metadata)
|
|
@@ -130,9 +138,7 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
130
138
|
|
|
131
139
|
def _optimistically_mutate():
|
|
132
140
|
# get existing tags
|
|
133
|
-
run =
|
|
134
|
-
"run", "self", {}, None, flow_id, run_id
|
|
135
|
-
)
|
|
141
|
+
run = cls.get_object("run", "self", {}, None, flow_id, run_id)
|
|
136
142
|
if not run:
|
|
137
143
|
raise MetaflowTaggingError(
|
|
138
144
|
msg="Run not found (%s, %s)" % (flow_id, run_id)
|
|
@@ -165,15 +171,13 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
165
171
|
validate_tags(next_user_tags_set, existing_tags=existing_user_tag_set)
|
|
166
172
|
|
|
167
173
|
# write new tag set to file system
|
|
168
|
-
|
|
174
|
+
cls._persist_tags_for_run(
|
|
169
175
|
flow_id, run_id, next_user_tags_set, existing_system_tag_set
|
|
170
176
|
)
|
|
171
177
|
|
|
172
178
|
# read tags back from file system to see if our optimism is misplaced
|
|
173
179
|
# I.e. did a concurrent mutate overwrite our change
|
|
174
|
-
run =
|
|
175
|
-
"run", "self", {}, None, flow_id, run_id
|
|
176
|
-
)
|
|
180
|
+
run = cls.get_object("run", "self", {}, None, flow_id, run_id)
|
|
177
181
|
if not run:
|
|
178
182
|
raise MetaflowTaggingError(
|
|
179
183
|
msg="Run not found for read-back check (%s, %s)" % (flow_id, run_id)
|
|
@@ -202,6 +206,70 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
202
206
|
"Tagging failed due to too many conflicting updates from other processes"
|
|
203
207
|
)
|
|
204
208
|
|
|
209
|
+
@classmethod
|
|
210
|
+
def filter_tasks_by_metadata(
|
|
211
|
+
cls,
|
|
212
|
+
flow_name: str,
|
|
213
|
+
run_id: str,
|
|
214
|
+
step_name: str,
|
|
215
|
+
field_name: str,
|
|
216
|
+
pattern: str,
|
|
217
|
+
) -> List[str]:
|
|
218
|
+
"""
|
|
219
|
+
Filter tasks by metadata field and pattern, returning task pathspecs that match criteria.
|
|
220
|
+
|
|
221
|
+
Parameters
|
|
222
|
+
----------
|
|
223
|
+
flow_name : str
|
|
224
|
+
Identifier for the flow
|
|
225
|
+
run_id : str
|
|
226
|
+
Identifier for the run
|
|
227
|
+
step_name : str
|
|
228
|
+
Name of the step to query tasks from
|
|
229
|
+
field_name : str
|
|
230
|
+
Name of metadata field to query
|
|
231
|
+
pattern : str
|
|
232
|
+
Pattern to match in metadata field value
|
|
233
|
+
|
|
234
|
+
Returns
|
|
235
|
+
-------
|
|
236
|
+
List[str]
|
|
237
|
+
List of task pathspecs that match the query criteria
|
|
238
|
+
"""
|
|
239
|
+
tasks = cls.get_object("step", "task", {}, None, flow_name, run_id, step_name)
|
|
240
|
+
if not tasks:
|
|
241
|
+
return []
|
|
242
|
+
|
|
243
|
+
regex = re.compile(pattern)
|
|
244
|
+
matching_task_pathspecs = []
|
|
245
|
+
|
|
246
|
+
for task in tasks:
|
|
247
|
+
task_id = task.get("task_id")
|
|
248
|
+
if not task_id:
|
|
249
|
+
continue
|
|
250
|
+
|
|
251
|
+
if pattern == ".*":
|
|
252
|
+
# If the pattern is ".*", we can match all tasks without reading metadata
|
|
253
|
+
matching_task_pathspecs.append(
|
|
254
|
+
f"{flow_name}/{run_id}/{step_name}/{task_id}"
|
|
255
|
+
)
|
|
256
|
+
continue
|
|
257
|
+
|
|
258
|
+
metadata = cls.get_object(
|
|
259
|
+
"task", "metadata", {}, None, flow_name, run_id, step_name, task_id
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
if any(
|
|
263
|
+
meta.get("field_name") == field_name
|
|
264
|
+
and regex.match(meta.get("value", ""))
|
|
265
|
+
for meta in metadata
|
|
266
|
+
):
|
|
267
|
+
matching_task_pathspecs.append(
|
|
268
|
+
f"{flow_name}/{run_id}/{step_name}/{task_id}"
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
return matching_task_pathspecs
|
|
272
|
+
|
|
205
273
|
@classmethod
|
|
206
274
|
def _get_object_internal(
|
|
207
275
|
cls, obj_type, obj_order, sub_type, sub_order, filters, attempt, *args
|
|
@@ -213,8 +281,6 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
213
281
|
if obj_type not in ("root", "flow", "run", "step", "task", "artifact"):
|
|
214
282
|
raise MetaflowInternalError(msg="Unexpected object type %s" % obj_type)
|
|
215
283
|
|
|
216
|
-
from metaflow.plugins.datastores.local_storage import LocalStorage
|
|
217
|
-
|
|
218
284
|
if obj_type == "artifact":
|
|
219
285
|
# Artifacts are actually part of the tasks in the filesystem
|
|
220
286
|
# E.g. we get here for (obj_type, sub_type) == (artifact, self)
|
|
@@ -241,13 +307,13 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
241
307
|
|
|
242
308
|
# Special handling of self, artifact, and metadata
|
|
243
309
|
if sub_type == "self":
|
|
244
|
-
meta_path =
|
|
310
|
+
meta_path = cls._get_metadir(*args[:obj_order])
|
|
245
311
|
if meta_path is None:
|
|
246
312
|
return None
|
|
247
313
|
self_file = os.path.join(meta_path, "_self.json")
|
|
248
314
|
if os.path.isfile(self_file):
|
|
249
315
|
obj = MetadataProvider._apply_filter(
|
|
250
|
-
[
|
|
316
|
+
[cls._read_json_file(self_file)], filters
|
|
251
317
|
)[0]
|
|
252
318
|
# For non-descendants of a run, we are done
|
|
253
319
|
|
|
@@ -258,7 +324,7 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
258
324
|
raise MetaflowInternalError(
|
|
259
325
|
msg="Unexpected object type %s" % obj_type
|
|
260
326
|
)
|
|
261
|
-
run =
|
|
327
|
+
run = cls.get_object(
|
|
262
328
|
"run", "self", {}, None, *args[:RUN_ORDER] # *[flow_id, run_id]
|
|
263
329
|
)
|
|
264
330
|
if not run:
|
|
@@ -275,7 +341,7 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
275
341
|
if obj_type not in ("root", "flow", "run", "step", "task"):
|
|
276
342
|
raise MetaflowInternalError(msg="Unexpected object type %s" % obj_type)
|
|
277
343
|
|
|
278
|
-
meta_path =
|
|
344
|
+
meta_path = cls._get_metadir(*args[:obj_order])
|
|
279
345
|
result = []
|
|
280
346
|
if meta_path is None:
|
|
281
347
|
return result
|
|
@@ -286,9 +352,7 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
286
352
|
attempts_done = sorted(glob.iglob(attempt_done_files))
|
|
287
353
|
if attempts_done:
|
|
288
354
|
successful_attempt = int(
|
|
289
|
-
|
|
290
|
-
"value"
|
|
291
|
-
]
|
|
355
|
+
cls._read_json_file(attempts_done[-1])["value"]
|
|
292
356
|
)
|
|
293
357
|
if successful_attempt is not None:
|
|
294
358
|
which_artifact = "*"
|
|
@@ -299,10 +363,10 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
299
363
|
"%d_artifact_%s.json" % (successful_attempt, which_artifact),
|
|
300
364
|
)
|
|
301
365
|
for obj in glob.iglob(artifact_files):
|
|
302
|
-
result.append(
|
|
366
|
+
result.append(cls._read_json_file(obj))
|
|
303
367
|
|
|
304
368
|
# We are getting artifacts. We should overlay with ancestral run's tags
|
|
305
|
-
run =
|
|
369
|
+
run = cls.get_object(
|
|
306
370
|
"run", "self", {}, None, *args[:RUN_ORDER] # *[flow_id, run_id]
|
|
307
371
|
)
|
|
308
372
|
if not run:
|
|
@@ -322,12 +386,12 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
322
386
|
if obj_type not in ("root", "flow", "run", "step", "task"):
|
|
323
387
|
raise MetaflowInternalError(msg="Unexpected object type %s" % obj_type)
|
|
324
388
|
result = []
|
|
325
|
-
meta_path =
|
|
389
|
+
meta_path = cls._get_metadir(*args[:obj_order])
|
|
326
390
|
if meta_path is None:
|
|
327
391
|
return result
|
|
328
392
|
files = os.path.join(meta_path, "sysmeta_*")
|
|
329
393
|
for obj in glob.iglob(files):
|
|
330
|
-
result.append(
|
|
394
|
+
result.append(cls._read_json_file(obj))
|
|
331
395
|
return result
|
|
332
396
|
|
|
333
397
|
# For the other types, we locate all the objects we need to find and return them
|
|
@@ -335,14 +399,13 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
335
399
|
raise MetaflowInternalError(msg="Unexpected object type %s" % obj_type)
|
|
336
400
|
if sub_type not in ("flow", "run", "step", "task"):
|
|
337
401
|
raise MetaflowInternalError(msg="unexpected sub type %s" % sub_type)
|
|
338
|
-
obj_path =
|
|
339
|
-
*args[:obj_order], create_on_absent=False
|
|
340
|
-
)
|
|
402
|
+
obj_path = cls._make_path(*args[:obj_order], create_on_absent=False)
|
|
341
403
|
result = []
|
|
342
404
|
if obj_path is None:
|
|
343
405
|
return result
|
|
344
406
|
skip_dirs = "*/" * (sub_order - obj_order)
|
|
345
|
-
|
|
407
|
+
storage_class = cls._get_storage_class()
|
|
408
|
+
all_meta = os.path.join(obj_path, skip_dirs, storage_class.METADATA_DIR)
|
|
346
409
|
SelfInfo = collections.namedtuple("SelfInfo", ["filepath", "run_id"])
|
|
347
410
|
self_infos = []
|
|
348
411
|
for meta_path in glob.iglob(all_meta):
|
|
@@ -352,9 +415,7 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
352
415
|
run_id = None
|
|
353
416
|
# flow and run do not need info from ancestral run
|
|
354
417
|
if sub_type in ("step", "task"):
|
|
355
|
-
run_id =
|
|
356
|
-
meta_path, sub_type
|
|
357
|
-
)
|
|
418
|
+
run_id = cls._deduce_run_id_from_meta_dir(meta_path, sub_type)
|
|
358
419
|
# obj_type IS run, or more granular than run, let's do sanity check vs args
|
|
359
420
|
if obj_order >= RUN_ORDER:
|
|
360
421
|
if run_id != args[RUN_ORDER - 1]:
|
|
@@ -364,10 +425,10 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
364
425
|
self_infos.append(SelfInfo(filepath=self_file, run_id=run_id))
|
|
365
426
|
|
|
366
427
|
for self_info in self_infos:
|
|
367
|
-
obj =
|
|
428
|
+
obj = cls._read_json_file(self_info.filepath)
|
|
368
429
|
if self_info.run_id:
|
|
369
430
|
flow_id_from_args = args[0]
|
|
370
|
-
run =
|
|
431
|
+
run = cls.get_object(
|
|
371
432
|
"run",
|
|
372
433
|
"self",
|
|
373
434
|
{},
|
|
@@ -386,8 +447,8 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
386
447
|
|
|
387
448
|
return MetadataProvider._apply_filter(result, filters)
|
|
388
449
|
|
|
389
|
-
@
|
|
390
|
-
def _deduce_run_id_from_meta_dir(meta_dir_path, sub_type):
|
|
450
|
+
@classmethod
|
|
451
|
+
def _deduce_run_id_from_meta_dir(cls, meta_dir_path, sub_type):
|
|
391
452
|
curr_order = ObjectOrder.type_to_order(sub_type)
|
|
392
453
|
levels_to_ascend = curr_order - ObjectOrder.type_to_order("run")
|
|
393
454
|
if levels_to_ascend < 0:
|
|
@@ -402,8 +463,8 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
402
463
|
)
|
|
403
464
|
return run_id
|
|
404
465
|
|
|
405
|
-
@
|
|
406
|
-
def _makedirs(path):
|
|
466
|
+
@classmethod
|
|
467
|
+
def _makedirs(cls, path):
|
|
407
468
|
# this is for python2 compatibility.
|
|
408
469
|
# Python3 has os.makedirs(exist_ok=True).
|
|
409
470
|
try:
|
|
@@ -415,17 +476,15 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
415
476
|
else:
|
|
416
477
|
raise
|
|
417
478
|
|
|
418
|
-
@
|
|
419
|
-
def _persist_tags_for_run(flow_id, run_id, tags, system_tags):
|
|
420
|
-
subpath =
|
|
421
|
-
flow_name=flow_id, run_id=run_id
|
|
422
|
-
)
|
|
479
|
+
@classmethod
|
|
480
|
+
def _persist_tags_for_run(cls, flow_id, run_id, tags, system_tags):
|
|
481
|
+
subpath = cls._create_and_get_metadir(flow_name=flow_id, run_id=run_id)
|
|
423
482
|
selfname = os.path.join(subpath, "_self.json")
|
|
424
483
|
if not os.path.isfile(selfname):
|
|
425
484
|
raise MetaflowInternalError(
|
|
426
485
|
msg="Could not verify Run existence on disk - missing %s" % selfname
|
|
427
486
|
)
|
|
428
|
-
|
|
487
|
+
cls._save_meta(
|
|
429
488
|
subpath,
|
|
430
489
|
{
|
|
431
490
|
"_self": MetadataProvider._run_to_json_static(
|
|
@@ -442,11 +501,11 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
442
501
|
tags = set()
|
|
443
502
|
if sys_tags is None:
|
|
444
503
|
sys_tags = set()
|
|
445
|
-
subpath = self._create_and_get_metadir(
|
|
504
|
+
subpath = self.__class__._create_and_get_metadir(
|
|
446
505
|
self._flow_name, run_id, step_name, task_id
|
|
447
506
|
)
|
|
448
507
|
selfname = os.path.join(subpath, "_self.json")
|
|
449
|
-
self._makedirs(subpath)
|
|
508
|
+
self.__class__._makedirs(subpath)
|
|
450
509
|
if os.path.isfile(selfname):
|
|
451
510
|
# There is a race here, but we are not aiming to make this as solid as
|
|
452
511
|
# the metadata service. This is used primarily for concurrent resumes,
|
|
@@ -483,26 +542,31 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
483
542
|
self._register_system_metadata(run_id, step_name, task_id, attempt)
|
|
484
543
|
return to_return
|
|
485
544
|
|
|
486
|
-
@
|
|
545
|
+
@classmethod
|
|
487
546
|
def _make_path(
|
|
488
|
-
|
|
547
|
+
cls,
|
|
548
|
+
flow_name=None,
|
|
549
|
+
run_id=None,
|
|
550
|
+
step_name=None,
|
|
551
|
+
task_id=None,
|
|
552
|
+
create_on_absent=True,
|
|
489
553
|
):
|
|
490
554
|
|
|
491
|
-
|
|
555
|
+
storage_class = cls._get_storage_class()
|
|
492
556
|
|
|
493
|
-
if
|
|
557
|
+
if storage_class.datastore_root is None:
|
|
494
558
|
|
|
495
559
|
def print_clean(line, **kwargs):
|
|
496
560
|
print(line)
|
|
497
561
|
|
|
498
|
-
|
|
562
|
+
storage_class.datastore_root = storage_class.get_datastore_root_from_config(
|
|
499
563
|
print_clean, create_on_absent=create_on_absent
|
|
500
564
|
)
|
|
501
|
-
if
|
|
565
|
+
if storage_class.datastore_root is None:
|
|
502
566
|
return None
|
|
503
567
|
|
|
504
568
|
if flow_name is None:
|
|
505
|
-
return
|
|
569
|
+
return storage_class.datastore_root
|
|
506
570
|
components = []
|
|
507
571
|
if flow_name:
|
|
508
572
|
components.append(flow_name)
|
|
@@ -512,37 +576,35 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
512
576
|
components.append(step_name)
|
|
513
577
|
if task_id:
|
|
514
578
|
components.append(task_id)
|
|
515
|
-
return
|
|
579
|
+
return storage_class().full_uri(storage_class.path_join(*components))
|
|
516
580
|
|
|
517
|
-
@
|
|
581
|
+
@classmethod
|
|
518
582
|
def _create_and_get_metadir(
|
|
519
|
-
flow_name=None, run_id=None, step_name=None, task_id=None
|
|
583
|
+
cls, flow_name=None, run_id=None, step_name=None, task_id=None
|
|
520
584
|
):
|
|
521
|
-
|
|
585
|
+
storage_class = cls._get_storage_class()
|
|
522
586
|
|
|
523
|
-
root_path =
|
|
524
|
-
|
|
525
|
-
)
|
|
526
|
-
subpath = os.path.join(root_path, LocalStorage.METADATA_DIR)
|
|
527
|
-
LocalMetadataProvider._makedirs(subpath)
|
|
587
|
+
root_path = cls._make_path(flow_name, run_id, step_name, task_id)
|
|
588
|
+
subpath = os.path.join(root_path, storage_class.METADATA_DIR)
|
|
589
|
+
cls._makedirs(subpath)
|
|
528
590
|
return subpath
|
|
529
591
|
|
|
530
|
-
@
|
|
531
|
-
def _get_metadir(flow_name=None, run_id=None, step_name=None, task_id=None):
|
|
532
|
-
|
|
592
|
+
@classmethod
|
|
593
|
+
def _get_metadir(cls, flow_name=None, run_id=None, step_name=None, task_id=None):
|
|
594
|
+
storage_class = cls._get_storage_class()
|
|
533
595
|
|
|
534
|
-
root_path =
|
|
596
|
+
root_path = cls._make_path(
|
|
535
597
|
flow_name, run_id, step_name, task_id, create_on_absent=False
|
|
536
598
|
)
|
|
537
599
|
if root_path is None:
|
|
538
600
|
return None
|
|
539
|
-
subpath = os.path.join(root_path,
|
|
601
|
+
subpath = os.path.join(root_path, storage_class.METADATA_DIR)
|
|
540
602
|
if os.path.isdir(subpath):
|
|
541
603
|
return subpath
|
|
542
604
|
return None
|
|
543
605
|
|
|
544
|
-
@
|
|
545
|
-
def _dump_json_to_file(filepath, data, allow_overwrite=False):
|
|
606
|
+
@classmethod
|
|
607
|
+
def _dump_json_to_file(cls, filepath, data, allow_overwrite=False):
|
|
546
608
|
if os.path.isfile(filepath) and not allow_overwrite:
|
|
547
609
|
return
|
|
548
610
|
try:
|
|
@@ -556,15 +618,13 @@ class LocalMetadataProvider(MetadataProvider):
|
|
|
556
618
|
if f and os.path.isfile(f.name):
|
|
557
619
|
os.remove(f.name)
|
|
558
620
|
|
|
559
|
-
@
|
|
560
|
-
def _read_json_file(filepath):
|
|
621
|
+
@classmethod
|
|
622
|
+
def _read_json_file(cls, filepath):
|
|
561
623
|
with open(filepath, "r") as f:
|
|
562
624
|
return json.load(f)
|
|
563
625
|
|
|
564
|
-
@
|
|
565
|
-
def _save_meta(root_dir, metadict, allow_overwrite=False):
|
|
626
|
+
@classmethod
|
|
627
|
+
def _save_meta(cls, root_dir, metadict, allow_overwrite=False):
|
|
566
628
|
for name, datum in metadict.items():
|
|
567
629
|
filename = os.path.join(root_dir, "%s.json" % name)
|
|
568
|
-
|
|
569
|
-
filename, datum, allow_overwrite=allow_overwrite
|
|
570
|
-
)
|
|
630
|
+
cls._dump_json_to_file(filename, datum, allow_overwrite=allow_overwrite)
|
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import random
|
|
3
|
+
import time
|
|
3
4
|
|
|
4
5
|
import requests
|
|
5
|
-
import time
|
|
6
6
|
|
|
7
|
+
from typing import List
|
|
7
8
|
from metaflow.exception import (
|
|
8
9
|
MetaflowException,
|
|
9
|
-
MetaflowTaggingError,
|
|
10
10
|
MetaflowInternalError,
|
|
11
|
+
MetaflowTaggingError,
|
|
11
12
|
)
|
|
12
|
-
from metaflow.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
SERVICE_URL,
|
|
16
|
-
)
|
|
17
|
-
from metaflow.metadata import MetadataProvider
|
|
18
|
-
from metaflow.metadata.heartbeat import HB_URL_KEY
|
|
13
|
+
from metaflow.metadata_provider import MetadataProvider
|
|
14
|
+
from metaflow.metadata_provider.heartbeat import HB_URL_KEY
|
|
15
|
+
from metaflow.metaflow_config import SERVICE_HEADERS, SERVICE_RETRY_COUNT, SERVICE_URL
|
|
19
16
|
from metaflow.sidecar import Message, MessageTypes, Sidecar
|
|
20
|
-
|
|
17
|
+
from urllib.parse import urlencode
|
|
21
18
|
from metaflow.util import version_parse
|
|
22
19
|
|
|
23
20
|
|
|
@@ -39,6 +36,23 @@ class ServiceException(MetaflowException):
|
|
|
39
36
|
class ServiceMetadataProvider(MetadataProvider):
|
|
40
37
|
TYPE = "service"
|
|
41
38
|
|
|
39
|
+
_session = requests.Session()
|
|
40
|
+
_session.mount(
|
|
41
|
+
"http://",
|
|
42
|
+
requests.adapters.HTTPAdapter(
|
|
43
|
+
pool_connections=20,
|
|
44
|
+
pool_maxsize=20,
|
|
45
|
+
max_retries=0, # Handle retries explicitly
|
|
46
|
+
pool_block=False,
|
|
47
|
+
),
|
|
48
|
+
)
|
|
49
|
+
_session.mount(
|
|
50
|
+
"https://",
|
|
51
|
+
requests.adapters.HTTPAdapter(
|
|
52
|
+
pool_connections=20, pool_maxsize=20, max_retries=0, pool_block=False
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
|
|
42
56
|
_supports_attempt_gets = None
|
|
43
57
|
_supports_tag_mutation = None
|
|
44
58
|
|
|
@@ -58,12 +72,18 @@ class ServiceMetadataProvider(MetadataProvider):
|
|
|
58
72
|
@classmethod
|
|
59
73
|
def compute_info(cls, val):
|
|
60
74
|
v = val.rstrip("/")
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
for i in range(SERVICE_RETRY_COUNT):
|
|
76
|
+
try:
|
|
77
|
+
resp = cls._session.get(
|
|
78
|
+
os.path.join(v, "ping"), headers=SERVICE_HEADERS.copy()
|
|
79
|
+
)
|
|
80
|
+
resp.raise_for_status()
|
|
81
|
+
except: # noqa E722
|
|
82
|
+
time.sleep(2 ** (i - 1))
|
|
83
|
+
else:
|
|
84
|
+
return v
|
|
85
|
+
|
|
86
|
+
raise ValueError("Metaflow service [%s] unreachable." % v)
|
|
67
87
|
|
|
68
88
|
@classmethod
|
|
69
89
|
def default_info(cls):
|
|
@@ -304,6 +324,64 @@ class ServiceMetadataProvider(MetadataProvider):
|
|
|
304
324
|
self._register_system_metadata(run_id, step_name, task["task_id"], attempt)
|
|
305
325
|
return task["task_id"], did_create
|
|
306
326
|
|
|
327
|
+
@classmethod
|
|
328
|
+
def filter_tasks_by_metadata(
|
|
329
|
+
cls,
|
|
330
|
+
flow_name: str,
|
|
331
|
+
run_id: str,
|
|
332
|
+
step_name: str,
|
|
333
|
+
field_name: str,
|
|
334
|
+
pattern: str,
|
|
335
|
+
) -> List[str]:
|
|
336
|
+
"""
|
|
337
|
+
Filter tasks by metadata field and pattern, returning task pathspecs that match criteria.
|
|
338
|
+
|
|
339
|
+
Parameters
|
|
340
|
+
----------
|
|
341
|
+
flow_name : str
|
|
342
|
+
Flow name, that the run belongs to.
|
|
343
|
+
run_id: str
|
|
344
|
+
Run id, together with flow_id, that identifies the specific Run whose tasks to query
|
|
345
|
+
step_name: str
|
|
346
|
+
Step name to query tasks from
|
|
347
|
+
field_name: str
|
|
348
|
+
Metadata field name to query
|
|
349
|
+
pattern: str
|
|
350
|
+
Pattern to match in metadata field value
|
|
351
|
+
|
|
352
|
+
Returns
|
|
353
|
+
-------
|
|
354
|
+
List[str]
|
|
355
|
+
List of task pathspecs that satisfy the query
|
|
356
|
+
"""
|
|
357
|
+
query_params = {}
|
|
358
|
+
|
|
359
|
+
if pattern == ".*":
|
|
360
|
+
# we do not need to filter tasks at all if pattern allows 'any'
|
|
361
|
+
query_params = {}
|
|
362
|
+
else:
|
|
363
|
+
if field_name:
|
|
364
|
+
query_params["metadata_field_name"] = field_name
|
|
365
|
+
if pattern:
|
|
366
|
+
query_params["pattern"] = pattern
|
|
367
|
+
|
|
368
|
+
url = ServiceMetadataProvider._obj_path(flow_name, run_id, step_name)
|
|
369
|
+
url = f"{url}/filtered_tasks?{urlencode(query_params)}"
|
|
370
|
+
|
|
371
|
+
try:
|
|
372
|
+
resp, _ = cls._request(None, url, "GET")
|
|
373
|
+
except Exception as e:
|
|
374
|
+
if e.http_code == 404:
|
|
375
|
+
# filter_tasks_by_metadata endpoint does not exist in the version of metadata service
|
|
376
|
+
# deployed currently. Raise a more informative error message.
|
|
377
|
+
raise MetaflowInternalError(
|
|
378
|
+
"The version of metadata service deployed currently does not support filtering tasks by metadata. "
|
|
379
|
+
"Upgrade Metadata service to version 2.5.0 or greater to use this feature."
|
|
380
|
+
) from e
|
|
381
|
+
# Other unknown exception
|
|
382
|
+
raise e
|
|
383
|
+
return resp
|
|
384
|
+
|
|
307
385
|
@staticmethod
|
|
308
386
|
def _obj_path(
|
|
309
387
|
flow_name,
|
|
@@ -412,27 +490,27 @@ class ServiceMetadataProvider(MetadataProvider):
|
|
|
412
490
|
if method == "GET":
|
|
413
491
|
if monitor:
|
|
414
492
|
with monitor.measure("metaflow.service_metadata.get"):
|
|
415
|
-
resp =
|
|
493
|
+
resp = cls._session.get(url, headers=SERVICE_HEADERS.copy())
|
|
416
494
|
else:
|
|
417
|
-
resp =
|
|
495
|
+
resp = cls._session.get(url, headers=SERVICE_HEADERS.copy())
|
|
418
496
|
elif method == "POST":
|
|
419
497
|
if monitor:
|
|
420
498
|
with monitor.measure("metaflow.service_metadata.post"):
|
|
421
|
-
resp =
|
|
499
|
+
resp = cls._session.post(
|
|
422
500
|
url, headers=SERVICE_HEADERS.copy(), json=data
|
|
423
501
|
)
|
|
424
502
|
else:
|
|
425
|
-
resp =
|
|
503
|
+
resp = cls._session.post(
|
|
426
504
|
url, headers=SERVICE_HEADERS.copy(), json=data
|
|
427
505
|
)
|
|
428
506
|
elif method == "PATCH":
|
|
429
507
|
if monitor:
|
|
430
508
|
with monitor.measure("metaflow.service_metadata.patch"):
|
|
431
|
-
resp =
|
|
509
|
+
resp = cls._session.patch(
|
|
432
510
|
url, headers=SERVICE_HEADERS.copy(), json=data
|
|
433
511
|
)
|
|
434
512
|
else:
|
|
435
|
-
resp =
|
|
513
|
+
resp = cls._session.patch(
|
|
436
514
|
url, headers=SERVICE_HEADERS.copy(), json=data
|
|
437
515
|
)
|
|
438
516
|
else:
|
|
@@ -475,7 +553,6 @@ class ServiceMetadataProvider(MetadataProvider):
|
|
|
475
553
|
resp.text,
|
|
476
554
|
)
|
|
477
555
|
time.sleep(2**i)
|
|
478
|
-
|
|
479
556
|
if resp:
|
|
480
557
|
raise ServiceException(
|
|
481
558
|
"Metadata request (%s) failed (code %s): %s"
|
|
@@ -499,9 +576,9 @@ class ServiceMetadataProvider(MetadataProvider):
|
|
|
499
576
|
try:
|
|
500
577
|
if monitor:
|
|
501
578
|
with monitor.measure("metaflow.service_metadata.get"):
|
|
502
|
-
resp =
|
|
579
|
+
resp = cls._session.get(url, headers=SERVICE_HEADERS.copy())
|
|
503
580
|
else:
|
|
504
|
-
resp =
|
|
581
|
+
resp = cls._session.get(url, headers=SERVICE_HEADERS.copy())
|
|
505
582
|
except:
|
|
506
583
|
if monitor:
|
|
507
584
|
with monitor.count("metaflow.service_metadata.failed_request"):
|
|
@@ -514,7 +591,7 @@ class ServiceMetadataProvider(MetadataProvider):
|
|
|
514
591
|
else:
|
|
515
592
|
if resp.status_code < 300:
|
|
516
593
|
return resp.headers.get("METADATA_SERVICE_VERSION", None)
|
|
517
|
-
elif resp.status_code
|
|
594
|
+
elif resp.status_code not in (503, 500):
|
|
518
595
|
raise ServiceException(
|
|
519
596
|
"Metadata request (%s) failed"
|
|
520
597
|
" (code %s): %s" % (url, resp.status_code, resp.text),
|