ob-metaflow 2.16.8.2rc1__py2.py3-none-any.whl → 2.17.0.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.

Files changed (62) hide show
  1. metaflow/_vendor/click/core.py +3 -4
  2. metaflow/_vendor/imghdr/__init__.py +7 -1
  3. metaflow/_vendor/yaml/__init__.py +427 -0
  4. metaflow/_vendor/yaml/composer.py +139 -0
  5. metaflow/_vendor/yaml/constructor.py +748 -0
  6. metaflow/_vendor/yaml/cyaml.py +101 -0
  7. metaflow/_vendor/yaml/dumper.py +62 -0
  8. metaflow/_vendor/yaml/emitter.py +1137 -0
  9. metaflow/_vendor/yaml/error.py +75 -0
  10. metaflow/_vendor/yaml/events.py +86 -0
  11. metaflow/_vendor/yaml/loader.py +63 -0
  12. metaflow/_vendor/yaml/nodes.py +49 -0
  13. metaflow/_vendor/yaml/parser.py +589 -0
  14. metaflow/_vendor/yaml/reader.py +185 -0
  15. metaflow/_vendor/yaml/representer.py +389 -0
  16. metaflow/_vendor/yaml/resolver.py +227 -0
  17. metaflow/_vendor/yaml/scanner.py +1435 -0
  18. metaflow/_vendor/yaml/serializer.py +111 -0
  19. metaflow/_vendor/yaml/tokens.py +104 -0
  20. metaflow/cli.py +11 -2
  21. metaflow/cli_components/run_cmds.py +0 -15
  22. metaflow/client/core.py +6 -1
  23. metaflow/extension_support/__init__.py +4 -3
  24. metaflow/flowspec.py +1 -113
  25. metaflow/graph.py +10 -134
  26. metaflow/lint.py +3 -70
  27. metaflow/metaflow_environment.py +14 -6
  28. metaflow/package/__init__.py +18 -9
  29. metaflow/packaging_sys/__init__.py +53 -43
  30. metaflow/packaging_sys/backend.py +21 -6
  31. metaflow/packaging_sys/tar_backend.py +16 -3
  32. metaflow/packaging_sys/v1.py +21 -21
  33. metaflow/plugins/argo/argo_client.py +31 -14
  34. metaflow/plugins/argo/argo_workflows.py +67 -22
  35. metaflow/plugins/argo/argo_workflows_cli.py +348 -85
  36. metaflow/plugins/argo/argo_workflows_deployer_objects.py +69 -0
  37. metaflow/plugins/aws/step_functions/step_functions.py +0 -6
  38. metaflow/plugins/aws/step_functions/step_functions_deployer_objects.py +30 -0
  39. metaflow/plugins/cards/card_modules/basic.py +3 -14
  40. metaflow/plugins/cards/card_modules/convert_to_native_type.py +7 -1
  41. metaflow/plugins/kubernetes/kubernetes_decorator.py +1 -1
  42. metaflow/plugins/kubernetes/kubernetes_job.py +8 -2
  43. metaflow/plugins/kubernetes/kubernetes_jobsets.py +26 -28
  44. metaflow/plugins/pypi/conda_decorator.py +4 -2
  45. metaflow/runner/click_api.py +14 -7
  46. metaflow/runner/deployer.py +160 -7
  47. metaflow/runner/subprocess_manager.py +20 -12
  48. metaflow/runtime.py +27 -102
  49. metaflow/task.py +25 -46
  50. metaflow/user_decorators/mutable_flow.py +3 -1
  51. metaflow/util.py +0 -29
  52. metaflow/vendor.py +23 -6
  53. metaflow/version.py +1 -1
  54. {ob_metaflow-2.16.8.2rc1.dist-info → ob_metaflow-2.17.0.1.dist-info}/METADATA +2 -2
  55. {ob_metaflow-2.16.8.2rc1.dist-info → ob_metaflow-2.17.0.1.dist-info}/RECORD +62 -45
  56. {ob_metaflow-2.16.8.2rc1.data → ob_metaflow-2.17.0.1.data}/data/share/metaflow/devtools/Makefile +0 -0
  57. {ob_metaflow-2.16.8.2rc1.data → ob_metaflow-2.17.0.1.data}/data/share/metaflow/devtools/Tiltfile +0 -0
  58. {ob_metaflow-2.16.8.2rc1.data → ob_metaflow-2.17.0.1.data}/data/share/metaflow/devtools/pick_services.sh +0 -0
  59. {ob_metaflow-2.16.8.2rc1.dist-info → ob_metaflow-2.17.0.1.dist-info}/WHEEL +0 -0
  60. {ob_metaflow-2.16.8.2rc1.dist-info → ob_metaflow-2.17.0.1.dist-info}/entry_points.txt +0 -0
  61. {ob_metaflow-2.16.8.2rc1.dist-info → ob_metaflow-2.17.0.1.dist-info}/licenses/LICENSE +0 -0
  62. {ob_metaflow-2.16.8.2rc1.dist-info → ob_metaflow-2.17.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,111 @@
1
+
2
+ __all__ = ['Serializer', 'SerializerError']
3
+
4
+ from .error import YAMLError
5
+ from .events import *
6
+ from .nodes import *
7
+
8
+ class SerializerError(YAMLError):
9
+ pass
10
+
11
+ class Serializer:
12
+
13
+ ANCHOR_TEMPLATE = 'id%03d'
14
+
15
+ def __init__(self, encoding=None,
16
+ explicit_start=None, explicit_end=None, version=None, tags=None):
17
+ self.use_encoding = encoding
18
+ self.use_explicit_start = explicit_start
19
+ self.use_explicit_end = explicit_end
20
+ self.use_version = version
21
+ self.use_tags = tags
22
+ self.serialized_nodes = {}
23
+ self.anchors = {}
24
+ self.last_anchor_id = 0
25
+ self.closed = None
26
+
27
+ def open(self):
28
+ if self.closed is None:
29
+ self.emit(StreamStartEvent(encoding=self.use_encoding))
30
+ self.closed = False
31
+ elif self.closed:
32
+ raise SerializerError("serializer is closed")
33
+ else:
34
+ raise SerializerError("serializer is already opened")
35
+
36
+ def close(self):
37
+ if self.closed is None:
38
+ raise SerializerError("serializer is not opened")
39
+ elif not self.closed:
40
+ self.emit(StreamEndEvent())
41
+ self.closed = True
42
+
43
+ #def __del__(self):
44
+ # self.close()
45
+
46
+ def serialize(self, node):
47
+ if self.closed is None:
48
+ raise SerializerError("serializer is not opened")
49
+ elif self.closed:
50
+ raise SerializerError("serializer is closed")
51
+ self.emit(DocumentStartEvent(explicit=self.use_explicit_start,
52
+ version=self.use_version, tags=self.use_tags))
53
+ self.anchor_node(node)
54
+ self.serialize_node(node, None, None)
55
+ self.emit(DocumentEndEvent(explicit=self.use_explicit_end))
56
+ self.serialized_nodes = {}
57
+ self.anchors = {}
58
+ self.last_anchor_id = 0
59
+
60
+ def anchor_node(self, node):
61
+ if node in self.anchors:
62
+ if self.anchors[node] is None:
63
+ self.anchors[node] = self.generate_anchor(node)
64
+ else:
65
+ self.anchors[node] = None
66
+ if isinstance(node, SequenceNode):
67
+ for item in node.value:
68
+ self.anchor_node(item)
69
+ elif isinstance(node, MappingNode):
70
+ for key, value in node.value:
71
+ self.anchor_node(key)
72
+ self.anchor_node(value)
73
+
74
+ def generate_anchor(self, node):
75
+ self.last_anchor_id += 1
76
+ return self.ANCHOR_TEMPLATE % self.last_anchor_id
77
+
78
+ def serialize_node(self, node, parent, index):
79
+ alias = self.anchors[node]
80
+ if node in self.serialized_nodes:
81
+ self.emit(AliasEvent(alias))
82
+ else:
83
+ self.serialized_nodes[node] = True
84
+ self.descend_resolver(parent, index)
85
+ if isinstance(node, ScalarNode):
86
+ detected_tag = self.resolve(ScalarNode, node.value, (True, False))
87
+ default_tag = self.resolve(ScalarNode, node.value, (False, True))
88
+ implicit = (node.tag == detected_tag), (node.tag == default_tag)
89
+ self.emit(ScalarEvent(alias, node.tag, implicit, node.value,
90
+ style=node.style))
91
+ elif isinstance(node, SequenceNode):
92
+ implicit = (node.tag
93
+ == self.resolve(SequenceNode, node.value, True))
94
+ self.emit(SequenceStartEvent(alias, node.tag, implicit,
95
+ flow_style=node.flow_style))
96
+ index = 0
97
+ for item in node.value:
98
+ self.serialize_node(item, node, index)
99
+ index += 1
100
+ self.emit(SequenceEndEvent())
101
+ elif isinstance(node, MappingNode):
102
+ implicit = (node.tag
103
+ == self.resolve(MappingNode, node.value, True))
104
+ self.emit(MappingStartEvent(alias, node.tag, implicit,
105
+ flow_style=node.flow_style))
106
+ for key, value in node.value:
107
+ self.serialize_node(key, node, None)
108
+ self.serialize_node(value, node, key)
109
+ self.emit(MappingEndEvent())
110
+ self.ascend_resolver()
111
+
@@ -0,0 +1,104 @@
1
+
2
+ class Token(object):
3
+ def __init__(self, start_mark, end_mark):
4
+ self.start_mark = start_mark
5
+ self.end_mark = end_mark
6
+ def __repr__(self):
7
+ attributes = [key for key in self.__dict__
8
+ if not key.endswith('_mark')]
9
+ attributes.sort()
10
+ arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
11
+ for key in attributes])
12
+ return '%s(%s)' % (self.__class__.__name__, arguments)
13
+
14
+ #class BOMToken(Token):
15
+ # id = '<byte order mark>'
16
+
17
+ class DirectiveToken(Token):
18
+ id = '<directive>'
19
+ def __init__(self, name, value, start_mark, end_mark):
20
+ self.name = name
21
+ self.value = value
22
+ self.start_mark = start_mark
23
+ self.end_mark = end_mark
24
+
25
+ class DocumentStartToken(Token):
26
+ id = '<document start>'
27
+
28
+ class DocumentEndToken(Token):
29
+ id = '<document end>'
30
+
31
+ class StreamStartToken(Token):
32
+ id = '<stream start>'
33
+ def __init__(self, start_mark=None, end_mark=None,
34
+ encoding=None):
35
+ self.start_mark = start_mark
36
+ self.end_mark = end_mark
37
+ self.encoding = encoding
38
+
39
+ class StreamEndToken(Token):
40
+ id = '<stream end>'
41
+
42
+ class BlockSequenceStartToken(Token):
43
+ id = '<block sequence start>'
44
+
45
+ class BlockMappingStartToken(Token):
46
+ id = '<block mapping start>'
47
+
48
+ class BlockEndToken(Token):
49
+ id = '<block end>'
50
+
51
+ class FlowSequenceStartToken(Token):
52
+ id = '['
53
+
54
+ class FlowMappingStartToken(Token):
55
+ id = '{'
56
+
57
+ class FlowSequenceEndToken(Token):
58
+ id = ']'
59
+
60
+ class FlowMappingEndToken(Token):
61
+ id = '}'
62
+
63
+ class KeyToken(Token):
64
+ id = '?'
65
+
66
+ class ValueToken(Token):
67
+ id = ':'
68
+
69
+ class BlockEntryToken(Token):
70
+ id = '-'
71
+
72
+ class FlowEntryToken(Token):
73
+ id = ','
74
+
75
+ class AliasToken(Token):
76
+ id = '<alias>'
77
+ def __init__(self, value, start_mark, end_mark):
78
+ self.value = value
79
+ self.start_mark = start_mark
80
+ self.end_mark = end_mark
81
+
82
+ class AnchorToken(Token):
83
+ id = '<anchor>'
84
+ def __init__(self, value, start_mark, end_mark):
85
+ self.value = value
86
+ self.start_mark = start_mark
87
+ self.end_mark = end_mark
88
+
89
+ class TagToken(Token):
90
+ id = '<tag>'
91
+ def __init__(self, value, start_mark, end_mark):
92
+ self.value = value
93
+ self.start_mark = start_mark
94
+ self.end_mark = end_mark
95
+
96
+ class ScalarToken(Token):
97
+ id = '<scalar>'
98
+ def __init__(self, value, plain, start_mark, end_mark, style=None):
99
+ self.value = value
100
+ self.plain = plain
101
+ self.start_mark = start_mark
102
+ self.end_mark = end_mark
103
+ self.style = style
104
+
metaflow/cli.py CHANGED
@@ -7,6 +7,7 @@ from datetime import datetime
7
7
 
