ob-metaflow 2.16.8.2rc0__py2.py3-none-any.whl → 2.16.8.2rc2__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 (61) hide show
  1. metaflow/_vendor/click/core.py +4 -3
  2. metaflow/_vendor/imghdr/__init__.py +1 -7
  3. metaflow/cli.py +2 -11
  4. metaflow/cli_components/run_cmds.py +15 -0
  5. metaflow/client/core.py +1 -6
  6. metaflow/extension_support/__init__.py +3 -4
  7. metaflow/flowspec.py +113 -1
  8. metaflow/graph.py +134 -10
  9. metaflow/lint.py +70 -3
  10. metaflow/metaflow_environment.py +6 -14
  11. metaflow/package/__init__.py +9 -18
  12. metaflow/packaging_sys/__init__.py +43 -53
  13. metaflow/packaging_sys/backend.py +6 -21
  14. metaflow/packaging_sys/tar_backend.py +3 -16
  15. metaflow/packaging_sys/v1.py +21 -21
  16. metaflow/plugins/argo/argo_client.py +14 -31
  17. metaflow/plugins/argo/argo_workflows.py +22 -66
  18. metaflow/plugins/argo/argo_workflows_cli.py +2 -1
  19. metaflow/plugins/argo/argo_workflows_deployer_objects.py +0 -69
  20. metaflow/plugins/aws/step_functions/step_functions.py +6 -0
  21. metaflow/plugins/aws/step_functions/step_functions_deployer_objects.py +0 -30
  22. metaflow/plugins/cards/card_modules/basic.py +14 -2
  23. metaflow/plugins/cards/card_modules/convert_to_native_type.py +1 -7
  24. metaflow/plugins/kubernetes/kubernetes_decorator.py +1 -1
  25. metaflow/plugins/kubernetes/kubernetes_jobsets.py +28 -26
  26. metaflow/plugins/pypi/conda_decorator.py +2 -4
  27. metaflow/runner/click_api.py +7 -14
  28. metaflow/runner/deployer.py +7 -160
  29. metaflow/runner/subprocess_manager.py +12 -20
  30. metaflow/runtime.py +102 -27
  31. metaflow/task.py +46 -25
  32. metaflow/user_decorators/mutable_flow.py +1 -3
  33. metaflow/util.py +29 -0
  34. metaflow/vendor.py +6 -23
  35. metaflow/version.py +1 -1
  36. {ob_metaflow-2.16.8.2rc0.dist-info → ob_metaflow-2.16.8.2rc2.dist-info}/METADATA +2 -2
  37. {ob_metaflow-2.16.8.2rc0.dist-info → ob_metaflow-2.16.8.2rc2.dist-info}/RECORD +44 -61
  38. metaflow/_vendor/yaml/__init__.py +0 -427
  39. metaflow/_vendor/yaml/composer.py +0 -139
  40. metaflow/_vendor/yaml/constructor.py +0 -748
  41. metaflow/_vendor/yaml/cyaml.py +0 -101
  42. metaflow/_vendor/yaml/dumper.py +0 -62
  43. metaflow/_vendor/yaml/emitter.py +0 -1137
  44. metaflow/_vendor/yaml/error.py +0 -75
  45. metaflow/_vendor/yaml/events.py +0 -86
  46. metaflow/_vendor/yaml/loader.py +0 -63
  47. metaflow/_vendor/yaml/nodes.py +0 -49
  48. metaflow/_vendor/yaml/parser.py +0 -589
  49. metaflow/_vendor/yaml/reader.py +0 -185
  50. metaflow/_vendor/yaml/representer.py +0 -389
  51. metaflow/_vendor/yaml/resolver.py +0 -227
  52. metaflow/_vendor/yaml/scanner.py +0 -1435
  53. metaflow/_vendor/yaml/serializer.py +0 -111
  54. metaflow/_vendor/yaml/tokens.py +0 -104
  55. {ob_metaflow-2.16.8.2rc0.data → ob_metaflow-2.16.8.2rc2.data}/data/share/metaflow/devtools/Makefile +0 -0
  56. {ob_metaflow-2.16.8.2rc0.data → ob_metaflow-2.16.8.2rc2.data}/data/share/metaflow/devtools/Tiltfile +0 -0
  57. {ob_metaflow-2.16.8.2rc0.data → ob_metaflow-2.16.8.2rc2.data}/data/share/metaflow/devtools/pick_services.sh +0 -0
  58. {ob_metaflow-2.16.8.2rc0.dist-info → ob_metaflow-2.16.8.2rc2.dist-info}/WHEEL +0 -0
  59. {ob_metaflow-2.16.8.2rc0.dist-info → ob_metaflow-2.16.8.2rc2.dist-info}/entry_points.txt +0 -0
  60. {ob_metaflow-2.16.8.2rc0.dist-info → ob_metaflow-2.16.8.2rc2.dist-info}/licenses/LICENSE +0 -0
  61. {ob_metaflow-2.16.8.2rc0.dist-info → ob_metaflow-2.16.8.2rc2.dist-info}/top_level.txt +0 -0
