ob-metaflow 2.15.13.1__py2.py3-none-any.whl → 2.19.7.1rc0__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 (169) hide show
  1. metaflow/__init__.py +10 -3
  2. metaflow/_vendor/imghdr/__init__.py +186 -0
  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/cards.py +4 -0
  21. metaflow/cli.py +125 -21
  22. metaflow/cli_components/init_cmd.py +1 -0
  23. metaflow/cli_components/run_cmds.py +204 -40
  24. metaflow/cli_components/step_cmd.py +160 -4
  25. metaflow/client/__init__.py +1 -0
  26. metaflow/client/core.py +198 -130
  27. metaflow/client/filecache.py +59 -32
  28. metaflow/cmd/code/__init__.py +2 -1
  29. metaflow/cmd/develop/stub_generator.py +49 -18
  30. metaflow/cmd/develop/stubs.py +9 -27
  31. metaflow/cmd/make_wrapper.py +30 -0
  32. metaflow/datastore/__init__.py +1 -0
  33. metaflow/datastore/content_addressed_store.py +40 -9
  34. metaflow/datastore/datastore_set.py +10 -1
  35. metaflow/datastore/flow_datastore.py +124 -4
  36. metaflow/datastore/spin_datastore.py +91 -0
  37. metaflow/datastore/task_datastore.py +92 -6
  38. metaflow/debug.py +5 -0
  39. metaflow/decorators.py +331 -82
  40. metaflow/extension_support/__init__.py +414 -356
  41. metaflow/extension_support/_empty_file.py +2 -2
  42. metaflow/flowspec.py +322 -82
  43. metaflow/graph.py +178 -15
  44. metaflow/includefile.py +25 -3
  45. metaflow/lint.py +94 -3
  46. metaflow/meta_files.py +13 -0
  47. metaflow/metadata_provider/metadata.py +13 -2
  48. metaflow/metaflow_config.py +66 -4
  49. metaflow/metaflow_environment.py +91 -25
  50. metaflow/metaflow_profile.py +18 -0
  51. metaflow/metaflow_version.py +16 -1
  52. metaflow/package/__init__.py +673 -0
  53. metaflow/packaging_sys/__init__.py +880 -0
  54. metaflow/packaging_sys/backend.py +128 -0
  55. metaflow/packaging_sys/distribution_support.py +153 -0
  56. metaflow/packaging_sys/tar_backend.py +99 -0
  57. metaflow/packaging_sys/utils.py +54 -0
  58. metaflow/packaging_sys/v1.py +527 -0
  59. metaflow/parameters.py +6 -2
  60. metaflow/plugins/__init__.py +6 -0
  61. metaflow/plugins/airflow/airflow.py +11 -1
  62. metaflow/plugins/airflow/airflow_cli.py +16 -5
  63. metaflow/plugins/argo/argo_client.py +42 -20
  64. metaflow/plugins/argo/argo_events.py +6 -6
  65. metaflow/plugins/argo/argo_workflows.py +1023 -344
  66. metaflow/plugins/argo/argo_workflows_cli.py +396 -94
  67. metaflow/plugins/argo/argo_workflows_decorator.py +9 -0
  68. metaflow/plugins/argo/argo_workflows_deployer_objects.py +75 -49
  69. metaflow/plugins/argo/capture_error.py +5 -2
  70. metaflow/plugins/argo/conditional_input_paths.py +35 -0
  71. metaflow/plugins/argo/exit_hooks.py +209 -0
  72. metaflow/plugins/argo/param_val.py +19 -0
  73. metaflow/plugins/aws/aws_client.py +6 -0
  74. metaflow/plugins/aws/aws_utils.py +33 -1
  75. metaflow/plugins/aws/batch/batch.py +72 -5
  76. metaflow/plugins/aws/batch/batch_cli.py +24 -3
  77. metaflow/plugins/aws/batch/batch_decorator.py +57 -6
  78. metaflow/plugins/aws/step_functions/step_functions.py +28 -3
  79. metaflow/plugins/aws/step_functions/step_functions_cli.py +49 -4
  80. metaflow/plugins/aws/step_functions/step_functions_deployer.py +3 -0
  81. metaflow/plugins/aws/step_functions/step_functions_deployer_objects.py +30 -0
  82. metaflow/plugins/cards/card_cli.py +20 -1
  83. metaflow/plugins/cards/card_creator.py +24 -1
  84. metaflow/plugins/cards/card_datastore.py +21 -49
  85. metaflow/plugins/cards/card_decorator.py +58 -6
  86. metaflow/plugins/cards/card_modules/basic.py +38 -9
  87. metaflow/plugins/cards/card_modules/bundle.css +1 -1
  88. metaflow/plugins/cards/card_modules/chevron/renderer.py +1 -1
  89. metaflow/plugins/cards/card_modules/components.py +592 -3
  90. metaflow/plugins/cards/card_modules/convert_to_native_type.py +34 -5
  91. metaflow/plugins/cards/card_modules/json_viewer.py +232 -0
  92. metaflow/plugins/cards/card_modules/main.css +1 -0
  93. metaflow/plugins/cards/card_modules/main.js +56 -41
  94. metaflow/plugins/cards/card_modules/test_cards.py +22 -6
  95. metaflow/plugins/cards/component_serializer.py +1 -8
  96. metaflow/plugins/cards/metadata.py +22 -0
  97. metaflow/plugins/catch_decorator.py +9 -0
  98. metaflow/plugins/datastores/local_storage.py +12 -6
  99. metaflow/plugins/datastores/spin_storage.py +12 -0
  100. metaflow/plugins/datatools/s3/s3.py +49 -17
  101. metaflow/plugins/datatools/s3/s3op.py +113 -66
  102. metaflow/plugins/env_escape/client_modules.py +102 -72
  103. metaflow/plugins/events_decorator.py +127 -121
  104. metaflow/plugins/exit_hook/__init__.py +0 -0
  105. metaflow/plugins/exit_hook/exit_hook_decorator.py +46 -0
  106. metaflow/plugins/exit_hook/exit_hook_script.py +52 -0
  107. metaflow/plugins/kubernetes/kubernetes.py +12 -1
  108. metaflow/plugins/kubernetes/kubernetes_cli.py +11 -0
  109. metaflow/plugins/kubernetes/kubernetes_decorator.py +25 -6
  110. metaflow/plugins/kubernetes/kubernetes_job.py +12 -4
  111. metaflow/plugins/kubernetes/kubernetes_jobsets.py +31 -30
  112. metaflow/plugins/metadata_providers/local.py +76 -82
  113. metaflow/plugins/metadata_providers/service.py +13 -9
  114. metaflow/plugins/metadata_providers/spin.py +16 -0
  115. metaflow/plugins/package_cli.py +36 -24
  116. metaflow/plugins/parallel_decorator.py +11 -2
  117. metaflow/plugins/parsers.py +16 -0
  118. metaflow/plugins/pypi/bootstrap.py +7 -1
  119. metaflow/plugins/pypi/conda_decorator.py +41 -82
  120. metaflow/plugins/pypi/conda_environment.py +14 -6
  121. metaflow/plugins/pypi/micromamba.py +9 -1
  122. metaflow/plugins/pypi/pip.py +41 -5
  123. metaflow/plugins/pypi/pypi_decorator.py +4 -4
  124. metaflow/plugins/pypi/utils.py +22 -0
  125. metaflow/plugins/secrets/__init__.py +3 -0
  126. metaflow/plugins/secrets/secrets_decorator.py +14 -178
  127. metaflow/plugins/secrets/secrets_func.py +49 -0
  128. metaflow/plugins/secrets/secrets_spec.py +101 -0
  129. metaflow/plugins/secrets/utils.py +74 -0
  130. metaflow/plugins/test_unbounded_foreach_decorator.py +2 -2
  131. metaflow/plugins/timeout_decorator.py +0 -1
  132. metaflow/plugins/uv/bootstrap.py +29 -1
  133. metaflow/plugins/uv/uv_environment.py +5 -3
  134. metaflow/pylint_wrapper.py +5 -1
  135. metaflow/runner/click_api.py +79 -26
  136. metaflow/runner/deployer.py +208 -6
  137. metaflow/runner/deployer_impl.py +32 -12
  138. metaflow/runner/metaflow_runner.py +266 -33
  139. metaflow/runner/subprocess_manager.py +21 -1
  140. metaflow/runner/utils.py +27 -16
  141. metaflow/runtime.py +660 -66
  142. metaflow/task.py +255 -26
  143. metaflow/user_configs/config_options.py +33 -21
  144. metaflow/user_configs/config_parameters.py +220 -58
  145. metaflow/user_decorators/__init__.py +0 -0
  146. metaflow/user_decorators/common.py +144 -0
  147. metaflow/user_decorators/mutable_flow.py +512 -0
  148. metaflow/user_decorators/mutable_step.py +424 -0
  149. metaflow/user_decorators/user_flow_decorator.py +264 -0
  150. metaflow/user_decorators/user_step_decorator.py +749 -0
  151. metaflow/util.py +197 -7
  152. metaflow/vendor.py +23 -7
  153. metaflow/version.py +1 -1
  154. {ob_metaflow-2.15.13.1.data → ob_metaflow-2.19.7.1rc0.data}/data/share/metaflow/devtools/Makefile +13 -2
  155. {ob_metaflow-2.15.13.1.data → ob_metaflow-2.19.7.1rc0.data}/data/share/metaflow/devtools/Tiltfile +107 -7
  156. {ob_metaflow-2.15.13.1.data → ob_metaflow-2.19.7.1rc0.data}/data/share/metaflow/devtools/pick_services.sh +1 -0
  157. {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/METADATA +2 -3
  158. {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/RECORD +162 -121
  159. {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/WHEEL +1 -1
  160. metaflow/_vendor/v3_5/__init__.py +0 -1
  161. metaflow/_vendor/v3_5/importlib_metadata/__init__.py +0 -644
  162. metaflow/_vendor/v3_5/importlib_metadata/_compat.py +0 -152
  163. metaflow/_vendor/v3_5/zipp.py +0 -329
  164. metaflow/info_file.py +0 -25
  165. metaflow/package.py +0 -203
  166. metaflow/user_configs/config_decorators.py +0 -568
  167. {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/entry_points.txt +0 -0
  168. {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/licenses/LICENSE +0 -0
  169. {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/top_level.txt +0 -0
@@ -6,6 +6,7 @@ import time
6
6
 
7
7
  from functools import wraps
8
8
  from io import BufferedIOBase, FileIO, RawIOBase
9
+ from typing import List, Optional
9
10
  from types import MethodType, FunctionType
10
11
 
11
12
  from .. import metaflow_config
@@ -98,8 +99,8 @@ class TaskDataStore(object):
98
99
  data_metadata=None,
99
100
  mode="r",
100
101
  allow_not_done=False,
102
+ persist=True,
101
103
  ):
102
-
103
104
  self._storage_impl = flow_datastore._storage_impl
104
105
  self.TYPE = self._storage_impl.TYPE
105
106
  self._ca_store = flow_datastore.ca_store
@@ -114,11 +115,12 @@ class TaskDataStore(object):
114
115
  self._attempt = attempt
115
116
  self._metadata = flow_datastore.metadata
116
117
  self._parent = flow_datastore
118
+ self._persist = persist
117
119
 
118
120
  # The GZIP encodings are for backward compatibility
119
121
  self._encodings = {"pickle-v2", "gzip+pickle-v2"}
120
122
  ver = sys.version_info[0] * 10 + sys.version_info[1]
121
- if ver >= 34:
123
+ if ver >= 36:
122
124
  self._encodings.add("pickle-v4")
123
125
  self._encodings.add("gzip+pickle-v4")
124
126
 
@@ -149,6 +151,8 @@ class TaskDataStore(object):
149
151
  )
150
152
  if self.has_metadata(check_meta, add_attempt=False):
151
153
  max_attempt = i
154
+ elif max_attempt is not None:
155
+ break
152
156
  if self._attempt is None:
153
157
  self._attempt = max_attempt
154
158
  elif max_attempt is None or self._attempt > max_attempt:
@@ -223,6 +227,9 @@ class TaskDataStore(object):
223
227
  @property
224
228
  def pathspec_index(self):
225
229
  idxstr = ",".join(map(str, (f.index for f in self["_foreach_stack"])))
230
+ if "_iteration_stack" in self:
231
+ itrstr = ",".join(map(str, (f for f in self["_iteration_stack"])))
232
+ return "%s/%s[%s][%s]" % (self._run_id, self._step_name, idxstr, itrstr)
226
233
  return "%s/%s[%s]" % (self._run_id, self._step_name, idxstr)
227
234
 
228
235
  @property
@@ -251,6 +258,72 @@ class TaskDataStore(object):
251
258
  """
252
259
  self.save_metadata({self.METADATA_ATTEMPT_SUFFIX: {"time": time.time()}})
253
260
 
261
+ @only_if_not_done
262
+ @require_mode("w")
263
+ def transfer_artifacts(
264
+ self, other_datastore: "TaskDataStore", names: Optional[List[str]] = None
265
+ ):
266
+ """
267
+ Copies the blobs from other_datastore to this datastore if the datastore roots
268
+ are different.
269
+
270
+ This is used specifically for spin so we can bring in artifacts from the original
271
+ datastore.
272
+
273
+ Parameters
274
+ ----------
275
+ other_datastore : TaskDataStore
276
+ Other datastore from which to copy artifacts from
277
+ names : List[str], optional, default None
278
+ If provided, only transfer the artifacts with these names. If None,
279
+ transfer all artifacts from the other datastore.
280
+ """
281
+ if (
282
+ other_datastore.TYPE == self.TYPE
283
+ and other_datastore._storage_impl.datastore_root
284
+ == self._storage_impl.datastore_root
285
+ ):
286
+ # Nothing to transfer -- artifacts are already saved properly
287
+ return
288
+
289
+ # Determine which artifacts need to be transferred
290
+ if names is None:
291
+ # Transfer all artifacts from other datastore
292
+ artifacts_to_transfer = list(other_datastore._objects.keys())
293
+ else:
294
+ # Transfer only specified artifacts
295
+ artifacts_to_transfer = [
296
+ name for name in names if name in other_datastore._objects
297
+ ]
298
+
299
+ if not artifacts_to_transfer:
300
+ return
301
+
302
+ # Get SHA keys for artifacts to transfer
303
+ shas_to_transfer = [
304
+ other_datastore._objects[name] for name in artifacts_to_transfer
305
+ ]
306
+
307
+ # Check which blobs are missing locally
308
+ missing_shas = []
309
+ for sha in shas_to_transfer:
310
+ local_path = self._ca_store._storage_impl.path_join(
311
+ self._ca_store._prefix, sha[:2], sha
312
+ )
313
+ if not self._ca_store._storage_impl.is_file([local_path])[0]:
314
+ missing_shas.append(sha)
315
+
316
+ if not missing_shas:
317
+ return # All blobs already exist locally
318
+
319
+ # Load blobs from other datastore in transfer mode
320
+ transfer_blobs = other_datastore._ca_store.load_blobs(
321
+ missing_shas, is_transfer=True
322
+ )
323
+
324
+ # Save blobs to local datastore in transfer mode
325
+ self._ca_store.save_blobs(transfer_blobs, is_transfer=True)
326
+
254
327
  @only_if_not_done
255
328
  @require_mode("w")
256
329
  def save_artifacts(self, artifacts_iter, len_hint=0):
@@ -289,7 +362,7 @@ class TaskDataStore(object):
289
362
  except (SystemError, OverflowError) as e:
290
363
  raise DataException(
291
364
  "Artifact *%s* is very large (over 2GB). "
292
- "You need to use Python 3.4 or newer if you want to "
365
+ "You need to use Python 3.6 or newer if you want to "
293
366
  "serialize large objects." % name
294
367
  ) from e
295
368
  except TypeError as e:
@@ -352,7 +425,7 @@ class TaskDataStore(object):
352
425
  encode_type = "gzip+pickle-v2"
353
426
  if encode_type not in self._encodings:
354
427
  raise DataException(
355
- "Python 3.4 or later is required to load artifact '%s'" % name
428
+ "Python 3.6 or later is required to load artifact '%s'" % name
356
429
  )
357
430
  else:
358
431
  to_load[self._objects[name]].append(name)
@@ -681,14 +754,16 @@ class TaskDataStore(object):
681
754
  flow : FlowSpec
682
755
  Flow to persist
683
756
  """
757
+ if not self._persist:
758
+ return
684
759
 
685
760
  if flow._datastore:
686
761
  self._objects.update(flow._datastore._objects)
687
762
  self._info.update(flow._datastore._info)
688
763
 
689
- # we create a list of valid_artifacts in advance, outside of
690
- # artifacts_iter, so we can provide a len_hint below
764
+ # Scan flow object FIRST
691
765
  valid_artifacts = []
766
+ current_artifact_names = set()
692
767
  for var in dir(flow):
693
768
  if var.startswith("__") or var in flow._EPHEMERAL:
694
769
  continue
@@ -705,6 +780,16 @@ class TaskDataStore(object):
705
780
  or isinstance(val, Parameter)
706
781
  ):
707
782
  valid_artifacts.append((var, val))
783
+ current_artifact_names.add(var)
784
+
785
+ # Transfer ONLY artifacts that aren't being overridden
786
+ if hasattr(flow._datastore, "orig_datastore"):
787
+ parent_artifacts = set(flow._datastore._objects.keys())
788
+ unchanged_artifacts = parent_artifacts - current_artifact_names
789
+ if unchanged_artifacts:
790
+ self.transfer_artifacts(
791
+ flow._datastore.orig_datastore, names=list(unchanged_artifacts)
792
+ )
708
793
 
709
794
  def artifacts_iter():
710
795
  # we consume the valid_artifacts list destructively to
@@ -720,6 +805,7 @@ class TaskDataStore(object):
720
805
  delattr(flow, var)
721
806
  yield var, val
722
807
 
808
+ # Save current artifacts
723
809
  self.save_artifacts(artifacts_iter(), len_hint=len(valid_artifacts))
724
810
 
725
811
  @only_if_not_done
metaflow/debug.py CHANGED
@@ -42,6 +42,11 @@ class Debug(object):
42
42
  filename = inspect.stack()[1][1]
43
43
  print("debug[%s %s:%s]: %s" % (typ, filename, lineno, s), file=sys.stderr)
44
44
 
45
+ def __getattr__(self, name):
46
+ # Small piece of code to get pyright and other linters to recognize that there
47
+ # are dynamic attributes.
48
+ return getattr(self, name)
49
+
45
50
  def noop(self, args):
46
51
  pass
47
52