metaflow 2.13.7__py2.py3-none-any.whl → 2.13.9__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/flowspec.py +3 -1
- metaflow/metaflow_config.py +3 -0
- metaflow/plugins/kubernetes/kubernetes_decorator.py +4 -4
- metaflow/plugins/pypi/bootstrap.py +91 -6
- metaflow/plugins/pypi/micromamba.py +29 -10
- metaflow/runner/click_api.py +50 -26
- metaflow/runner/deployer_impl.py +14 -5
- metaflow/runner/metaflow_runner.py +14 -5
- metaflow/version.py +1 -1
- {metaflow-2.13.7.dist-info → metaflow-2.13.9.dist-info}/METADATA +2 -2
- {metaflow-2.13.7.dist-info → metaflow-2.13.9.dist-info}/RECORD +15 -15
- {metaflow-2.13.7.dist-info → metaflow-2.13.9.dist-info}/LICENSE +0 -0
- {metaflow-2.13.7.dist-info → metaflow-2.13.9.dist-info}/WHEEL +0 -0
- {metaflow-2.13.7.dist-info → metaflow-2.13.9.dist-info}/entry_points.txt +0 -0
- {metaflow-2.13.7.dist-info → metaflow-2.13.9.dist-info}/top_level.txt +0 -0
metaflow/flowspec.py
CHANGED
@@ -226,7 +226,9 @@ class FlowSpec(metaclass=FlowSpecMeta):
|
|
226
226
|
def _process_config_decorators(cls, config_options, ignore_errors=False):
|
227
227
|
|
228
228
|
# Fast path for no user configurations
|
229
|
-
if not cls._flow_state.get(_FlowState.CONFIG_DECORATORS)
|
229
|
+
if not cls._flow_state.get(_FlowState.CONFIG_DECORATORS) and all(
|
230
|
+
len(step.config_decorators) == 0 for step in cls._steps
|
231
|
+
):
|
230
232
|
# Process parameters to allow them to also use config values easily
|
231
233
|
for var, param in cls._get_parameters():
|
232
234
|
if param.IS_CONFIG_PARAMETER:
|
metaflow/metaflow_config.py
CHANGED
@@ -433,6 +433,9 @@ CONDA_PACKAGE_GSROOT = from_conf("CONDA_PACKAGE_GSROOT")
|
|
433
433
|
# should result in an appreciable speedup in flow environment initialization.
|
434
434
|
CONDA_DEPENDENCY_RESOLVER = from_conf("CONDA_DEPENDENCY_RESOLVER", "conda")
|
435
435
|
|
436
|
+
# Default to not using fast init binary.
|
437
|
+
CONDA_USE_FAST_INIT = from_conf("CONDA_USE_FAST_INIT", False)
|
438
|
+
|
436
439
|
###
|
437
440
|
# Escape hatch configuration
|
438
441
|
###
|
@@ -600,10 +600,10 @@ class KubernetesDecorator(StepDecorator):
|
|
600
600
|
# local file system after the user code has finished execution.
|
601
601
|
# This happens via datastore as a communication bridge.
|
602
602
|
|
603
|
-
# TODO: There is no guarantee that
|
604
|
-
# task_finished is invoked.
|
605
|
-
#
|
606
|
-
if self.metadata.TYPE == "local":
|
603
|
+
# TODO: There is no guarantee that task_pre_step executes before
|
604
|
+
# task_finished is invoked.
|
605
|
+
# For now we guard against the missing metadata object in this case.
|
606
|
+
if hasattr(self, "metadata") and self.metadata.TYPE == "local":
|
607
607
|
# Note that the datastore is *always* Amazon S3 (see
|
608
608
|
# runtime_task_created function).
|
609
609
|
sync_local_metadata_to_datastore(
|
@@ -10,7 +10,7 @@ import tarfile
|
|
10
10
|
import time
|
11
11
|
from urllib.error import URLError
|
12
12
|
from urllib.request import urlopen
|
13
|
-
from metaflow.metaflow_config import DATASTORE_LOCAL_DIR
|
13
|
+
from metaflow.metaflow_config import DATASTORE_LOCAL_DIR, CONDA_USE_FAST_INIT
|
14
14
|
from metaflow.plugins import DATASTORES
|
15
15
|
from metaflow.plugins.pypi.utils import MICROMAMBA_MIRROR_URL, MICROMAMBA_URL
|
16
16
|
from metaflow.util import which
|
@@ -19,6 +19,8 @@ import warnings
|
|
19
19
|
|
20
20
|
from . import MAGIC_FILE, _datastore_packageroot
|
21
21
|
|
22
|
+
FAST_INIT_BIN_URL = "https://fast-flow-init.outerbounds.sh/{platform}/fast-env-0.1.1.gz"
|
23
|
+
|
22
24
|
# Bootstraps a valid conda virtual environment composed of conda and pypi packages
|
23
25
|
|
24
26
|
|
@@ -58,9 +60,14 @@ if __name__ == "__main__":
|
|
58
60
|
# fi
|
59
61
|
# fi
|
60
62
|
|
61
|
-
def run_cmd(cmd):
|
63
|
+
def run_cmd(cmd, stdin_str=None):
|
62
64
|
result = subprocess.run(
|
63
|
-
cmd,
|
65
|
+
cmd,
|
66
|
+
shell=True,
|
67
|
+
input=stdin_str,
|
68
|
+
stdout=subprocess.PIPE,
|
69
|
+
stderr=subprocess.PIPE,
|
70
|
+
text=True,
|
64
71
|
)
|
65
72
|
if result.returncode != 0:
|
66
73
|
print(f"Bootstrap failed while executing: {cmd}")
|
@@ -68,6 +75,58 @@ if __name__ == "__main__":
|
|
68
75
|
print("Stderr:", result.stderr)
|
69
76
|
sys.exit(1)
|
70
77
|
|
78
|
+
@timer
|
79
|
+
def install_fast_initializer(architecture):
|
80
|
+
import gzip
|
81
|
+
|
82
|
+
fast_initializer_path = os.path.join(
|
83
|
+
os.getcwd(), "fast-initializer", "bin", "fast-initializer"
|
84
|
+
)
|
85
|
+
|
86
|
+
if which("fast-initializer"):
|
87
|
+
return which("fast-initializer")
|
88
|
+
if os.path.exists(fast_initializer_path):
|
89
|
+
os.environ["PATH"] += os.pathsep + os.path.dirname(fast_initializer_path)
|
90
|
+
return fast_initializer_path
|
91
|
+
|
92
|
+
url = FAST_INIT_BIN_URL.format(platform=architecture)
|
93
|
+
|
94
|
+
# Prepare directory once
|
95
|
+
os.makedirs(os.path.dirname(fast_initializer_path), exist_ok=True)
|
96
|
+
|
97
|
+
# Download and decompress in one go
|
98
|
+
def _download_and_extract(url):
|
99
|
+
headers = {
|
100
|
+
"Accept-Encoding": "gzip, deflate, br",
|
101
|
+
"Connection": "keep-alive",
|
102
|
+
"User-Agent": "python-urllib",
|
103
|
+
}
|
104
|
+
|
105
|
+
max_retries = 3
|
106
|
+
for attempt in range(max_retries):
|
107
|
+
try:
|
108
|
+
req = Request(url, headers=headers)
|
109
|
+
with urlopen(req) as response:
|
110
|
+
with gzip.GzipFile(fileobj=response) as gz:
|
111
|
+
with open(fast_initializer_path, "wb") as f:
|
112
|
+
f.write(gz.read())
|
113
|
+
break
|
114
|
+
except (URLError, IOError) as e:
|
115
|
+
if attempt == max_retries - 1:
|
116
|
+
raise Exception(
|
117
|
+
f"Failed to download fast-initializer after {max_retries} attempts: {e}"
|
118
|
+
)
|
119
|
+
time.sleep(2**attempt)
|
120
|
+
|
121
|
+
_download_and_extract(url)
|
122
|
+
|
123
|
+
# Set executable permission
|
124
|
+
os.chmod(fast_initializer_path, 0o755)
|
125
|
+
|
126
|
+
# Update PATH only once at the end
|
127
|
+
os.environ["PATH"] += os.pathsep + os.path.dirname(fast_initializer_path)
|
128
|
+
return fast_initializer_path
|
129
|
+
|
71
130
|
@timer
|
72
131
|
def install_micromamba(architecture):
|
73
132
|
micromamba_dir = os.path.join(os.getcwd(), "micromamba")
|
@@ -268,6 +327,29 @@ if __name__ == "__main__":
|
|
268
327
|
# wait for conda environment to be created
|
269
328
|
futures["conda_env"].result()
|
270
329
|
|
330
|
+
@timer
|
331
|
+
def fast_setup_environment(architecture, storage, env, prefix, pkgs_dir):
|
332
|
+
install_fast_initializer(architecture)
|
333
|
+
|
334
|
+
# Get package urls
|
335
|
+
conda_pkgs = env["conda"]
|
336
|
+
pypi_pkgs = env.get("pypi", [])
|
337
|
+
conda_pkg_urls = [package["path"] for package in conda_pkgs]
|
338
|
+
pypi_pkg_urls = [package["path"] for package in pypi_pkgs]
|
339
|
+
|
340
|
+
# Create string with package URLs
|
341
|
+
all_package_urls = ""
|
342
|
+
for url in conda_pkg_urls:
|
343
|
+
all_package_urls += f"{storage.datastore_root}/{url}\n"
|
344
|
+
all_package_urls += "---\n"
|
345
|
+
for url in pypi_pkg_urls:
|
346
|
+
all_package_urls += f"{storage.datastore_root}/{url}\n"
|
347
|
+
|
348
|
+
# Initialize environment
|
349
|
+
# NOTE: For the time being the fast-initializer only works for the S3 datastore implementation
|
350
|
+
cmd = f"fast-initializer --prefix {prefix} --packages-dir {pkgs_dir}"
|
351
|
+
run_cmd(cmd, all_package_urls)
|
352
|
+
|
271
353
|
if len(sys.argv) != 5:
|
272
354
|
print("Usage: bootstrap.py <flow_name> <id> <datastore_type> <architecture>")
|
273
355
|
sys.exit(1)
|
@@ -299,9 +381,12 @@ if __name__ == "__main__":
|
|
299
381
|
with open(os.path.join(manifest_dir, MAGIC_FILE)) as f:
|
300
382
|
env = json.load(f)[id_][architecture]
|
301
383
|
|
302
|
-
|
303
|
-
architecture, storage, env, prefix,
|
304
|
-
|
384
|
+
if CONDA_USE_FAST_INIT:
|
385
|
+
fast_setup_environment(architecture, storage, env, prefix, pkgs_dir)
|
386
|
+
else:
|
387
|
+
setup_environment(
|
388
|
+
architecture, storage, env, prefix, conda_pkgs_dir, pypi_pkgs_dir
|
389
|
+
)
|
305
390
|
|
306
391
|
except Exception as e:
|
307
392
|
print(f"Error: {str(e)}", file=sys.stderr)
|
@@ -10,6 +10,7 @@ from metaflow.exception import MetaflowException
|
|
10
10
|
from metaflow.util import which
|
11
11
|
|
12
12
|
from .utils import MICROMAMBA_MIRROR_URL, MICROMAMBA_URL, conda_platform
|
13
|
+
from threading import Lock
|
13
14
|
|
14
15
|
|
15
16
|
class MicromambaException(MetaflowException):
|
@@ -37,7 +38,7 @@ class Micromamba(object):
|
|
37
38
|
_home = os.environ.get("METAFLOW_TOKEN_HOME")
|
38
39
|
else:
|
39
40
|
_home = os.environ.get("METAFLOW_HOME", "~/.metaflowconfig")
|
40
|
-
_path_to_hidden_micromamba = os.path.join(
|
41
|
+
self._path_to_hidden_micromamba = os.path.join(
|
41
42
|
os.path.expanduser(_home),
|
42
43
|
"micromamba",
|
43
44
|
)
|
@@ -47,22 +48,40 @@ class Micromamba(object):
|
|
47
48
|
else:
|
48
49
|
self.logger = lambda *args, **kwargs: None # No-op logger if not provided
|
49
50
|
|
50
|
-
self.
|
51
|
+
self._bin = (
|
51
52
|
which(os.environ.get("METAFLOW_PATH_TO_MICROMAMBA") or "micromamba")
|
52
53
|
or which("./micromamba") # to support remote execution
|
53
54
|
or which("./bin/micromamba")
|
54
|
-
or which(os.path.join(_path_to_hidden_micromamba, "bin/micromamba"))
|
55
|
+
or which(os.path.join(self._path_to_hidden_micromamba, "bin/micromamba"))
|
55
56
|
)
|
56
|
-
|
57
|
+
|
58
|
+
# We keep a mutex as environments are resolved in parallel,
|
59
|
+
# which causes a race condition in case micromamba needs to be installed first.
|
60
|
+
self.install_mutex = Lock()
|
61
|
+
|
62
|
+
@property
|
63
|
+
def bin(self) -> str:
|
64
|
+
"Defer installing Micromamba until when the binary path is actually requested"
|
65
|
+
if self._bin is not None:
|
66
|
+
return self._bin
|
67
|
+
with self.install_mutex:
|
68
|
+
# another check as micromamba might have been installed when the mutex is released.
|
69
|
+
if self._bin is not None:
|
70
|
+
return self._bin
|
71
|
+
|
57
72
|
# Install Micromamba on the fly.
|
58
73
|
# TODO: Make this optional at some point.
|
59
|
-
_install_micromamba(_path_to_hidden_micromamba)
|
60
|
-
self.
|
74
|
+
_install_micromamba(self._path_to_hidden_micromamba)
|
75
|
+
self._bin = which(
|
76
|
+
os.path.join(self._path_to_hidden_micromamba, "bin/micromamba")
|
77
|
+
)
|
78
|
+
|
79
|
+
if self._bin is None:
|
80
|
+
msg = "No installation for *Micromamba* found.\n"
|
81
|
+
msg += "Visit https://mamba.readthedocs.io/en/latest/micromamba-installation.html for installation instructions."
|
82
|
+
raise MetaflowException(msg)
|
61
83
|
|
62
|
-
|
63
|
-
msg = "No installation for *Micromamba* found.\n"
|
64
|
-
msg += "Visit https://mamba.readthedocs.io/en/latest/micromamba-installation.html for installation instructions."
|
65
|
-
raise MetaflowException(msg)
|
84
|
+
return self._bin
|
66
85
|
|
67
86
|
def solve(self, id_, packages, python, platform):
|
68
87
|
# Performance enhancements
|
metaflow/runner/click_api.py
CHANGED
@@ -16,7 +16,7 @@ import itertools
|
|
16
16
|
import uuid
|
17
17
|
import json
|
18
18
|
from collections import OrderedDict
|
19
|
-
from typing import Any, Callable, Dict, List, Optional
|
19
|
+
from typing import Any, Callable, Dict, List, Optional, Type
|
20
20
|
from typing import OrderedDict as TOrderedDict
|
21
21
|
from typing import Tuple as TTuple
|
22
22
|
from typing import Union
|
@@ -96,8 +96,13 @@ def _method_sanity_check(
|
|
96
96
|
check_type(supplied_v, annotations[supplied_k])
|
97
97
|
except TypeCheckError:
|
98
98
|
raise TypeError(
|
99
|
-
"Invalid type for '%s', expected: '%s', default is '%s'"
|
100
|
-
% (
|
99
|
+
"Invalid type for '%s' (%s), expected: '%s', default is '%s'"
|
100
|
+
% (
|
101
|
+
supplied_k,
|
102
|
+
type(supplied_k),
|
103
|
+
annotations[supplied_k],
|
104
|
+
defaults[supplied_k],
|
105
|
+
)
|
101
106
|
)
|
102
107
|
|
103
108
|
# Clean up values to make them into what click expects
|
@@ -184,26 +189,35 @@ def _lazy_load_command(
|
|
184
189
|
raise AttributeError()
|
185
190
|
|
186
191
|
|
187
|
-
def get_annotation(param:
|
192
|
+
def get_annotation(param: click.Parameter) -> TTuple[Type, bool]:
|
188
193
|
py_type = click_to_python_types[type(param.type)]
|
194
|
+
if param.nargs == -1:
|
195
|
+
# This is the equivalent of *args effectively
|
196
|
+
# so the type annotation should be the type of the
|
197
|
+
# elements in the list
|
198
|
+
return py_type, True
|
189
199
|
if not param.required:
|
190
|
-
if param.multiple or param.nargs
|
191
|
-
return Optional[List[py_type]]
|
200
|
+
if param.multiple or param.nargs > 1:
|
201
|
+
return Optional[Union[List[py_type], TTuple[py_type]]], False
|
192
202
|
else:
|
193
|
-
return Optional[py_type]
|
203
|
+
return Optional[py_type], False
|
194
204
|
else:
|
195
|
-
if param.multiple or param.nargs
|
196
|
-
return List[py_type]
|
205
|
+
if param.multiple or param.nargs > 1:
|
206
|
+
return Union[List[py_type], TTuple[py_type]], False
|
197
207
|
else:
|
198
|
-
return py_type
|
208
|
+
return py_type, False
|
199
209
|
|
200
210
|
|
201
211
|
def get_inspect_param_obj(p: Union[click.Argument, click.Option], kind: str):
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
212
|
+
annotation, is_vararg = get_annotation(p)
|
213
|
+
return (
|
214
|
+
inspect.Parameter(
|
215
|
+
name="args" if is_vararg else p.name,
|
216
|
+
kind=inspect.Parameter.VAR_POSITIONAL if is_vararg else kind,
|
217
|
+
default=inspect.Parameter.empty if is_vararg else p.default,
|
218
|
+
annotation=annotation,
|
219
|
+
),
|
220
|
+
annotation,
|
207
221
|
)
|
208
222
|
|
209
223
|
|
@@ -224,21 +238,29 @@ def extract_flow_class_from_file(flow_file: str) -> FlowSpec:
|
|
224
238
|
path_was_added = True
|
225
239
|
|
226
240
|
try:
|
241
|
+
# Get module name from the file path
|
242
|
+
module_name = os.path.splitext(os.path.basename(flow_file))[0]
|
243
|
+
|
227
244
|
# Check if the module has already been loaded
|
228
245
|
if flow_file in loaded_modules:
|
229
246
|
module = loaded_modules[flow_file]
|
230
247
|
else:
|
231
248
|
# Load the module if it's not already loaded
|
232
|
-
spec = importlib.util.spec_from_file_location(
|
249
|
+
spec = importlib.util.spec_from_file_location(module_name, flow_file)
|
233
250
|
module = importlib.util.module_from_spec(spec)
|
234
251
|
spec.loader.exec_module(module)
|
235
252
|
# Cache the loaded module
|
236
253
|
loaded_modules[flow_file] = module
|
237
|
-
classes = inspect.getmembers(module, inspect.isclass)
|
238
254
|
|
255
|
+
classes = inspect.getmembers(module, inspect.isclass)
|
239
256
|
flow_cls = None
|
257
|
+
|
240
258
|
for _, kls in classes:
|
241
|
-
if
|
259
|
+
if (
|
260
|
+
kls is not FlowSpec
|
261
|
+
and kls.__module__ == module_name
|
262
|
+
and issubclass(kls, FlowSpec)
|
263
|
+
):
|
242
264
|
if flow_cls is not None:
|
243
265
|
raise MetaflowException(
|
244
266
|
"Multiple FlowSpec classes found in %s" % flow_file
|
@@ -319,7 +341,7 @@ class MetaflowAPI(object):
|
|
319
341
|
defaults,
|
320
342
|
) = extract_all_params(cli_collection)
|
321
343
|
|
322
|
-
def _method(_self, **kwargs):
|
344
|
+
def _method(_self, *args, **kwargs):
|
323
345
|
method_params = _method_sanity_check(
|
324
346
|
possible_arg_params,
|
325
347
|
possible_opt_params,
|
@@ -381,6 +403,9 @@ class MetaflowAPI(object):
|
|
381
403
|
else:
|
382
404
|
components.append("--%s" % k)
|
383
405
|
components.append(str(i))
|
406
|
+
elif v is None:
|
407
|
+
continue # Skip None values -- they are defaults and converting
|
408
|
+
# them to string will not be what the user wants
|
384
409
|
else:
|
385
410
|
components.append("--%s" % k)
|
386
411
|
if v != "flag":
|
@@ -492,17 +517,16 @@ def extract_all_params(cmd_obj: Union[click.Command, click.Group]):
|
|
492
517
|
|
493
518
|
for each_param in cmd_obj.params:
|
494
519
|
if isinstance(each_param, click.Argument):
|
495
|
-
arg_params_sigs[each_param.name] =
|
496
|
-
each_param, inspect.Parameter.POSITIONAL_ONLY
|
520
|
+
arg_params_sigs[each_param.name], annotations[each_param.name] = (
|
521
|
+
get_inspect_param_obj(each_param, inspect.Parameter.POSITIONAL_ONLY)
|
497
522
|
)
|
498
523
|
arg_parameters[each_param.name] = each_param
|
499
524
|
elif isinstance(each_param, click.Option):
|
500
|
-
opt_params_sigs[each_param.name] =
|
501
|
-
each_param, inspect.Parameter.KEYWORD_ONLY
|
525
|
+
opt_params_sigs[each_param.name], annotations[each_param.name] = (
|
526
|
+
get_inspect_param_obj(each_param, inspect.Parameter.KEYWORD_ONLY)
|
502
527
|
)
|
503
528
|
opt_parameters[each_param.name] = each_param
|
504
529
|
|
505
|
-
annotations[each_param.name] = get_annotation(each_param)
|
506
530
|
defaults[each_param.name] = each_param.default
|
507
531
|
|
508
532
|
# first, fill in positional arguments
|
@@ -539,7 +563,7 @@ def extract_group(cmd_obj: click.Group, flow_parameters: List[Parameter]) -> Cal
|
|
539
563
|
defaults,
|
540
564
|
) = extract_all_params(cmd_obj)
|
541
565
|
|
542
|
-
def _method(_self, **kwargs):
|
566
|
+
def _method(_self, *args, **kwargs):
|
543
567
|
method_params = _method_sanity_check(
|
544
568
|
possible_arg_params, possible_opt_params, annotations, defaults, **kwargs
|
545
569
|
)
|
@@ -572,7 +596,7 @@ def extract_command(
|
|
572
596
|
defaults,
|
573
597
|
) = extract_all_params(cmd_obj)
|
574
598
|
|
575
|
-
def _method(_self, **kwargs):
|
599
|
+
def _method(_self, *args, **kwargs):
|
576
600
|
method_params = _method_sanity_check(
|
577
601
|
possible_arg_params, possible_opt_params, annotations, defaults, **kwargs
|
578
602
|
)
|
metaflow/runner/deployer_impl.py
CHANGED
@@ -63,11 +63,20 @@ class DeployerImpl(object):
|
|
63
63
|
|
64
64
|
from metaflow.parameters import flow_context
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
66
|
+
# Reload the CLI with an "empty" flow -- this will remove any configuration
|
67
|
+
# and parameter options. They are re-added in from_cli (called below).
|
68
|
+
to_reload = [
|
69
|
+
"metaflow.cli",
|
70
|
+
"metaflow.cli_components.run_cmds",
|
71
|
+
"metaflow.cli_components.init_cmd",
|
72
|
+
]
|
73
|
+
with flow_context(None):
|
74
|
+
[
|
75
|
+
importlib.reload(sys.modules[module])
|
76
|
+
for module in to_reload
|
77
|
+
if module in sys.modules
|
78
|
+
]
|
79
|
+
|
71
80
|
from metaflow.cli import start
|
72
81
|
from metaflow.runner.click_api import MetaflowAPI
|
73
82
|
|
@@ -269,11 +269,20 @@ class Runner(metaclass=RunnerMeta):
|
|
269
269
|
|
270
270
|
from metaflow.parameters import flow_context
|
271
271
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
272
|
+
# Reload the CLI with an "empty" flow -- this will remove any configuration
|
273
|
+
# and parameter options. They are re-added in from_cli (called below).
|
274
|
+
to_reload = [
|
275
|
+
"metaflow.cli",
|
276
|
+
"metaflow.cli_components.run_cmds",
|
277
|
+
"metaflow.cli_components.init_cmd",
|
278
|
+
]
|
279
|
+
with flow_context(None):
|
280
|
+
[
|
281
|
+
importlib.reload(sys.modules[module])
|
282
|
+
for module in to_reload
|
283
|
+
if module in sys.modules
|
284
|
+
]
|
285
|
+
|
277
286
|
from metaflow.cli import start
|
278
287
|
from metaflow.runner.click_api import MetaflowAPI
|
279
288
|
|
metaflow/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
metaflow_version = "2.13.
|
1
|
+
metaflow_version = "2.13.9"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: metaflow
|
3
|
-
Version: 2.13.
|
3
|
+
Version: 2.13.9
|
4
4
|
Summary: Metaflow: More Data Science, Less Engineering
|
5
5
|
Author: Metaflow Developers
|
6
6
|
Author-email: help@metaflow.org
|
@@ -26,7 +26,7 @@ License-File: LICENSE
|
|
26
26
|
Requires-Dist: requests
|
27
27
|
Requires-Dist: boto3
|
28
28
|
Provides-Extra: stubs
|
29
|
-
Requires-Dist: metaflow-stubs==2.13.
|
29
|
+
Requires-Dist: metaflow-stubs==2.13.9; extra == "stubs"
|
30
30
|
Dynamic: author
|
31
31
|
Dynamic: author-email
|
32
32
|
Dynamic: classifier
|
@@ -10,13 +10,13 @@ metaflow/decorators.py,sha256=cbOCahmwVlnHklMN2O_j5DKvZA7m_Q72_6LBzzBZRhk,24131
|
|
10
10
|
metaflow/event_logger.py,sha256=joTVRqZPL87nvah4ZOwtqWX8NeraM_CXKXXGVpKGD8o,780
|
11
11
|
metaflow/events.py,sha256=ahjzkSbSnRCK9RZ-9vTfUviz_6gMvSO9DGkJ86X80-k,5300
|
12
12
|
metaflow/exception.py,sha256=_m9ZBJM0cooHRslDqfxCPQmkChqaTh6fGxp7HvISnYI,5161
|
13
|
-
metaflow/flowspec.py,sha256=
|
13
|
+
metaflow/flowspec.py,sha256=XxgE0sJ7cpnkoIRNvuN8Z3V2ob1VHzEE8XSDph_GUCg,35597
|
14
14
|
metaflow/graph.py,sha256=cdpnWr85aEj_rRn-7EjbndWjr_i8Dt3P7-oPUW0NNpI,12393
|
15
15
|
metaflow/includefile.py,sha256=kWKDSlzVcRVNGG9PV5eB3o2ynrzqhVsfaLtkqjshn7Q,20948
|
16
16
|
metaflow/info_file.py,sha256=wtf2_F0M6dgiUu74AFImM8lfy5RrUw5Yj7Rgs2swKRY,686
|
17
17
|
metaflow/integrations.py,sha256=LlsaoePRg03DjENnmLxZDYto3NwWc9z_PtU6nJxLldg,1480
|
18
18
|
metaflow/lint.py,sha256=x4p6tnRzYqNNniCGXyrUW0WuYfTUgnaOMRivxvnxask,11661
|
19
|
-
metaflow/metaflow_config.py,sha256=
|
19
|
+
metaflow/metaflow_config.py,sha256=Uu5GmiVLlAu1-VT6MTprnQ_kPC5WrRS_C2UJ-qgNi9I,23477
|
20
20
|
metaflow/metaflow_config_funcs.py,sha256=5GlvoafV6SxykwfL8D12WXSfwjBN_NsyuKE_Q3gjGVE,6738
|
21
21
|
metaflow/metaflow_current.py,sha256=pfkXmkyHeMJhxIs6HBJNBEaBDpcl5kz9Wx5mW6F_3qo,7164
|
22
22
|
metaflow/metaflow_environment.py,sha256=rojFyGdyY56sN1HaEb1-0XX53Q3XPNnl0SaH-8xXZ8w,7987
|
@@ -36,7 +36,7 @@ metaflow/tuple_util.py,sha256=_G5YIEhuugwJ_f6rrZoelMFak3DqAR2tt_5CapS1XTY,830
|
|
36
36
|
metaflow/unbounded_foreach.py,sha256=p184WMbrMJ3xKYHwewj27ZhRUsSj_kw1jlye5gA9xJk,387
|
37
37
|
metaflow/util.py,sha256=hKjHl6NYJkKBSU2tzdVbddfOX1zWK73T4GCO42A0XB4,14666
|
38
38
|
metaflow/vendor.py,sha256=FchtA9tH22JM-eEtJ2c9FpUdMn8sSb1VHuQS56EcdZk,5139
|
39
|
-
metaflow/version.py,sha256=
|
39
|
+
metaflow/version.py,sha256=xeHffcr9LL_YPy5rUqIu5yORGDOAVqaxh4ieE2_npAY,28
|
40
40
|
metaflow/_vendor/__init__.py,sha256=y_CiwUD3l4eAKvTVDZeqgVujMy31cAM1qjAB-HfI-9s,353
|
41
41
|
metaflow/_vendor/typing_extensions.py,sha256=0nUs5p1A_UrZigrAVBoOEM6TxU37zzPDUtiij1ZwpNc,110417
|
42
42
|
metaflow/_vendor/zipp.py,sha256=ajztOH-9I7KA_4wqDYygtHa6xUBVZgFpmZ8FE74HHHI,8425
|
@@ -291,7 +291,7 @@ metaflow/plugins/kubernetes/kube_utils.py,sha256=jdFMGbEmIow-oli26v31W9CmbZXigx0
|
|
291
291
|
metaflow/plugins/kubernetes/kubernetes.py,sha256=g_E5jBhoMSDzGFnP5PDQiVPPllUr1wulVcG3tz247G8,29668
|
292
292
|
metaflow/plugins/kubernetes/kubernetes_cli.py,sha256=o_o0BDEJFpTuga7txRmkvZH8OIuTb5kI4UaG6xbzf84,13929
|
293
293
|
metaflow/plugins/kubernetes/kubernetes_client.py,sha256=tuvXP-QKpdeSmzVolB2R_TaacOr5DIb0j642eKcjsiM,6491
|
294
|
-
metaflow/plugins/kubernetes/kubernetes_decorator.py,sha256=
|
294
|
+
metaflow/plugins/kubernetes/kubernetes_decorator.py,sha256=Yg32f1VWPPvV2pECufBG4VqyZw_QNY39R836G8UVLKw,30844
|
295
295
|
metaflow/plugins/kubernetes/kubernetes_job.py,sha256=pO9ExyAVCDoAoWFn9oFcos2aa0MQk4_D61O-T4E10E8,31826
|
296
296
|
metaflow/plugins/kubernetes/kubernetes_jobsets.py,sha256=9kU43eE5IvIa7y-POzBdxnJOazWsedKhwQ51Tu1HN_A,42471
|
297
297
|
metaflow/plugins/kubernetes/spot_metadata_cli.py,sha256=an0nWCxgflmqIPBCBrlb4m3DereDFFJBLt-KKhqcHc8,1670
|
@@ -300,10 +300,10 @@ metaflow/plugins/metadata_providers/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uz
|
|
300
300
|
metaflow/plugins/metadata_providers/local.py,sha256=9UAxe9caN6kU1lkSlIoJbRGgTqsMa62cBTnyMwhqiaA,22446
|
301
301
|
metaflow/plugins/metadata_providers/service.py,sha256=NKZfFMamx6upP6aFRJfXlfYIhySgFNzz6kbp1yPD7LA,20222
|
302
302
|
metaflow/plugins/pypi/__init__.py,sha256=0YFZpXvX7HCkyBFglatual7XGifdA1RwC3U4kcizyak,1037
|
303
|
-
metaflow/plugins/pypi/bootstrap.py,sha256=
|
303
|
+
metaflow/plugins/pypi/bootstrap.py,sha256=oRfJkAp99R338nYX2wq4FrV0Ax5h4QqqifNmAXrM3CY,14892
|
304
304
|
metaflow/plugins/pypi/conda_decorator.py,sha256=piFcE4uGmWhhbGlxMK0GHd7BGEyqy6r9BFy8Mjoi80Q,15937
|
305
305
|
metaflow/plugins/pypi/conda_environment.py,sha256=d5BAiY_aJJdlJ5h3N5nGSDmVoOY-8BVKqEbA5nrCpCY,22113
|
306
|
-
metaflow/plugins/pypi/micromamba.py,sha256=
|
306
|
+
metaflow/plugins/pypi/micromamba.py,sha256=LLJ2dGGOEyld07W8iI6dtE01h2Y1PQnBhU-dMBssZ3c,16502
|
307
307
|
metaflow/plugins/pypi/pip.py,sha256=H0cIy8odpZ-JTn4SwF0b74tuC3uRU7X8TdAQJ2kODG8,13971
|
308
308
|
metaflow/plugins/pypi/pypi_decorator.py,sha256=ybNgo-T5Z_0W2KNuED0pdjyI0qygZ4a1MXAzKqdHt_E,7250
|
309
309
|
metaflow/plugins/pypi/pypi_environment.py,sha256=FYMg8kF3lXqcLfRYWD83a9zpVjcoo_TARqMGZ763rRk,230
|
@@ -312,10 +312,10 @@ metaflow/plugins/secrets/__init__.py,sha256=mhJaN2eMS_ZZVewAMR2E-JdP5i0t3v9e6Dcw
|
|
312
312
|
metaflow/plugins/secrets/inline_secrets_provider.py,sha256=EChmoBGA1i7qM3jtYwPpLZDBybXLergiDlN63E0u3x8,294
|
313
313
|
metaflow/plugins/secrets/secrets_decorator.py,sha256=s-sFzPWOjahhpr5fMj-ZEaHkDYAPTO0isYXGvaUwlG8,11273
|
314
314
|
metaflow/runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
315
|
-
metaflow/runner/click_api.py,sha256=
|
315
|
+
metaflow/runner/click_api.py,sha256=hCwIxeehI4XtgIrQRjr10k6oFmTdx_60lih5fXUc6wU,22894
|
316
316
|
metaflow/runner/deployer.py,sha256=Yas_SZCss3kfJw3hLC8_IyzgiytUFGoEGHz-l-rBBKk,8980
|
317
|
-
metaflow/runner/deployer_impl.py,sha256=
|
318
|
-
metaflow/runner/metaflow_runner.py,sha256=
|
317
|
+
metaflow/runner/deployer_impl.py,sha256=Kab9rLoA3EiBJDtTTulhPCeKzqiljW366nx2Tm0LYy0,6143
|
318
|
+
metaflow/runner/metaflow_runner.py,sha256=L302ew_BPBPs-NnW8n92dqqbqmHwrwGL5D6kTZvl5vY,16074
|
319
319
|
metaflow/runner/nbdeploy.py,sha256=Sp5w-6nCZwjHaRBHWxi8udya-RYnJOB76KNLjB4L7Gs,4166
|
320
320
|
metaflow/runner/nbrun.py,sha256=LhJu-Teoi7wTkNxg0kpNPVXFxH_9P4lvtp0ysMEIFJ8,7299
|
321
321
|
metaflow/runner/subprocess_manager.py,sha256=K6uZXnqdgeW0vHUAVwoolSpDSLp1EVHiBtyD7f_vwac,22050
|
@@ -360,9 +360,9 @@ metaflow/user_configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
|
|
360
360
|
metaflow/user_configs/config_decorators.py,sha256=Tj0H88UT8Q6pylXxHXgiA6cqnNlw4d3mR7M8J9g3ZUg,20139
|
361
361
|
metaflow/user_configs/config_options.py,sha256=t6c9KNVGz9GNK55YAow74Lof4sDZqCbeeZSzldUBFmA,21072
|
362
362
|
metaflow/user_configs/config_parameters.py,sha256=oeJGVKu1ao_YQX6Lg6P2FEv5k5-_F4sARLlVpTW9ezM,15502
|
363
|
-
metaflow-2.13.
|
364
|
-
metaflow-2.13.
|
365
|
-
metaflow-2.13.
|
366
|
-
metaflow-2.13.
|
367
|
-
metaflow-2.13.
|
368
|
-
metaflow-2.13.
|
363
|
+
metaflow-2.13.9.dist-info/LICENSE,sha256=nl_Lt5v9VvJ-5lWJDT4ddKAG-VZ-2IaLmbzpgYDz2hU,11343
|
364
|
+
metaflow-2.13.9.dist-info/METADATA,sha256=7wOsTSpzHy1tnEuiaSz8qvAk4A5vE_zd4m98Hk-rOZI,6121
|
365
|
+
metaflow-2.13.9.dist-info/WHEEL,sha256=9Hm2OB-j1QcCUq9Jguht7ayGIIZBRTdOXD1qg9cCgPM,109
|
366
|
+
metaflow-2.13.9.dist-info/entry_points.txt,sha256=IKwTN1T3I5eJL3uo_vnkyxVffcgnRdFbKwlghZfn27k,57
|
367
|
+
metaflow-2.13.9.dist-info/top_level.txt,sha256=v1pDHoWaSaKeuc5fKTRSfsXCKSdW1zvNVmvA-i0if3o,9
|
368
|
+
metaflow-2.13.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|