8
8
  import metaflow.tracing as tracing
9
9
  from metaflow._vendor import click
10
+ from metaflow.system import _system_logger, _system_monitor
10
11
 
11
12
  from . import decorators, lint, metaflow_version, parameters, plugins
12
13
  from .cli_args import cli_args
@@ -26,7 +27,6 @@ from .metaflow_config import (
26
27
  DEFAULT_PACKAGE_SUFFIXES,
27
28
  )
28
29
  from .metaflow_current import current
29
- from metaflow.system import _system_monitor, _system_logger
30
30
  from .metaflow_environment import MetaflowEnvironment
31
31
  from .packaging_sys import MetaflowCodeContent
32
32
  from .plugins import (
@@ -38,9 +38,9 @@ from .plugins import (
38
38
  )
39
39
  from .pylint_wrapper import PyLint
40
40
  from .R import metaflow_r_version, use_r
41
- from .util import get_latest_run_id, resolve_identity
42
41
  from .user_configs.config_options import LocalFileInput, config_options
43
42
  from .user_configs.config_parameters import ConfigValue
43
+ from .util import get_latest_run_id, resolve_identity
44
44
 
45
45
  ERASE_TO_EOL = "\033[K"
46
46
  HIGHLIGHT = "red"
@@ -56,6 +56,15 @@ def echo_dev_null(*args, **kwargs):
56
56
 
57
57
 
58
58
  def echo_always(line, **kwargs):
59
+ if kwargs.pop("wrap", False):
60
+ import textwrap
61
+
62
+ indent_str = INDENT if kwargs.get("indent", None) else ""
63
+ effective_width = 80 - len(indent_str)
64
+ wrapped = textwrap.wrap(line, width=effective_width, break_long_words=False)
65
+ line = "\n".join(indent_str + l for l in wrapped)
66
+ kwargs["indent"] = False
67
+
59
68
  kwargs["err"] = kwargs.get("err", True)
60
69
  if kwargs.pop("indent", None):
61
70
  line = "\n".join(INDENT + x for x in line.splitlines())
@@ -13,8 +13,6 @@ from ..package import MetaflowPackage
13
13
  from ..runtime import NativeRuntime
14
14
  from ..system import _system_logger
15
15
 
16
- # from ..client.core import Run
17
-
18
16
  from ..tagging_util import validate_tags
19
17
  from ..util import get_latest_run_id, write_latest_run_id
20
18
 
@@ -232,19 +230,6 @@ def resume(
232
230
  step_to_rerun, ",".join(list(obj.graph.nodes.keys()))
233
231
  )
234
232
  )
