ob-metaflow 2.12.30.2__py2.py3-none-any.whl → 2.13.6.1__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/__init__.py +3 -0
- metaflow/cards.py +1 -0
- metaflow/cli.py +185 -717
- 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 +51 -0
- metaflow/cli_components/run_cmds.py +362 -0
- metaflow/cli_components/step_cmd.py +176 -0
- metaflow/cli_components/utils.py +140 -0
- metaflow/cmd/develop/stub_generator.py +9 -2
- metaflow/datastore/flow_datastore.py +2 -2
- metaflow/decorators.py +63 -2
- metaflow/exception.py +8 -2
- metaflow/extension_support/plugins.py +42 -27
- metaflow/flowspec.py +176 -23
- metaflow/graph.py +28 -27
- metaflow/includefile.py +50 -22
- metaflow/lint.py +35 -20
- metaflow/metadata_provider/heartbeat.py +23 -8
- metaflow/metaflow_config.py +10 -1
- metaflow/multicore_utils.py +31 -14
- metaflow/package.py +17 -3
- metaflow/parameters.py +97 -25
- metaflow/plugins/__init__.py +22 -0
- metaflow/plugins/airflow/airflow.py +18 -17
- metaflow/plugins/airflow/airflow_cli.py +1 -0
- metaflow/plugins/argo/argo_client.py +0 -2
- metaflow/plugins/argo/argo_workflows.py +195 -132
- metaflow/plugins/argo/argo_workflows_cli.py +1 -1
- metaflow/plugins/argo/argo_workflows_decorator.py +2 -4
- metaflow/plugins/argo/argo_workflows_deployer_objects.py +51 -9
- metaflow/plugins/argo/jobset_input_paths.py +0 -1
- metaflow/plugins/aws/aws_utils.py +6 -1
- metaflow/plugins/aws/batch/batch_client.py +1 -3
- metaflow/plugins/aws/batch/batch_decorator.py +13 -13
- 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 +33 -1
- metaflow/plugins/aws/step_functions/step_functions_cli.py +1 -1
- metaflow/plugins/aws/step_functions/step_functions_decorator.py +0 -1
- metaflow/plugins/aws/step_functions/step_functions_deployer_objects.py +7 -9
- metaflow/plugins/cards/card_cli.py +7 -2
- metaflow/plugins/cards/card_creator.py +1 -0
- metaflow/plugins/cards/card_decorator.py +79 -8
- metaflow/plugins/cards/card_modules/basic.py +56 -5
- metaflow/plugins/cards/card_modules/card.py +16 -1
- metaflow/plugins/cards/card_modules/components.py +64 -16
- metaflow/plugins/cards/card_modules/main.js +27 -25
- metaflow/plugins/cards/card_modules/test_cards.py +4 -4
- metaflow/plugins/cards/component_serializer.py +1 -1
- metaflow/plugins/datatools/s3/s3.py +12 -4
- metaflow/plugins/datatools/s3/s3op.py +3 -3
- metaflow/plugins/events_decorator.py +338 -186
- metaflow/plugins/kubernetes/kube_utils.py +84 -1
- metaflow/plugins/kubernetes/kubernetes.py +40 -92
- metaflow/plugins/kubernetes/kubernetes_cli.py +32 -7
- metaflow/plugins/kubernetes/kubernetes_decorator.py +76 -4
- metaflow/plugins/kubernetes/kubernetes_job.py +23 -20
- metaflow/plugins/kubernetes/kubernetes_jobsets.py +41 -20
- metaflow/plugins/kubernetes/spot_metadata_cli.py +69 -0
- metaflow/plugins/kubernetes/spot_monitor_sidecar.py +109 -0
- metaflow/plugins/parallel_decorator.py +4 -1
- metaflow/plugins/project_decorator.py +33 -5
- metaflow/plugins/pypi/bootstrap.py +249 -81
- metaflow/plugins/pypi/conda_decorator.py +20 -10
- metaflow/plugins/pypi/conda_environment.py +83 -27
- metaflow/plugins/pypi/micromamba.py +82 -37
- metaflow/plugins/pypi/pip.py +9 -6
- metaflow/plugins/pypi/pypi_decorator.py +11 -9
- metaflow/plugins/pypi/utils.py +4 -2
- metaflow/plugins/timeout_decorator.py +2 -2
- metaflow/runner/click_api.py +240 -50
- metaflow/runner/deployer.py +1 -1
- metaflow/runner/deployer_impl.py +12 -11
- metaflow/runner/metaflow_runner.py +68 -34
- metaflow/runner/nbdeploy.py +2 -0
- metaflow/runner/nbrun.py +1 -1
- metaflow/runner/subprocess_manager.py +61 -10
- metaflow/runner/utils.py +208 -44
- metaflow/runtime.py +216 -112
- metaflow/sidecar/sidecar_worker.py +1 -1
- metaflow/tracing/tracing_modules.py +4 -1
- metaflow/user_configs/__init__.py +0 -0
- metaflow/user_configs/config_decorators.py +563 -0
- metaflow/user_configs/config_options.py +548 -0
- metaflow/user_configs/config_parameters.py +436 -0
- metaflow/util.py +22 -0
- metaflow/version.py +1 -1
- {ob_metaflow-2.12.30.2.dist-info → ob_metaflow-2.13.6.1.dist-info}/METADATA +12 -3
- {ob_metaflow-2.12.30.2.dist-info → ob_metaflow-2.13.6.1.dist-info}/RECORD +96 -84
- {ob_metaflow-2.12.30.2.dist-info → ob_metaflow-2.13.6.1.dist-info}/WHEEL +1 -1
- {ob_metaflow-2.12.30.2.dist-info → ob_metaflow-2.13.6.1.dist-info}/LICENSE +0 -0
- {ob_metaflow-2.12.30.2.dist-info → ob_metaflow-2.13.6.1.dist-info}/entry_points.txt +0 -0
- {ob_metaflow-2.12.30.2.dist-info → ob_metaflow-2.13.6.1.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import functools
|
|
1
2
|
import json
|
|
2
3
|
import os
|
|
4
|
+
import re
|
|
3
5
|
import subprocess
|
|
4
6
|
import tempfile
|
|
7
|
+
import time
|
|
5
8
|
|
|
6
9
|
from metaflow.exception import MetaflowException
|
|
7
10
|
from metaflow.util import which
|
|
8
11
|
|
|
9
|
-
from .utils import conda_platform
|
|
12
|
+
from .utils import MICROMAMBA_MIRROR_URL, MICROMAMBA_URL, conda_platform
|
|
10
13
|
|
|
11
14
|
|
|
12
15
|
class MicromambaException(MetaflowException):
|
|
@@ -19,8 +22,13 @@ class MicromambaException(MetaflowException):
|
|
|
19
22
|
super(MicromambaException, self).__init__(msg)
|
|
20
23
|
|
|
21
24
|
|
|
25
|
+
GLIBC_VERSION = os.environ.get("CONDA_OVERRIDE_GLIBC", "2.38")
|
|
26
|
+
|
|
27
|
+
_double_equal_match = re.compile("==(?=[<=>!~])")
|
|
28
|
+
|
|
29
|
+
|
|
22
30
|
class Micromamba(object):
|
|
23
|
-
def __init__(self):
|
|
31
|
+
def __init__(self, logger=None):
|
|
24
32
|
# micromamba is a tiny version of the mamba package manager and comes with
|
|
25
33
|
# metaflow specific performance enhancements.
|
|
26
34
|
|
|
@@ -33,6 +41,12 @@ class Micromamba(object):
|
|
|
33
41
|
os.path.expanduser(_home),
|
|
34
42
|
"micromamba",
|
|
35
43
|
)
|
|
44
|
+
|
|
45
|
+
if logger:
|
|
46
|
+
self.logger = logger
|
|
47
|
+
else:
|
|
48
|
+
self.logger = lambda *args, **kwargs: None # No-op logger if not provided
|
|
49
|
+
|
|
36
50
|
self.bin = (
|
|
37
51
|
which(os.environ.get("METAFLOW_PATH_TO_MICROMAMBA") or "micromamba")
|
|
38
52
|
or which("./micromamba") # to support remote execution
|
|
@@ -70,6 +84,9 @@ class Micromamba(object):
|
|
|
70
84
|
"MAMBA_ADD_PIP_AS_PYTHON_DEPENDENCY": "true",
|
|
71
85
|
"CONDA_SUBDIR": platform,
|
|
72
86
|
# "CONDA_UNSATISFIABLE_HINTS_CHECK_DEPTH": "0" # https://github.com/conda/conda/issues/9862
|
|
87
|
+
# Add a default glibc version for linux-64 environments (ignored for other platforms)
|
|
88
|
+
# TODO: Make the version configurable
|
|
89
|
+
"CONDA_OVERRIDE_GLIBC": GLIBC_VERSION,
|
|
73
90
|
}
|
|
74
91
|
cmd = [
|
|
75
92
|
"create",
|
|
@@ -78,6 +95,7 @@ class Micromamba(object):
|
|
|
78
95
|
"--dry-run",
|
|
79
96
|
"--no-extra-safety-checks",
|
|
80
97
|
"--repodata-ttl=86400",
|
|
98
|
+
"--safety-checks=disabled",
|
|
81
99
|
"--retry-clean-cache",
|
|
82
100
|
"--prefix=%s/prefix" % tmp_dir,
|
|
83
101
|
]
|
|
@@ -86,15 +104,17 @@ class Micromamba(object):
|
|
|
86
104
|
cmd.append("--channel=%s" % channel)
|
|
87
105
|
|
|
88
106
|
for package, version in packages.items():
|
|
89
|
-
|
|
107
|
+
version_string = "%s==%s" % (package, version)
|
|
108
|
+
cmd.append(_double_equal_match.sub("", version_string))
|
|
90
109
|
if python:
|
|
91
110
|
cmd.append("python==%s" % python)
|
|
92
111
|
# TODO: Ensure a human readable message is returned when the environment
|
|
93
112
|
# can't be resolved for any and all reasons.
|
|
94
|
-
|
|
113
|
+
solved_packages = [
|
|
95
114
|
{k: v for k, v in item.items() if k in ["url"]}
|
|
96
115
|
for item in self._call(cmd, env)["actions"]["LINK"]
|
|
97
116
|
]
|
|
117
|
+
return solved_packages
|
|
98
118
|
|
|
99
119
|
def download(self, id_, packages, python, platform):
|
|
100
120
|
# Unfortunately all the packages need to be catalogued in package cache
|
|
@@ -103,8 +123,6 @@ class Micromamba(object):
|
|
|
103
123
|
# Micromamba is painfully slow in determining if many packages are infact
|
|
104
124
|
# already cached. As a perf heuristic, we check if the environment already
|
|
105
125
|
# exists to short circuit package downloads.
|
|
106
|
-
if self.path_to_environment(id_, platform):
|
|
107
|
-
return
|
|
108
126
|
|
|
109
127
|
prefix = "{env_dirs}/{keyword}/{platform}/{id}".format(
|
|
110
128
|
env_dirs=self.info()["envs_dirs"][0],
|
|
@@ -113,13 +131,18 @@ class Micromamba(object):
|
|
|
113
131
|
id=id_,
|
|
114
132
|
)
|
|
115
133
|
|
|
116
|
-
#
|
|
134
|
+
# cheap check
|
|
117
135
|
if os.path.exists(f"{prefix}/fake.done"):
|
|
118
136
|
return
|
|
119
137
|
|
|
138
|
+
# somewhat expensive check
|
|
139
|
+
if self.path_to_environment(id_, platform):
|
|
140
|
+
return
|
|
141
|
+
|
|
120
142
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
121
143
|
env = {
|
|
122
144
|
"CONDA_SUBDIR": platform,
|
|
145
|
+
"CONDA_OVERRIDE_GLIBC": GLIBC_VERSION,
|
|
123
146
|
}
|
|
124
147
|
cmd = [
|
|
125
148
|
"create",
|
|
@@ -159,6 +182,7 @@ class Micromamba(object):
|
|
|
159
182
|
# use hardlinks when possible, otherwise copy files
|
|
160
183
|
# disabled for now since it adds to environment creation latencies
|
|
161
184
|
"CONDA_ALLOW_SOFTLINKS": "0",
|
|
185
|
+
"CONDA_OVERRIDE_GLIBC": GLIBC_VERSION,
|
|
162
186
|
}
|
|
163
187
|
cmd = [
|
|
164
188
|
"create",
|
|
@@ -174,6 +198,7 @@ class Micromamba(object):
|
|
|
174
198
|
cmd.append("{url}".format(**package))
|
|
175
199
|
self._call(cmd, env)
|
|
176
200
|
|
|
201
|
+
@functools.lru_cache(maxsize=None)
|
|
177
202
|
def info(self):
|
|
178
203
|
return self._call(["config", "list", "-a"])
|
|
179
204
|
|
|
@@ -198,18 +223,24 @@ class Micromamba(object):
|
|
|
198
223
|
}
|
|
199
224
|
directories = self.info()["pkgs_dirs"]
|
|
200
225
|
# search all package caches for packages
|
|
201
|
-
|
|
202
|
-
|
|
226
|
+
|
|
227
|
+
file_to_path = {}
|
|
228
|
+
for d in directories:
|
|
229
|
+
if os.path.isdir(d):
|
|
230
|
+
try:
|
|
231
|
+
with os.scandir(d) as entries:
|
|
232
|
+
for entry in entries:
|
|
233
|
+
if entry.is_file():
|
|
234
|
+
# Prefer the first occurrence if the file exists in multiple directories
|
|
235
|
+
file_to_path.setdefault(entry.name, entry.path)
|
|
236
|
+
except OSError:
|
|
237
|
+
continue
|
|
238
|
+
ret = {
|
|
239
|
+
# set package tarball local paths to None if package tarballs are missing
|
|
240
|
+
url: file_to_path.get(file)
|
|
203
241
|
for url, file in packages_to_filenames.items()
|
|
204
|
-
for d in directories
|
|
205
|
-
if os.path.isdir(d)
|
|
206
|
-
and file in os.listdir(d)
|
|
207
|
-
and os.path.isfile(os.path.join(d, file))
|
|
208
242
|
}
|
|
209
|
-
|
|
210
|
-
for url in packages_to_filenames:
|
|
211
|
-
metadata.setdefault(url, None)
|
|
212
|
-
return metadata
|
|
243
|
+
return ret
|
|
213
244
|
|
|
214
245
|
def interpreter(self, id_):
|
|
215
246
|
return os.path.join(self.path_to_environment(id_), "bin/python")
|
|
@@ -296,7 +327,7 @@ class Micromamba(object):
|
|
|
296
327
|
stderr="\n".join(err),
|
|
297
328
|
)
|
|
298
329
|
)
|
|
299
|
-
except (TypeError, ValueError)
|
|
330
|
+
except (TypeError, ValueError):
|
|
300
331
|
pass
|
|
301
332
|
raise MicromambaException(
|
|
302
333
|
msg.format(
|
|
@@ -312,23 +343,37 @@ def _install_micromamba(installation_location):
|
|
|
312
343
|
# Unfortunately no 32bit binaries are available for micromamba, which ideally
|
|
313
344
|
# shouldn't be much of a problem in today's world.
|
|
314
345
|
platform = conda_platform()
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
# requires bzip2
|
|
319
|
-
result = subprocess.Popen(
|
|
320
|
-
f"curl -Ls https://micro.mamba.pm/api/micromamba/{platform}/1.5.7 | tar -xvj -C {installation_location} bin/micromamba",
|
|
321
|
-
shell=True,
|
|
322
|
-
stderr=subprocess.PIPE,
|
|
323
|
-
stdout=subprocess.PIPE,
|
|
324
|
-
)
|
|
325
|
-
_, err = result.communicate()
|
|
326
|
-
if result.returncode != 0:
|
|
327
|
-
raise MicromambaException(
|
|
328
|
-
f"Micromamba installation '{result.args}' failed:\n{err.decode()}"
|
|
329
|
-
)
|
|
346
|
+
url = MICROMAMBA_URL.format(platform=platform, version="1.5.7")
|
|
347
|
+
mirror_url = MICROMAMBA_MIRROR_URL.format(platform=platform, version="1.5.7")
|
|
348
|
+
os.makedirs(installation_location, exist_ok=True)
|
|
330
349
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
350
|
+
def _download_and_extract(url):
|
|
351
|
+
max_retries = 3
|
|
352
|
+
for attempt in range(max_retries):
|
|
353
|
+
try:
|
|
354
|
+
# https://mamba.readthedocs.io/en/latest/micromamba-installation.html#manual-installation
|
|
355
|
+
# requires bzip2
|
|
356
|
+
result = subprocess.Popen(
|
|
357
|
+
f"curl -Ls {url} | tar -xvj -C {installation_location} bin/micromamba",
|
|
358
|
+
shell=True,
|
|
359
|
+
stderr=subprocess.PIPE,
|
|
360
|
+
stdout=subprocess.PIPE,
|
|
361
|
+
)
|
|
362
|
+
_, err = result.communicate()
|
|
363
|
+
if result.returncode != 0:
|
|
364
|
+
raise MicromambaException(
|
|
365
|
+
f"Micromamba installation '{result.args}' failed:\n{err.decode()}"
|
|
366
|
+
)
|
|
367
|
+
except subprocess.CalledProcessError as e:
|
|
368
|
+
if attempt == max_retries - 1:
|
|
369
|
+
raise MicromambaException(
|
|
370
|
+
"Micromamba installation failed:\n{}".format(e.stderr.decode())
|
|
371
|
+
)
|
|
372
|
+
time.sleep(2**attempt)
|
|
373
|
+
|
|
374
|
+
try:
|
|
375
|
+
# prioritize downloading from mirror
|
|
376
|
+
_download_and_extract(mirror_url)
|
|
377
|
+
except Exception:
|
|
378
|
+
# download from official source as a fallback
|
|
379
|
+
_download_and_extract(url)
|
metaflow/plugins/pypi/pip.py
CHANGED
|
@@ -50,10 +50,14 @@ INSTALLATION_MARKER = "{prefix}/.pip/id"
|
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
class Pip(object):
|
|
53
|
-
def __init__(self, micromamba=None):
|
|
53
|
+
def __init__(self, micromamba=None, logger=None):
|
|
54
54
|
# pip is assumed to be installed inside a conda environment managed by
|
|
55
55
|
# micromamba. pip commands are executed using `micromamba run --prefix`
|
|
56
|
-
self.micromamba = micromamba or Micromamba()
|
|
56
|
+
self.micromamba = micromamba or Micromamba(logger)
|
|
57
|
+
if logger:
|
|
58
|
+
self.logger = logger
|
|
59
|
+
else:
|
|
60
|
+
self.logger = lambda *args, **kwargs: None # No-op logger if not provided
|
|
57
61
|
|
|
58
62
|
def solve(self, id_, packages, python, platform):
|
|
59
63
|
prefix = self.micromamba.path_to_environment(id_)
|
|
@@ -102,9 +106,8 @@ class Pip(object):
|
|
|
102
106
|
except PipPackageNotFound as ex:
|
|
103
107
|
# pretty print package errors
|
|
104
108
|
raise PipException(
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"Note that ***@pypi*** does not currently support source distributions"
|
|
109
|
+
"Unable to find a binary distribution compatible with %s for %s.\n\n"
|
|
110
|
+
"Note: ***@pypi*** does not currently support source distributions"
|
|
108
111
|
% (ex.package_spec, platform)
|
|
109
112
|
)
|
|
110
113
|
|
|
@@ -123,7 +126,7 @@ class Pip(object):
|
|
|
123
126
|
**res,
|
|
124
127
|
subdir_str=(
|
|
125
128
|
"#subdirectory=%s" % subdirectory if subdirectory else ""
|
|
126
|
-
)
|
|
129
|
+
),
|
|
127
130
|
)
|
|
128
131
|
# used to deduplicate the storage location in case wheel does not
|
|
129
132
|
# build with enough unique identifiers.
|
|
@@ -25,9 +25,10 @@ class PyPIStepDecorator(StepDecorator):
|
|
|
25
25
|
defaults = {"packages": {}, "python": None, "disabled": None} # wheels
|
|
26
26
|
|
|
27
27
|
def __init__(self, attributes=None, statically_defined=False):
|
|
28
|
-
self.
|
|
29
|
-
attributes.
|
|
28
|
+
self._attributes_with_user_values = (
|
|
29
|
+
set(attributes.keys()) if attributes is not None else set()
|
|
30
30
|
)
|
|
31
|
+
|
|
31
32
|
super().__init__(attributes, statically_defined)
|
|
32
33
|
|
|
33
34
|
def step_init(self, flow, graph, step, decos, environment, flow_datastore, logger):
|
|
@@ -42,10 +43,9 @@ class PyPIStepDecorator(StepDecorator):
|
|
|
42
43
|
if "pypi_base" in self.flow._flow_decorators:
|
|
43
44
|
pypi_base = self.flow._flow_decorators["pypi_base"][0]
|
|
44
45
|
super_attributes = pypi_base.attributes
|
|
45
|
-
self.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
46
|
+
self._attributes_with_user_values.update(
|
|
47
|
+
pypi_base._attributes_with_user_values
|
|
48
|
+
)
|
|
49
49
|
self.attributes["packages"] = {
|
|
50
50
|
**super_attributes["packages"],
|
|
51
51
|
**self.attributes["packages"],
|
|
@@ -106,7 +106,7 @@ class PyPIStepDecorator(StepDecorator):
|
|
|
106
106
|
environment.set_local_root(LocalStorage.get_datastore_root_from_config(logger))
|
|
107
107
|
|
|
108
108
|
def is_attribute_user_defined(self, name):
|
|
109
|
-
return name in self.
|
|
109
|
+
return name in self._attributes_with_user_values
|
|
110
110
|
|
|
111
111
|
|
|
112
112
|
class PyPIFlowDecorator(FlowDecorator):
|
|
@@ -129,9 +129,10 @@ class PyPIFlowDecorator(FlowDecorator):
|
|
|
129
129
|
defaults = {"packages": {}, "python": None, "disabled": None}
|
|
130
130
|
|
|
131
131
|
def __init__(self, attributes=None, statically_defined=False):
|
|
132
|
-
self.
|
|
133
|
-
attributes.
|
|
132
|
+
self._attributes_with_user_values = (
|
|
133
|
+
set(attributes.keys()) if attributes is not None else set()
|
|
134
134
|
)
|
|
135
|
+
|
|
135
136
|
super().__init__(attributes, statically_defined)
|
|
136
137
|
|
|
137
138
|
def flow_init(
|
|
@@ -140,6 +141,7 @@ class PyPIFlowDecorator(FlowDecorator):
|
|
|
140
141
|
from metaflow import decorators
|
|
141
142
|
|
|
142
143
|
decorators._attach_decorators(flow, ["pypi"])
|
|
144
|
+
decorators._init(flow)
|
|
143
145
|
|
|
144
146
|
# @pypi uses a conda environment to create a virtual environment.
|
|
145
147
|
# The conda environment can be created through micromamba.
|
metaflow/plugins/pypi/utils.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import platform
|
|
3
2
|
import sys
|
|
4
3
|
|
|
@@ -17,10 +16,13 @@ else:
|
|
|
17
16
|
from metaflow._vendor.packaging import tags
|
|
18
17
|
from metaflow._vendor.packaging.utils import parse_wheel_filename
|
|
19
18
|
|
|
20
|
-
from urllib.parse import unquote
|
|
19
|
+
from urllib.parse import unquote
|
|
21
20
|
|
|
22
21
|
from metaflow.exception import MetaflowException
|
|
23
22
|
|
|
23
|
+
MICROMAMBA_URL = "https://micro.mamba.pm/api/micromamba/{platform}/{version}"
|
|
24
|
+
MICROMAMBA_MIRROR_URL = "https://micromamba.outerbounds.sh/{platform}/{version}.tar.bz2"
|
|
25
|
+
|
|
24
26
|
|
|
25
27
|
def conda_platform():
|
|
26
28
|
# Returns the conda platform for the Python interpreter
|
|
@@ -37,8 +37,8 @@ class TimeoutDecorator(StepDecorator):
|
|
|
37
37
|
name = "timeout"
|
|
38
38
|
defaults = {"seconds": 0, "minutes": 0, "hours": 0}
|
|
39
39
|
|
|
40
|
-
def
|
|
41
|
-
super(
|
|
40
|
+
def init(self):
|
|
41
|
+
super().init()
|
|
42
42
|
# Initialize secs in __init__ so other decorators could safely use this
|
|
43
43
|
# value without worrying about decorator order.
|
|
44
44
|
# Convert values in attributes to type:int since they can be type:str
|