metaflow 2.15.20__py2.py3-none-any.whl → 2.16.0__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 +7 -1
- metaflow/cli.py +16 -1
- metaflow/cli_components/init_cmd.py +1 -0
- metaflow/cli_components/run_cmds.py +6 -2
- metaflow/client/core.py +22 -30
- metaflow/datastore/task_datastore.py +0 -1
- metaflow/debug.py +5 -0
- metaflow/decorators.py +230 -70
- metaflow/extension_support/__init__.py +15 -8
- metaflow/extension_support/_empty_file.py +2 -2
- metaflow/flowspec.py +80 -53
- metaflow/graph.py +24 -2
- metaflow/meta_files.py +13 -0
- metaflow/metadata_provider/metadata.py +7 -1
- metaflow/metaflow_config.py +5 -0
- metaflow/metaflow_environment.py +82 -25
- metaflow/metaflow_version.py +1 -1
- metaflow/package/__init__.py +664 -0
- metaflow/packaging_sys/__init__.py +870 -0
- metaflow/packaging_sys/backend.py +113 -0
- metaflow/packaging_sys/distribution_support.py +153 -0
- metaflow/packaging_sys/tar_backend.py +86 -0
- metaflow/packaging_sys/utils.py +91 -0
- metaflow/packaging_sys/v1.py +476 -0
- metaflow/plugins/airflow/airflow.py +5 -1
- metaflow/plugins/airflow/airflow_cli.py +15 -4
- metaflow/plugins/argo/argo_workflows.py +23 -17
- metaflow/plugins/argo/argo_workflows_cli.py +16 -4
- metaflow/plugins/aws/batch/batch.py +22 -3
- metaflow/plugins/aws/batch/batch_cli.py +3 -0
- metaflow/plugins/aws/batch/batch_decorator.py +13 -5
- metaflow/plugins/aws/step_functions/step_functions.py +4 -1
- metaflow/plugins/aws/step_functions/step_functions_cli.py +15 -4
- metaflow/plugins/cards/card_decorator.py +0 -5
- metaflow/plugins/kubernetes/kubernetes.py +8 -1
- metaflow/plugins/kubernetes/kubernetes_cli.py +3 -0
- metaflow/plugins/kubernetes/kubernetes_decorator.py +13 -5
- metaflow/plugins/package_cli.py +25 -23
- metaflow/plugins/parallel_decorator.py +4 -2
- metaflow/plugins/pypi/bootstrap.py +8 -2
- metaflow/plugins/pypi/conda_decorator.py +39 -82
- metaflow/plugins/pypi/conda_environment.py +6 -2
- metaflow/plugins/pypi/pypi_decorator.py +4 -4
- metaflow/plugins/test_unbounded_foreach_decorator.py +2 -2
- metaflow/plugins/timeout_decorator.py +0 -1
- metaflow/plugins/uv/bootstrap.py +11 -0
- metaflow/plugins/uv/uv_environment.py +4 -2
- metaflow/pylint_wrapper.py +5 -1
- metaflow/runner/click_api.py +5 -4
- metaflow/runner/subprocess_manager.py +14 -2
- metaflow/runtime.py +37 -11
- metaflow/task.py +91 -7
- metaflow/user_configs/config_options.py +13 -8
- metaflow/user_configs/config_parameters.py +0 -4
- metaflow/user_decorators/__init__.py +0 -0
- metaflow/user_decorators/common.py +144 -0
- metaflow/user_decorators/mutable_flow.py +499 -0
- metaflow/user_decorators/mutable_step.py +424 -0
- metaflow/user_decorators/user_flow_decorator.py +263 -0
- metaflow/user_decorators/user_step_decorator.py +712 -0
- metaflow/util.py +4 -1
- metaflow/version.py +1 -1
- {metaflow-2.15.20.dist-info → metaflow-2.16.0.dist-info}/METADATA +2 -2
- {metaflow-2.15.20.dist-info → metaflow-2.16.0.dist-info}/RECORD +71 -60
- metaflow/info_file.py +0 -25
- metaflow/package.py +0 -203
- metaflow/user_configs/config_decorators.py +0 -568
- {metaflow-2.15.20.data → metaflow-2.16.0.data}/data/share/metaflow/devtools/Makefile +0 -0
- {metaflow-2.15.20.data → metaflow-2.16.0.data}/data/share/metaflow/devtools/Tiltfile +0 -0
- {metaflow-2.15.20.data → metaflow-2.16.0.data}/data/share/metaflow/devtools/pick_services.sh +0 -0
- {metaflow-2.15.20.dist-info → metaflow-2.16.0.dist-info}/WHEEL +0 -0
- {metaflow-2.15.20.dist-info → metaflow-2.16.0.dist-info}/entry_points.txt +0 -0
- {metaflow-2.15.20.dist-info → metaflow-2.16.0.dist-info}/licenses/LICENSE +0 -0
- {metaflow-2.15.20.dist-info → metaflow-2.16.0.dist-info}/top_level.txt +0 -0
@@ -12,7 +12,7 @@ from importlib.abc import MetaPathFinder, Loader
|
|
12
12
|
from itertools import chain
|
13
13
|
from pathlib import Path
|
14
14
|
|
15
|
-
from metaflow.
|
15
|
+
from metaflow.meta_files import read_info_file
|
16
16
|
|
17
17
|
|
18
18
|
#
|
@@ -214,6 +214,10 @@ def package_mfext_all():
|
|
214
214
|
yield path_tuple
|
215
215
|
|
216
216
|
|
217
|
+
def package_mfext_all_descriptions():
|
218
|
+
return _all_packages
|
219
|
+
|
220
|
+
|
217
221
|
def load_globals(module, dst_globals, extra_indent=False):
|
218
222
|
if extra_indent:
|
219
223
|
extra_indent = " "
|
@@ -808,13 +812,16 @@ def _get_extension_packages(ignore_info_file=False, restrict_to_directories=None
|
|
808
812
|
" Extends '%s' with config '%s'"
|
809
813
|
% (_extension_points[idx], config_module)
|
810
814
|
)
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
815
|
+
if files_to_include:
|
816
|
+
mf_pkg_list.append(package_name)
|
817
|
+
mf_ext_packages[package_name] = {
|
818
|
+
"root_paths": [package_path],
|
819
|
+
"meta_module": meta_module,
|
820
|
+
"files": files_to_include,
|
821
|
+
"version": "_local_",
|
822
|
+
}
|
823
|
+
else:
|
824
|
+
_ext_debug("Skipping package as no files found (empty dir?)")
|
818
825
|
|
819
826
|
# Sanity check that we only have one package per configuration file.
|
820
827
|
# This prevents multiple packages from providing the same named configuration
|
@@ -1,2 +1,2 @@
|
|
1
|
-
# This file serves as a __init__.py for metaflow_extensions
|
2
|
-
# and needs to remain empty.
|
1
|
+
# This file serves as a __init__.py for metaflow_extensions or metaflow
|
2
|
+
# packages when they are packaged and needs to remain empty.
|
metaflow/flowspec.py
CHANGED
@@ -7,7 +7,7 @@ import reprlib
|
|
7
7
|
from enum import Enum
|
8
8
|
from itertools import islice
|
9
9
|
from types import FunctionType, MethodType
|
10
|
-
from typing import TYPE_CHECKING, Any, Callable,
|
10
|
+
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Tuple
|
11
11
|
|
12
12
|
from . import cmd_with_io, parameters
|
13
13
|
from .debug import debug
|
@@ -23,13 +23,14 @@ from .extension_support import extension_info
|
|
23
23
|
|
24
24
|
from .graph import FlowGraph
|
25
25
|
from .unbounded_foreach import UnboundedForeachInput
|
26
|
-
from .user_configs.
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
26
|
+
from .user_configs.config_parameters import ConfigValue
|
27
|
+
|
28
|
+
from .user_decorators.mutable_flow import MutableFlow
|
29
|
+
from .user_decorators.mutable_step import MutableStep
|
30
|
+
from .user_decorators.user_flow_decorator import FlowMutator
|
31
|
+
from .user_decorators.user_step_decorator import StepMutator
|
32
|
+
|
33
|
+
|
33
34
|
from .util import to_pod
|
34
35
|
from .metaflow_config import INCLUDE_FOREACH_STACK, MAXIMUM_FOREACH_VALUE_CHARS
|
35
36
|
|
@@ -79,6 +80,10 @@ class _FlowState(Enum):
|
|
79
80
|
CONFIGS = 1
|
80
81
|
CONFIG_DECORATORS = 2
|
81
82
|
CACHED_PARAMETERS = 3
|
83
|
+
SET_CONFIG_PARAMETERS = (
|
84
|
+
4 # These are Parameters that now have a ConfigValue (converted)
|
85
|
+
)
|
86
|
+
# but we need to remember them.
|
82
87
|
|
83
88
|
|
84
89
|
class FlowSpecMeta(type):
|
@@ -136,6 +141,7 @@ class FlowSpecMeta(type):
|
|
136
141
|
cls._flow_state.setdefault(_FlowState.CONFIG_DECORATORS, []).extend(
|
137
142
|
base_configs
|
138
143
|
)
|
144
|
+
|
139
145
|
cls._init_graph()
|
140
146
|
|
141
147
|
def _init_graph(cls):
|
@@ -232,8 +238,8 @@ class FlowSpec(metaclass=FlowSpecMeta):
|
|
232
238
|
|
233
239
|
@classmethod
|
234
240
|
def _process_config_decorators(cls, config_options, process_configs=True):
|
235
|
-
|
236
241
|
if cls._configs_processed:
|
242
|
+
debug.userconf_exec("Mutating step/flow decorators already processed")
|
237
243
|
return None
|
238
244
|
cls._configs_processed = True
|
239
245
|
|
@@ -244,18 +250,20 @@ class FlowSpec(metaclass=FlowSpecMeta):
|
|
244
250
|
):
|
245
251
|
# Process parameters to allow them to also use config values easily
|
246
252
|
for var, param in cls._get_parameters():
|
247
|
-
if param.IS_CONFIG_PARAMETER:
|
253
|
+
if isinstance(param, ConfigValue) or param.IS_CONFIG_PARAMETER:
|
248
254
|
continue
|
249
255
|
param.init(not process_configs)
|
250
256
|
return None
|
251
257
|
|
252
258
|
debug.userconf_exec("Processing mutating step/flow decorators")
|
253
259
|
# We need to convert all the user configurations from DelayedEvaluationParameters
|
254
|
-
# to actual values so they can be used as is in the
|
260
|
+
# to actual values so they can be used as is in the mutators.
|
255
261
|
|
256
|
-
# We
|
257
|
-
#
|
258
|
-
|
262
|
+
# We, however, need to make sure _get_parameters still works properly so
|
263
|
+
# we store what was a config and has been set to a specific value.
|
264
|
+
# This is safe to do for now because all other uses of _get_parameters typically
|
265
|
+
# do not rely on the variable itself but just the parameter.
|
266
|
+
to_save_configs = []
|
259
267
|
cls._check_parameters(config_parameters=True)
|
260
268
|
for var, param in cls._get_parameters():
|
261
269
|
if not param.IS_CONFIG_PARAMETER:
|
@@ -267,71 +275,72 @@ class FlowSpec(metaclass=FlowSpecMeta):
|
|
267
275
|
# We store the value as well so that in _set_constants, we don't try
|
268
276
|
# to recompute (no guarantee that it is stable)
|
269
277
|
param._store_value(val)
|
270
|
-
|
278
|
+
to_save_configs.append((var, param))
|
271
279
|
debug.userconf_exec("Setting config %s to %s" % (var, str(val)))
|
272
280
|
setattr(cls, var, val)
|
273
281
|
|
274
|
-
|
275
|
-
#
|
276
|
-
|
277
|
-
|
282
|
+
cls._flow_state[_FlowState.SET_CONFIG_PARAMETERS] = to_save_configs
|
283
|
+
# Run all the decorators. We first run the flow-level decorators
|
284
|
+
# and then the step level ones to maintain a consistent order with how
|
285
|
+
# other decorators are run.
|
278
286
|
|
279
|
-
# Run all the decorators. Step decorators are directly in the step and
|
280
|
-
# we will run those first and *then* we run all the flow level decorators
|
281
|
-
for step in cls._steps:
|
282
|
-
for deco in step.config_decorators:
|
283
|
-
if isinstance(deco, CustomStepDecorator):
|
284
|
-
debug.userconf_exec(
|
285
|
-
"Evaluating step level decorator %s for %s"
|
286
|
-
% (deco.__class__.__name__, step.name)
|
287
|
-
)
|
288
|
-
deco.evaluate(MutableStep(cls, step))
|
289
|
-
else:
|
290
|
-
raise MetaflowInternalError(
|
291
|
-
"A non CustomFlowDecorator found in step custom decorators"
|
292
|
-
)
|
293
|
-
if step.config_decorators:
|
294
|
-
# We remove all mention of the custom step decorator
|
295
|
-
setattr(cls, step.name, step)
|
296
|
-
|
297
|
-
mutable_flow = MutableFlow(cls)
|
298
287
|
for deco in cls._flow_state.get(_FlowState.CONFIG_DECORATORS, []):
|
299
|
-
if isinstance(deco,
|
288
|
+
if isinstance(deco, FlowMutator):
|
289
|
+
inserted_by_value = [deco.decorator_name] + (deco.inserted_by or [])
|
290
|
+
mutable_flow = MutableFlow(
|
291
|
+
cls,
|
292
|
+
pre_mutate=True,
|
293
|
+
statically_defined=deco.statically_defined,
|
294
|
+
inserted_by=inserted_by_value,
|
295
|
+
)
|
300
296
|
# Sanity check to make sure we are applying the decorator to the right
|
301
297
|
# class
|
302
298
|
if not deco._flow_cls == cls and not issubclass(cls, deco._flow_cls):
|
303
299
|
raise MetaflowInternalError(
|
304
|
-
"
|
300
|
+
"FlowMutator registered on the wrong flow -- "
|
305
301
|
"expected %s but got %s"
|
306
302
|
% (deco._flow_cls.__name__, cls.__name__)
|
307
303
|
)
|
308
304
|
debug.userconf_exec(
|
309
305
|
"Evaluating flow level decorator %s" % deco.__class__.__name__
|
310
306
|
)
|
311
|
-
deco.
|
307
|
+
deco.pre_mutate(mutable_flow)
|
312
308
|
# We reset cached_parameters on the very off chance that the user added
|
313
309
|
# more configurations based on the configuration
|
314
310
|
if _FlowState.CACHED_PARAMETERS in cls._flow_state:
|
315
311
|
del cls._flow_state[_FlowState.CACHED_PARAMETERS]
|
316
312
|
else:
|
317
313
|
raise MetaflowInternalError(
|
318
|
-
"A non
|
314
|
+
"A non FlowMutator found in flow custom decorators"
|
319
315
|
)
|
320
316
|
|
317
|
+
for step in cls._steps:
|
318
|
+
for deco in step.config_decorators:
|
319
|
+
if isinstance(deco, StepMutator):
|
320
|
+
inserted_by_value = [deco.decorator_name] + (deco.inserted_by or [])
|
321
|
+
debug.userconf_exec(
|
322
|
+
"Evaluating step level decorator %s for %s"
|
323
|
+
% (deco.__class__.__name__, step.name)
|
324
|
+
)
|
325
|
+
deco.pre_mutate(
|
326
|
+
MutableStep(
|
327
|
+
cls,
|
328
|
+
step,
|
329
|
+
pre_mutate=True,
|
330
|
+
statically_defined=deco.statically_defined,
|
331
|
+
inserted_by=inserted_by_value,
|
332
|
+
)
|
333
|
+
)
|
334
|
+
else:
|
335
|
+
raise MetaflowInternalError(
|
336
|
+
"A non StepMutator found in step custom decorators"
|
337
|
+
)
|
338
|
+
|
321
339
|
# Process parameters to allow them to also use config values easily
|
322
340
|
for var, param in cls._get_parameters():
|
323
341
|
if param.IS_CONFIG_PARAMETER:
|
324
342
|
continue
|
325
343
|
param.init()
|
326
|
-
# Reset all configs that were already present in the class.
|
327
|
-
# TODO: This means that users can't override configs directly. Not sure if this
|
328
|
-
# is a pattern we want to support
|
329
|
-
for var, param in to_reset_configs:
|
330
|
-
setattr(cls, var, param)
|
331
|
-
|
332
|
-
# Reset cached parameters again since we added back the config parameters
|
333
|
-
if _FlowState.CACHED_PARAMETERS in cls._flow_state:
|
334
|
-
del cls._flow_state[_FlowState.CACHED_PARAMETERS]
|
335
344
|
|
336
345
|
# Set the current flow class we are in (the one we just created)
|
337
346
|
parameters.replace_flow_context(cls)
|
@@ -402,9 +411,19 @@ class FlowSpec(metaclass=FlowSpecMeta):
|
|
402
411
|
"name": deco.name,
|
403
412
|
"attributes": to_pod(deco.attributes),
|
404
413
|
"statically_defined": deco.statically_defined,
|
414
|
+
"inserted_by": deco.inserted_by,
|
405
415
|
}
|
406
416
|
for deco in flow_decorators(self)
|
407
417
|
if not deco.name.startswith("_")
|
418
|
+
]
|
419
|
+
+ [
|
420
|
+
{
|
421
|
+
"name": deco.__class__.__name__,
|
422
|
+
"attributes": {},
|
423
|
+
"statically_defined": deco.statically_defined,
|
424
|
+
"inserted_by": deco.inserted_by,
|
425
|
+
}
|
426
|
+
for deco in self._flow_state.get(_FlowState.CONFIG_DECORATORS, [])
|
408
427
|
],
|
409
428
|
"extensions": extension_info(),
|
410
429
|
}
|
@@ -413,11 +432,19 @@ class FlowSpec(metaclass=FlowSpecMeta):
|
|
413
432
|
@classmethod
|
414
433
|
def _get_parameters(cls):
|
415
434
|
cached = cls._flow_state.get(_FlowState.CACHED_PARAMETERS)
|
435
|
+
returned = set()
|
416
436
|
if cached is not None:
|
437
|
+
for set_config in cls._flow_state.get(_FlowState.SET_CONFIG_PARAMETERS, []):
|
438
|
+
returned.add(set_config[0])
|
439
|
+
yield set_config[0], set_config[1]
|
417
440
|
for var in cached:
|
418
|
-
|
441
|
+
if var not in returned:
|
442
|
+
yield var, getattr(cls, var)
|
419
443
|
return
|
420
444
|
build_list = []
|
445
|
+
for set_config in cls._flow_state.get(_FlowState.SET_CONFIG_PARAMETERS, []):
|
446
|
+
returned.add(set_config[0])
|
447
|
+
yield set_config[0], set_config[1]
|
421
448
|
for var in dir(cls):
|
422
449
|
if var[0] == "_" or var in cls._NON_PARAMETERS:
|
423
450
|
continue
|
@@ -425,7 +452,7 @@ class FlowSpec(metaclass=FlowSpecMeta):
|
|
425
452
|
val = getattr(cls, var)
|
426
453
|
except:
|
427
454
|
continue
|
428
|
-
if isinstance(val, Parameter):
|
455
|
+
if isinstance(val, Parameter) and var not in returned:
|
429
456
|
build_list.append(var)
|
430
457
|
yield var, val
|
431
458
|
cls._flow_state[_FlowState.CACHED_PARAMETERS] = build_list
|
metaflow/graph.py
CHANGED
@@ -2,6 +2,8 @@ import inspect
|
|
2
2
|
import ast
|
3
3
|
import re
|
4
4
|
|
5
|
+
from itertools import chain
|
6
|
+
|
5
7
|
|
6
8
|
from .util import to_pod
|
7
9
|
|
@@ -45,13 +47,17 @@ def deindent_docstring(doc):
|
|
45
47
|
|
46
48
|
|
47
49
|
class DAGNode(object):
|
48
|
-
def __init__(
|
50
|
+
def __init__(
|
51
|
+
self, func_ast, decos, wrappers, config_decorators, doc, source_file, lineno
|
52
|
+
):
|
49
53
|
self.name = func_ast.name
|
50
54
|
self.source_file = source_file
|
51
55
|
# lineno is the start line of decorators in source_file
|
52
56
|
# func_ast.lineno is lines from decorators start to def of function
|
53
57
|
self.func_lineno = lineno + func_ast.lineno - 1
|
54
58
|
self.decorators = decos
|
59
|
+
self.wrappers = wrappers
|
60
|
+
self.config_decorators = config_decorators
|
55
61
|
self.doc = deindent_docstring(doc)
|
56
62
|
self.parallel_step = any(getattr(deco, "IS_PARALLEL", False) for deco in decos)
|
57
63
|
|
@@ -181,7 +187,13 @@ class FlowGraph(object):
|
|
181
187
|
source_code = deindent_docstring("".join(source_lines))
|
182
188
|
function_ast = ast.parse(source_code).body[0]
|
183
189
|
node = DAGNode(
|
184
|
-
function_ast,
|
190
|
+
function_ast,
|
191
|
+
func.decorators,
|
192
|
+
func.wrappers,
|
193
|
+
func.config_decorators,
|
194
|
+
func.__doc__,
|
195
|
+
source_file,
|
196
|
+
lineno,
|
185
197
|
)
|
186
198
|
nodes[element] = node
|
187
199
|
return nodes
|
@@ -293,9 +305,19 @@ class FlowGraph(object):
|
|
293
305
|
"name": deco.name,
|
294
306
|
"attributes": to_pod(deco.attributes),
|
295
307
|
"statically_defined": deco.statically_defined,
|
308
|
+
"inserted_by": deco.inserted_by,
|
296
309
|
}
|
297
310
|
for deco in node.decorators
|
298
311
|
if not deco.name.startswith("_")
|
312
|
+
]
|
313
|
+
+ [
|
314
|
+
{
|
315
|
+
"name": deco.decorator_name,
|
316
|
+
"attributes": {"_args": deco._args, **deco._kwargs},
|
317
|
+
"statically_defined": deco.statically_defined,
|
318
|
+
"inserted_by": deco.inserted_by,
|
319
|
+
}
|
320
|
+
for deco in chain(node.wrappers, node.config_decorators)
|
299
321
|
],
|
300
322
|
"next": node.out_funcs,
|
301
323
|
}
|
metaflow/meta_files.py
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
_UNINITIALIZED = object()
|
2
|
+
_info_file_content = _UNINITIALIZED
|
3
|
+
|
4
|
+
|
5
|
+
def read_info_file():
|
6
|
+
# Prevent circular import
|
7
|
+
from .packaging_sys import MetaflowCodeContent
|
8
|
+
|
9
|
+
global _info_file_content
|
10
|
+
|
11
|
+
if id(_info_file_content) == id(_UNINITIALIZED):
|
12
|
+
_info_file_content = MetaflowCodeContent.get_info()
|
13
|
+
return _info_file_content
|
@@ -674,11 +674,17 @@ class MetadataProvider(object):
|
|
674
674
|
if code_sha:
|
675
675
|
code_url = os.environ.get("METAFLOW_CODE_URL")
|
676
676
|
code_ds = os.environ.get("METAFLOW_CODE_DS")
|
677
|
+
code_metadata = os.environ.get("METAFLOW_CODE_METADATA")
|
677
678
|
metadata.append(
|
678
679
|
MetaDatum(
|
679
680
|
field="code-package",
|
680
681
|
value=json.dumps(
|
681
|
-
{
|
682
|
+
{
|
683
|
+
"ds_type": code_ds,
|
684
|
+
"sha": code_sha,
|
685
|
+
"location": code_url,
|
686
|
+
"metadata": code_metadata,
|
687
|
+
}
|
682
688
|
),
|
683
689
|
type="code-package",
|
684
690
|
tags=["attempt_id:{0}".format(attempt)],
|
metaflow/metaflow_config.py
CHANGED
@@ -449,6 +449,10 @@ CONDA_USE_FAST_INIT = from_conf("CONDA_USE_FAST_INIT", False)
|
|
449
449
|
# Print out warning if escape hatch is not used for the target packages
|
450
450
|
ESCAPE_HATCH_WARNING = from_conf("ESCAPE_HATCH_WARNING", True)
|
451
451
|
|
452
|
+
###
|
453
|
+
# Features
|
454
|
+
###
|
455
|
+
FEAT_ALWAYS_UPLOAD_CODE_PACKAGE = from_conf("FEAT_ALWAYS_UPLOAD_CODE_PACKAGE", False)
|
452
456
|
###
|
453
457
|
# Debug configuration
|
454
458
|
###
|
@@ -460,6 +464,7 @@ DEBUG_OPTIONS = [
|
|
460
464
|
"stubgen",
|
461
465
|
"userconf",
|
462
466
|
"conda",
|
467
|
+
"package",
|
463
468
|
]
|
464
469
|
|
465
470
|
for typ in DEBUG_OPTIONS:
|
metaflow/metaflow_environment.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import json
|
1
2
|
import os
|
2
3
|
import platform
|
3
4
|
import sys
|
@@ -8,6 +9,8 @@ from . import metaflow_git
|
|
8
9
|
from metaflow.exception import MetaflowException
|
9
10
|
from metaflow.extension_support import dump_module_info
|
10
11
|
from metaflow.mflog import BASH_MFLOG, BASH_FLUSH_LOGS
|
12
|
+
from metaflow.package import MetaflowPackage
|
13
|
+
|
11
14
|
from . import R
|
12
15
|
|
13
16
|
|
@@ -49,8 +52,36 @@ class MetaflowEnvironment(object):
|
|
49
52
|
|
50
53
|
def add_to_package(self):
|
51
54
|
"""
|
52
|
-
|
53
|
-
|
55
|
+
Called to add custom files needed for this environment. This hook will be
|
56
|
+
called in the `MetaflowPackage` class where metaflow compiles the code package
|
57
|
+
tarball. This hook can return one of two things (the first is for backwards
|
58
|
+
compatibility -- move to the second):
|
59
|
+
- a generator yielding a tuple of `(file_path, arcname)` to add files to
|
60
|
+
the code package. `file_path` is the path to the file on the local filesystem
|
61
|
+
and `arcname` is the path relative to the packaged code.
|
62
|
+
- a generator yielding a tuple of `(content, arcname, type)` where:
|
63
|
+
- type is one of
|
64
|
+
ContentType.{USER_CONTENT, CODE_CONTENT, MODULE_CONTENT, OTHER_CONTENT}
|
65
|
+
- for USER_CONTENT:
|
66
|
+
- the file will be included relative to the directory containing the
|
67
|
+
user's flow file.
|
68
|
+
- content: path to the file to include
|
69
|
+
- arcname: path relative to the directory containing the user's flow file
|
70
|
+
- for CODE_CONTENT:
|
71
|
+
- the file will be included relative to the code directory in the package.
|
72
|
+
This will be the directory containing `metaflow`.
|
73
|
+
- content: path to the file to include
|
74
|
+
- arcname: path relative to the code directory in the package
|
75
|
+
- for MODULE_CONTENT:
|
76
|
+
- the module will be added to the code package as a python module. It will
|
77
|
+
be accessible as usual (import <module_name>)
|
78
|
+
- content: name of the module
|
79
|
+
- arcname: None (ignored)
|
80
|
+
- for OTHER_CONTENT:
|
81
|
+
- the file will be included relative to any other configuration/metadata
|
82
|
+
files for the flow
|
83
|
+
- content: path to the file to include
|
84
|
+
- arcname: path relative to the config directory in the package
|
54
85
|
"""
|
55
86
|
return []
|
56
87
|
|
@@ -157,29 +188,55 @@ class MetaflowEnvironment(object):
|
|
157
188
|
# skip pip installs if we know that packages might already be available
|
158
189
|
return "if [ -z $METAFLOW_SKIP_INSTALL_DEPENDENCIES ]; then {}; fi".format(cmd)
|
159
190
|
|
160
|
-
def get_package_commands(
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
191
|
+
def get_package_commands(
|
192
|
+
self, code_package_url, datastore_type, code_package_metadata=None
|
193
|
+
):
|
194
|
+
# HACK: We want to keep forward compatibility with compute layers so that
|
195
|
+
# they can still call get_package_commands and NOT pass any metadata. If
|
196
|
+
# there is no additional information, we *assume* that it is the default
|
197
|
+
# used.
|
198
|
+
if code_package_metadata is None:
|
199
|
+
code_package_metadata = json.dumps(
|
200
|
+
{
|
201
|
+
"version": 0,
|
202
|
+
"archive_format": "tgz",
|
203
|
+
"mfcontent_version": 1,
|
204
|
+
}
|
205
|
+
)
|
206
|
+
cmds = (
|
207
|
+
[
|
208
|
+
BASH_MFLOG,
|
209
|
+
BASH_FLUSH_LOGS,
|
210
|
+
"mflog 'Setting up task environment.'",
|
211
|
+
self._get_install_dependencies_cmd(datastore_type),
|
212
|
+
"mkdir metaflow",
|
213
|
+
"cd metaflow",
|
214
|
+
"mkdir .metaflow", # mute local datastore creation log
|
215
|
+
"i=0; while [ $i -le 5 ]; do "
|
216
|
+
"mflog 'Downloading code package...'; "
|
217
|
+
+ self._get_download_code_package_cmd(code_package_url, datastore_type)
|
218
|
+
+ " && mflog 'Code package downloaded.' && break; "
|
219
|
+
"sleep 10; i=$((i+1)); "
|
220
|
+
"done",
|
221
|
+
"if [ $i -gt 5 ]; then "
|
222
|
+
"mflog 'Failed to download code package from %s "
|
223
|
+
"after 6 tries. Exiting...' && exit 1; "
|
224
|
+
"fi" % code_package_url,
|
225
|
+
]
|
226
|
+
+ MetaflowPackage.get_extract_commands(
|
227
|
+
code_package_metadata, "job.tar", dest_dir="."
|
228
|
+
)
|
229
|
+
+ [
|
230
|
+
"export %s=%s:$(printenv %s)" % (k, v.replace('"', '\\"'), k)
|
231
|
+
for k, v in MetaflowPackage.get_post_extract_env_vars(
|
232
|
+
code_package_metadata, dest_dir="."
|
233
|
+
).items()
|
234
|
+
]
|
235
|
+
+ [
|
236
|
+
"mflog 'Task is starting.'",
|
237
|
+
"flush_mflogs",
|
238
|
+
]
|
239
|
+
)
|
183
240
|
return cmds
|
184
241
|
|
185
242
|
def get_environment_info(self, include_ext_info=False):
|
metaflow/metaflow_version.py
CHANGED
@@ -11,7 +11,7 @@ import subprocess
|
|
11
11
|
from os import path, name, environ, listdir
|
12
12
|
|
13
13
|
from metaflow.extension_support import update_package_info
|
14
|
-
from metaflow.
|
14
|
+
from metaflow.meta_files import read_info_file
|
15
15
|
|
16
16
|
|
17
17
|
# True/False correspond to the value `public`` in get_version
|