235
-
236
- ## TODO: instead of checking execution path here, can add a warning later
237
- ## instead of throwing an error. This is for resuming a step which was not
238
- ## taken inside a branch i.e. not present in the execution path.
239
-
240
- # origin_run = Run(f"{obj.flow.name}/{origin_run_id}", _namespace_check=False)
241
- # executed_steps = {step.path_components[-1] for step in origin_run}
242
- # if step_to_rerun not in executed_steps:
243
- # raise CommandException(
244
- # f"Cannot resume from step '{step_to_rerun}'. This step was not "
245
- # f"part of the original execution path for run '{origin_run_id}'."
246
- # )
247
-
248
233
  steps_to_rerun = {step_to_rerun}
249
234
 
250
235
  if run_id:
metaflow/client/core.py CHANGED
@@ -831,10 +831,12 @@ class MetaflowCode(object):
831
831
  )
832
832
  self._code_obj = BytesIO(blobdata)
833
833
  self._info = MetaflowPackage.cls_get_info(self._code_metadata, self._code_obj)
834
+ self._code_obj.seek(0)
834
835
  if self._info:
835
836
  self._flowspec = MetaflowPackage.cls_get_content(
836
837
  self._code_metadata, self._code_obj, self._info["script"]
837
838
  )
839
+ self._code_obj.seek(0)
838
840
  else:
