metaflow 2.15.21__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.
Files changed (74) hide show
  1. metaflow/__init__.py +7 -1
  2. metaflow/cli.py +16 -1
  3. metaflow/cli_components/init_cmd.py +1 -0
  4. metaflow/cli_components/run_cmds.py +6 -2
  5. metaflow/client/core.py +22 -30
  6. metaflow/datastore/task_datastore.py +0 -1
  7. metaflow/debug.py +5 -0
  8. metaflow/decorators.py +230 -70
  9. metaflow/extension_support/__init__.py +15 -8
  10. metaflow/extension_support/_empty_file.py +2 -2
  11. metaflow/flowspec.py +80 -53
  12. metaflow/graph.py +24 -2
  13. metaflow/meta_files.py +13 -0
  14. metaflow/metadata_provider/metadata.py +7 -1
  15. metaflow/metaflow_config.py +5 -0
  16. metaflow/metaflow_environment.py +82 -25
  17. metaflow/metaflow_version.py +1 -1
  18. metaflow/package/__init__.py +664 -0
  19. metaflow/packaging_sys/__init__.py +870 -0
  20. metaflow/packaging_sys/backend.py +113 -0
  21. metaflow/packaging_sys/distribution_support.py +153 -0
  22. metaflow/packaging_sys/tar_backend.py +86 -0
  23. metaflow/packaging_sys/utils.py +91 -0
  24. metaflow/packaging_sys/v1.py +476 -0
  25. metaflow/plugins/airflow/airflow.py +5 -1
  26. metaflow/plugins/airflow/airflow_cli.py +15 -4
  27. metaflow/plugins/argo/argo_workflows.py +15 -4
  28. metaflow/plugins/argo/argo_workflows_cli.py +16 -4
  29. metaflow/plugins/aws/batch/batch.py +22 -3
  30. metaflow/plugins/aws/batch/batch_cli.py +3 -0
  31. metaflow/plugins/aws/batch/batch_decorator.py +13 -5
  32. metaflow/plugins/aws/step_functions/step_functions.py +4 -1
  33. metaflow/plugins/aws/step_functions/step_functions_cli.py +15 -4
  34. metaflow/plugins/cards/card_decorator.py +0 -5
  35. metaflow/plugins/kubernetes/kubernetes.py +8 -1
  36. metaflow/plugins/kubernetes/kubernetes_cli.py +3 -0
  37. metaflow/plugins/kubernetes/kubernetes_decorator.py +13 -5
  38. metaflow/plugins/package_cli.py +25 -23
  39. metaflow/plugins/parallel_decorator.py +4 -2
  40. metaflow/plugins/pypi/bootstrap.py +8 -2
  41. metaflow/plugins/pypi/conda_decorator.py +39 -82
  42. metaflow/plugins/pypi/conda_environment.py +6 -2
  43. metaflow/plugins/pypi/pypi_decorator.py +4 -4
  44. metaflow/plugins/test_unbounded_foreach_decorator.py +2 -2
  45. metaflow/plugins/timeout_decorator.py +0 -1
  46. metaflow/plugins/uv/bootstrap.py +11 -0
  47. metaflow/plugins/uv/uv_environment.py +4 -2
  48. metaflow/pylint_wrapper.py +5 -1
  49. metaflow/runner/click_api.py +5 -4
  50. metaflow/runner/subprocess_manager.py +14 -2
  51. metaflow/runtime.py +37 -11
  52. metaflow/task.py +91 -7
  53. metaflow/user_configs/config_options.py +13 -8
  54. metaflow/user_configs/config_parameters.py +0 -4
  55. metaflow/user_decorators/__init__.py +0 -0
  56. metaflow/user_decorators/common.py +144 -0
  57. metaflow/user_decorators/mutable_flow.py +499 -0
  58. metaflow/user_decorators/mutable_step.py +424 -0
  59. metaflow/user_decorators/user_flow_decorator.py +263 -0
  60. metaflow/user_decorators/user_step_decorator.py +712 -0
  61. metaflow/util.py +4 -1
  62. metaflow/version.py +1 -1
  63. {metaflow-2.15.21.dist-info → metaflow-2.16.0.dist-info}/METADATA +2 -2
  64. {metaflow-2.15.21.dist-info → metaflow-2.16.0.dist-info}/RECORD +71 -60
  65. metaflow/info_file.py +0 -25
  66. metaflow/package.py +0 -203
  67. metaflow/user_configs/config_decorators.py +0 -568
  68. {metaflow-2.15.21.data → metaflow-2.16.0.data}/data/share/metaflow/devtools/Makefile +0 -0
  69. {metaflow-2.15.21.data → metaflow-2.16.0.data}/data/share/metaflow/devtools/Tiltfile +0 -0
  70. {metaflow-2.15.21.data → metaflow-2.16.0.data}/data/share/metaflow/devtools/pick_services.sh +0 -0
  71. {metaflow-2.15.21.dist-info → metaflow-2.16.0.dist-info}/WHEEL +0 -0
  72. {metaflow-2.15.21.dist-info → metaflow-2.16.0.dist-info}/entry_points.txt +0 -0
  73. {metaflow-2.15.21.dist-info → metaflow-2.16.0.dist-info}/licenses/LICENSE +0 -0
  74. {metaflow-2.15.21.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.info_file import read_info_file
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
- mf_pkg_list.append(package_name)
812
- mf_ext_packages[package_name] = {
813
- "root_paths": [package_path],
814
- "meta_module": meta_module,
815
- "files": files_to_include,
816
- "version": "_local_",
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 when it is packaged
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, Generator, List, Optional, Tuple
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.config_decorators import (
27
- ConfigValue,
28
- CustomFlowDecorator,
29
- CustomStepDecorator,
30
- MutableFlow,
31
- MutableStep,
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 config decorators.
260
+ # to actual values so they can be used as is in the mutators.
255
261
 
256
- # We then reset them to be proper configs so they can be re-evaluated in
257
- # _set_constants
258
- to_reset_configs = []
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
- to_reset_configs.append((var, param))
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
- # Reset cached parameters since we have replaced configs already with ConfigValue
275
- # so they are not parameters anymore to be re-evaluated when we do _get_parameters
276
- if _FlowState.CACHED_PARAMETERS in cls._flow_state:
277
- del cls._flow_state[_FlowState.CACHED_PARAMETERS]
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, CustomFlowDecorator):
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
- "CustomFlowDecorator registered on the wrong flow -- "
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.evaluate(mutable_flow)
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 CustomFlowDecorator found in flow custom decorators"
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
- yield var, getattr(cls, var)
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__(self, func_ast, decos, doc, source_file, lineno):
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, func.decorators, func.__doc__, source_file, lineno
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
- {"ds_type": code_ds, "sha": code_sha, "location": code_url}
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)],
@@ -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:
@@ -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
- A list of tuples (file, arcname) to add to the job package.
53
- `arcname` is an alternative name for the file in the job package.
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(self, code_package_url, datastore_type):
161
- cmds = [
162
- BASH_MFLOG,
163
- BASH_FLUSH_LOGS,
164
- "mflog 'Setting up task environment.'",
165
- self._get_install_dependencies_cmd(datastore_type),
166
- "mkdir metaflow",
167
- "cd metaflow",
168
- "mkdir .metaflow", # mute local datastore creation log
169
- "i=0; while [ $i -le 5 ]; do "
170
- "mflog 'Downloading code package...'; "
171
- + self._get_download_code_package_cmd(code_package_url, datastore_type)
172
- + " && mflog 'Code package downloaded.' && break; "
173
- "sleep 10; i=$((i+1)); "
174
- "done",
175
- "if [ $i -gt 5 ]; then "
176
- "mflog 'Failed to download code package from %s "
177
- "after 6 tries. Exiting...' && exit 1; "
178
- "fi" % code_package_url,
179
- "TAR_OPTIONS='--warning=no-timestamp' tar xf job.tar",
180
- "mflog 'Task is starting.'",
181
- "flush_mflogs",
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):
@@ -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.info_file import CURRENT_DIRECTORY, read_info_file
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