ob-metaflow 2.11.13.1__py2.py3-none-any.whl → 2.19.7.1rc0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- metaflow/R.py +10 -7
- metaflow/__init__.py +40 -25
- metaflow/_vendor/imghdr/__init__.py +186 -0
- metaflow/_vendor/importlib_metadata/__init__.py +1063 -0
- metaflow/_vendor/importlib_metadata/_adapters.py +68 -0
- metaflow/_vendor/importlib_metadata/_collections.py +30 -0
- metaflow/_vendor/importlib_metadata/_compat.py +71 -0
- metaflow/_vendor/importlib_metadata/_functools.py +104 -0
- metaflow/_vendor/importlib_metadata/_itertools.py +73 -0
- metaflow/_vendor/importlib_metadata/_meta.py +48 -0
- metaflow/_vendor/importlib_metadata/_text.py +99 -0
- metaflow/_vendor/importlib_metadata/py.typed +0 -0
- metaflow/_vendor/typeguard/__init__.py +48 -0
- metaflow/_vendor/typeguard/_checkers.py +1070 -0
- metaflow/_vendor/typeguard/_config.py +108 -0
- metaflow/_vendor/typeguard/_decorators.py +233 -0
- metaflow/_vendor/typeguard/_exceptions.py +42 -0
- metaflow/_vendor/typeguard/_functions.py +308 -0
- metaflow/_vendor/typeguard/_importhook.py +213 -0
- metaflow/_vendor/typeguard/_memo.py +48 -0
- metaflow/_vendor/typeguard/_pytest_plugin.py +127 -0
- metaflow/_vendor/typeguard/_suppression.py +86 -0
- metaflow/_vendor/typeguard/_transformer.py +1229 -0
- metaflow/_vendor/typeguard/_union_transformer.py +55 -0
- metaflow/_vendor/typeguard/_utils.py +173 -0
- metaflow/_vendor/typeguard/py.typed +0 -0
- metaflow/_vendor/typing_extensions.py +3641 -0
- metaflow/_vendor/v3_7/importlib_metadata/__init__.py +1063 -0
- metaflow/_vendor/v3_7/importlib_metadata/_adapters.py +68 -0
- metaflow/_vendor/v3_7/importlib_metadata/_collections.py +30 -0
- metaflow/_vendor/v3_7/importlib_metadata/_compat.py +71 -0
- metaflow/_vendor/v3_7/importlib_metadata/_functools.py +104 -0
- metaflow/_vendor/v3_7/importlib_metadata/_itertools.py +73 -0
- metaflow/_vendor/v3_7/importlib_metadata/_meta.py +48 -0
- metaflow/_vendor/v3_7/importlib_metadata/_text.py +99 -0
- metaflow/_vendor/v3_7/importlib_metadata/py.typed +0 -0
- metaflow/_vendor/v3_7/typeguard/__init__.py +48 -0
- metaflow/_vendor/v3_7/typeguard/_checkers.py +906 -0
- metaflow/_vendor/v3_7/typeguard/_config.py +108 -0
- metaflow/_vendor/v3_7/typeguard/_decorators.py +237 -0
- metaflow/_vendor/v3_7/typeguard/_exceptions.py +42 -0
- metaflow/_vendor/v3_7/typeguard/_functions.py +310 -0
- metaflow/_vendor/v3_7/typeguard/_importhook.py +213 -0
- metaflow/_vendor/v3_7/typeguard/_memo.py +48 -0
- metaflow/_vendor/v3_7/typeguard/_pytest_plugin.py +100 -0
- metaflow/_vendor/v3_7/typeguard/_suppression.py +88 -0
- metaflow/_vendor/v3_7/typeguard/_transformer.py +1207 -0
- metaflow/_vendor/v3_7/typeguard/_union_transformer.py +54 -0
- metaflow/_vendor/v3_7/typeguard/_utils.py +169 -0
- metaflow/_vendor/v3_7/typeguard/py.typed +0 -0
- metaflow/_vendor/v3_7/typing_extensions.py +3072 -0
- metaflow/_vendor/yaml/__init__.py +427 -0
- metaflow/_vendor/yaml/composer.py +139 -0
- metaflow/_vendor/yaml/constructor.py +748 -0
- metaflow/_vendor/yaml/cyaml.py +101 -0
- metaflow/_vendor/yaml/dumper.py +62 -0
- metaflow/_vendor/yaml/emitter.py +1137 -0
- metaflow/_vendor/yaml/error.py +75 -0
- metaflow/_vendor/yaml/events.py +86 -0
- metaflow/_vendor/yaml/loader.py +63 -0
- metaflow/_vendor/yaml/nodes.py +49 -0
- metaflow/_vendor/yaml/parser.py +589 -0
- metaflow/_vendor/yaml/reader.py +185 -0
- metaflow/_vendor/yaml/representer.py +389 -0
- metaflow/_vendor/yaml/resolver.py +227 -0
- metaflow/_vendor/yaml/scanner.py +1435 -0
- metaflow/_vendor/yaml/serializer.py +111 -0
- metaflow/_vendor/yaml/tokens.py +104 -0
- metaflow/cards.py +5 -0
- metaflow/cli.py +331 -785
- metaflow/cli_args.py +17 -0
- metaflow/cli_components/__init__.py +0 -0
- metaflow/cli_components/dump_cmd.py +96 -0
- metaflow/cli_components/init_cmd.py +52 -0
- metaflow/cli_components/run_cmds.py +546 -0
- metaflow/cli_components/step_cmd.py +334 -0
- metaflow/cli_components/utils.py +140 -0
- metaflow/client/__init__.py +1 -0
- metaflow/client/core.py +467 -73
- metaflow/client/filecache.py +75 -35
- metaflow/clone_util.py +7 -1
- metaflow/cmd/code/__init__.py +231 -0
- metaflow/cmd/develop/stub_generator.py +756 -288
- metaflow/cmd/develop/stubs.py +12 -28
- metaflow/cmd/main_cli.py +6 -4
- metaflow/cmd/make_wrapper.py +78 -0
- metaflow/datastore/__init__.py +1 -0
- metaflow/datastore/content_addressed_store.py +41 -10
- metaflow/datastore/datastore_set.py +11 -2
- metaflow/datastore/flow_datastore.py +156 -10
- metaflow/datastore/spin_datastore.py +91 -0
- metaflow/datastore/task_datastore.py +154 -39
- metaflow/debug.py +5 -0
- metaflow/decorators.py +404 -78
- metaflow/exception.py +8 -2
- metaflow/extension_support/__init__.py +527 -376
- metaflow/extension_support/_empty_file.py +2 -2
- metaflow/extension_support/plugins.py +49 -31
- metaflow/flowspec.py +482 -33
- metaflow/graph.py +210 -42
- metaflow/includefile.py +84 -40
- metaflow/lint.py +141 -22
- metaflow/meta_files.py +13 -0
- metaflow/{metadata → metadata_provider}/heartbeat.py +24 -8
- metaflow/{metadata → metadata_provider}/metadata.py +86 -1
- metaflow/metaflow_config.py +175 -28
- metaflow/metaflow_config_funcs.py +51 -3
- metaflow/metaflow_current.py +4 -10
- metaflow/metaflow_environment.py +139 -53
- metaflow/metaflow_git.py +115 -0
- metaflow/metaflow_profile.py +18 -0
- metaflow/metaflow_version.py +150 -66
- metaflow/mflog/__init__.py +4 -3
- metaflow/mflog/save_logs.py +2 -2
- metaflow/multicore_utils.py +31 -14
- metaflow/package/__init__.py +673 -0
- metaflow/packaging_sys/__init__.py +880 -0
- metaflow/packaging_sys/backend.py +128 -0
- metaflow/packaging_sys/distribution_support.py +153 -0
- metaflow/packaging_sys/tar_backend.py +99 -0
- metaflow/packaging_sys/utils.py +54 -0
- metaflow/packaging_sys/v1.py +527 -0
- metaflow/parameters.py +149 -28
- metaflow/plugins/__init__.py +74 -5
- metaflow/plugins/airflow/airflow.py +40 -25
- metaflow/plugins/airflow/airflow_cli.py +22 -5
- metaflow/plugins/airflow/airflow_decorator.py +1 -1
- metaflow/plugins/airflow/airflow_utils.py +5 -3
- metaflow/plugins/airflow/sensors/base_sensor.py +4 -4
- metaflow/plugins/airflow/sensors/external_task_sensor.py +2 -2
- metaflow/plugins/airflow/sensors/s3_sensor.py +2 -2
- metaflow/plugins/argo/argo_client.py +78 -33
- metaflow/plugins/argo/argo_events.py +6 -6
- metaflow/plugins/argo/argo_workflows.py +2410 -527
- metaflow/plugins/argo/argo_workflows_cli.py +571 -121
- metaflow/plugins/argo/argo_workflows_decorator.py +43 -12
- metaflow/plugins/argo/argo_workflows_deployer.py +106 -0
- metaflow/plugins/argo/argo_workflows_deployer_objects.py +453 -0
- metaflow/plugins/argo/capture_error.py +73 -0
- metaflow/plugins/argo/conditional_input_paths.py +35 -0
- metaflow/plugins/argo/exit_hooks.py +209 -0
- metaflow/plugins/argo/jobset_input_paths.py +15 -0
- metaflow/plugins/argo/param_val.py +19 -0
- metaflow/plugins/aws/aws_client.py +10 -3
- metaflow/plugins/aws/aws_utils.py +55 -2
- metaflow/plugins/aws/batch/batch.py +72 -5
- metaflow/plugins/aws/batch/batch_cli.py +33 -10
- metaflow/plugins/aws/batch/batch_client.py +4 -3
- metaflow/plugins/aws/batch/batch_decorator.py +102 -35
- metaflow/plugins/aws/secrets_manager/aws_secrets_manager_secrets_provider.py +13 -10
- metaflow/plugins/aws/step_functions/dynamo_db_client.py +0 -3
- metaflow/plugins/aws/step_functions/production_token.py +1 -1
- metaflow/plugins/aws/step_functions/step_functions.py +65 -8
- metaflow/plugins/aws/step_functions/step_functions_cli.py +101 -7
- metaflow/plugins/aws/step_functions/step_functions_decorator.py +1 -2
- metaflow/plugins/aws/step_functions/step_functions_deployer.py +97 -0
- metaflow/plugins/aws/step_functions/step_functions_deployer_objects.py +264 -0
- metaflow/plugins/azure/azure_exceptions.py +1 -1
- metaflow/plugins/azure/azure_secret_manager_secrets_provider.py +240 -0
- metaflow/plugins/azure/azure_tail.py +1 -1
- metaflow/plugins/azure/includefile_support.py +2 -0
- metaflow/plugins/cards/card_cli.py +66 -30
- metaflow/plugins/cards/card_creator.py +25 -1
- metaflow/plugins/cards/card_datastore.py +21 -49
- metaflow/plugins/cards/card_decorator.py +132 -8
- metaflow/plugins/cards/card_modules/basic.py +112 -17
- metaflow/plugins/cards/card_modules/bundle.css +1 -1
- metaflow/plugins/cards/card_modules/card.py +16 -1
- metaflow/plugins/cards/card_modules/chevron/renderer.py +1 -1
- metaflow/plugins/cards/card_modules/components.py +665 -28
- metaflow/plugins/cards/card_modules/convert_to_native_type.py +36 -7
- metaflow/plugins/cards/card_modules/json_viewer.py +232 -0
- metaflow/plugins/cards/card_modules/main.css +1 -0
- metaflow/plugins/cards/card_modules/main.js +68 -49
- metaflow/plugins/cards/card_modules/renderer_tools.py +1 -0
- metaflow/plugins/cards/card_modules/test_cards.py +26 -12
- metaflow/plugins/cards/card_server.py +39 -14
- metaflow/plugins/cards/component_serializer.py +2 -9
- metaflow/plugins/cards/metadata.py +22 -0
- metaflow/plugins/catch_decorator.py +9 -0
- metaflow/plugins/datastores/azure_storage.py +10 -1
- metaflow/plugins/datastores/gs_storage.py +6 -2
- metaflow/plugins/datastores/local_storage.py +12 -6
- metaflow/plugins/datastores/spin_storage.py +12 -0
- metaflow/plugins/datatools/local.py +2 -0
- metaflow/plugins/datatools/s3/s3.py +126 -75
- metaflow/plugins/datatools/s3/s3op.py +254 -121
- metaflow/plugins/env_escape/__init__.py +3 -3
- metaflow/plugins/env_escape/client_modules.py +102 -72
- metaflow/plugins/env_escape/server.py +7 -0
- metaflow/plugins/env_escape/stub.py +24 -5
- metaflow/plugins/events_decorator.py +343 -185
- metaflow/plugins/exit_hook/__init__.py +0 -0
- metaflow/plugins/exit_hook/exit_hook_decorator.py +46 -0
- metaflow/plugins/exit_hook/exit_hook_script.py +52 -0
- metaflow/plugins/gcp/__init__.py +1 -1
- metaflow/plugins/gcp/gcp_secret_manager_secrets_provider.py +11 -6
- metaflow/plugins/gcp/gs_tail.py +10 -6
- metaflow/plugins/gcp/includefile_support.py +3 -0
- metaflow/plugins/kubernetes/kube_utils.py +108 -0
- metaflow/plugins/kubernetes/kubernetes.py +411 -130
- metaflow/plugins/kubernetes/kubernetes_cli.py +168 -36
- metaflow/plugins/kubernetes/kubernetes_client.py +104 -2
- metaflow/plugins/kubernetes/kubernetes_decorator.py +246 -88
- metaflow/plugins/kubernetes/kubernetes_job.py +253 -581
- metaflow/plugins/kubernetes/kubernetes_jobsets.py +1071 -0
- metaflow/plugins/kubernetes/spot_metadata_cli.py +69 -0
- metaflow/plugins/kubernetes/spot_monitor_sidecar.py +109 -0
- metaflow/plugins/logs_cli.py +359 -0
- metaflow/plugins/{metadata → metadata_providers}/local.py +144 -84
- metaflow/plugins/{metadata → metadata_providers}/service.py +103 -26
- metaflow/plugins/metadata_providers/spin.py +16 -0
- metaflow/plugins/package_cli.py +36 -24
- metaflow/plugins/parallel_decorator.py +128 -11
- metaflow/plugins/parsers.py +16 -0
- metaflow/plugins/project_decorator.py +51 -5
- metaflow/plugins/pypi/bootstrap.py +357 -105
- metaflow/plugins/pypi/conda_decorator.py +82 -81
- metaflow/plugins/pypi/conda_environment.py +187 -52
- metaflow/plugins/pypi/micromamba.py +157 -47
- metaflow/plugins/pypi/parsers.py +268 -0
- metaflow/plugins/pypi/pip.py +88 -13
- metaflow/plugins/pypi/pypi_decorator.py +37 -1
- metaflow/plugins/pypi/utils.py +48 -2
- metaflow/plugins/resources_decorator.py +2 -2
- metaflow/plugins/secrets/__init__.py +3 -0
- metaflow/plugins/secrets/secrets_decorator.py +26 -181
- metaflow/plugins/secrets/secrets_func.py +49 -0
- metaflow/plugins/secrets/secrets_spec.py +101 -0
- metaflow/plugins/secrets/utils.py +74 -0
- metaflow/plugins/tag_cli.py +4 -7
- metaflow/plugins/test_unbounded_foreach_decorator.py +41 -6
- metaflow/plugins/timeout_decorator.py +3 -3
- metaflow/plugins/uv/__init__.py +0 -0
- metaflow/plugins/uv/bootstrap.py +128 -0
- metaflow/plugins/uv/uv_environment.py +72 -0
- metaflow/procpoll.py +1 -1
- metaflow/pylint_wrapper.py +5 -1
- metaflow/runner/__init__.py +0 -0
- metaflow/runner/click_api.py +717 -0
- metaflow/runner/deployer.py +470 -0
- metaflow/runner/deployer_impl.py +201 -0
- metaflow/runner/metaflow_runner.py +714 -0
- metaflow/runner/nbdeploy.py +132 -0
- metaflow/runner/nbrun.py +225 -0
- metaflow/runner/subprocess_manager.py +650 -0
- metaflow/runner/utils.py +335 -0
- metaflow/runtime.py +1078 -260
- metaflow/sidecar/sidecar_worker.py +1 -1
- metaflow/system/__init__.py +5 -0
- metaflow/system/system_logger.py +85 -0
- metaflow/system/system_monitor.py +108 -0
- metaflow/system/system_utils.py +19 -0
- metaflow/task.py +521 -225
- metaflow/tracing/__init__.py +7 -7
- metaflow/tracing/span_exporter.py +31 -38
- metaflow/tracing/tracing_modules.py +38 -43
- metaflow/tuple_util.py +27 -0
- metaflow/user_configs/__init__.py +0 -0
- metaflow/user_configs/config_options.py +563 -0
- metaflow/user_configs/config_parameters.py +598 -0
- metaflow/user_decorators/__init__.py +0 -0
- metaflow/user_decorators/common.py +144 -0
- metaflow/user_decorators/mutable_flow.py +512 -0
- metaflow/user_decorators/mutable_step.py +424 -0
- metaflow/user_decorators/user_flow_decorator.py +264 -0
- metaflow/user_decorators/user_step_decorator.py +749 -0
- metaflow/util.py +243 -27
- metaflow/vendor.py +23 -7
- metaflow/version.py +1 -1
- ob_metaflow-2.19.7.1rc0.data/data/share/metaflow/devtools/Makefile +355 -0
- ob_metaflow-2.19.7.1rc0.data/data/share/metaflow/devtools/Tiltfile +726 -0
- ob_metaflow-2.19.7.1rc0.data/data/share/metaflow/devtools/pick_services.sh +105 -0
- ob_metaflow-2.19.7.1rc0.dist-info/METADATA +87 -0
- ob_metaflow-2.19.7.1rc0.dist-info/RECORD +445 -0
- {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/WHEEL +1 -1
- {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/entry_points.txt +1 -0
- metaflow/_vendor/v3_5/__init__.py +0 -1
- metaflow/_vendor/v3_5/importlib_metadata/__init__.py +0 -644
- metaflow/_vendor/v3_5/importlib_metadata/_compat.py +0 -152
- metaflow/package.py +0 -188
- ob_metaflow-2.11.13.1.dist-info/METADATA +0 -85
- ob_metaflow-2.11.13.1.dist-info/RECORD +0 -308
- /metaflow/_vendor/{v3_5/zipp.py → zipp.py} +0 -0
- /metaflow/{metadata → metadata_provider}/__init__.py +0 -0
- /metaflow/{metadata → metadata_provider}/util.py +0 -0
- /metaflow/plugins/{metadata → metadata_providers}/__init__.py +0 -0
- {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info/licenses}/LICENSE +0 -0
- {ob_metaflow-2.11.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/top_level.txt +0 -0
metaflow/decorators.py
CHANGED
|
@@ -1,24 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
import importlib
|
|
2
2
|
import json
|
|
3
3
|
import re
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from functools import partial
|
|
6
|
+
from typing import Any, Callable, Dict, List, NewType, Tuple, TypeVar, Union, overload
|
|
6
7
|
|
|
7
|
-
from .flowspec import FlowSpec
|
|
8
|
+
from .flowspec import FlowSpec, FlowStateItems
|
|
8
9
|
from .exception import (
|
|
9
10
|
MetaflowInternalError,
|
|
10
11
|
MetaflowException,
|
|
11
12
|
InvalidDecoratorAttribute,
|
|
12
13
|
)
|
|
13
14
|
|
|
15
|
+
from .debug import debug
|
|
16
|
+
from .parameters import current_flow
|
|
17
|
+
from .user_configs.config_parameters import (
|
|
18
|
+
UNPACK_KEY,
|
|
19
|
+
resolve_delayed_evaluator,
|
|
20
|
+
unpack_delayed_evaluator,
|
|
21
|
+
)
|
|
22
|
+
from .user_decorators.mutable_flow import MutableFlow
|
|
23
|
+
from .user_decorators.mutable_step import MutableStep
|
|
24
|
+
from .user_decorators.user_flow_decorator import FlowMutator, FlowMutatorMeta
|
|
25
|
+
from .user_decorators.user_step_decorator import (
|
|
26
|
+
StepMutator,
|
|
27
|
+
UserStepDecoratorBase,
|
|
28
|
+
UserStepDecoratorMeta,
|
|
29
|
+
)
|
|
30
|
+
from .metaflow_config import SPIN_ALLOWED_DECORATORS
|
|
14
31
|
from metaflow._vendor import click
|
|
15
32
|
|
|
16
|
-
try:
|
|
17
|
-
unicode
|
|
18
|
-
except NameError:
|
|
19
|
-
unicode = str
|
|
20
|
-
basestring = str
|
|
21
|
-
|
|
22
33
|
|
|
23
34
|
class BadStepDecoratorException(MetaflowException):
|
|
24
35
|
headline = "Syntax error"
|
|
@@ -29,7 +40,7 @@ class BadStepDecoratorException(MetaflowException):
|
|
|
29
40
|
"not declared as a @step. Make sure you apply this decorator "
|
|
30
41
|
"on a function which has @step on the line just before the "
|
|
31
42
|
"function name and @{deco} is above @step.".format(
|
|
32
|
-
deco=deco, func=func
|
|
43
|
+
deco=deco, func=getattr(func, "__name__", str(func))
|
|
33
44
|
)
|
|
34
45
|
)
|
|
35
46
|
super(BadStepDecoratorException, self).__init__(msg)
|
|
@@ -50,11 +61,14 @@ class UnknownStepDecoratorException(MetaflowException):
|
|
|
50
61
|
headline = "Unknown step decorator"
|
|
51
62
|
|
|
52
63
|
def __init__(self, deconame):
|
|
53
|
-
from .plugins import STEP_DECORATORS
|
|
54
|
-
|
|
55
64
|
decos = ", ".join(
|
|
56
|
-
|
|
65
|
+
[
|
|
66
|
+
x
|
|
67
|
+
for x in UserStepDecoratorMeta.all_decorators().keys()
|
|
68
|
+
if not x.endswith("_internal")
|
|
69
|
+
]
|
|
57
70
|
)
|
|
71
|
+
|
|
58
72
|
msg = (
|
|
59
73
|
"Unknown step decorator *{deconame}*. The following decorators are "
|
|
60
74
|
"supported: *{decos}*".format(deconame=deconame, decos=decos)
|
|
@@ -79,9 +93,7 @@ class UnknownFlowDecoratorException(MetaflowException):
|
|
|
79
93
|
headline = "Unknown flow decorator"
|
|
80
94
|
|
|
81
95
|
def __init__(self, deconame):
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
decos = ", ".join(t.name for t in FLOW_DECORATORS)
|
|
96
|
+
decos = ", ".join(FlowMutatorMeta.all_decorators().keys())
|
|
85
97
|
msg = (
|
|
86
98
|
"Unknown flow decorator *{deconame}*. The following decorators are "
|
|
87
99
|
"supported: *{decos}*".format(deconame=deconame, decos=decos)
|
|
@@ -110,21 +122,48 @@ class Decorator(object):
|
|
|
110
122
|
# `allow_multiple` allows setting many decorators of the same type to a step/flow.
|
|
111
123
|
allow_multiple = False
|
|
112
124
|
|
|
113
|
-
def __init__(self, attributes=None, statically_defined=False):
|
|
125
|
+
def __init__(self, attributes=None, statically_defined=False, inserted_by=None):
|
|
114
126
|
self.attributes = self.defaults.copy()
|
|
115
127
|
self.statically_defined = statically_defined
|
|
128
|
+
self.inserted_by = inserted_by
|
|
129
|
+
self._user_defined_attributes = set()
|
|
130
|
+
self._ran_init = False
|
|
116
131
|
|
|
117
132
|
if attributes:
|
|
118
133
|
for k, v in attributes.items():
|
|
119
|
-
if k in self.defaults:
|
|
134
|
+
if k in self.defaults or k.startswith(UNPACK_KEY):
|
|
120
135
|
self.attributes[k] = v
|
|
136
|
+
if not k.startswith(UNPACK_KEY):
|
|
137
|
+
self._user_defined_attributes.add(k)
|
|
121
138
|
else:
|
|
122
139
|
raise InvalidDecoratorAttribute(self.name, k, self.defaults)
|
|
123
140
|
|
|
141
|
+
def init(self):
|
|
142
|
+
"""
|
|
143
|
+
Initializes the decorator. In general, any operation you would do in __init__
|
|
144
|
+
should be done here.
|
|
145
|
+
"""
|
|
146
|
+
pass
|
|
147
|
+
|
|
148
|
+
def external_init(self):
|
|
149
|
+
# In some cases (specifically when using remove_decorator), we may need to call
|
|
150
|
+
# init multiple times. Short-circuit re-evaluating.
|
|
151
|
+
if self._ran_init:
|
|
152
|
+
return
|
|
153
|
+
|
|
154
|
+
# Note that by design, later values override previous ones.
|
|
155
|
+
self.attributes, new_user_attributes = unpack_delayed_evaluator(self.attributes)
|
|
156
|
+
self._user_defined_attributes.update(new_user_attributes)
|
|
157
|
+
self.attributes = resolve_delayed_evaluator(self.attributes, to_dict=True)
|
|
158
|
+
|
|
159
|
+
if "init" in self.__class__.__dict__:
|
|
160
|
+
self.init()
|
|
161
|
+
self._ran_init = True
|
|
162
|
+
|
|
124
163
|
@classmethod
|
|
125
|
-
def
|
|
164
|
+
def extract_args_kwargs_from_decorator_spec(cls, deco_spec):
|
|
126
165
|
if len(deco_spec) == 0:
|
|
127
|
-
return
|
|
166
|
+
return [], {}
|
|
128
167
|
|
|
129
168
|
attrs = {}
|
|
130
169
|
# TODO: Do we really want to allow spaces in the names of attributes?!?
|
|
@@ -144,9 +183,20 @@ class Decorator(object):
|
|
|
144
183
|
val_parsed = val.strip()
|
|
145
184
|
|
|
146
185
|
attrs[name.strip()] = val_parsed
|
|
147
|
-
|
|
186
|
+
|
|
187
|
+
return [], attrs
|
|
188
|
+
|
|
189
|
+
@classmethod
|
|
190
|
+
def parse_decorator_spec(cls, deco_spec):
|
|
191
|
+
if len(deco_spec) == 0:
|
|
192
|
+
return cls()
|
|
193
|
+
|
|
194
|
+
_, kwargs = cls.extract_args_kwargs_from_decorator_spec(deco_spec)
|
|
195
|
+
return cls(attributes=kwargs)
|
|
148
196
|
|
|
149
197
|
def make_decorator_spec(self):
|
|
198
|
+
# Make sure all attributes are evaluated
|
|
199
|
+
self.external_init()
|
|
150
200
|
attrs = {k: v for k, v in self.attributes.items() if v is not None}
|
|
151
201
|
if attrs:
|
|
152
202
|
attr_list = []
|
|
@@ -154,17 +204,31 @@ class Decorator(object):
|
|
|
154
204
|
# escaping but for more complex types (typically dictionaries or lists),
|
|
155
205
|
# we dump using JSON.
|
|
156
206
|
for k, v in attrs.items():
|
|
157
|
-
if isinstance(v, (int, float,
|
|
207
|
+
if isinstance(v, (int, float, str)):
|
|
158
208
|
attr_list.append("%s=%s" % (k, str(v)))
|
|
159
209
|
else:
|
|
160
210
|
attr_list.append("%s=%s" % (k, json.dumps(v).replace('"', '\\"')))
|
|
211
|
+
|
|
161
212
|
attrstr = ",".join(attr_list)
|
|
162
213
|
return "%s:%s" % (self.name, attrstr)
|
|
163
214
|
else:
|
|
164
215
|
return self.name
|
|
165
216
|
|
|
217
|
+
def get_args_kwargs(self) -> Tuple[List[Any], Dict[str, Any]]:
|
|
218
|
+
"""
|
|
219
|
+
Get the arguments and keyword arguments of the decorator.
|
|
220
|
+
|
|
221
|
+
Returns
|
|
222
|
+
-------
|
|
223
|
+
Tuple[List[Any], Dict[str, Any]]
|
|
224
|
+
A tuple containing a list of arguments and a dictionary of keyword arguments.
|
|
225
|
+
"""
|
|
226
|
+
return [], dict(self.attributes)
|
|
227
|
+
|
|
166
228
|
def __str__(self):
|
|
167
|
-
mode = "
|
|
229
|
+
mode = "static" if self.statically_defined else "dynamic"
|
|
230
|
+
if self.inserted_by:
|
|
231
|
+
mode += " (inserted by %s)" % " from ".join(self.inserted_by)
|
|
168
232
|
attrs = " ".join("%s=%s" % x for x in self.attributes.items())
|
|
169
233
|
if attrs:
|
|
170
234
|
attrs = " " + attrs
|
|
@@ -173,13 +237,9 @@ class Decorator(object):
|
|
|
173
237
|
|
|
174
238
|
|
|
175
239
|
class FlowDecorator(Decorator):
|
|
176
|
-
_flow_decorators = []
|
|
177
240
|
options = {}
|
|
178
241
|
|
|
179
242
|
def __init__(self, *args, **kwargs):
|
|
180
|
-
# Note that this assumes we are executing one flow per process, so we have a global list of
|
|
181
|
-
# _flow_decorators. A similar setup is used in parameters.
|
|
182
|
-
self._flow_decorators.append(self)
|
|
183
243
|
super(FlowDecorator, self).__init__(*args, **kwargs)
|
|
184
244
|
|
|
185
245
|
def flow_init(
|
|
@@ -204,8 +264,14 @@ class FlowDecorator(Decorator):
|
|
|
204
264
|
|
|
205
265
|
# compare this to parameters.add_custom_parameters
|
|
206
266
|
def add_decorator_options(cmd):
|
|
267
|
+
flow_cls = getattr(current_flow, "flow_cls", None)
|
|
268
|
+
if flow_cls is None:
|
|
269
|
+
return cmd
|
|
270
|
+
|
|
207
271
|
seen = {}
|
|
208
|
-
for
|
|
272
|
+
existing_params = set(p.name.lower() for p in cmd.params)
|
|
273
|
+
# Add decorator options
|
|
274
|
+
for deco in flow_decorators(flow_cls):
|
|
209
275
|
for option, kwargs in deco.options.items():
|
|
210
276
|
if option in seen:
|
|
211
277
|
msg = (
|
|
@@ -215,14 +281,24 @@ def add_decorator_options(cmd):
|
|
|
215
281
|
% (deco.name, option, seen[option])
|
|
216
282
|
)
|
|
217
283
|
raise MetaflowInternalError(msg)
|
|
284
|
+
elif deco.name.lower() in existing_params:
|
|
285
|
+
raise MetaflowInternalError(
|
|
286
|
+
"Flow decorator '%s' uses an option '%s' which is a reserved "
|
|
287
|
+
"keyword. Please use a different option name." % (deco.name, option)
|
|
288
|
+
)
|
|
218
289
|
else:
|
|
290
|
+
kwargs["envvar"] = "METAFLOW_FLOW_%s" % option.upper()
|
|
219
291
|
seen[option] = deco.name
|
|
220
292
|
cmd.params.insert(0, click.Option(("--" + option,), **kwargs))
|
|
221
293
|
return cmd
|
|
222
294
|
|
|
223
295
|
|
|
224
|
-
def flow_decorators():
|
|
225
|
-
return
|
|
296
|
+
def flow_decorators(flow_cls):
|
|
297
|
+
return [
|
|
298
|
+
d
|
|
299
|
+
for deco_list in flow_cls._flow_state[FlowStateItems.FLOW_DECORATORS].values()
|
|
300
|
+
for d in deco_list
|
|
301
|
+
]
|
|
226
302
|
|
|
227
303
|
|
|
228
304
|
class StepDecorator(Decorator):
|
|
@@ -271,15 +347,36 @@ class StepDecorator(Decorator):
|
|
|
271
347
|
|
|
272
348
|
def add_to_package(self):
|
|
273
349
|
"""
|
|
274
|
-
Called to add custom
|
|
350
|
+
Called to add custom files needed for this environment. This hook will be
|
|
275
351
|
called in the `MetaflowPackage` class where metaflow compiles the code package
|
|
276
|
-
tarball. This hook
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
352
|
+
tarball. This hook can return one of two things (the first is for backwards
|
|
353
|
+
compatibility -- move to the second):
|
|
354
|
+
- a generator yielding a tuple of `(file_path, arcname)` to add files to
|
|
355
|
+
the code package. `file_path` is the path to the file on the local filesystem
|
|
356
|
+
and `arcname` is the path relative to the packaged code.
|
|
357
|
+
- a generator yielding a tuple of `(content, arcname, type)` where:
|
|
358
|
+
- type is one of
|
|
359
|
+
ContentType.{USER_CONTENT, CODE_CONTENT, MODULE_CONTENT, OTHER_CONTENT}
|
|
360
|
+
- for USER_CONTENT:
|
|
361
|
+
- the file will be included relative to the directory containing the
|
|
362
|
+
user's flow file.
|
|
363
|
+
- content: path to the file to include
|
|
364
|
+
- arcname: path relative to the directory containing the user's flow file
|
|
365
|
+
- for CODE_CONTENT:
|
|
366
|
+
- the file will be included relative to the code directory in the package.
|
|
367
|
+
This will be the directory containing `metaflow`.
|
|
368
|
+
- content: path to the file to include
|
|
369
|
+
- arcname: path relative to the code directory in the package
|
|
370
|
+
- for MODULE_CONTENT:
|
|
371
|
+
- the module will be added to the code package as a python module. It will
|
|
372
|
+
be accessible as usual (import <module_name>)
|
|
373
|
+
- content: name of the module
|
|
374
|
+
- arcname: None (ignored)
|
|
375
|
+
- for OTHER_CONTENT:
|
|
376
|
+
- the file will be included relative to any other configuration/metadata
|
|
377
|
+
files for the flow
|
|
378
|
+
- content: path to the file to include
|
|
379
|
+
- arcname: path relative to the config directory in the package
|
|
283
380
|
"""
|
|
284
381
|
return []
|
|
285
382
|
|
|
@@ -399,12 +496,20 @@ def _base_flow_decorator(decofunc, *args, **kwargs):
|
|
|
399
496
|
cls = args[0]
|
|
400
497
|
if isinstance(cls, type) and issubclass(cls, FlowSpec):
|
|
401
498
|
# flow decorators add attributes in the class dictionary,
|
|
402
|
-
#
|
|
403
|
-
|
|
499
|
+
# cls._flow_state[FlowStateItems.FLOW_DECORATORS]. This is of type `{key:[decos]}`
|
|
500
|
+
self_flow_decos = cls._flow_state.self_data[FlowStateItems.FLOW_DECORATORS]
|
|
501
|
+
inherited_flow_decos = cls._flow_state.inherited_data.get(
|
|
502
|
+
FlowStateItems.FLOW_DECORATORS, {}
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
if (
|
|
506
|
+
decofunc.name in self_flow_decos
|
|
507
|
+
or decofunc.name in inherited_flow_decos
|
|
508
|
+
) and not decofunc.allow_multiple:
|
|
404
509
|
raise DuplicateFlowDecoratorException(decofunc.name)
|
|
405
510
|
else:
|
|
406
511
|
deco_instance = decofunc(attributes=kwargs, statically_defined=True)
|
|
407
|
-
|
|
512
|
+
self_flow_decos.setdefault(decofunc.name, []).append(deco_instance)
|
|
408
513
|
else:
|
|
409
514
|
raise BadFlowDecoratorException(decofunc.name)
|
|
410
515
|
return cls
|
|
@@ -423,10 +528,13 @@ def _base_step_decorator(decotype, *args, **kwargs):
|
|
|
423
528
|
Decorator prototype for all step decorators. This function gets specialized
|
|
424
529
|
and imported for all decorators types by _import_plugin_decorators().
|
|
425
530
|
"""
|
|
531
|
+
|
|
426
532
|
if args:
|
|
427
533
|
# No keyword arguments specified for the decorator, e.g. @foobar.
|
|
428
534
|
# The first argument is the function to be decorated.
|
|
429
535
|
func = args[0]
|
|
536
|
+
if isinstance(func, (StepMutator, UserStepDecoratorBase)):
|
|
537
|
+
func = func._my_step
|
|
430
538
|
if not hasattr(func, "is_step"):
|
|
431
539
|
raise BadStepDecoratorException(decotype.name, func)
|
|
432
540
|
|
|
@@ -450,6 +558,80 @@ def _base_step_decorator(decotype, *args, **kwargs):
|
|
|
450
558
|
return wrap
|
|
451
559
|
|
|
452
560
|
|
|
561
|
+
_all_step_decos = None
|
|
562
|
+
_all_flow_decos = None
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
def get_all_step_decos():
|
|
566
|
+
global _all_step_decos
|
|
567
|
+
if _all_step_decos is None:
|
|
568
|
+
from .plugins import STEP_DECORATORS
|
|
569
|
+
|
|
570
|
+
_all_step_decos = {decotype.name: decotype for decotype in STEP_DECORATORS}
|
|
571
|
+
return _all_step_decos
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def get_all_flow_decos():
|
|
575
|
+
global _all_flow_decos
|
|
576
|
+
if _all_flow_decos is None:
|
|
577
|
+
from .plugins import FLOW_DECORATORS
|
|
578
|
+
|
|
579
|
+
_all_flow_decos = {decotype.name: decotype for decotype in FLOW_DECORATORS}
|
|
580
|
+
return _all_flow_decos
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
def extract_step_decorator_from_decospec(decospec: str):
|
|
584
|
+
splits = decospec.split(":", 1)
|
|
585
|
+
deconame = splits[0]
|
|
586
|
+
|
|
587
|
+
# Check if it is a user-defined decorator or metaflow decorator
|
|
588
|
+
deco_cls = UserStepDecoratorMeta.get_decorator_by_name(deconame)
|
|
589
|
+
if deco_cls is not None:
|
|
590
|
+
return (
|
|
591
|
+
deco_cls.parse_decorator_spec(splits[1] if len(splits) > 1 else ""),
|
|
592
|
+
len(splits) > 1,
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
# Check if this is a decorator we can import
|
|
596
|
+
if "." in deconame:
|
|
597
|
+
# We consider this to be a import path to a user decorator so
|
|
598
|
+
# something like "my_package.my_decorator"
|
|
599
|
+
module_name, class_name = deconame.rsplit(".", 1)
|
|
600
|
+
try:
|
|
601
|
+
module = importlib.import_module(module_name)
|
|
602
|
+
except ImportError as e:
|
|
603
|
+
raise MetaflowException(
|
|
604
|
+
"Could not import user decorator %s" % deconame
|
|
605
|
+
) from e
|
|
606
|
+
deco_cls = getattr(module, class_name, None)
|
|
607
|
+
if (
|
|
608
|
+
deco_cls is None
|
|
609
|
+
or not isinstance(deco_cls, type)
|
|
610
|
+
or not issubclass(deco_cls, UserStepDecoratorBase)
|
|
611
|
+
):
|
|
612
|
+
raise UnknownStepDecoratorException(deconame)
|
|
613
|
+
return (
|
|
614
|
+
deco_cls.parse_decorator_spec(splits[1] if len(splits) > 1 else ""),
|
|
615
|
+
len(splits) > 1,
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
raise UnknownStepDecoratorException(deconame)
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def extract_flow_decorator_from_decospec(decospec: str):
|
|
622
|
+
splits = decospec.split(":", 1)
|
|
623
|
+
deconame = splits[0]
|
|
624
|
+
# Check if it is a user-defined decorator or metaflow decorator
|
|
625
|
+
deco_cls = FlowMutatorMeta.get_decorator_by_name(deconame)
|
|
626
|
+
if deco_cls is not None:
|
|
627
|
+
return (
|
|
628
|
+
deco_cls.parse_decorator_spec(splits[1] if len(splits) > 1 else ""),
|
|
629
|
+
len(splits) > 1,
|
|
630
|
+
)
|
|
631
|
+
else:
|
|
632
|
+
raise UnknownFlowDecoratorException(deconame)
|
|
633
|
+
|
|
634
|
+
|
|
453
635
|
def _attach_decorators(flow, decospecs):
|
|
454
636
|
"""
|
|
455
637
|
Attach decorators to all steps during runtime. This has the same
|
|
@@ -462,6 +644,7 @@ def _attach_decorators(flow, decospecs):
|
|
|
462
644
|
#
|
|
463
645
|
# Note that each step gets its own instance of the decorator class,
|
|
464
646
|
# so decorator can maintain step-specific state.
|
|
647
|
+
|
|
465
648
|
for step in flow:
|
|
466
649
|
_attach_decorators_to_step(step, decospecs)
|
|
467
650
|
|
|
@@ -472,35 +655,95 @@ def _attach_decorators_to_step(step, decospecs):
|
|
|
472
655
|
effect as if you defined the decorators statically in the source for
|
|
473
656
|
the step.
|
|
474
657
|
"""
|
|
475
|
-
|
|
658
|
+
for decospec in decospecs:
|
|
659
|
+
step_deco, _ = extract_step_decorator_from_decospec(decospec)
|
|
660
|
+
if isinstance(step_deco, StepDecorator):
|
|
661
|
+
# Check multiple
|
|
662
|
+
if (
|
|
663
|
+
step_deco.name not in [deco.name for deco in step.decorators]
|
|
664
|
+
or step_deco.allow_multiple
|
|
665
|
+
):
|
|
666
|
+
step.decorators.append(step_deco)
|
|
667
|
+
# Else it is ignored -- this is a non-static decorator
|
|
476
668
|
|
|
477
|
-
|
|
669
|
+
else:
|
|
670
|
+
step_deco.add_or_raise(step, False, 1, None)
|
|
478
671
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
672
|
+
|
|
673
|
+
def _should_skip_decorator_for_spin(
|
|
674
|
+
deco, is_spin, skip_decorators, logger, decorator_type="decorator"
|
|
675
|
+
):
|
|
676
|
+
"""
|
|
677
|
+
Determine if a decorator should be skipped for spin steps.
|
|
678
|
+
|
|
679
|
+
Parameters:
|
|
680
|
+
-----------
|
|
681
|
+
deco : Decorator
|
|
682
|
+
The decorator instance to check
|
|
683
|
+
is_spin : bool
|
|
684
|
+
Whether this is a spin step
|
|
685
|
+
skip_decorators : bool
|
|
686
|
+
Whether to skip all decorators
|
|
687
|
+
logger : callable
|
|
688
|
+
Logger function for warnings
|
|
689
|
+
decorator_type : str
|
|
690
|
+
Type of decorator ("Flow decorator" or "Step decorator") for logging
|
|
691
|
+
|
|
692
|
+
Returns:
|
|
693
|
+
--------
|
|
694
|
+
bool
|
|
695
|
+
True if the decorator should be skipped, False otherwise
|
|
696
|
+
"""
|
|
697
|
+
if not is_spin:
|
|
698
|
+
return False
|
|
699
|
+
|
|
700
|
+
# Skip all decorator hooks if skip_decorators is True
|
|
701
|
+
if skip_decorators:
|
|
702
|
+
return True
|
|
703
|
+
|
|
704
|
+
# Run decorator hooks for spin steps only if they are in the whitelist
|
|
705
|
+
if deco.name not in SPIN_ALLOWED_DECORATORS:
|
|
706
|
+
logger(
|
|
707
|
+
f"[Warning] Ignoring {decorator_type} '{deco.name}' as it is not supported in spin steps.",
|
|
708
|
+
system_msg=True,
|
|
709
|
+
timestamp=False,
|
|
710
|
+
bad=True,
|
|
711
|
+
)
|
|
712
|
+
return True
|
|
713
|
+
|
|
714
|
+
return False
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
def _init(flow, only_non_static=False):
|
|
718
|
+
flow_decos = flow._flow_state[FlowStateItems.FLOW_DECORATORS]
|
|
719
|
+
for decorators in flow_decos.values():
|
|
720
|
+
for deco in decorators:
|
|
721
|
+
deco.external_init()
|
|
722
|
+
|
|
723
|
+
for flowstep in flow:
|
|
724
|
+
for deco in flowstep.decorators:
|
|
725
|
+
deco.external_init()
|
|
726
|
+
for deco in flowstep.config_decorators or []:
|
|
727
|
+
deco.external_init()
|
|
728
|
+
for deco in flowstep.wrappers or []:
|
|
729
|
+
deco.external_init()
|
|
497
730
|
|
|
498
731
|
|
|
499
732
|
def _init_flow_decorators(
|
|
500
|
-
flow,
|
|
733
|
+
flow,
|
|
734
|
+
graph,
|
|
735
|
+
environment,
|
|
736
|
+
flow_datastore,
|
|
737
|
+
metadata,
|
|
738
|
+
logger,
|
|
739
|
+
echo,
|
|
740
|
+
deco_options,
|
|
741
|
+
is_spin=False,
|
|
742
|
+
skip_decorators=False,
|
|
501
743
|
):
|
|
502
744
|
# Since all flow decorators are stored as `{key:[deco]}` we iterate through each of them.
|
|
503
|
-
|
|
745
|
+
flow_decos = flow._flow_state[FlowStateItems.FLOW_DECORATORS]
|
|
746
|
+
for decorators in flow_decos.values():
|
|
504
747
|
# First resolve the `options` for the flow decorator.
|
|
505
748
|
# Options are passed from cli.
|
|
506
749
|
# For example `@project` can take a `--name` / `--branch` from the cli as options.
|
|
@@ -517,11 +760,19 @@ def _init_flow_decorators(
|
|
|
517
760
|
)
|
|
518
761
|
else:
|
|
519
762
|
# Each "non-multiple" flow decorator is only allowed to have one set of options
|
|
763
|
+
# Note that there may be no deco_options if a MutableFlow config injected
|
|
764
|
+
# the decorator.
|
|
520
765
|
deco_flow_init_options = {
|
|
521
|
-
option: deco_options
|
|
522
|
-
|
|
766
|
+
option: deco_options.get(
|
|
767
|
+
option.replace("-", "_"), option_info["default"]
|
|
768
|
+
)
|
|
769
|
+
for option, option_info in deco.options.items()
|
|
523
770
|
}
|
|
524
771
|
for deco in decorators:
|
|
772
|
+
if _should_skip_decorator_for_spin(
|
|
773
|
+
deco, is_spin, skip_decorators, logger, "Flow decorator"
|
|
774
|
+
):
|
|
775
|
+
continue
|
|
525
776
|
deco.flow_init(
|
|
526
777
|
flow,
|
|
527
778
|
graph,
|
|
@@ -534,9 +785,89 @@ def _init_flow_decorators(
|
|
|
534
785
|
)
|
|
535
786
|
|
|
536
787
|
|
|
537
|
-
def _init_step_decorators(
|
|
788
|
+
def _init_step_decorators(
|
|
789
|
+
flow,
|
|
790
|
+
graph,
|
|
791
|
+
environment,
|
|
792
|
+
flow_datastore,
|
|
793
|
+
logger,
|
|
794
|
+
is_spin=False,
|
|
795
|
+
skip_decorators=False,
|
|
796
|
+
):
|
|
797
|
+
# NOTE: We don't need the graph but keeping it for backwards compatibility with
|
|
798
|
+
# extensions that use it directly. We will remove it at some point.
|
|
799
|
+
|
|
800
|
+
# We call the mutate method for both the flow and step mutators.
|
|
801
|
+
cls = flow.__class__
|
|
802
|
+
# Run all the decorators. We first run the flow-level decorators
|
|
803
|
+
# and then the step level ones to maintain a consistent order with how
|
|
804
|
+
# other decorators are run.
|
|
805
|
+
|
|
806
|
+
for deco in cls._flow_state[FlowStateItems.FLOW_MUTATORS]:
|
|
807
|
+
if isinstance(deco, FlowMutator):
|
|
808
|
+
inserted_by_value = [deco.decorator_name] + (deco.inserted_by or [])
|
|
809
|
+
mutable_flow = MutableFlow(
|
|
810
|
+
cls,
|
|
811
|
+
pre_mutate=False,
|
|
812
|
+
statically_defined=deco.statically_defined,
|
|
813
|
+
inserted_by=inserted_by_value,
|
|
814
|
+
)
|
|
815
|
+
# Sanity check to make sure we are applying the decorator to the right
|
|
816
|
+
# class
|
|
817
|
+
if not deco._flow_cls == cls and not issubclass(cls, deco._flow_cls):
|
|
818
|
+
raise MetaflowInternalError(
|
|
819
|
+
"FlowMutator registered on the wrong flow -- "
|
|
820
|
+
"expected %s but got %s" % (deco._flow_cls.__name__, cls.__name__)
|
|
821
|
+
)
|
|
822
|
+
debug.userconf_exec(
|
|
823
|
+
"Evaluating flow level decorator %s (mutate)" % deco.__class__.__name__
|
|
824
|
+
)
|
|
825
|
+
deco.mutate(mutable_flow)
|
|
826
|
+
# We reset cached_parameters on the very off chance that the user added
|
|
827
|
+
# more configurations based on the configuration
|
|
828
|
+
if cls._flow_state[FlowStateItems.CACHED_PARAMETERS] is not None:
|
|
829
|
+
cls._flow_state[FlowStateItems.CACHED_PARAMETERS] = None
|
|
830
|
+
else:
|
|
831
|
+
raise MetaflowInternalError(
|
|
832
|
+
"A non FlowMutator found in flow custom decorators"
|
|
833
|
+
)
|
|
834
|
+
|
|
835
|
+
for step in cls._steps:
|
|
836
|
+
for deco in step.config_decorators:
|
|
837
|
+
inserted_by_value = [deco.decorator_name] + (deco.inserted_by or [])
|
|
838
|
+
|
|
839
|
+
if isinstance(deco, StepMutator):
|
|
840
|
+
debug.userconf_exec(
|
|
841
|
+
"Evaluating step level decorator %s for %s (mutate)"
|
|
842
|
+
% (deco.__class__.__name__, step.name)
|
|
843
|
+
)
|
|
844
|
+
deco.mutate(
|
|
845
|
+
MutableStep(
|
|
846
|
+
cls,
|
|
847
|
+
step,
|
|
848
|
+
pre_mutate=False,
|
|
849
|
+
statically_defined=deco.statically_defined,
|
|
850
|
+
inserted_by=inserted_by_value,
|
|
851
|
+
)
|
|
852
|
+
)
|
|
853
|
+
else:
|
|
854
|
+
raise MetaflowInternalError(
|
|
855
|
+
"A non StepMutator found in step custom decorators"
|
|
856
|
+
)
|
|
857
|
+
|
|
858
|
+
if step.config_decorators:
|
|
859
|
+
# We remove all mention of the custom step decorator
|
|
860
|
+
setattr(cls, step.name, step)
|
|
861
|
+
|
|
862
|
+
cls._init_graph()
|
|
863
|
+
graph = flow._graph
|
|
864
|
+
|
|
538
865
|
for step in flow:
|
|
539
866
|
for deco in step.decorators:
|
|
867
|
+
if _should_skip_decorator_for_spin(
|
|
868
|
+
deco, is_spin, skip_decorators, logger, "Step decorator"
|
|
869
|
+
):
|
|
870
|
+
continue
|
|
540
871
|
deco.step_init(
|
|
541
872
|
flow,
|
|
542
873
|
graph,
|
|
@@ -560,20 +891,18 @@ StepFlag = NewType("StepFlag", bool)
|
|
|
560
891
|
|
|
561
892
|
@overload
|
|
562
893
|
def step(
|
|
563
|
-
f: Callable[[FlowSpecDerived], None]
|
|
564
|
-
) -> Callable[[FlowSpecDerived, StepFlag], None]:
|
|
565
|
-
...
|
|
894
|
+
f: Callable[[FlowSpecDerived], None],
|
|
895
|
+
) -> Callable[[FlowSpecDerived, StepFlag], None]: ...
|
|
566
896
|
|
|
567
897
|
|
|
568
898
|
@overload
|
|
569
899
|
def step(
|
|
570
900
|
f: Callable[[FlowSpecDerived, Any], None],
|
|
571
|
-
) -> Callable[[FlowSpecDerived, Any, StepFlag], None]:
|
|
572
|
-
...
|
|
901
|
+
) -> Callable[[FlowSpecDerived, Any, StepFlag], None]: ...
|
|
573
902
|
|
|
574
903
|
|
|
575
904
|
def step(
|
|
576
|
-
f: Union[Callable[[FlowSpecDerived], None], Callable[[FlowSpecDerived, Any], None]]
|
|
905
|
+
f: Union[Callable[[FlowSpecDerived], None], Callable[[FlowSpecDerived, Any], None]],
|
|
577
906
|
):
|
|
578
907
|
"""
|
|
579
908
|
Marks a method in a FlowSpec as a Metaflow Step. Note that this
|
|
@@ -608,12 +937,9 @@ def step(
|
|
|
608
937
|
"""
|
|
609
938
|
f.is_step = True
|
|
610
939
|
f.decorators = []
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
except:
|
|
615
|
-
# python 2
|
|
616
|
-
f.name = f.__func__.func_name
|
|
940
|
+
f.config_decorators = []
|
|
941
|
+
f.wrappers = []
|
|
942
|
+
f.name = f.__name__
|
|
617
943
|
return f
|
|
618
944
|
|
|
619
945
|
|