839
841
  raise MetaflowInternalError("Code package metadata is invalid.")
840
842
 
@@ -885,7 +887,9 @@ class MetaflowCode(object):
885
887
  TarFile for everything in this code package
886
888
  """
887
889
  if self._backend.type == "tgz":
888
- return self._backend.cls_open(self._code_obj)
890
+ to_return = self._backend.cls_open(self._code_obj)
891
+ self._code_obj.seek(0)
892
+ return to_return
889
893
  raise RuntimeError("Archive is not a tarball")
890
894
 
891
895
  def extract(self) -> TemporaryDirectory:
@@ -921,6 +925,7 @@ class MetaflowCode(object):
921
925
  MetaflowPackage.cls_extract_into(
922
926
  self._code_metadata, self._code_obj, tmp.name, ContentType.USER_CONTENT
923
927
  )
928
+ self._code_obj.seek(0)
924
929
  return tmp
925
930
 
926
931
  @property
@@ -205,9 +205,10 @@ def package_mfext_all():
205
205
  # the packaged metaflow_extensions directory "self-contained" so that
206
206
  # python doesn't go and search other parts of the system for more
207
207
  # metaflow_extensions.
208
- yield os.path.join(
209
- os.path.dirname(os.path.abspath(__file__)), "_empty_file.py"
210
- ), os.path.join(EXT_PKG, "__init__.py")
208
+ if _all_packages:
209
+ yield os.path.join(
210
+ os.path.dirname(os.path.abspath(__file__)), "_empty_file.py"
211
+ ), os.path.join(EXT_PKG, "__init__.py")
211
212
 
212
213
  for p in _all_packages:
213
214
  for path_tuple in package_mfext_package(p):
metaflow/flowspec.py CHANGED
@@ -788,35 +788,6 @@ class FlowSpec(metaclass=FlowSpecMeta):
788
788
  value = item if _is_primitive_type(item) else reprlib.Repr().repr(item)
789
789
  return basestring(value)[:MAXIMUM_FOREACH_VALUE_CHARS]
790
790
 
791
- def _validate_switch_cases(self, switch_cases, step):
792
- resolved_cases = {}
793
- for case_key, step_method in switch_cases.items():
794
- if isinstance(case_key, str) and case_key.startswith("config:"):
795
- full_path = case_key[len("config:") :]
796
- parts = full_path.split(".", 1)
797
- if len(parts) == 2:
798
- config_var_name, config_key_name = parts
799
- try:
800
- config_obj = getattr(self, config_var_name)
801
- resolved_key = str(getattr(config_obj, config_key_name))
802
- except AttributeError:
803
- msg = (
804
- "Step *{step}* references unknown config '{path}' "
805
- "in switch case.".format(step=step, path=full_path)
806
- )
807
- raise InvalidNextException(msg)
808
- else:
809
- raise MetaflowInternalError(
810
- "Invalid config path format in switch case."
811
- )
812
- else:
813
- resolved_key = case_key
814
-
815
- func_name = step_method.__func__.__name__
816
- resolved_cases[resolved_key] = func_name
817
-
818
- return resolved_cases
819
-
820
791
  def next(self, *dsts: Callable[..., None], **kwargs) -> None:
821
792
  """
