ob-metaflow 2.9.10.1__py2.py3-none-any.whl → 2.10.2.6__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.
Potentially problematic release.
This version of ob-metaflow might be problematic. Click here for more details.
- metaflow/_vendor/packaging/__init__.py +15 -0
- metaflow/_vendor/packaging/_elffile.py +108 -0
- metaflow/_vendor/packaging/_manylinux.py +238 -0
- metaflow/_vendor/packaging/_musllinux.py +80 -0
- metaflow/_vendor/packaging/_parser.py +328 -0
- metaflow/_vendor/packaging/_structures.py +61 -0
- metaflow/_vendor/packaging/_tokenizer.py +188 -0
- metaflow/_vendor/packaging/markers.py +245 -0
- metaflow/_vendor/packaging/requirements.py +95 -0
- metaflow/_vendor/packaging/specifiers.py +1005 -0
- metaflow/_vendor/packaging/tags.py +546 -0
- metaflow/_vendor/packaging/utils.py +141 -0
- metaflow/_vendor/packaging/version.py +563 -0
- metaflow/_vendor/v3_7/__init__.py +1 -0
- metaflow/_vendor/v3_7/zipp.py +329 -0
- metaflow/metaflow_config.py +2 -1
- metaflow/metaflow_environment.py +3 -1
- metaflow/mflog/mflog.py +7 -1
- metaflow/multicore_utils.py +12 -2
- metaflow/plugins/__init__.py +8 -3
- metaflow/plugins/airflow/airflow.py +13 -0
- metaflow/plugins/argo/argo_client.py +16 -0
- metaflow/plugins/argo/argo_events.py +7 -1
- metaflow/plugins/argo/argo_workflows.py +62 -0
- metaflow/plugins/argo/argo_workflows_cli.py +15 -0
- metaflow/plugins/aws/batch/batch.py +10 -0
- metaflow/plugins/aws/batch/batch_cli.py +1 -2
- metaflow/plugins/aws/batch/batch_decorator.py +2 -9
- metaflow/plugins/datatools/s3/s3.py +4 -0
- metaflow/plugins/env_escape/client.py +24 -3
- metaflow/plugins/env_escape/stub.py +2 -8
- metaflow/plugins/kubernetes/kubernetes.py +13 -0
- metaflow/plugins/kubernetes/kubernetes_cli.py +1 -2
- metaflow/plugins/kubernetes/kubernetes_decorator.py +9 -2
- metaflow/plugins/pypi/__init__.py +29 -0
- metaflow/plugins/pypi/bootstrap.py +131 -0
- metaflow/plugins/pypi/conda_decorator.py +335 -0
- metaflow/plugins/pypi/conda_environment.py +414 -0
- metaflow/plugins/pypi/micromamba.py +294 -0
- metaflow/plugins/pypi/pip.py +205 -0
- metaflow/plugins/pypi/pypi_decorator.py +130 -0
- metaflow/plugins/pypi/pypi_environment.py +7 -0
- metaflow/plugins/pypi/utils.py +75 -0
- metaflow/task.py +0 -3
- metaflow/vendor.py +1 -0
- {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/METADATA +1 -1
- {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/RECORD +51 -33
- {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/WHEEL +1 -1
- metaflow/plugins/conda/__init__.py +0 -90
- metaflow/plugins/conda/batch_bootstrap.py +0 -104
- metaflow/plugins/conda/conda.py +0 -247
- metaflow/plugins/conda/conda_environment.py +0 -136
- metaflow/plugins/conda/conda_flow_decorator.py +0 -35
- metaflow/plugins/conda/conda_step_decorator.py +0 -416
- {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/LICENSE +0 -0
- {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/entry_points.txt +0 -0
- {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/top_level.txt +0 -0
metaflow/plugins/conda/conda.py
DELETED
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
import errno
|
|
2
|
-
import os
|
|
3
|
-
import json
|
|
4
|
-
import subprocess
|
|
5
|
-
import time
|
|
6
|
-
from distutils.version import LooseVersion
|
|
7
|
-
|
|
8
|
-
from metaflow.exception import MetaflowException
|
|
9
|
-
from metaflow.metaflow_config import CONDA_DEPENDENCY_RESOLVER
|
|
10
|
-
from metaflow.metaflow_environment import InvalidEnvironmentException
|
|
11
|
-
from metaflow.util import which
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class CondaException(MetaflowException):
|
|
15
|
-
headline = "Conda ran into an error while setting up environment."
|
|
16
|
-
|
|
17
|
-
def __init__(self, error):
|
|
18
|
-
if isinstance(error, (list,)):
|
|
19
|
-
error = "\n".join(error)
|
|
20
|
-
msg = "{error}".format(error=error)
|
|
21
|
-
super(CondaException, self).__init__(msg)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class CondaStepException(CondaException):
|
|
25
|
-
def __init__(self, exception, step):
|
|
26
|
-
msg = "Step: {step}, Error: {error}".format(step=step, error=exception.message)
|
|
27
|
-
super(CondaStepException, self).__init__(msg)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class Conda(object):
|
|
31
|
-
def __init__(self):
|
|
32
|
-
dependency_solver = CONDA_DEPENDENCY_RESOLVER.lower()
|
|
33
|
-
self._bin = which(dependency_solver)
|
|
34
|
-
# Check if the dependency solver exists.
|
|
35
|
-
if self._bin is None:
|
|
36
|
-
raise InvalidEnvironmentException(
|
|
37
|
-
"No %s installation found. Install %s first."
|
|
38
|
-
% (dependency_solver, dependency_solver)
|
|
39
|
-
)
|
|
40
|
-
# Check for a minimum version for conda when conda or mamba is used
|
|
41
|
-
# for dependency resolution.
|
|
42
|
-
if dependency_solver == "conda" or dependency_solver == "mamba":
|
|
43
|
-
if LooseVersion(self._info()["conda_version"]) < LooseVersion("4.6.0"):
|
|
44
|
-
msg = "Conda version 4.6.0 or newer is required."
|
|
45
|
-
if dependency_solver == "mamba":
|
|
46
|
-
msg += " Visit https://mamba.readthedocs.io/en/latest/installation.html for installation instructions."
|
|
47
|
-
else:
|
|
48
|
-
msg += " Visit https://docs.conda.io/en/latest/miniconda.html for installation instructions."
|
|
49
|
-
raise InvalidEnvironmentException(msg)
|
|
50
|
-
# Check if conda-forge is available as a channel to pick up Metaflow's
|
|
51
|
-
# dependencies. This check will go away once all of Metaflow's
|
|
52
|
-
# dependencies are vendored in.
|
|
53
|
-
if "conda-forge" not in "\t".join(self._info()["channels"]):
|
|
54
|
-
raise InvalidEnvironmentException(
|
|
55
|
-
"Conda channel 'conda-forge' is required. Specify it with CONDA_CHANNELS environment variable."
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
def create(
|
|
59
|
-
self,
|
|
60
|
-
step_name,
|
|
61
|
-
env_id,
|
|
62
|
-
deps,
|
|
63
|
-
architecture=None,
|
|
64
|
-
explicit=False,
|
|
65
|
-
disable_safety_checks=False,
|
|
66
|
-
):
|
|
67
|
-
# Create the conda environment
|
|
68
|
-
try:
|
|
69
|
-
with CondaLock(self._env_lock_file(env_id)):
|
|
70
|
-
self._remove(env_id)
|
|
71
|
-
self._create(
|
|
72
|
-
env_id, deps, explicit, architecture, disable_safety_checks
|
|
73
|
-
)
|
|
74
|
-
return self._deps(env_id)
|
|
75
|
-
except CondaException as e:
|
|
76
|
-
raise CondaStepException(e, step_name)
|
|
77
|
-
|
|
78
|
-
def remove(self, step_name, env_id):
|
|
79
|
-
# Remove the conda environment
|
|
80
|
-
try:
|
|
81
|
-
with CondaLock(self._env_lock_file(env_id)):
|
|
82
|
-
self._remove(env_id)
|
|
83
|
-
except CondaException as e:
|
|
84
|
-
raise CondaStepException(e, step_name)
|
|
85
|
-
|
|
86
|
-
def python(self, env_id):
|
|
87
|
-
# Get Python interpreter for the conda environment
|
|
88
|
-
return os.path.join(self._env_path(env_id), "bin/python")
|
|
89
|
-
|
|
90
|
-
def environments(self, flow):
|
|
91
|
-
# List all conda environments associated with the flow
|
|
92
|
-
envs = self._info()["envs"]
|
|
93
|
-
ret = {}
|
|
94
|
-
for env in envs:
|
|
95
|
-
name = os.path.basename(env)
|
|
96
|
-
if name.startswith("metaflow_%s" % flow):
|
|
97
|
-
ret[name] = env
|
|
98
|
-
return ret
|
|
99
|
-
|
|
100
|
-
def package_info(self, env_id):
|
|
101
|
-
# Show conda environment package configuration
|
|
102
|
-
# Not every parameter is exposed via conda cli hence this ignominy
|
|
103
|
-
metadata = os.path.join(self._env_path(env_id), "conda-meta")
|
|
104
|
-
for path, dirs, files in os.walk(metadata):
|
|
105
|
-
for file in files:
|
|
106
|
-
if file.endswith(".json"):
|
|
107
|
-
with open(os.path.join(path, file)) as f:
|
|
108
|
-
yield json.loads(f.read())
|
|
109
|
-
|
|
110
|
-
def _info(self):
|
|
111
|
-
return json.loads(self._call_conda(["info"]))
|
|
112
|
-
|
|
113
|
-
def _create(
|
|
114
|
-
self,
|
|
115
|
-
env_id,
|
|
116
|
-
deps,
|
|
117
|
-
explicit=False,
|
|
118
|
-
architecture=None,
|
|
119
|
-
disable_safety_checks=False,
|
|
120
|
-
):
|
|
121
|
-
cmd = ["create", "--yes", "--no-default-packages", "--name", env_id, "--quiet"]
|
|
122
|
-
if explicit:
|
|
123
|
-
cmd.append("--no-deps")
|
|
124
|
-
cmd.extend(deps)
|
|
125
|
-
self._call_conda(
|
|
126
|
-
cmd, architecture=architecture, disable_safety_checks=disable_safety_checks
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
def _remove(self, env_id):
|
|
130
|
-
self._call_conda(["env", "remove", "--name", env_id, "--yes", "--quiet"])
|
|
131
|
-
|
|
132
|
-
def _install(self, env_id, deps, explicit=False):
|
|
133
|
-
cmd = ["install", "--yes", "--name", env_id, "--quiet"]
|
|
134
|
-
if explicit:
|
|
135
|
-
cmd.append("--no-deps")
|
|
136
|
-
cmd.extend(deps)
|
|
137
|
-
self._call_conda(cmd)
|
|
138
|
-
|
|
139
|
-
def _install_order(self, env_id):
|
|
140
|
-
cmd = ["list", "--name", env_id, "--explicit"]
|
|
141
|
-
response = self._call_conda(cmd).decode("utf-8")
|
|
142
|
-
emit = False
|
|
143
|
-
result = []
|
|
144
|
-
for line in response.splitlines():
|
|
145
|
-
if emit:
|
|
146
|
-
result.append(line.split("/")[-1])
|
|
147
|
-
if not emit and line == "@EXPLICIT":
|
|
148
|
-
emit = True
|
|
149
|
-
return result
|
|
150
|
-
|
|
151
|
-
def _deps(self, env_id):
|
|
152
|
-
exact_deps = []
|
|
153
|
-
urls = []
|
|
154
|
-
for package in self.package_info(env_id):
|
|
155
|
-
exact_deps.append(
|
|
156
|
-
"%s=%s=%s" % (package["name"], package["version"], package["build"])
|
|
157
|
-
)
|
|
158
|
-
urls.append(package["url"])
|
|
159
|
-
order = self._install_order(env_id)
|
|
160
|
-
return (exact_deps, urls, order)
|
|
161
|
-
|
|
162
|
-
def _env_path(self, env_id):
|
|
163
|
-
envs = self._info()["envs"]
|
|
164
|
-
for env in envs:
|
|
165
|
-
name = os.path.basename(env)
|
|
166
|
-
if name == env_id:
|
|
167
|
-
return env
|
|
168
|
-
return None
|
|
169
|
-
|
|
170
|
-
def _env_lock_file(self, env_id):
|
|
171
|
-
return os.path.join(self._info()["envs_dirs"][0], "mf_env-creation.lock")
|
|
172
|
-
|
|
173
|
-
def _call_conda(self, args, architecture=None, disable_safety_checks=False):
|
|
174
|
-
try:
|
|
175
|
-
env = {
|
|
176
|
-
"CONDA_JSON": "True",
|
|
177
|
-
"CONDA_SUBDIR": (architecture if architecture else ""),
|
|
178
|
-
"MAMBA_NO_BANNER": "1",
|
|
179
|
-
"MAMBA_JSON": "True",
|
|
180
|
-
}
|
|
181
|
-
if disable_safety_checks:
|
|
182
|
-
env["CONDA_SAFETY_CHECKS"] = "disabled"
|
|
183
|
-
return subprocess.check_output(
|
|
184
|
-
[self._bin] + args, stderr=subprocess.PIPE, env=dict(os.environ, **env)
|
|
185
|
-
).strip()
|
|
186
|
-
except subprocess.CalledProcessError as e:
|
|
187
|
-
try:
|
|
188
|
-
output = json.loads(e.output)
|
|
189
|
-
err = [output["error"]]
|
|
190
|
-
for error in output.get("errors", []):
|
|
191
|
-
err.append(error["error"])
|
|
192
|
-
raise CondaException(err)
|
|
193
|
-
except (TypeError, ValueError) as ve:
|
|
194
|
-
pass
|
|
195
|
-
raise CondaException(
|
|
196
|
-
"command '{cmd}' returned error ({code}): {output}, stderr={stderr}".format(
|
|
197
|
-
cmd=e.cmd, code=e.returncode, output=e.output, stderr=e.stderr
|
|
198
|
-
)
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
class CondaLock(object):
|
|
203
|
-
def __init__(self, lock, timeout=3600, delay=10):
|
|
204
|
-
self.lock = lock
|
|
205
|
-
self.locked = False
|
|
206
|
-
self.timeout = timeout
|
|
207
|
-
self.delay = delay
|
|
208
|
-
|
|
209
|
-
def _acquire(self):
|
|
210
|
-
start = time.time()
|
|
211
|
-
try:
|
|
212
|
-
os.makedirs(os.path.dirname(self.lock))
|
|
213
|
-
except OSError as x:
|
|
214
|
-
if x.errno != errno.EEXIST:
|
|
215
|
-
raise
|
|
216
|
-
while True:
|
|
217
|
-
try:
|
|
218
|
-
self.fd = os.open(self.lock, os.O_CREAT | os.O_EXCL | os.O_RDWR)
|
|
219
|
-
self.locked = True
|
|
220
|
-
break
|
|
221
|
-
except OSError as e:
|
|
222
|
-
if e.errno != errno.EEXIST:
|
|
223
|
-
raise
|
|
224
|
-
if self.timeout is None:
|
|
225
|
-
raise CondaException("Could not acquire lock {}".format(self.lock))
|
|
226
|
-
if (time.time() - start) >= self.timeout:
|
|
227
|
-
raise CondaException(
|
|
228
|
-
"Timeout occurred while acquiring lock {}".format(self.lock)
|
|
229
|
-
)
|
|
230
|
-
time.sleep(self.delay)
|
|
231
|
-
|
|
232
|
-
def _release(self):
|
|
233
|
-
if self.locked:
|
|
234
|
-
os.close(self.fd)
|
|
235
|
-
os.unlink(self.lock)
|
|
236
|
-
self.locked = False
|
|
237
|
-
|
|
238
|
-
def __enter__(self):
|
|
239
|
-
if not self.locked:
|
|
240
|
-
self._acquire()
|
|
241
|
-
return self
|
|
242
|
-
|
|
243
|
-
def __exit__(self, type, value, traceback):
|
|
244
|
-
self.__del__()
|
|
245
|
-
|
|
246
|
-
def __del__(self):
|
|
247
|
-
self._release()
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import os
|
|
3
|
-
import sys
|
|
4
|
-
import tarfile
|
|
5
|
-
|
|
6
|
-
from io import BytesIO
|
|
7
|
-
|
|
8
|
-
from metaflow.metaflow_environment import MetaflowEnvironment
|
|
9
|
-
from metaflow.exception import MetaflowException
|
|
10
|
-
from metaflow.mflog import BASH_SAVE_LOGS
|
|
11
|
-
|
|
12
|
-
from .conda import Conda
|
|
13
|
-
from . import get_conda_manifest_path, CONDA_MAGIC_FILE
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class CondaEnvironment(MetaflowEnvironment):
|
|
17
|
-
TYPE = "conda"
|
|
18
|
-
_filecache = None
|
|
19
|
-
|
|
20
|
-
def __init__(self, flow):
|
|
21
|
-
self.flow = flow
|
|
22
|
-
self.local_root = None
|
|
23
|
-
# A conda environment sits on top of whatever default environment
|
|
24
|
-
# the user has, so we get that environment to be able to forward
|
|
25
|
-
# any calls we don't handle specifically to that one.
|
|
26
|
-
from ...plugins import ENVIRONMENTS
|
|
27
|
-
from metaflow.metaflow_config import DEFAULT_ENVIRONMENT
|
|
28
|
-
|
|
29
|
-
if DEFAULT_ENVIRONMENT == self.TYPE:
|
|
30
|
-
# If the default environment is Conda itself then fallback on
|
|
31
|
-
# the default 'default environment'
|
|
32
|
-
self.base_env = MetaflowEnvironment(self.flow)
|
|
33
|
-
else:
|
|
34
|
-
self.base_env = [
|
|
35
|
-
e
|
|
36
|
-
for e in ENVIRONMENTS + [MetaflowEnvironment]
|
|
37
|
-
if e.TYPE == DEFAULT_ENVIRONMENT
|
|
38
|
-
][0](self.flow)
|
|
39
|
-
|
|
40
|
-
def init_environment(self, echo):
|
|
41
|
-
# Print a message for now
|
|
42
|
-
echo("Bootstrapping conda environment..." + "(this could take a few minutes)")
|
|
43
|
-
self.base_env.init_environment(echo)
|
|
44
|
-
|
|
45
|
-
def validate_environment(self, echo, datastore_type):
|
|
46
|
-
return self.base_env.validate_environment(echo, datastore_type)
|
|
47
|
-
|
|
48
|
-
def decospecs(self):
|
|
49
|
-
# Apply conda decorator and base environment's decorators to all steps
|
|
50
|
-
return ("conda",) + self.base_env.decospecs()
|
|
51
|
-
|
|
52
|
-
def _get_conda_decorator(self, step_name):
|
|
53
|
-
step = next(step for step in self.flow if step.name == step_name)
|
|
54
|
-
decorator = next(deco for deco in step.decorators if deco.name == "conda")
|
|
55
|
-
# Guaranteed to have a conda decorator because of self.decospecs()
|
|
56
|
-
return decorator
|
|
57
|
-
|
|
58
|
-
def _get_env_id(self, step_name):
|
|
59
|
-
conda_decorator = self._get_conda_decorator(step_name)
|
|
60
|
-
if conda_decorator.is_enabled():
|
|
61
|
-
return conda_decorator._env_id()
|
|
62
|
-
return None
|
|
63
|
-
|
|
64
|
-
def _get_executable(self, step_name):
|
|
65
|
-
env_id = self._get_env_id(step_name)
|
|
66
|
-
if env_id is not None:
|
|
67
|
-
return os.path.join(env_id, "bin/python -s")
|
|
68
|
-
return None
|
|
69
|
-
|
|
70
|
-
def set_local_root(self, ds_root):
|
|
71
|
-
self.local_root = ds_root
|
|
72
|
-
|
|
73
|
-
def bootstrap_commands(self, step_name, datastore_type):
|
|
74
|
-
# Bootstrap conda and execution environment for step
|
|
75
|
-
env_id = self._get_env_id(step_name)
|
|
76
|
-
if env_id is not None:
|
|
77
|
-
return [
|
|
78
|
-
"echo 'Bootstrapping environment...'",
|
|
79
|
-
'python -m metaflow.plugins.conda.batch_bootstrap "%s" %s "%s"'
|
|
80
|
-
% (self.flow.name, env_id, datastore_type),
|
|
81
|
-
"echo 'Environment bootstrapped.'",
|
|
82
|
-
]
|
|
83
|
-
return []
|
|
84
|
-
|
|
85
|
-
def add_to_package(self):
|
|
86
|
-
files = self.base_env.add_to_package()
|
|
87
|
-
# Add conda manifest file to job package at the top level.
|
|
88
|
-
path = get_conda_manifest_path(self.local_root, self.flow.name)
|
|
89
|
-
if os.path.exists(path):
|
|
90
|
-
files.append((path, os.path.basename(path)))
|
|
91
|
-
return files
|
|
92
|
-
|
|
93
|
-
def pylint_config(self):
|
|
94
|
-
config = self.base_env.pylint_config()
|
|
95
|
-
# Disable (import-error) in pylint
|
|
96
|
-
config.append("--disable=F0401")
|
|
97
|
-
return config
|
|
98
|
-
|
|
99
|
-
def executable(self, step_name):
|
|
100
|
-
# Get relevant python interpreter for step
|
|
101
|
-
executable = self._get_executable(step_name)
|
|
102
|
-
if executable is not None:
|
|
103
|
-
return executable
|
|
104
|
-
return self.base_env.executable(step_name)
|
|
105
|
-
|
|
106
|
-
@classmethod
|
|
107
|
-
def get_client_info(cls, flow_name, metadata):
|
|
108
|
-
if cls._filecache is None:
|
|
109
|
-
from metaflow.client.filecache import FileCache
|
|
110
|
-
|
|
111
|
-
cls._filecache = FileCache()
|
|
112
|
-
info = metadata.get("code-package")
|
|
113
|
-
env_id = metadata.get("conda_env_id")
|
|
114
|
-
if info is None or env_id is None:
|
|
115
|
-
return {"type": "conda"}
|
|
116
|
-
info = json.loads(info)
|
|
117
|
-
_, blobdata = cls._filecache.get_data(
|
|
118
|
-
info["ds_type"], flow_name, info["location"], info["sha"]
|
|
119
|
-
)
|
|
120
|
-
with tarfile.open(fileobj=BytesIO(blobdata), mode="r:gz") as tar:
|
|
121
|
-
conda_file = tar.extractfile(CONDA_MAGIC_FILE)
|
|
122
|
-
if conda_file is None:
|
|
123
|
-
return {"type": "conda"}
|
|
124
|
-
info = json.loads(conda_file.read().decode("utf-8"))
|
|
125
|
-
new_info = {
|
|
126
|
-
"type": "conda",
|
|
127
|
-
"explicit": info[env_id]["explicit"],
|
|
128
|
-
"deps": info[env_id]["deps"],
|
|
129
|
-
}
|
|
130
|
-
return new_info
|
|
131
|
-
|
|
132
|
-
def get_package_commands(self, code_package_url, datastore_type):
|
|
133
|
-
return self.base_env.get_package_commands(code_package_url, datastore_type)
|
|
134
|
-
|
|
135
|
-
def get_environment_info(self, include_ext_info=False):
|
|
136
|
-
return self.base_env.get_environment_info(include_ext_info)
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
from metaflow.decorators import FlowDecorator
|
|
2
|
-
from metaflow.metaflow_environment import InvalidEnvironmentException
|
|
3
|
-
|
|
4
|
-
from typing import Dict
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class CondaFlowDecorator(FlowDecorator):
|
|
8
|
-
"""
|
|
9
|
-
Specifies the Conda environment for all steps of the flow.
|
|
10
|
-
|
|
11
|
-
Use `@conda_base` to set common libraries required by all
|
|
12
|
-
steps and use `@conda` to specify step-specific additions.
|
|
13
|
-
|
|
14
|
-
Parameters
|
|
15
|
-
----------
|
|
16
|
-
libraries : Dict[str, str], default: {}
|
|
17
|
-
Libraries to use for this flow. The key is the name of the package
|
|
18
|
-
and the value is the version to use.
|
|
19
|
-
python : str, optional
|
|
20
|
-
Version of Python to use, e.g. '3.7.4'. A default value of None means
|
|
21
|
-
to use the current Python version.
|
|
22
|
-
disabled : bool, default: False
|
|
23
|
-
If set to True, disables Conda.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
name = "conda_base"
|
|
27
|
-
defaults = {"libraries": {}, "python": None, "disabled": None}
|
|
28
|
-
|
|
29
|
-
def flow_init(
|
|
30
|
-
self, flow, graph, environment, flow_datastore, metadata, logger, echo, options
|
|
31
|
-
):
|
|
32
|
-
if environment.TYPE != "conda":
|
|
33
|
-
raise InvalidEnvironmentException(
|
|
34
|
-
"The *@conda* decorator requires " "--environment=conda"
|
|
35
|
-
)
|