@@ -203,19 +203,6 @@ class MetaflowEnvironment(object):
203
203
  "mfcontent_version": 1,
204
204
  }
205
205
  )
206
-
207
- extra_exports = []
208
- for k, v in MetaflowPackage.get_post_extract_env_vars(
209
- code_package_metadata, dest_dir="$(pwd)"
210
- ).items():
211
- if k.endswith(":"):
212
- # If the value ends with a colon, we override the existing value
213
- extra_exports.append("export %s=%s" % (k[:-1], v))
214
- else:
215
- extra_exports.append(
216
- "export %s=%s:$(printenv %s)" % (k, v.replace('"', '\\"'), k)
217
- )
218
-
219
206
  cmds = (
220
207
  [
221
208
  BASH_MFLOG,
@@ -239,7 +226,12 @@ class MetaflowEnvironment(object):
239
226
  + MetaflowPackage.get_extract_commands(
240
227
  code_package_metadata, "job.tar", dest_dir="."
241
228
  )
242
- + extra_exports
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
+ ]
243
235
  + [
244
236
  "mflog 'Task is starting.'",
245
237
  "flush_mflogs",
@@ -17,6 +17,7 @@ from ..packaging_sys.utils import suffix_filter, walk
17
17
  from ..metaflow_config import DEFAULT_PACKAGE_SUFFIXES
18
18
  from ..exception import MetaflowException
19
19
  from ..user_configs.config_parameters import dump_config_values
20
+ from ..util import get_metaflow_root
20
21
  from .. import R
21
22
 
22
23
  DEFAULT_SUFFIXES_LIST = DEFAULT_PACKAGE_SUFFIXES.split(",")
@@ -75,22 +76,12 @@ class MetaflowPackage(object):
75
76
  from ..user_decorators.user_flow_decorator import FlowMutatorMeta
76
77
  from ..user_decorators.user_step_decorator import UserStepDecoratorMeta
77
78
 
78
- # Be very defensive here to filter modules in case there are
79
- # some badly behaved modules that have weird values for
80
- # METAFLOW_PACKAGE_POLICY for example.
81
- try:
82
- if (
83
- m.__name__ in FlowMutatorMeta._import_modules
84
- or m.__name__ in UserStepDecoratorMeta._import_modules
85
- or (
86
- hasattr(m, "METAFLOW_PACKAGE_POLICY")
87
- and m.METAFLOW_PACKAGE_POLICY == "include"
88
- )
89
- ):
90
- return True
91
- return False
92
- except:
93
- return False
79
+ if (
80
+ m.__name__ in FlowMutatorMeta._import_modules
81
+ or m.__name__ in UserStepDecoratorMeta._import_modules
82
+ or hasattr(m, "METAFLOW_PACKAGE")
83
+ ):
84
+ return True
94
85
 
95
86
  if mfcontent is None:
96
87
  self._mfcontent = MetaflowCodeContentV1(criteria=_module_selector)
@@ -359,10 +350,10 @@ class MetaflowPackage(object):
359
350
  """
360
351
  backend = cls.get_backend(pkg_metadata)
361
352
  with backend.cls_open(archive) as opened_archive:
362
- include_members = MetaflowCodeContent.get_archive_content_members(
353
+ include_names = MetaflowCodeContent.get_archive_content_names(
363
354
  opened_archive, content_types, backend
364
355
  )
365
- backend.cls_extract_members(opened_archive, include_members, dest_dir)
356
+ backend.extract_members(include_names, dest_dir)
366
357
 
367
358
  def user_tuples(self, timeout: Optional[float] = None):
368
359
  # Wait for at least the blob to be formed
@@ -118,7 +118,9 @@ class MetaflowCodeContent:
118
118
  return handling_cls.get_filename_impl(mfcontent_info, filename, content_type)
119
119
 
120
120
  @classmethod
121
- def get_env_vars_for_packaged_metaflow(cls, dest_dir: str) -> Dict[str, str]:
121
+ def get_env_vars_for_packaged_metaflow(
122
+ cls, dest_dir: str
123
+ ) -> Optional[Dict[str, str]]:
122
124
  """
123
125
  Get the environment variables that are needed to run Metaflow when it is
124
126
  packaged. This is typically used to set the PYTHONPATH to include the
@@ -126,19 +128,17 @@ class MetaflowCodeContent:
126
128
 
127
129
  Returns
128
130
  -------
129
- Dict[str, str]
131
+ Optional[Dict[str, str]]
130
132
  The environment variables that are needed to run Metaflow when it is
131
- packaged it present.
133
+ packaged -- None if there are no such variables (not packaged for example)
132
134
  """
133
- mfcontent_info = cls._extract_mfcontent_info(dest_dir)
135
+ mfcontent_info = cls._extract_mfcontent_info()
134
136
  if mfcontent_info is None:
135
137
  # No MFCONTENT_MARKER file found -- this is not a packaged Metaflow code
136
138
  # package so no environment variables to set.
137
- return {}
139
+ return None
138
140
  handling_cls = cls._get_mfcontent_class(mfcontent_info)
139
- v = handling_cls.get_post_extract_env_vars_impl(dest_dir)
140
- v["METAFLOW_EXTRACTED_ROOT:"] = dest_dir
141
- return v
141
+ return handling_cls.get_post_extract_env_vars_impl(dest_dir)
142
142
 
143
143
  @classmethod
144
144
  def get_archive_info(
@@ -216,15 +216,15 @@ class MetaflowCodeContent:
216
216
  )
217
217
 
218
218
  @classmethod
219
- def get_archive_content_members(
219
+ def get_archive_content_names(
220
220
  cls,
221
221
  archive: Any,
222
222
  content_types: Optional[int] = None,
223
223
  packaging_backend: Type[PackagingBackend] = TarPackagingBackend,
224
- ) -> List[Any]:
224
+ ) -> List[str]:
225
225
  mfcontent_info = cls._extract_archive_mfcontent_info(archive, packaging_backend)
226
226
  handling_cls = cls._get_mfcontent_class(mfcontent_info)
227
- return handling_cls.get_archive_content_members_impl(
227
+ return handling_cls.get_archive_content_names_impl(
228
228
  mfcontent_info, archive, content_types, packaging_backend
229
229
  )
230
230
 
@@ -276,9 +276,7 @@ class MetaflowCodeContent:
276
276
  "Invalid package -- unknown version %s in info: %s"
277
277
  % (version_id, cls._mappings)
278
278
  )
279
- v = cls._mappings[version_id].get_post_extract_env_vars_impl(dest_dir)
280
- v["METAFLOW_EXTRACTED_ROOT:"] = dest_dir
281
- return v
279
+ return cls._mappings[version_id].get_post_extract_env_vars_impl(dest_dir)
282
280
 
283
281
  # Implement the _impl methods in the base subclass (in this file). These need to
284
282
  # happen with as few imports as possible to prevent circular dependencies.
@@ -339,14 +337,14 @@ class MetaflowCodeContent:
339
337
  raise NotImplementedError("get_archive_filename_impl not implemented")
340
338
 
341
339
  @classmethod
342
- def get_archive_content_members_impl(
340
+ def get_archive_content_names_impl(
343
341
  cls,
344
342
  mfcontent_info: Optional[Dict[str, Any]],
345
343
  archive: Any,
346
344
  content_types: Optional[int] = None,
347
345
  packaging_backend: Type[PackagingBackend] = TarPackagingBackend,
348
- ) -> List[Any]:
349
- raise NotImplementedError("get_archive_content_members_impl not implemented")
346
+ ) -> List[str]:
347
+ raise NotImplementedError("get_archive_content_names_impl not implemented")
350
348
 
351
349
  @classmethod
352
350
  def get_post_extract_env_vars_impl(cls, dest_dir: str) -> Dict[str, str]:
@@ -525,22 +523,19 @@ class MetaflowCodeContent:
525
523
  return mfcontent_info
526
524
 
527
525
  @classmethod
528
- def _extract_mfcontent_info(
529
- cls, target_dir: Optional[str] = None
530
- ) -> Optional[Dict[str, Any]]:
531
- target_dir = target_dir or "_local"
532
- if target_dir in cls._cached_mfcontent_info:
533
- return cls._cached_mfcontent_info[target_dir]
526
+ def _extract_mfcontent_info(cls) -> Optional[Dict[str, Any]]:
527
+ if "_local" in cls._cached_mfcontent_info:
528
+ return cls._cached_mfcontent_info["_local"]
534
529
 
535
530
  mfcontent_info = None # type: Optional[Dict[str, Any]]
536
- if target_dir == "_local":
537
- root = os.environ.get("METAFLOW_EXTRACTED_ROOT", get_metaflow_root())
538
- else:
539
- root = target_dir
540
- if os.path.exists(os.path.join(root, MFCONTENT_MARKER)):
541
- with open(os.path.join(root, MFCONTENT_MARKER), "r", encoding="utf-8") as f:
531
+ if os.path.exists(os.path.join(get_metaflow_root(), MFCONTENT_MARKER)):
532
+ with open(
533
+ os.path.join(get_metaflow_root(), MFCONTENT_MARKER),
534
+ "r",
535
+ encoding="utf-8",
536
+ ) as f:
542
537
  mfcontent_info = json.load(f)
543
- cls._cached_mfcontent_info[target_dir] = mfcontent_info
538
+ cls._cached_mfcontent_info["_local"] = mfcontent_info
544
539
  return mfcontent_info
545
540
 
546
541
  def get_package_version(self) -> int:
@@ -632,13 +627,13 @@ class MetaflowCodeContentV0(MetaflowCodeContent, version_id=0):
632
627
  return None
633
628
 
634
629
  @classmethod
635
- def get_archive_content_members_impl(
630
+ def get_archive_content_names_impl(
636
631
  cls,
637
632
  mfcontent_info: Optional[Dict[str, Any]],
638
633
  archive: Any,
639
634
  content_types: Optional[int] = None,
640
635
  packaging_backend: Type[PackagingBackend] = TarPackagingBackend,
641
- ) -> List[Any]:
636
+ ) -> List[str]:
642
637
  """
643
638
  For V0, we use a static list of known files to classify the content
644
639
  """
@@ -654,20 +649,16 @@ class MetaflowCodeContentV0(MetaflowCodeContent, version_id=0):
654
649
  "condav2-1.cnd": ContentType.OTHER_CONTENT.value,
655
650
  }
656
651
  to_return = []
657
- for member in packaging_backend.cls_list_members(archive):
658
- filename = packaging_backend.cls_member_name(member)
659
- added = False
652
+ for filename in packaging_backend.cls_list_members(archive):
660
653
  for prefix, classification in known_prefixes.items():
661
654
  if (
662
655
  prefix[-1] == "/" and filename.startswith(prefix)
663
656
  ) or prefix == filename:
664
657
  if content_types & classification:
665
- to_return.append(member)
666
- added = True
667
- break
668
- if not added and content_types & ContentType.USER_CONTENT.value:
669
- # Everything else is user content
670
- to_return.append(member)
658
+ to_return.append(filename)
659
+ elif content_types & ContentType.USER_CONTENT.value:
660
+ # Everything else is user content
661
+ to_return.append(filename)
671
662
  return to_return
672
663
 
673
664
  @classmethod
@@ -714,7 +705,7 @@ class MetaflowCodeContentV1Base(MetaflowCodeContent, version_id=1):
714
705
  cls, mfcontent_info: Optional[Dict[str, Any]], filename: str, in_archive: bool
715
706
  ) -> str:
716
707
  if in_archive:
717
- return os.path.join(cls._other_dir, filename)
708
+ return filename
718
709
  return os.path.join(get_metaflow_root(), "..", cls._other_dir, filename)
719
710
 
720
711
  @classmethod
@@ -722,7 +713,7 @@ class MetaflowCodeContentV1Base(MetaflowCodeContent, version_id=1):
722
713
  cls, mfcontent_info: Optional[Dict[str, Any]], filename: str, in_archive: bool
723
714
  ) -> str:
724
715
  if in_archive:
725
- return os.path.join(cls._code_dir, filename)
716
+ return filename
726
717
  return os.path.join(get_metaflow_root(), filename)
727
718
 
728
719
  @classmethod
@@ -841,38 +832,37 @@ class MetaflowCodeContentV1Base(MetaflowCodeContent, version_id=1):
841
832
  return None
842
833
 
843
834
  @classmethod
844
- def get_archive_content_members_impl(
835
+ def get_archive_content_names_impl(
845
836
  cls,
846
837
  mfcontent_info: Optional[Dict[str, Any]],
847
838
  archive: Any,
848
839
  content_types: Optional[int] = None,
849
840
  packaging_backend: Type[PackagingBackend] = TarPackagingBackend,
850
- ) -> List[Any]:
841
+ ) -> List[str]:
851
842
  to_return = []
852
843
  module_content = set(mfcontent_info.get("module_files", []))
853
- for member in packaging_backend.cls_list_members(archive):
854
- filename = packaging_backend.cls_member_name(member)
844
+ for filename in packaging_backend.cls_list_members(archive):
855
845
  if filename.startswith(cls._other_dir) and (
856
846
  content_types & ContentType.OTHER_CONTENT.value
857
847
  ):
858
- to_return.append(member)
848
+ to_return.append(filename)
859
849
  elif filename.startswith(cls._code_dir):
860
850
  # Special case for marker which is a other content even if in code.
861
- if filename == MFCONTENT_MARKER:
851
+ if filename == f"{cls._code_dir}/{MFCONTENT_MARKER}":
862
852
  if content_types & ContentType.OTHER_CONTENT.value:
863
- to_return.append(member)
853
+ to_return.append(filename)
864
854
  else:
865
855
  continue
866
856
  # Here it is either module or code
867
857
  if os.path.join(cls._code_dir, filename) in module_content:
868
858
  if content_types & ContentType.MODULE_CONTENT.value:
869
- to_return.append(member)
859
+ to_return.append(filename)
870
860
  elif content_types & ContentType.CODE_CONTENT.value:
871
- to_return.append(member)
861
+ to_return.append(filename)
872
862
  else:
873
863
  if content_types & ContentType.USER_CONTENT.value:
874
864
  # Everything else is user content
875
- to_return.append(member)
865
+ to_return.append(filename)
876
866
  return to_return
877
867
 
878
868
  @classmethod
@@ -57,15 +57,6 @@ class PackagingBackend(ABC):
57
57
  """Open the archive from the given content."""
58
58
  pass
59
59
 
60
- @classmethod
61
- @abstractmethod
62
- def cls_member_name(cls, member: Union[Any, str]) -> str:
63
- """
64
- Returns the name of the member as a string.
65
- This is used to ensure consistent naming across different archive formats.
66
- """
67
- pass
68
-
69
60
  @classmethod
70
61
  @abstractmethod
71
62
  def cls_has_member(cls, archive: Any, name: str) -> bool:
@@ -81,20 +72,14 @@ class PackagingBackend(ABC):
81
72
  def cls_extract_members(
82
73
  cls,
83
74
  archive: Any,
84
- members: Optional[List[Any]] = None,
75
+ members: Optional[List[str]] = None,
85
76
  dest_dir: str = ".",
86
77
  ) -> None:
87
78
  pass
88
79
 
89
80
  @classmethod
90
81
  @abstractmethod
91
- def cls_list_names(cls, archive: Any) -> Optional[List[str]]:
92
- pass
93
-
94
- @classmethod
95
- @abstractmethod
96
- def cls_list_members(cls, archive: Any) -> Optional[List[Any]]:
97
- """List all members in the archive."""
82
+ def cls_list_members(cls, archive: Any) -> Optional[List[str]]:
98
83
  pass
99
84
 
100
85
  def has_member(self, name: str) -> bool:
@@ -108,17 +93,17 @@ class PackagingBackend(ABC):
108
93
  raise ValueError("Cannot get member from an uncreated archive")
109
94
 
110
95
  def extract_members(
111
- self, members: Optional[List[Any]] = None, dest_dir: str = "."
96
+ self, members: Optional[List[str]] = None, dest_dir: str = "."
112
97
  ) -> None:
113
98
  if self._archive:
114
99
  self.cls_extract_members(self._archive, members, dest_dir)
115
100
  else:
116
101
  raise ValueError("Cannot extract from an uncreated archive")
117
102
 
118
- def list_names(self) -> Optional[List[str]]:
103
+ def list_members(self) -> Optional[List[str]]:
119
104
  if self._archive:
120
- return self.cls_list_names(self._archive)
121
- raise ValueError("Cannot list names from an uncreated archive")
105
+ return self.cls_list_members(self._archive)
106
+ raise ValueError("Cannot list members from an uncreated archive")
122
107
 
123
108
  def __enter__(self):
124
109
  self.create()
@@ -1,7 +1,7 @@
1
1
  import tarfile
2
2
 
3
3
  from io import BytesIO
4
- from typing import Any, IO, List, Optional, Union
4
+ from typing import IO, List, Optional, Union
5
5
 
6
6
  from .backend import PackagingBackend
7
7
 
@@ -56,13 +56,6 @@ class TarPackagingBackend(PackagingBackend):
56
56
  def cls_open(cls, content: IO[bytes]) -> tarfile.TarFile:
57
57
  return tarfile.open(fileobj=content, mode="r:gz")
58
58
 
59
- @classmethod
60
- def cls_member_name(cls, member: Union[tarfile.TarInfo, str]) -> str:
61
- """
62
- Returns the name of the member as a string.
63
- """
64
- return member.name if isinstance(member, tarfile.TarInfo) else member
65
-
66
59
  @classmethod
67
60
  def cls_has_member(cls, archive: tarfile.TarFile, name: str) -> bool:
68
61
  try:
@@ -83,17 +76,11 @@ class TarPackagingBackend(PackagingBackend):
83
76
  def cls_extract_members(
84
77
  cls,
85
78
  archive: tarfile.TarFile,
86
- members: Optional[List[Any]] = None,
79
+ members: Optional[List[str]] = None,
87
80
  dest_dir: str = ".",
88
81
  ) -> None:
89
82
  archive.extractall(path=dest_dir, members=members)
90
83
 
91
84
  @classmethod
92
- def cls_list_members(
93
- cls, archive: tarfile.TarFile
94
- ) -> Optional[List[tarfile.TarInfo]]:
95
- return archive.getmembers() or None
96
-
97
- @classmethod
98
- def cls_list_names(cls, archive: tarfile.TarFile) -> Optional[List[str]]:
85
+ def cls_list_members(cls, archive: tarfile.TarFile) -> Optional[List[str]]:
99
86
  return archive.getnames() or None
@@ -61,25 +61,23 @@ class MetaflowCodeContentV1(MetaflowCodeContentV1Base):
61
61
  else:
62
62
  new_modules = []
63
63
 
64
- self._modules = {} # type: Dict[str, _ModuleInfo]
65
- # We do this explicitly module by module to harden it against misbehaving
66
- # modules like the one in:
67
- # https://github.com/Netflix/metaflow/issues/2512
68
- # We will silently ignore modules that are not well built.
69
- for name, mod in new_modules:
70
- try:
71
- minfo = _ModuleInfo(
72
- name,
73
- set(
74
- Path(p).resolve().as_posix()
75
- for p in getattr(mod, "__path__", [mod.__file__])
76
- ),
77
- mod,
78
- True, # This is a Metaflow module (see filter below)
79
- )
80
- except:
81
- continue
82
- self._modules[name] = minfo
64
+ self._modules = {
65
+ name: _ModuleInfo(
66
+ name,
67
+ set(
68
+ Path(p).resolve().as_posix()
69
+ for p in getattr(mod, "__path__", [mod.__file__])
70
+ ),
71
+ mod,
72
+ True, # This is a Metaflow module (see filter below)
73
+ )
74
+ for (name, mod) in new_modules
75
+ }
76
+
77
+ # Filter the modules
78
+ self._modules = {
79
+ name: info for name, info in self._modules.items() if criteria(info.module)
80
+ }
83
81
 
84
82
  # Contain metadata information regarding the distributions packaged.
85
83
  # This allows Metaflow to "fake" distribution information when packaged
@@ -357,14 +355,16 @@ class MetaflowCodeContentV1(MetaflowCodeContentV1Base):
357
355
  )
358
356
  yield json.dumps(self.create_mfcontent_info()).encode(
359
357
  "utf-8"
360
- ), MFCONTENT_MARKER
358
+ ), os.path.join(self._code_dir, MFCONTENT_MARKER)
361
359
  else:
362
360
  for k in self._other_content.keys():
363
361
  yield "<generated %s content>" % (os.path.basename(k)), k
364
362
  yield "<generated %s content>" % (
365
363
  os.path.basename(self._dist_info_file)
366
364
  ), os.path.join(self._other_dir, self._dist_info_file)
367
- yield "<generated %s content>" % MFCONTENT_MARKER, MFCONTENT_MARKER
365
+ yield "<generated %s content>" % MFCONTENT_MARKER, os.path.join(
366
+ self._code_dir, MFCONTENT_MARKER
367
+ )
368
368
 
369
369
  def _metaflow_distribution_files(self) -> Generator[Tuple[str, str], None, None]:
370
370
  debug.package_exec("Including Metaflow from '%s'" % self._metaflow_root)
@@ -58,38 +58,21 @@ class ArgoClient(object):
58
58
  json.loads(e.body)["message"] if e.body is not None else e.reason
59
59
  )
60
60
 
61
- def get_workflow_templates(self, page_size=100):
61
+ def get_workflow_templates(self):
62
62
  client = self._client.get()
63
- continue_token = None
64
-
65
- while True:
66
- try:
67
- params = {"limit": page_size}
68
- if continue_token:
69
- params["_continue"] = continue_token
70
-
71
- response = client.CustomObjectsApi().list_namespaced_custom_object(
72
- group=self._group,
73
- version=self._version,
74
- namespace=self._namespace,
75
- plural="workflowtemplates",
76
- **params,
77
- )
78
-
79
- for item in response.get("items", []):
80
- yield item
81
-
82
- metadata = response.get("metadata", {})
83
- continue_token = metadata.get("continue")
84
-
85
- if not continue_token:
86
- break
87
- except client.rest.ApiException as e:
88
- if e.status == 404:
89
- return None
90
- raise ArgoClientException(
91
- json.loads(e.body)["message"] if e.body is not None else e.reason
92
- )
63
+ try:
64
+ return client.CustomObjectsApi().list_namespaced_custom_object(
65
+ group=self._group,
66
+ version=self._version,
67
+ namespace=self._namespace,
68
+ plural="workflowtemplates",
69
+ )["items"]
70
+ except client.rest.ApiException as e:
71
+ if e.status == 404:
72
+ return None
73
+ raise ArgoClientException(
74
+ json.loads(e.body)["message"] if e.body is not None else e.reason
75
+ )
93
76
 
94
77
  def register_workflow_template(self, name, workflow_template):
95
78
  # Unfortunately, Kubernetes client does not handle optimistic
@@ -216,14 +216,23 @@ class ArgoWorkflows(object):
216
216
  return name.replace(".", "-")
217
217
 
218
218
  @staticmethod
219
- def list_templates(flow_name, all=False, page_size=100):
219
+ def list_templates(flow_name, all=False):
220
220
  client = ArgoClient(namespace=KUBERNETES_NAMESPACE)
221
221
 
222
- for template in client.get_workflow_templates(page_size=page_size):
223
- if all or flow_name == template["metadata"].get("annotations", {}).get(
224
- "metaflow/flow_name", None
225
- ):
226
- yield template["metadata"]["name"]
222
+ templates = client.get_workflow_templates()
223
+ if templates is None:
224
+ return []
225
+
226
+ template_names = [
227
+ template["metadata"]["name"]
228
+ for template in templates
229
+ if all
230
+ or flow_name
231
+ == template["metadata"]
232
+ .get("annotations", {})
233
+ .get("metaflow/flow_name", None)
234
+ ]
235
+ return template_names
227
236
 
228
237
  @staticmethod
229
238
  def delete(name):
@@ -956,6 +965,11 @@ class ArgoWorkflows(object):
956
965
  dag_task = DAGTask(self._sanitize(node.name)).template(
957
966
  self._sanitize(node.name)
958
967
  )
968
+ if node.type == "split-switch":
969
+ raise ArgoWorkflowsException(
970
+ "Deploying flows with switch statement "
971
+ "to Argo Workflows is not supported currently."
972
+ )
959
973
  elif (
960
974
  node.is_inside_foreach
961
975
  and self.graph[node.in_funcs[0]].type == "foreach"
@@ -3277,8 +3291,8 @@ class ArgoWorkflows(object):
3277
3291
  Trigger().template(
3278
3292
  TriggerTemplate(self.name)
3279
3293
  # Trigger a deployed workflow template
3280
- .k8s_trigger(
3281
- StandardK8STrigger()
3294
+ .argo_workflow_trigger(
3295
+ ArgoWorkflowTrigger()
3282
3296
  .source(
3283
3297
  {
3284
3298
  "resource": {
@@ -4256,10 +4270,6 @@ class TriggerTemplate(object):
4256
4270
  self.payload = tree()
4257
4271
  self.payload["name"] = name
4258
4272
 
4259
- def k8s_trigger(self, k8s_trigger):
4260
- self.payload["k8s"] = k8s_trigger.to_json()
4261
- return self
4262
-
4263
4273
  def argo_workflow_trigger(self, argo_workflow_trigger):
4264
4274
  self.payload["argoWorkflow"] = argo_workflow_trigger.to_json()
4265
4275
  return self
@@ -4334,57 +4344,3 @@ class TriggerParameter(object):
4334
4344
 
4335
4345
  def __str__(self):
4336
4346
  return json.dumps(self.payload, indent=4)
4337
-
4338
-
4339
- class StandardK8STrigger(object):
4340
- # https://pkg.go.dev/github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1#StandardK8STrigger
4341
-
4342
- def __init__(self):
4343
- tree = lambda: defaultdict(tree)
4344
- self.payload = tree()
4345
- self.payload["operation"] = "create"
4346
-
4347
- def operation(self, operation):
4348
- self.payload["operation"] = operation
4349
- return self
4350
-
4351
- def group(self, group):
4352
- self.payload["group"] = group
4353
- return self
4354
-
4355
- def version(self, version):
4356
- self.payload["version"] = version
4357
- return self
4358
-
4359
- def resource(self, resource):
4360
- self.payload["resource"] = resource
4361
- return self
4362
-
4363
- def namespace(self, namespace):
4364
- self.payload["namespace"] = namespace
4365
- return self
4366
-
4367
- def source(self, source):
4368
- self.payload["source"] = source
4369
- return self
4370
-
4371
- def parameters(self, trigger_parameters):
4372
- if "parameters" not in self.payload:
4373
- self.payload["parameters"] = []
4374
- for trigger_parameter in trigger_parameters:
4375
- self.payload["parameters"].append(trigger_parameter.to_json())
4376
- return self
4377
-
4378
- def live_object(self, live_object=True):
4379
- self.payload["liveObject"] = live_object
4380
- return self
4381
-
4382
- def patch_strategy(self, patch_strategy):
4383
- self.payload["patchStrategy"] = patch_strategy
4384
- return self
4385
-
4386
- def to_json(self):
4387
- return self.payload
4388
-
4389
- def __str__(self):
4390
- return json.dumps(self.payload, indent=4)
@@ -1011,7 +1011,8 @@ def terminate(obj, run_id, authorize=None):
1011
1011
  )
1012
1012
  @click.pass_obj
1013
1013
  def list_workflow_templates(obj, all=None):
1014
- for template_name in ArgoWorkflows.list_templates(obj.flow.name, all):
1014
+ templates = ArgoWorkflows.list_templates(obj.flow.name, all)
1015
+ for template_name in templates:
1015
1016
  obj.echo_always(template_name)
1016
1017
 
1017
1018