822
793
  Indicates the next step to execute after this step has completed.
@@ -841,15 +812,6 @@ class FlowSpec(metaclass=FlowSpecMeta):
841
812
  evaluates to an iterator. A task will be launched for each value in the iterator and
842
813
  each task will execute the code specified by the step `foreach_step`.
843
814
 
844
- - Switch statement:
845
- ```
846
- self.next({"case1": self.step_a, "case2": self.step_b}, condition='condition_variable')
847
- ```
848
- In this situation, `step_a` and `step_b` are methods in the current class decorated
849
- with the `@step` decorator and `condition_variable` is a variable name in the current
850
- class. The value of the condition variable determines which step to execute. If the
851
- value doesn't match any of the dictionary keys, a RuntimeError is raised.
852
-
853
815
  Parameters
854
816
  ----------
855
817
  dsts : Callable[..., None]
@@ -865,7 +827,6 @@ class FlowSpec(metaclass=FlowSpecMeta):
865
827
 
866
828
  foreach = kwargs.pop("foreach", None)
867
829
  num_parallel = kwargs.pop("num_parallel", None)
868
- condition = kwargs.pop("condition", None)
869
830
  if kwargs:
870
831
  kw = next(iter(kwargs))
871
832
  msg = (
@@ -882,79 +843,6 @@ class FlowSpec(metaclass=FlowSpecMeta):
882
843
  )
