metaflow 2.12.28__py2.py3-none-any.whl → 2.12.29__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/__init__.py +2 -3
- metaflow/cli.py +23 -13
- metaflow/client/core.py +2 -2
- metaflow/clone_util.py +1 -1
- metaflow/cmd/develop/stub_generator.py +623 -233
- metaflow/datastore/task_datastore.py +1 -1
- metaflow/extension_support/plugins.py +1 -0
- metaflow/flowspec.py +2 -2
- metaflow/includefile.py +8 -14
- metaflow/metaflow_config.py +4 -0
- metaflow/metaflow_current.py +1 -1
- metaflow/parameters.py +3 -0
- metaflow/plugins/__init__.py +12 -3
- metaflow/plugins/airflow/airflow_cli.py +5 -0
- metaflow/plugins/airflow/airflow_decorator.py +1 -1
- metaflow/plugins/argo/argo_workflows_decorator.py +1 -1
- metaflow/plugins/argo/argo_workflows_deployer.py +77 -263
- metaflow/plugins/argo/argo_workflows_deployer_objects.py +381 -0
- metaflow/plugins/aws/batch/batch_cli.py +1 -1
- metaflow/plugins/aws/batch/batch_decorator.py +2 -2
- metaflow/plugins/aws/step_functions/step_functions_cli.py +7 -0
- metaflow/plugins/aws/step_functions/step_functions_decorator.py +1 -1
- metaflow/plugins/aws/step_functions/step_functions_deployer.py +65 -224
- metaflow/plugins/aws/step_functions/step_functions_deployer_objects.py +236 -0
- metaflow/plugins/azure/includefile_support.py +2 -0
- metaflow/plugins/cards/card_cli.py +3 -2
- metaflow/plugins/cards/card_modules/components.py +9 -9
- metaflow/plugins/cards/card_server.py +39 -14
- metaflow/plugins/datatools/local.py +2 -0
- metaflow/plugins/datatools/s3/s3.py +2 -0
- metaflow/plugins/env_escape/__init__.py +3 -3
- metaflow/plugins/gcp/includefile_support.py +3 -0
- metaflow/plugins/kubernetes/kubernetes_cli.py +1 -1
- metaflow/plugins/kubernetes/kubernetes_decorator.py +5 -4
- metaflow/plugins/{metadata → metadata_providers}/local.py +2 -2
- metaflow/plugins/{metadata → metadata_providers}/service.py +2 -2
- metaflow/plugins/parallel_decorator.py +1 -1
- metaflow/plugins/pypi/conda_decorator.py +1 -1
- metaflow/plugins/test_unbounded_foreach_decorator.py +1 -1
- metaflow/runner/click_api.py +4 -0
- metaflow/runner/deployer.py +139 -269
- metaflow/runner/deployer_impl.py +167 -0
- metaflow/runner/metaflow_runner.py +10 -9
- metaflow/runner/nbdeploy.py +12 -13
- metaflow/runner/nbrun.py +3 -3
- metaflow/runner/utils.py +55 -8
- metaflow/runtime.py +1 -1
- metaflow/task.py +1 -1
- metaflow/version.py +1 -1
- {metaflow-2.12.28.dist-info → metaflow-2.12.29.dist-info}/METADATA +2 -2
- {metaflow-2.12.28.dist-info → metaflow-2.12.29.dist-info}/RECORD +60 -57
- /metaflow/{metadata → metadata_provider}/__init__.py +0 -0
- /metaflow/{metadata → metadata_provider}/heartbeat.py +0 -0
- /metaflow/{metadata → metadata_provider}/metadata.py +0 -0
- /metaflow/{metadata → metadata_provider}/util.py +0 -0
- /metaflow/plugins/{metadata → metadata_providers}/__init__.py +0 -0
- {metaflow-2.12.28.dist-info → metaflow-2.12.29.dist-info}/LICENSE +0 -0
- {metaflow-2.12.28.dist-info → metaflow-2.12.29.dist-info}/WHEEL +0 -0
- {metaflow-2.12.28.dist-info → metaflow-2.12.29.dist-info}/entry_points.txt +0 -0
- {metaflow-2.12.28.dist-info → metaflow-2.12.29.dist-info}/top_level.txt +0 -0
@@ -1,253 +1,94 @@
|
|
1
|
-
import
|
2
|
-
import json
|
3
|
-
import tempfile
|
4
|
-
from typing import Optional, ClassVar, List
|
5
|
-
|
6
|
-
from metaflow.plugins.aws.step_functions.step_functions import StepFunctions
|
7
|
-
from metaflow.runner.deployer import (
|
8
|
-
DeployerImpl,
|
9
|
-
DeployedFlow,
|
10
|
-
TriggeredRun,
|
11
|
-
get_lower_level_group,
|
12
|
-
handle_timeout,
|
13
|
-
)
|
14
|
-
|
15
|
-
|
16
|
-
def terminate(instance: TriggeredRun, **kwargs):
|
17
|
-
"""
|
18
|
-
Terminate the running workflow.
|
19
|
-
|
20
|
-
Parameters
|
21
|
-
----------
|
22
|
-
**kwargs : Any
|
23
|
-
Additional arguments to pass to the terminate command.
|
24
|
-
|
25
|
-
Returns
|
26
|
-
-------
|
27
|
-
bool
|
28
|
-
True if the command was successful, False otherwise.
|
29
|
-
"""
|
30
|
-
_, run_id = instance.pathspec.split("/")
|
1
|
+
from typing import Any, ClassVar, Dict, Optional, TYPE_CHECKING, Type
|
31
2
|
|
32
|
-
|
33
|
-
command = get_lower_level_group(
|
34
|
-
instance.deployer.api,
|
35
|
-
instance.deployer.top_level_kwargs,
|
36
|
-
instance.deployer.TYPE,
|
37
|
-
instance.deployer.deployer_kwargs,
|
38
|
-
).terminate(run_id=run_id, **kwargs)
|
3
|
+
from metaflow.runner.deployer_impl import DeployerImpl
|
39
4
|
|
40
|
-
|
41
|
-
|
42
|
-
env=instance.deployer.env_vars,
|
43
|
-
cwd=instance.deployer.cwd,
|
44
|
-
show_output=instance.deployer.show_output,
|
45
|
-
)
|
46
|
-
|
47
|
-
command_obj = instance.deployer.spm.get(pid)
|
48
|
-
return command_obj.process.returncode == 0
|
49
|
-
|
50
|
-
|
51
|
-
def production_token(instance: DeployedFlow):
|
52
|
-
"""
|
53
|
-
Get the production token for the deployed flow.
|
54
|
-
|
55
|
-
Returns
|
56
|
-
-------
|
57
|
-
str, optional
|
58
|
-
The production token, None if it cannot be retrieved.
|
59
|
-
"""
|
60
|
-
try:
|
61
|
-
_, production_token = StepFunctions.get_existing_deployment(
|
62
|
-
instance.deployer.name
|
63
|
-
)
|
64
|
-
return production_token
|
65
|
-
except TypeError:
|
66
|
-
return None
|
67
|
-
|
68
|
-
|
69
|
-
def list_runs(instance: DeployedFlow, states: Optional[List[str]] = None):
|
70
|
-
"""
|
71
|
-
List runs of the deployed flow.
|
72
|
-
|
73
|
-
Parameters
|
74
|
-
----------
|
75
|
-
states : Optional[List[str]], optional
|
76
|
-
A list of states to filter the runs by. Allowed values are:
|
77
|
-
RUNNING, SUCCEEDED, FAILED, TIMED_OUT, ABORTED.
|
78
|
-
If not provided, all states will be considered.
|
79
|
-
|
80
|
-
Returns
|
81
|
-
-------
|
82
|
-
List[TriggeredRun]
|
83
|
-
A list of TriggeredRun objects representing the runs of the deployed flow.
|
84
|
-
|
85
|
-
Raises
|
86
|
-
------
|
87
|
-
ValueError
|
88
|
-
If any of the provided states are invalid or if there are duplicate states.
|
89
|
-
"""
|
90
|
-
VALID_STATES = {"RUNNING", "SUCCEEDED", "FAILED", "TIMED_OUT", "ABORTED"}
|
91
|
-
|
92
|
-
if states is None:
|
93
|
-
states = []
|
94
|
-
|
95
|
-
unique_states = set(states)
|
96
|
-
if not unique_states.issubset(VALID_STATES):
|
97
|
-
invalid_states = unique_states - VALID_STATES
|
98
|
-
raise ValueError(
|
99
|
-
f"Invalid states found: {invalid_states}. Valid states are: {VALID_STATES}"
|
100
|
-
)
|
101
|
-
|
102
|
-
if len(states) != len(unique_states):
|
103
|
-
raise ValueError("Duplicate states are not allowed")
|
104
|
-
|
105
|
-
triggered_runs = []
|
106
|
-
executions = StepFunctions.list(instance.deployer.name, states)
|
107
|
-
|
108
|
-
for e in executions:
|
109
|
-
run_id = "sfn-%s" % e["name"]
|
110
|
-
tr = TriggeredRun(
|
111
|
-
deployer=instance.deployer,
|
112
|
-
content=json.dumps(
|
113
|
-
{
|
114
|
-
"metadata": instance.deployer.metadata,
|
115
|
-
"pathspec": "/".join((instance.deployer.flow_name, run_id)),
|
116
|
-
"name": run_id,
|
117
|
-
}
|
118
|
-
),
|
119
|
-
)
|
120
|
-
tr._enrich_object({"terminate": terminate})
|
121
|
-
triggered_runs.append(tr)
|
122
|
-
|
123
|
-
return triggered_runs
|
124
|
-
|
125
|
-
|
126
|
-
def delete(instance: DeployedFlow, **kwargs):
|
127
|
-
"""
|
128
|
-
Delete the deployed flow.
|
129
|
-
|
130
|
-
Parameters
|
131
|
-
----------
|
132
|
-
**kwargs : Any
|
133
|
-
Additional arguments to pass to the delete command.
|
134
|
-
|
135
|
-
Returns
|
136
|
-
-------
|
137
|
-
bool
|
138
|
-
True if the command was successful, False otherwise.
|
139
|
-
"""
|
140
|
-
command = get_lower_level_group(
|
141
|
-
instance.deployer.api,
|
142
|
-
instance.deployer.top_level_kwargs,
|
143
|
-
instance.deployer.TYPE,
|
144
|
-
instance.deployer.deployer_kwargs,
|
145
|
-
).delete(**kwargs)
|
146
|
-
|
147
|
-
pid = instance.deployer.spm.run_command(
|
148
|
-
[sys.executable, *command],
|
149
|
-
env=instance.deployer.env_vars,
|
150
|
-
cwd=instance.deployer.cwd,
|
151
|
-
show_output=instance.deployer.show_output,
|
152
|
-
)
|
153
|
-
|
154
|
-
command_obj = instance.deployer.spm.get(pid)
|
155
|
-
return command_obj.process.returncode == 0
|
156
|
-
|
157
|
-
|
158
|
-
def trigger(instance: DeployedFlow, **kwargs):
|
159
|
-
"""
|
160
|
-
Trigger a new run for the deployed flow.
|
161
|
-
|
162
|
-
Parameters
|
163
|
-
----------
|
164
|
-
**kwargs : Any
|
165
|
-
Additional arguments to pass to the trigger command, `Parameters` in particular
|
166
|
-
|
167
|
-
Returns
|
168
|
-
-------
|
169
|
-
StepFunctionsTriggeredRun
|
170
|
-
The triggered run instance.
|
171
|
-
|
172
|
-
Raises
|
173
|
-
------
|
174
|
-
Exception
|
175
|
-
If there is an error during the trigger process.
|
176
|
-
"""
|
177
|
-
with tempfile.TemporaryDirectory() as temp_dir:
|
178
|
-
tfp_runner_attribute = tempfile.NamedTemporaryFile(dir=temp_dir, delete=False)
|
179
|
-
|
180
|
-
# every subclass needs to have `self.deployer_kwargs`
|
181
|
-
command = get_lower_level_group(
|
182
|
-
instance.deployer.api,
|
183
|
-
instance.deployer.top_level_kwargs,
|
184
|
-
instance.deployer.TYPE,
|
185
|
-
instance.deployer.deployer_kwargs,
|
186
|
-
).trigger(deployer_attribute_file=tfp_runner_attribute.name, **kwargs)
|
187
|
-
|
188
|
-
pid = instance.deployer.spm.run_command(
|
189
|
-
[sys.executable, *command],
|
190
|
-
env=instance.deployer.env_vars,
|
191
|
-
cwd=instance.deployer.cwd,
|
192
|
-
show_output=instance.deployer.show_output,
|
193
|
-
)
|
194
|
-
|
195
|
-
command_obj = instance.deployer.spm.get(pid)
|
196
|
-
content = handle_timeout(
|
197
|
-
tfp_runner_attribute, command_obj, instance.deployer.file_read_timeout
|
198
|
-
)
|
199
|
-
|
200
|
-
if command_obj.process.returncode == 0:
|
201
|
-
triggered_run = TriggeredRun(deployer=instance.deployer, content=content)
|
202
|
-
triggered_run._enrich_object({"terminate": terminate})
|
203
|
-
return triggered_run
|
204
|
-
|
205
|
-
raise Exception(
|
206
|
-
"Error triggering %s on %s for %s"
|
207
|
-
% (instance.deployer.name, instance.deployer.TYPE, instance.deployer.flow_file)
|
208
|
-
)
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
import metaflow.plugins.aws.step_functions.step_functions_deployer_objects
|
209
7
|
|
210
8
|
|
211
9
|
class StepFunctionsDeployer(DeployerImpl):
|
212
10
|
"""
|
213
11
|
Deployer implementation for AWS Step Functions.
|
214
12
|
|
215
|
-
|
13
|
+
Parameters
|
216
14
|
----------
|
217
|
-
|
218
|
-
The
|
15
|
+
name : str, optional, default None
|
16
|
+
State Machine name. The flow name is used instead if this option is not specified.
|
219
17
|
"""
|
220
18
|
|
221
19
|
TYPE: ClassVar[Optional[str]] = "step-functions"
|
222
20
|
|
223
|
-
def __init__(self, deployer_kwargs, **kwargs):
|
21
|
+
def __init__(self, deployer_kwargs: Dict[str, str], **kwargs):
|
224
22
|
"""
|
225
23
|
Initialize the StepFunctionsDeployer.
|
226
24
|
|
227
25
|
Parameters
|
228
26
|
----------
|
229
|
-
deployer_kwargs :
|
27
|
+
deployer_kwargs : Dict[str, str]
|
230
28
|
The deployer-specific keyword arguments.
|
231
29
|
**kwargs : Any
|
232
30
|
Additional arguments to pass to the superclass constructor.
|
233
31
|
"""
|
234
|
-
self.
|
32
|
+
self._deployer_kwargs = deployer_kwargs
|
235
33
|
super().__init__(**kwargs)
|
236
34
|
|
237
|
-
|
35
|
+
@property
|
36
|
+
def deployer_kwargs(self) -> Dict[str, Any]:
|
37
|
+
return self._deployer_kwargs
|
38
|
+
|
39
|
+
@staticmethod
|
40
|
+
def deployed_flow_type() -> (
|
41
|
+
Type[
|
42
|
+
"metaflow.plugins.aws.step_functions.step_functions_deployer_objects.StepFunctionsDeployedFlow"
|
43
|
+
]
|
44
|
+
):
|
45
|
+
from .step_functions_deployer_objects import StepFunctionsDeployedFlow
|
46
|
+
|
47
|
+
return StepFunctionsDeployedFlow
|
48
|
+
|
49
|
+
def create(
|
50
|
+
self, **kwargs
|
51
|
+
) -> "metaflow.plugins.aws.step_functions.step_functions_deployer_objects.StepFunctionsDeployedFlow":
|
238
52
|
"""
|
239
|
-
|
53
|
+
Create a new AWS Step Functions State Machine deployment.
|
240
54
|
|
241
55
|
Parameters
|
242
56
|
----------
|
243
|
-
|
244
|
-
|
57
|
+
authorize : str, optional, default None
|
58
|
+
Authorize using this production token. Required when re-deploying an existing flow
|
59
|
+
for the first time. The token is cached in METAFLOW_HOME.
|
60
|
+
generate_new_token : bool, optional, default False
|
61
|
+
Generate a new production token for this flow. Moves the production flow to a new namespace.
|
62
|
+
given_token : str, optional, default None
|
63
|
+
Use the given production token for this flow. Moves the production flow to the given namespace.
|
64
|
+
tags : List[str], optional, default None
|
65
|
+
Annotate all objects produced by AWS Step Functions runs with these tags.
|
66
|
+
user_namespace : str, optional, default None
|
67
|
+
Change the namespace from the default (production token) to the given tag.
|
68
|
+
only_json : bool, optional, default False
|
69
|
+
Only print out JSON sent to AWS Step Functions without deploying anything.
|
70
|
+
max_workers : int, optional, default 100
|
71
|
+
Maximum number of parallel processes.
|
72
|
+
workflow_timeout : int, optional, default None
|
73
|
+
Workflow timeout in seconds.
|
74
|
+
log_execution_history : bool, optional, default False
|
75
|
+
Log AWS Step Functions execution history to AWS CloudWatch Logs log group.
|
76
|
+
use_distributed_map : bool, optional, default False
|
77
|
+
Use AWS Step Functions Distributed Map instead of Inline Map for defining foreach
|
78
|
+
tasks in Amazon State Language.
|
79
|
+
deployer_attribute_file : str, optional, default None
|
80
|
+
Write the workflow name to the specified file. Used internally for Metaflow's Deployer API.
|
81
|
+
|
82
|
+
Returns
|
83
|
+
-------
|
84
|
+
StepFunctionsDeployedFlow
|
85
|
+
The Flow deployed to AWS Step Functions.
|
245
86
|
"""
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
87
|
+
from .step_functions_deployer_objects import StepFunctionsDeployedFlow
|
88
|
+
|
89
|
+
return self._create(StepFunctionsDeployedFlow, **kwargs)
|
90
|
+
|
91
|
+
|
92
|
+
_addl_stubgen_modules = [
|
93
|
+
"metaflow.plugins.aws.step_functions.step_functions_deployer_objects"
|
94
|
+
]
|
@@ -0,0 +1,236 @@
|
|
1
|
+
import sys
|
2
|
+
import json
|
3
|
+
import tempfile
|
4
|
+
from typing import ClassVar, Optional, List
|
5
|
+
|
6
|
+
from metaflow.plugins.aws.step_functions.step_functions import StepFunctions
|
7
|
+
from metaflow.runner.deployer import DeployedFlow, TriggeredRun
|
8
|
+
|
9
|
+
from metaflow.runner.utils import get_lower_level_group, handle_timeout
|
10
|
+
|
11
|
+
|
12
|
+
class StepFunctionsTriggeredRun(TriggeredRun):
|
13
|
+
"""
|
14
|
+
A class representing a triggered AWS Step Functions state machine execution.
|
15
|
+
"""
|
16
|
+
|
17
|
+
def terminate(self, **kwargs) -> bool:
|
18
|
+
"""
|
19
|
+
Terminate the running state machine execution.
|
20
|
+
|
21
|
+
Parameters
|
22
|
+
----------
|
23
|
+
authorize : str, optional, default None
|
24
|
+
Authorize the termination with a production token.
|
25
|
+
|
26
|
+
Returns
|
27
|
+
-------
|
28
|
+
bool
|
29
|
+
True if the command was successful, False otherwise.
|
30
|
+
"""
|
31
|
+
_, run_id = self.pathspec.split("/")
|
32
|
+
|
33
|
+
# every subclass needs to have `self.deployer_kwargs`
|
34
|
+
command = get_lower_level_group(
|
35
|
+
self.deployer.api,
|
36
|
+
self.deployer.top_level_kwargs,
|
37
|
+
self.deployer.TYPE,
|
38
|
+
self.deployer.deployer_kwargs,
|
39
|
+
).terminate(run_id=run_id, **kwargs)
|
40
|
+
|
41
|
+
pid = self.deployer.spm.run_command(
|
42
|
+
[sys.executable, *command],
|
43
|
+
env=self.deployer.env_vars,
|
44
|
+
cwd=self.deployer.cwd,
|
45
|
+
show_output=self.deployer.show_output,
|
46
|
+
)
|
47
|
+
|
48
|
+
command_obj = self.deployer.spm.get(pid)
|
49
|
+
return command_obj.process.returncode == 0
|
50
|
+
|
51
|
+
|
52
|
+
class StepFunctionsDeployedFlow(DeployedFlow):
|
53
|
+
"""
|
54
|
+
A class representing a deployed AWS Step Functions state machine.
|
55
|
+
"""
|
56
|
+
|
57
|
+
TYPE: ClassVar[Optional[str]] = "step-functions"
|
58
|
+
|
59
|
+
@classmethod
|
60
|
+
def from_deployment(cls, identifier: str, metadata: Optional[str] = None):
|
61
|
+
"""
|
62
|
+
This method is not currently implemented for Step Functions.
|
63
|
+
|
64
|
+
Raises
|
65
|
+
------
|
66
|
+
NotImplementedError
|
67
|
+
This method is not implemented for Step Functions.
|
68
|
+
"""
|
69
|
+
raise NotImplementedError(
|
70
|
+
"from_deployment is not implemented for StepFunctions"
|
71
|
+
)
|
72
|
+
|
73
|
+
@property
|
74
|
+
def production_token(self: DeployedFlow) -> Optional[str]:
|
75
|
+
"""
|
76
|
+
Get the production token for the deployed flow.
|
77
|
+
|
78
|
+
Returns
|
79
|
+
-------
|
80
|
+
str, optional
|
81
|
+
The production token, None if it cannot be retrieved.
|
82
|
+
"""
|
83
|
+
try:
|
84
|
+
_, production_token = StepFunctions.get_existing_deployment(
|
85
|
+
self.deployer.name
|
86
|
+
)
|
87
|
+
return production_token
|
88
|
+
except TypeError:
|
89
|
+
return None
|
90
|
+
|
91
|
+
def list_runs(
|
92
|
+
self, states: Optional[List[str]] = None
|
93
|
+
) -> List[StepFunctionsTriggeredRun]:
|
94
|
+
"""
|
95
|
+
List runs of the deployed flow.
|
96
|
+
|
97
|
+
Parameters
|
98
|
+
----------
|
99
|
+
states : List[str], optional, default None
|
100
|
+
A list of states to filter the runs by. Allowed values are:
|
101
|
+
RUNNING, SUCCEEDED, FAILED, TIMED_OUT, ABORTED.
|
102
|
+
If not provided, all states will be considered.
|
103
|
+
|
104
|
+
Returns
|
105
|
+
-------
|
106
|
+
List[StepFunctionsTriggeredRun]
|
107
|
+
A list of TriggeredRun objects representing the runs of the deployed flow.
|
108
|
+
|
109
|
+
Raises
|
110
|
+
------
|
111
|
+
ValueError
|
112
|
+
If any of the provided states are invalid or if there are duplicate states.
|
113
|
+
"""
|
114
|
+
VALID_STATES = {"RUNNING", "SUCCEEDED", "FAILED", "TIMED_OUT", "ABORTED"}
|
115
|
+
|
116
|
+
if states is None:
|
117
|
+
states = []
|
118
|
+
|
119
|
+
unique_states = set(states)
|
120
|
+
if not unique_states.issubset(VALID_STATES):
|
121
|
+
invalid_states = unique_states - VALID_STATES
|
122
|
+
raise ValueError(
|
123
|
+
f"Invalid states found: {invalid_states}. Valid states are: {VALID_STATES}"
|
124
|
+
)
|
125
|
+
|
126
|
+
if len(states) != len(unique_states):
|
127
|
+
raise ValueError("Duplicate states are not allowed")
|
128
|
+
|
129
|
+
triggered_runs = []
|
130
|
+
executions = StepFunctions.list(self.deployer.name, states)
|
131
|
+
|
132
|
+
for e in executions:
|
133
|
+
run_id = "sfn-%s" % e["name"]
|
134
|
+
tr = StepFunctionsTriggeredRun(
|
135
|
+
deployer=self.deployer,
|
136
|
+
content=json.dumps(
|
137
|
+
{
|
138
|
+
"metadata": self.deployer.metadata,
|
139
|
+
"pathspec": "/".join((self.deployer.flow_name, run_id)),
|
140
|
+
"name": run_id,
|
141
|
+
}
|
142
|
+
),
|
143
|
+
)
|
144
|
+
triggered_runs.append(tr)
|
145
|
+
|
146
|
+
return triggered_runs
|
147
|
+
|
148
|
+
def delete(self, **kwargs) -> bool:
|
149
|
+
"""
|
150
|
+
Delete the deployed state machine.
|
151
|
+
|
152
|
+
Parameters
|
153
|
+
----------
|
154
|
+
authorize : str, optional, default None
|
155
|
+
Authorize the deletion with a production token.
|
156
|
+
|
157
|
+
Returns
|
158
|
+
-------
|
159
|
+
bool
|
160
|
+
True if the command was successful, False otherwise.
|
161
|
+
"""
|
162
|
+
command = get_lower_level_group(
|
163
|
+
self.deployer.api,
|
164
|
+
self.deployer.top_level_kwargs,
|
165
|
+
self.deployer.TYPE,
|
166
|
+
self.deployer.deployer_kwargs,
|
167
|
+
).delete(**kwargs)
|
168
|
+
|
169
|
+
pid = self.deployer.spm.run_command(
|
170
|
+
[sys.executable, *command],
|
171
|
+
env=self.deployer.env_vars,
|
172
|
+
cwd=self.deployer.cwd,
|
173
|
+
show_output=self.deployer.show_output,
|
174
|
+
)
|
175
|
+
|
176
|
+
command_obj = self.deployer.spm.get(pid)
|
177
|
+
return command_obj.process.returncode == 0
|
178
|
+
|
179
|
+
def trigger(self, **kwargs) -> StepFunctionsTriggeredRun:
|
180
|
+
"""
|
181
|
+
Trigger a new run for the deployed flow.
|
182
|
+
|
183
|
+
Parameters
|
184
|
+
----------
|
185
|
+
**kwargs : Any
|
186
|
+
Additional arguments to pass to the trigger command,
|
187
|
+
`Parameters` in particular
|
188
|
+
|
189
|
+
Returns
|
190
|
+
-------
|
191
|
+
StepFunctionsTriggeredRun
|
192
|
+
The triggered run instance.
|
193
|
+
|
194
|
+
Raises
|
195
|
+
------
|
196
|
+
Exception
|
197
|
+
If there is an error during the trigger process.
|
198
|
+
"""
|
199
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
200
|
+
tfp_runner_attribute = tempfile.NamedTemporaryFile(
|
201
|
+
dir=temp_dir, delete=False
|
202
|
+
)
|
203
|
+
|
204
|
+
# every subclass needs to have `self.deployer_kwargs`
|
205
|
+
command = get_lower_level_group(
|
206
|
+
self.deployer.api,
|
207
|
+
self.deployer.top_level_kwargs,
|
208
|
+
self.deployer.TYPE,
|
209
|
+
self.deployer.deployer_kwargs,
|
210
|
+
).trigger(deployer_attribute_file=tfp_runner_attribute.name, **kwargs)
|
211
|
+
|
212
|
+
pid = self.deployer.spm.run_command(
|
213
|
+
[sys.executable, *command],
|
214
|
+
env=self.deployer.env_vars,
|
215
|
+
cwd=self.deployer.cwd,
|
216
|
+
show_output=self.deployer.show_output,
|
217
|
+
)
|
218
|
+
|
219
|
+
command_obj = self.deployer.spm.get(pid)
|
220
|
+
content = handle_timeout(
|
221
|
+
tfp_runner_attribute, command_obj, self.deployer.file_read_timeout
|
222
|
+
)
|
223
|
+
|
224
|
+
if command_obj.process.returncode == 0:
|
225
|
+
return StepFunctionsTriggeredRun(
|
226
|
+
deployer=self.deployer, content=content
|
227
|
+
)
|
228
|
+
|
229
|
+
raise Exception(
|
230
|
+
"Error triggering %s on %s for %s"
|
231
|
+
% (
|
232
|
+
self.deployer.name,
|
233
|
+
self.deployer.TYPE,
|
234
|
+
self.deployer.flow_file,
|
235
|
+
)
|
236
|
+
)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from metaflow.client import Task
|
2
|
-
from metaflow import
|
2
|
+
from metaflow.parameters import JSONTypeClass
|
3
|
+
from metaflow import namespace
|
3
4
|
from metaflow.util import resolve_identity
|
4
5
|
from metaflow.exception import (
|
5
6
|
CommandException,
|
@@ -551,7 +552,7 @@ def update_card(mf_card, mode, task, data, timeout_value=None):
|
|
551
552
|
"--options",
|
552
553
|
default=None,
|
553
554
|
show_default=True,
|
554
|
-
type=
|
555
|
+
type=JSONTypeClass(),
|
555
556
|
help="arguments of the card being created.",
|
556
557
|
)
|
557
558
|
@click.option(
|
@@ -712,15 +712,15 @@ class ProgressBar(UserComponent):
|
|
712
712
|
|
713
713
|
Parameters
|
714
714
|
----------
|
715
|
-
max : int
|
715
|
+
max : int, default 100
|
716
716
|
The maximum value of the progress bar.
|
717
|
-
label : str, optional
|
717
|
+
label : str, optional, default None
|
718
718
|
Optional label for the progress bar.
|
719
|
-
value : int,
|
719
|
+
value : int, default 0
|
720
720
|
Optional initial value of the progress bar.
|
721
|
-
unit : str, optional
|
721
|
+
unit : str, optional, default None
|
722
722
|
Optional unit for the progress bar.
|
723
|
-
metadata : str, optional
|
723
|
+
metadata : str, optional, default None
|
724
724
|
Optional additional information to show on the progress bar.
|
725
725
|
"""
|
726
726
|
|
@@ -731,10 +731,10 @@ class ProgressBar(UserComponent):
|
|
731
731
|
def __init__(
|
732
732
|
self,
|
733
733
|
max: int = 100,
|
734
|
-
label: str = None,
|
734
|
+
label: Optional[str] = None,
|
735
735
|
value: int = 0,
|
736
|
-
unit: str = None,
|
737
|
-
metadata: str = None,
|
736
|
+
unit: Optional[str] = None,
|
737
|
+
metadata: Optional[str] = None,
|
738
738
|
):
|
739
739
|
self._label = label
|
740
740
|
self._max = max
|
@@ -742,7 +742,7 @@ class ProgressBar(UserComponent):
|
|
742
742
|
self._unit = unit
|
743
743
|
self._metadata = metadata
|
744
744
|
|
745
|
-
def update(self, new_value: int, metadata: str = None):
|
745
|
+
def update(self, new_value: int, metadata: Optional[str] = None):
|
746
746
|
self._value = new_value
|
747
747
|
if metadata is not None:
|
748
748
|
self._metadata = metadata
|
@@ -20,14 +20,9 @@ except ImportError:
|
|
20
20
|
from .card_client import CardContainer
|
21
21
|
from .exception import CardNotPresentException
|
22
22
|
from .card_resolver import resolve_paths_from_task
|
23
|
-
from metaflow.metaflow_config import DATASTORE_LOCAL_DIR
|
24
23
|
from metaflow import namespace
|
25
|
-
from metaflow.exception import
|
26
|
-
|
27
|
-
MetaflowNotFound,
|
28
|
-
MetaflowNamespaceMismatch,
|
29
|
-
)
|
30
|
-
|
24
|
+
from metaflow.exception import MetaflowNotFound
|
25
|
+
from metaflow.plugins.datastores.local_storage import LocalStorage
|
31
26
|
|
32
27
|
VIEWER_PATH = os.path.join(
|
33
28
|
os.path.dirname(os.path.abspath(__file__)), "card_viewer", "viewer.html"
|
@@ -50,18 +45,48 @@ class RunWatcher(Thread):
|
|
50
45
|
def __init__(self, flow_name, connection: Connection):
|
51
46
|
super().__init__()
|
52
47
|
|
53
|
-
self._watch_file = os.path.join(
|
54
|
-
os.getcwd(), DATASTORE_LOCAL_DIR, flow_name, "latest_run"
|
55
|
-
)
|
56
|
-
self._current_run_id = self.get_run_id()
|
57
48
|
self.daemon = True
|
58
49
|
self._connection = connection
|
50
|
+
self._flow_name = flow_name
|
51
|
+
|
52
|
+
self._watch_file = self._initialize_watch_file()
|
53
|
+
if self._watch_file is None:
|
54
|
+
_ClickLogger(
|
55
|
+
"Warning: Could not initialize watch file location.", fg="yellow"
|
56
|
+
)
|
57
|
+
|
58
|
+
self._current_run_id = self.get_run_id()
|
59
|
+
|
60
|
+
def _initialize_watch_file(self):
|
61
|
+
local_root = LocalStorage.datastore_root
|
62
|
+
if local_root is None:
|
63
|
+
local_root = LocalStorage.get_datastore_root_from_config(
|
64
|
+
lambda _: None, create_on_absent=False
|
65
|
+
)
|
66
|
+
|
67
|
+
return (
|
68
|
+
os.path.join(local_root, self._flow_name, "latest_run")
|
69
|
+
if local_root
|
70
|
+
else None
|
71
|
+
)
|
59
72
|
|
60
73
|
def get_run_id(self):
|
61
|
-
if
|
74
|
+
# Try to reinitialize watch file if needed
|
75
|
+
if not self._watch_file:
|
76
|
+
self._watch_file = self._initialize_watch_file()
|
77
|
+
|
78
|
+
# Early return if watch file is still None or doesn't exist
|
79
|
+
if not (self._watch_file and os.path.exists(self._watch_file)):
|
80
|
+
return None
|
81
|
+
|
82
|
+
try:
|
83
|
+
with open(self._watch_file, "r") as f:
|
84
|
+
return f.read().strip()
|
85
|
+
except (IOError, OSError) as e:
|
86
|
+
_ClickLogger(
|
87
|
+
"Warning: Could not read run ID from watch file: %s" % e, fg="yellow"
|
88
|
+
)
|
62
89
|
return None
|
63
|
-
with open(self._watch_file, "r") as f:
|
64
|
-
return f.read().strip()
|
65
90
|
|
66
91
|
def watch(self):
|
67
92
|
while True:
|