metaflow 2.12.28__py2.py3-none-any.whl → 2.12.30__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/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.30.dist-info}/METADATA +2 -2
- {metaflow-2.12.28.dist-info → metaflow-2.12.30.dist-info}/RECORD +59 -56
- {metaflow-2.12.28.dist-info → metaflow-2.12.30.dist-info}/WHEEL +1 -1
- /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.30.dist-info}/LICENSE +0 -0
- {metaflow-2.12.28.dist-info → metaflow-2.12.30.dist-info}/entry_points.txt +0 -0
- {metaflow-2.12.28.dist-info → metaflow-2.12.30.dist-info}/top_level.txt +0 -0
@@ -124,9 +124,9 @@ def load():
|
|
124
124
|
cur_path = os.path.dirname(__file__)
|
125
125
|
sys.path = [p for p in old_paths if p != cur_path]
|
126
126
|
# Handle special case where we launch a shell (including with a command)
|
127
|
-
# and we are in the CWD (searched if '' is
|
128
|
-
if cur_path == os.getcwd() and sys.path
|
129
|
-
sys.path
|
127
|
+
# and we are in the CWD (searched if '' is present in sys.path)
|
128
|
+
if cur_path == os.getcwd() and '' in sys.path:
|
129
|
+
sys.path.remove("")
|
130
130
|
|
131
131
|
# Remove the module (this file) to reload it properly. Do *NOT* update sys.modules but
|
132
132
|
# modify directly since it may be referenced elsewhere
|
@@ -9,7 +9,7 @@ import metaflow.tracing as tracing
|
|
9
9
|
from metaflow import JSONTypeClass, util
|
10
10
|
from metaflow._vendor import click
|
11
11
|
from metaflow.exception import METAFLOW_EXIT_DISALLOW_RETRY, MetaflowException
|
12
|
-
from metaflow.
|
12
|
+
from metaflow.metadata_provider.util import sync_local_metadata_from_datastore
|
13
13
|
from metaflow.metaflow_config import DATASTORE_LOCAL_DIR, KUBERNETES_LABELS
|
14
14
|
from metaflow.mflog import TASK_LOG_SOURCE
|
15
15
|
from metaflow.unbounded_foreach import UBF_CONTROL, UBF_TASK
|
@@ -7,8 +7,8 @@ import time
|
|
7
7
|
from metaflow import current
|
8
8
|
from metaflow.decorators import StepDecorator
|
9
9
|
from metaflow.exception import MetaflowException
|
10
|
-
from metaflow.
|
11
|
-
from metaflow.
|
10
|
+
from metaflow.metadata_provider import MetaDatum
|
11
|
+
from metaflow.metadata_provider.util import sync_local_metadata_to_datastore
|
12
12
|
from metaflow.metaflow_config import (
|
13
13
|
DATASTORE_LOCAL_DIR,
|
14
14
|
KUBERNETES_CONTAINER_IMAGE,
|
@@ -73,8 +73,9 @@ class KubernetesDecorator(StepDecorator):
|
|
73
73
|
in Metaflow configuration.
|
74
74
|
node_selector: Union[Dict[str,str], str], optional, default None
|
75
75
|
Kubernetes node selector(s) to apply to the pod running the task.
|
76
|
-
Can be passed in as a comma separated string of values e.g.
|
77
|
-
|
76
|
+
Can be passed in as a comma separated string of values e.g.
|
77
|
+
'kubernetes.io/os=linux,kubernetes.io/arch=amd64' or as a dictionary
|
78
|
+
{'kubernetes.io/os': 'linux', 'kubernetes.io/arch': 'amd64'}
|
78
79
|
namespace : str, default METAFLOW_KUBERNETES_NAMESPACE
|
79
80
|
Kubernetes namespace to use when launching pod in Kubernetes.
|
80
81
|
gpu : int, optional, default None
|
@@ -8,9 +8,9 @@ import time
|
|
8
8
|
from collections import namedtuple
|
9
9
|
|
10
10
|
from metaflow.exception import MetaflowInternalError, MetaflowTaggingError
|
11
|
-
from metaflow.
|
11
|
+
from metaflow.metadata_provider.metadata import ObjectOrder
|
12
12
|
from metaflow.metaflow_config import DATASTORE_LOCAL_DIR
|
13
|
-
from metaflow.
|
13
|
+
from metaflow.metadata_provider import MetadataProvider
|
14
14
|
from metaflow.tagging_util import MAX_USER_TAG_SET_SIZE, validate_tags
|
15
15
|
|
16
16
|
|
@@ -14,8 +14,8 @@ from metaflow.metaflow_config import (
|
|
14
14
|
SERVICE_HEADERS,
|
15
15
|
SERVICE_URL,
|
16
16
|
)
|
17
|
-
from metaflow.
|
18
|
-
from metaflow.
|
17
|
+
from metaflow.metadata_provider import MetadataProvider
|
18
|
+
from metaflow.metadata_provider.heartbeat import HB_URL_KEY
|
19
19
|
from metaflow.sidecar import Message, MessageTypes, Sidecar
|
20
20
|
|
21
21
|
from metaflow.util import version_parse
|
@@ -2,7 +2,7 @@ from collections import namedtuple
|
|
2
2
|
from metaflow.decorators import StepDecorator
|
3
3
|
from metaflow.unbounded_foreach import UBF_CONTROL, CONTROL_TASK_TAG
|
4
4
|
from metaflow.exception import MetaflowException
|
5
|
-
from metaflow.
|
5
|
+
from metaflow.metadata_provider import MetaDatum
|
6
6
|
from metaflow.metaflow_current import current, Parallel
|
7
7
|
import os
|
8
8
|
import sys
|
@@ -8,7 +8,7 @@ import tempfile
|
|
8
8
|
|
9
9
|
from metaflow.decorators import FlowDecorator, StepDecorator
|
10
10
|
from metaflow.extension_support import EXT_PKG
|
11
|
-
from metaflow.
|
11
|
+
from metaflow.metadata_provider import MetaDatum
|
12
12
|
from metaflow.metaflow_environment import InvalidEnvironmentException
|
13
13
|
from metaflow.util import get_metaflow_root
|
14
14
|
|
@@ -15,7 +15,7 @@ from metaflow.unbounded_foreach import (
|
|
15
15
|
CONTROL_TASK_TAG,
|
16
16
|
)
|
17
17
|
from metaflow.util import to_unicode
|
18
|
-
from metaflow.
|
18
|
+
from metaflow.metadata_provider import MetaDatum
|
19
19
|
|
20
20
|
|
21
21
|
class InternalTestUnboundedForeachInput(UnboundedForeachInput):
|
metaflow/runner/click_api.py
CHANGED
@@ -193,6 +193,10 @@ class MetaflowAPI(object):
|
|
193
193
|
def chain(self):
|
194
194
|
return self._chain
|
195
195
|
|
196
|
+
@property
|
197
|
+
def name(self):
|
198
|
+
return self._API_NAME
|
199
|
+
|
196
200
|
@classmethod
|
197
201
|
def from_cli(cls, flow_file: str, cli_collection: Callable) -> Callable:
|
198
202
|
flow_cls = extract_flow_class_from_file(flow_file)
|
metaflow/runner/deployer.py
CHANGED
@@ -1,53 +1,50 @@
|
|
1
|
-
import os
|
2
|
-
import sys
|
3
1
|
import json
|
4
2
|
import time
|
5
|
-
import importlib
|
6
|
-
import functools
|
7
|
-
import tempfile
|
8
3
|
|
9
|
-
from typing import
|
4
|
+
from typing import ClassVar, Dict, Optional, TYPE_CHECKING
|
10
5
|
|
11
6
|
from metaflow.exception import MetaflowNotFound
|
12
|
-
from metaflow.
|
13
|
-
from metaflow.runner.utils import handle_timeout
|
7
|
+
from metaflow.metaflow_config import DEFAULT_FROM_DEPLOYMENT_IMPL
|
14
8
|
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
import metaflow
|
11
|
+
import metaflow.runner.deployer_impl
|
15
12
|
|
16
|
-
def get_lower_level_group(
|
17
|
-
api, top_level_kwargs: Dict, _type: Optional[str], deployer_kwargs: Dict
|
18
|
-
):
|
19
|
-
"""
|
20
|
-
Retrieve a lower-level group from the API based on the type and provided arguments.
|
21
13
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
14
|
+
class DeployerMeta(type):
|
15
|
+
def __new__(mcs, name, bases, dct):
|
16
|
+
cls = super().__new__(mcs, name, bases, dct)
|
17
|
+
|
18
|
+
from metaflow.plugins import DEPLOYER_IMPL_PROVIDERS
|
19
|
+
|
20
|
+
def _injected_method(method_name, deployer_class):
|
21
|
+
def f(self, **deployer_kwargs):
|
22
|
+
return deployer_class(
|
23
|
+
deployer_kwargs=deployer_kwargs,
|
24
|
+
flow_file=self.flow_file,
|
25
|
+
show_output=self.show_output,
|
26
|
+
profile=self.profile,
|
27
|
+
env=self.env,
|
28
|
+
cwd=self.cwd,
|
29
|
+
file_read_timeout=self.file_read_timeout,
|
30
|
+
**self.top_level_kwargs,
|
31
|
+
)
|
32
|
+
|
33
|
+
f.__doc__ = provider_class.__doc__ or ""
|
34
|
+
f.__name__ = method_name
|
35
|
+
return f
|
36
|
+
|
37
|
+
for provider_class in DEPLOYER_IMPL_PROVIDERS:
|
38
|
+
# TYPE is the name of the CLI groups i.e.
|
39
|
+
# `argo-workflows` instead of `argo_workflows`
|
40
|
+
# The injected method names replace '-' by '_' though.
|
41
|
+
method_name = provider_class.TYPE.replace("-", "_")
|
42
|
+
setattr(cls, method_name, _injected_method(method_name, provider_class))
|
43
|
+
|
44
|
+
return cls
|
48
45
|
|
49
46
|
|
50
|
-
class Deployer(
|
47
|
+
class Deployer(metaclass=DeployerMeta):
|
51
48
|
"""
|
52
49
|
Use the `Deployer` class to configure and access one of the production
|
53
50
|
orchestrators supported by Metaflow.
|
@@ -81,7 +78,7 @@ class Deployer(object):
|
|
81
78
|
env: Optional[Dict] = None,
|
82
79
|
cwd: Optional[str] = None,
|
83
80
|
file_read_timeout: int = 3600,
|
84
|
-
**kwargs
|
81
|
+
**kwargs,
|
85
82
|
):
|
86
83
|
self.flow_file = flow_file
|
87
84
|
self.show_output = show_output
|
@@ -91,56 +88,16 @@ class Deployer(object):
|
|
91
88
|
self.file_read_timeout = file_read_timeout
|
92
89
|
self.top_level_kwargs = kwargs
|
93
90
|
|
94
|
-
from metaflow.plugins import DEPLOYER_IMPL_PROVIDERS
|
95
|
-
|
96
|
-
for provider_class in DEPLOYER_IMPL_PROVIDERS:
|
97
|
-
# TYPE is the name of the CLI groups i.e.
|
98
|
-
# `argo-workflows` instead of `argo_workflows`
|
99
|
-
# The injected method names replace '-' by '_' though.
|
100
|
-
method_name = provider_class.TYPE.replace("-", "_")
|
101
|
-
setattr(Deployer, method_name, self.__make_function(provider_class))
|
102
|
-
|
103
|
-
def __make_function(self, deployer_class):
|
104
|
-
"""
|
105
|
-
Create a function for the given deployer class.
|
106
|
-
|
107
|
-
Parameters
|
108
|
-
----------
|
109
|
-
deployer_class : Type[DeployerImpl]
|
110
|
-
Deployer implementation class.
|
111
|
-
|
112
|
-
Returns
|
113
|
-
-------
|
114
|
-
Callable
|
115
|
-
Function that initializes and returns an instance of the deployer class.
|
116
|
-
"""
|
117
|
-
|
118
|
-
def f(self, **deployer_kwargs):
|
119
|
-
return deployer_class(
|
120
|
-
deployer_kwargs=deployer_kwargs,
|
121
|
-
flow_file=self.flow_file,
|
122
|
-
show_output=self.show_output,
|
123
|
-
profile=self.profile,
|
124
|
-
env=self.env,
|
125
|
-
cwd=self.cwd,
|
126
|
-
file_read_timeout=self.file_read_timeout,
|
127
|
-
**self.top_level_kwargs
|
128
|
-
)
|
129
|
-
|
130
|
-
return f
|
131
|
-
|
132
91
|
|
133
92
|
class TriggeredRun(object):
|
134
93
|
"""
|
135
|
-
TriggeredRun class represents a run that has been triggered on a
|
136
|
-
|
137
|
-
Only when the `start` task starts running, the `run` object corresponding to the run
|
138
|
-
becomes available.
|
94
|
+
TriggeredRun class represents a run that has been triggered on a
|
95
|
+
production orchestrator.
|
139
96
|
"""
|
140
97
|
|
141
98
|
def __init__(
|
142
99
|
self,
|
143
|
-
deployer: "DeployerImpl",
|
100
|
+
deployer: "metaflow.runner.deployer_impl.DeployerImpl",
|
144
101
|
content: str,
|
145
102
|
):
|
146
103
|
self.deployer = deployer
|
@@ -149,31 +106,18 @@ class TriggeredRun(object):
|
|
149
106
|
self.pathspec = content_json.get("pathspec")
|
150
107
|
self.name = content_json.get("name")
|
151
108
|
|
152
|
-
def
|
153
|
-
"""
|
154
|
-
Enrich the TriggeredRun object with additional properties and methods.
|
155
|
-
|
156
|
-
Parameters
|
157
|
-
----------
|
158
|
-
env : dict
|
159
|
-
Environment dictionary containing properties and methods to add.
|
160
|
-
"""
|
161
|
-
for k, v in env.items():
|
162
|
-
if isinstance(v, property):
|
163
|
-
setattr(self.__class__, k, v)
|
164
|
-
elif callable(v):
|
165
|
-
setattr(self, k, functools.partial(v, self))
|
166
|
-
else:
|
167
|
-
setattr(self, k, v)
|
168
|
-
|
169
|
-
def wait_for_run(self, timeout=None):
|
109
|
+
def wait_for_run(self, timeout: Optional[int] = None):
|
170
110
|
"""
|
171
111
|
Wait for the `run` property to become available.
|
172
112
|
|
113
|
+
The `run` property becomes available only after the `start` task of the triggered
|
114
|
+
flow starts running.
|
115
|
+
|
173
116
|
Parameters
|
174
117
|
----------
|
175
|
-
timeout : int, optional
|
176
|
-
Maximum time to wait for the `run` to become available, in seconds. If
|
118
|
+
timeout : int, optional, default None
|
119
|
+
Maximum time to wait for the `run` to become available, in seconds. If
|
120
|
+
None, wait indefinitely.
|
177
121
|
|
178
122
|
Raises
|
179
123
|
------
|
@@ -194,7 +138,7 @@ class TriggeredRun(object):
|
|
194
138
|
time.sleep(check_interval)
|
195
139
|
|
196
140
|
@property
|
197
|
-
def run(self):
|
141
|
+
def run(self) -> Optional["metaflow.Run"]:
|
198
142
|
"""
|
199
143
|
Retrieve the `Run` object for the triggered run.
|
200
144
|
|
@@ -214,178 +158,104 @@ class TriggeredRun(object):
|
|
214
158
|
return None
|
215
159
|
|
216
160
|
|
217
|
-
class
|
218
|
-
|
219
|
-
|
161
|
+
class DeployedFlowMeta(type):
|
162
|
+
def __new__(mcs, name, bases, dct):
|
163
|
+
cls = super().__new__(mcs, name, bases, dct)
|
164
|
+
if not bases:
|
165
|
+
# Inject methods only in DeployedFlow and not any of its
|
166
|
+
# subclasses
|
167
|
+
from metaflow.plugins import DEPLOYER_IMPL_PROVIDERS
|
220
168
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
def __init__(self, deployer: "DeployerImpl"):
|
228
|
-
self.deployer = deployer
|
169
|
+
allowed_providers = dict(
|
170
|
+
{
|
171
|
+
provider.TYPE.replace("-", "_"): provider
|
172
|
+
for provider in DEPLOYER_IMPL_PROVIDERS
|
173
|
+
}
|
174
|
+
)
|
229
175
|
|
230
|
-
|
231
|
-
|
232
|
-
|
176
|
+
def _default_injected_method():
|
177
|
+
def f(
|
178
|
+
cls,
|
179
|
+
identifier: str,
|
180
|
+
metadata: Optional[str] = None,
|
181
|
+
impl: str = DEFAULT_FROM_DEPLOYMENT_IMPL.replace("-", "_"),
|
182
|
+
) -> "DeployedFlow":
|
183
|
+
"""
|
184
|
+
Retrieves a `DeployedFlow` object from an identifier and optional
|
185
|
+
metadata. The `impl` parameter specifies the deployer implementation
|
186
|
+
to use (like `argo-workflows`).
|
187
|
+
|
188
|
+
Parameters
|
189
|
+
----------
|
190
|
+
identifier : str
|
191
|
+
Deployer specific identifier for the workflow to retrieve
|
192
|
+
metadata : str, optional, default None
|
193
|
+
Optional deployer specific metadata.
|
194
|
+
impl : str, optional, default given by METAFLOW_DEFAULT_FROM_DEPLOYMENT_IMPL
|
195
|
+
The default implementation to use if not specified
|
196
|
+
|
197
|
+
Returns
|
198
|
+
-------
|
199
|
+
DeployedFlow
|
200
|
+
A `DeployedFlow` object representing the deployed flow corresponding
|
201
|
+
to the identifier
|
202
|
+
"""
|
203
|
+
if impl in allowed_providers:
|
204
|
+
return (
|
205
|
+
allowed_providers[impl]
|
206
|
+
.deployed_flow_type()
|
207
|
+
.from_deployment(identifier, metadata)
|
208
|
+
)
|
209
|
+
else:
|
210
|
+
raise ValueError(
|
211
|
+
f"No deployer '{impl}' exists; valid deployers are: "
|
212
|
+
f"{list(allowed_providers.keys())}"
|
213
|
+
)
|
214
|
+
|
215
|
+
f.__name__ = "from_deployment"
|
216
|
+
return f
|
217
|
+
|
218
|
+
def _per_type_injected_method(method_name, impl):
|
219
|
+
def f(
|
220
|
+
cls,
|
221
|
+
identifier: str,
|
222
|
+
metadata: Optional[str] = None,
|
223
|
+
):
|
224
|
+
return (
|
225
|
+
allowed_providers[impl]
|
226
|
+
.deployed_flow_type()
|
227
|
+
.from_deployment(identifier, metadata)
|
228
|
+
)
|
229
|
+
|
230
|
+
f.__name__ = method_name
|
231
|
+
return f
|
232
|
+
|
233
|
+
setattr(cls, "from_deployment", classmethod(_default_injected_method()))
|
234
|
+
|
235
|
+
for impl in allowed_providers:
|
236
|
+
method_name = f"from_{impl}"
|
237
|
+
setattr(
|
238
|
+
cls,
|
239
|
+
method_name,
|
240
|
+
classmethod(_per_type_injected_method(method_name, impl)),
|
241
|
+
)
|
233
242
|
|
234
|
-
|
235
|
-
----------
|
236
|
-
env : dict
|
237
|
-
Environment dictionary containing properties and methods to add.
|
238
|
-
"""
|
239
|
-
for k, v in env.items():
|
240
|
-
if isinstance(v, property):
|
241
|
-
setattr(self.__class__, k, v)
|
242
|
-
elif callable(v):
|
243
|
-
setattr(self, k, functools.partial(v, self))
|
244
|
-
else:
|
245
|
-
setattr(self, k, v)
|
243
|
+
return cls
|
246
244
|
|
247
245
|
|
248
|
-
class
|
246
|
+
class DeployedFlow(metaclass=DeployedFlowMeta):
|
249
247
|
"""
|
250
|
-
|
251
|
-
class variable that matches the name of the CLI group.
|
248
|
+
DeployedFlow class represents a flow that has been deployed.
|
252
249
|
|
253
|
-
|
254
|
-
|
255
|
-
flow_file : str
|
256
|
-
Path to the flow file to deploy.
|
257
|
-
show_output : bool, default True
|
258
|
-
Show the 'stdout' and 'stderr' to the console by default.
|
259
|
-
profile : Optional[str], default None
|
260
|
-
Metaflow profile to use for the deployment. If not specified, the default
|
261
|
-
profile is used.
|
262
|
-
env : Optional[Dict], default None
|
263
|
-
Additional environment variables to set for the deployment.
|
264
|
-
cwd : Optional[str], default None
|
265
|
-
The directory to run the subprocess in; if not specified, the current
|
266
|
-
directory is used.
|
267
|
-
file_read_timeout : int, default 3600
|
268
|
-
The timeout until which we try to read the deployer attribute file.
|
269
|
-
**kwargs : Any
|
270
|
-
Additional arguments that you would pass to `python myflow.py` before
|
271
|
-
the deployment command.
|
250
|
+
This class is not meant to be instantiated directly. Instead, it is returned from
|
251
|
+
methods of `Deployer`.
|
272
252
|
"""
|
273
253
|
|
254
|
+
# This should match the TYPE value in DeployerImpl for proper stub generation
|
274
255
|
TYPE: ClassVar[Optional[str]] = None
|
275
256
|
|
276
|
-
def __init__(
|
277
|
-
self
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
env: Optional[Dict] = None,
|
282
|
-
cwd: Optional[str] = None,
|
283
|
-
file_read_timeout: int = 3600,
|
284
|
-
**kwargs
|
285
|
-
):
|
286
|
-
if self.TYPE is None:
|
287
|
-
raise ValueError(
|
288
|
-
"DeployerImpl doesn't have a 'TYPE' to target. Please use a sub-class of DeployerImpl."
|
289
|
-
)
|
290
|
-
|
291
|
-
if "metaflow.cli" in sys.modules:
|
292
|
-
importlib.reload(sys.modules["metaflow.cli"])
|
293
|
-
from metaflow.cli import start
|
294
|
-
from metaflow.runner.click_api import MetaflowAPI
|
295
|
-
|
296
|
-
self.flow_file = flow_file
|
297
|
-
self.show_output = show_output
|
298
|
-
self.profile = profile
|
299
|
-
self.env = env
|
300
|
-
self.cwd = cwd
|
301
|
-
self.file_read_timeout = file_read_timeout
|
302
|
-
|
303
|
-
self.env_vars = os.environ.copy()
|
304
|
-
self.env_vars.update(self.env or {})
|
305
|
-
if self.profile:
|
306
|
-
self.env_vars["METAFLOW_PROFILE"] = profile
|
307
|
-
|
308
|
-
self.spm = SubprocessManager()
|
309
|
-
self.top_level_kwargs = kwargs
|
310
|
-
self.api = MetaflowAPI.from_cli(self.flow_file, start)
|
311
|
-
|
312
|
-
def __enter__(self) -> "DeployerImpl":
|
313
|
-
return self
|
314
|
-
|
315
|
-
def create(self, **kwargs) -> DeployedFlow:
|
316
|
-
"""
|
317
|
-
Create a deployed flow using the deployer implementation.
|
318
|
-
|
319
|
-
Parameters
|
320
|
-
----------
|
321
|
-
**kwargs : Any
|
322
|
-
Additional arguments to pass to `create` corresponding to the
|
323
|
-
command line arguments of `create`
|
324
|
-
|
325
|
-
Returns
|
326
|
-
-------
|
327
|
-
DeployedFlow
|
328
|
-
DeployedFlow object representing the deployed flow.
|
329
|
-
|
330
|
-
Raises
|
331
|
-
------
|
332
|
-
Exception
|
333
|
-
If there is an error during deployment.
|
334
|
-
"""
|
335
|
-
with tempfile.TemporaryDirectory() as temp_dir:
|
336
|
-
tfp_runner_attribute = tempfile.NamedTemporaryFile(
|
337
|
-
dir=temp_dir, delete=False
|
338
|
-
)
|
339
|
-
# every subclass needs to have `self.deployer_kwargs`
|
340
|
-
command = get_lower_level_group(
|
341
|
-
self.api, self.top_level_kwargs, self.TYPE, self.deployer_kwargs
|
342
|
-
).create(deployer_attribute_file=tfp_runner_attribute.name, **kwargs)
|
343
|
-
|
344
|
-
pid = self.spm.run_command(
|
345
|
-
[sys.executable, *command],
|
346
|
-
env=self.env_vars,
|
347
|
-
cwd=self.cwd,
|
348
|
-
show_output=self.show_output,
|
349
|
-
)
|
350
|
-
|
351
|
-
command_obj = self.spm.get(pid)
|
352
|
-
content = handle_timeout(
|
353
|
-
tfp_runner_attribute, command_obj, self.file_read_timeout
|
354
|
-
)
|
355
|
-
content = json.loads(content)
|
356
|
-
self.name = content.get("name")
|
357
|
-
self.flow_name = content.get("flow_name")
|
358
|
-
self.metadata = content.get("metadata")
|
359
|
-
# Additional info is used to pass additional deployer specific information.
|
360
|
-
# It is used in non-OSS deployers (extensions).
|
361
|
-
self.additional_info = content.get("additional_info", {})
|
362
|
-
|
363
|
-
if command_obj.process.returncode == 0:
|
364
|
-
deployed_flow = DeployedFlow(deployer=self)
|
365
|
-
self._enrich_deployed_flow(deployed_flow)
|
366
|
-
return deployed_flow
|
367
|
-
|
368
|
-
raise Exception("Error deploying %s to %s" % (self.flow_file, self.TYPE))
|
369
|
-
|
370
|
-
def _enrich_deployed_flow(self, deployed_flow: DeployedFlow):
|
371
|
-
"""
|
372
|
-
Enrich the DeployedFlow object with additional properties and methods.
|
373
|
-
|
374
|
-
Parameters
|
375
|
-
----------
|
376
|
-
deployed_flow : DeployedFlow
|
377
|
-
The DeployedFlow object to enrich.
|
378
|
-
"""
|
379
|
-
raise NotImplementedError
|
380
|
-
|
381
|
-
def __exit__(self, exc_type, exc_value, traceback):
|
382
|
-
"""
|
383
|
-
Cleanup resources on exit.
|
384
|
-
"""
|
385
|
-
self.cleanup()
|
386
|
-
|
387
|
-
def cleanup(self):
|
388
|
-
"""
|
389
|
-
Cleanup resources.
|
390
|
-
"""
|
391
|
-
self.spm.cleanup()
|
257
|
+
def __init__(self, deployer: "metaflow.runner.deployer_impl.DeployerImpl"):
|
258
|
+
self.deployer = deployer
|
259
|
+
self.name = self.deployer.name
|
260
|
+
self.flow_name = self.deployer.flow_name
|
261
|
+
self.metadata = self.deployer.metadata
|