883
844
  raise InvalidNextException(msg)
884
845
 
885
- # check: switch case using condition
886
- if condition is not None:
887
- if len(dsts) != 1 or not isinstance(dsts[0], dict) or not dsts[0]:
888
- msg = (
889
- "Step *{step}* has an invalid self.next() transition. "
890
- "When using 'condition', the transition must be to a single, "
891
- "non-empty dictionary mapping condition values to step methods.".format(
892
- step=step
893
- )
894
- )
895
- raise InvalidNextException(msg)
896
-
897
- if not isinstance(condition, basestring):
898
- msg = (
899
- "Step *{step}* has an invalid self.next() transition. "
900
- "The argument to 'condition' must be a string.".format(step=step)
901
- )
902
- raise InvalidNextException(msg)
903
-
904
- if foreach is not None or num_parallel is not None:
905
- msg = (
906
- "Step *{step}* has an invalid self.next() transition. "
907
- "Switch statements cannot be combined with foreach or num_parallel.".format(
908
- step=step
909
- )
910
- )
911
- raise InvalidNextException(msg)
912
-
913
- switch_cases = dsts[0]
914
-
915
- # Validate that condition variable exists
916
- try:
917
- condition_value = getattr(self, condition)
918
- except AttributeError:
919
- msg = (
920
- "Condition variable *self.{var}* in step *{step}* "
921
- "does not exist. Make sure you set self.{var} in this step.".format(
922
- step=step, var=condition
923
- )
924
- )
925
- raise InvalidNextException(msg)
926
-
927
- resolved_switch_cases = self._validate_switch_cases(switch_cases, step)
928
-
929
- if str(condition_value) not in resolved_switch_cases:
930
- available_cases = list(resolved_switch_cases.keys())
931
- raise RuntimeError(
932
- f"Switch condition variable '{condition}' has value '{condition_value}' "
933
- f"which is not in the available cases: {available_cases}"
934
- )
935
-
936
- # Get the chosen step and set transition directly
937
- chosen_step = resolved_switch_cases[str(condition_value)]
938
-
939
- # Validate that the chosen step exists
940
- if not hasattr(self, chosen_step):
941
- msg = (
942
- "Step *{step}* specifies a switch transition to an "
943
- "unknown step, *{name}*.".format(step=step, name=chosen_step)
944
- )
945
- raise InvalidNextException(msg)
946
-
947
- self._transition = ([chosen_step], None)
948
- return
949
-
950
- # Check for an invalid transition: a dictionary used without a 'condition' parameter.
951
- if len(dsts) == 1 and isinstance(dsts[0], dict):
952
- msg = (
953
- "Step *{step}* has an invalid self.next() transition. "
954
- "Dictionary argument requires 'condition' parameter.".format(step=step)
955
- )
956
- raise InvalidNextException(msg)
957
-
958
846
  # check: all destinations are methods of this object
959
847
  funcs = []
960
848
  for i, dst in enumerate(dsts):
@@ -1045,7 +933,7 @@ class FlowSpec(metaclass=FlowSpecMeta):
1045
933
  self._foreach_var = foreach
1046
934
 
1047
935
  # check: non-keyword transitions are valid
1048
- if foreach is None and condition is None:
936
+ if foreach is None:
1049
937
  if len(dsts) < 1:
1050
938
  msg = (
1051
939
  "Step *{step}* has an invalid self.next() transition. "