metaflow 2.18.10__py2.py3-none-any.whl → 2.18.12__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.
@@ -121,6 +121,8 @@ class ArgoWorkflows(object):
121
121
  incident_io_metadata: List[str] = None,
122
122
  enable_heartbeat_daemon=True,
123
123
  enable_error_msg_capture=False,
124
+ workflow_title=None,
125
+ workflow_description=None,
124
126
  ):
125
127
  # Some high-level notes -
126
128
  #
@@ -177,6 +179,8 @@ class ArgoWorkflows(object):
177
179
  )
178
180
  self.enable_heartbeat_daemon = enable_heartbeat_daemon
179
181
  self.enable_error_msg_capture = enable_error_msg_capture
182
+ self.workflow_title = workflow_title
183
+ self.workflow_description = workflow_description
180
184
  self.parameters = self._process_parameters()
181
185
  self.config_parameters = self._process_config_parameters()
182
186
  self.triggers, self.trigger_options = self._process_triggers()
@@ -430,6 +434,25 @@ class ArgoWorkflows(object):
430
434
  "metaflow/project_flow_name": current.project_flow_name,
431
435
  }
432
436
  )
437
+
438
+ # Add Argo Workflows title and description annotations
439
+ # https://argo-workflows.readthedocs.io/en/latest/title-and-description/
440
+ # Use CLI-provided values or auto-populate from metadata
441
+ title = (
442
+ (self.workflow_title.strip() if self.workflow_title else None)
443
+ or current.get("project_flow_name")
444
+ or self.flow.name
445
+ )
446
+
447
+ description = (
448
+ self.workflow_description.strip() if self.workflow_description else None
449
+ ) or (self.flow.__doc__.strip() if self.flow.__doc__ else None)
450
+
451
+ if title:
452
+ annotations["workflows.argoproj.io/title"] = title
453
+ if description:
454
+ annotations["workflows.argoproj.io/description"] = description
455
+
433
456
  return annotations
434
457
 
435
458
  def _get_schedule(self):
@@ -894,7 +917,16 @@ class ArgoWorkflows(object):
894
917
  .annotations(
895
918
  {
896
919
  **annotations,
897
- **self._base_annotations,
920
+ **{
921
+ k: v
922
+ for k, v in self._base_annotations.items()
923
+ if k
924
+ # Skip custom title/description for workflows as this makes it harder to find specific runs.
925
+ not in [
926
+ "workflows.argoproj.io/title",
927
+ "workflows.argoproj.io/description",
928
+ ]
929
+ },
898
930
  **{"metaflow/run_id": "argo-{{workflow.name}}"},
899
931
  }
900
932
  )
@@ -227,6 +227,18 @@ def argo_workflows(obj, name=None):
227
227
  show_default=True,
228
228
  help="Capture stack trace of first failed task in exit hook.",
229
229
  )
230
+ @click.option(
231
+ "--workflow-title",
232
+ default=None,
233
+ type=str,
234
+ help="Custom title for the workflow displayed in Argo Workflows UI. Defaults to `project_flow_name`. Supports markdown formatting.",
235
+ )
236
+ @click.option(
237
+ "--workflow-description",
238
+ default=None,
239
+ type=str,
240
+ help="Custom description for the workflow displayed in Argo Workflows UI. Defaults to the flow's docstring if available. Supports markdown formatting and multi-line text.",
241
+ )
230
242
  @click.pass_obj
231
243
  def create(
232
244
  obj,
@@ -248,6 +260,8 @@ def create(
248
260
  incident_io_alert_source_config_id=None,
249
261
  incident_io_metadata=None,
250
262
  enable_heartbeat_daemon=True,
263
+ workflow_title=None,
264
+ workflow_description=None,
251
265
  deployer_attribute_file=None,
252
266
  enable_error_msg_capture=False,
253
267
  ):
@@ -312,6 +326,8 @@ def create(
312
326
  incident_io_metadata,
313
327
  enable_heartbeat_daemon,
314
328
  enable_error_msg_capture,
329
+ workflow_title,
330
+ workflow_description,
315
331
  )
316
332
 
317
333
  if only_json:
@@ -658,6 +674,8 @@ def make_flow(
658
674
  incident_io_metadata,
659
675
  enable_heartbeat_daemon,
660
676
  enable_error_msg_capture,
677
+ workflow_title,
678
+ workflow_description,
661
679
  ):
662
680
  # TODO: Make this check less specific to Amazon S3 as we introduce
663
681
  # support for more cloud object stores.
@@ -750,6 +768,8 @@ def make_flow(
750
768
  incident_io_metadata=incident_io_metadata,
751
769
  enable_heartbeat_daemon=enable_heartbeat_daemon,
752
770
  enable_error_msg_capture=enable_error_msg_capture,
771
+ workflow_title=workflow_title,
772
+ workflow_description=workflow_description,
753
773
  )
754
774
 
755
775
 
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  import os
3
- from datetime import datetime
3
+ from datetime import datetime, timezone
4
4
 
5
5
  ###
6
6
  # Algorithm to determine 1st error:
@@ -26,6 +26,9 @@ def parse_workflow_failures():
26
26
  def group_failures_by_template(failures):
27
27
  groups = {}
28
28
  for failure in failures:
29
+ if failure.get("finishedAt", None) is None:
30
+ timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
31
+ failure["finishedAt"] = timestamp
29
32
  groups.setdefault(failure["templateName"], []).append(failure)
30
33
  return groups
31
34
 
@@ -53,7 +56,7 @@ def determine_first_error():
53
56
  grouped_failures = group_failures_by_template(failures)
54
57
  for group in grouped_failures.values():
55
58
  group.sort(
56
- key=lambda x: datetime.strptime(x["finishedAt"], "%Y-%m-%dT%H:%M:%SZ")
59
+ key=lambda g: datetime.strptime(g["finishedAt"], "%Y-%m-%dT%H:%M:%SZ")
57
60
  )
58
61
 
59
62
  earliest_group = grouped_failures[
@@ -2,7 +2,7 @@ import base64
2
2
  import json
3
3
  import os
4
4
  from .card import MetaflowCard, MetaflowCardComponent, with_default_component_id
5
- from .convert_to_native_type import TaskToDict
5
+ from .convert_to_native_type import TaskToDict, MAX_ARTIFACT_SIZE
6
6
  import uuid
7
7
  import inspect
8
8
 
@@ -376,9 +376,14 @@ class TaskInfoComponent(MetaflowCardComponent):
376
376
  components=[],
377
377
  runtime=False,
378
378
  flow=None,
379
+ max_artifact_size=None,
379
380
  ):
380
381
  self._task = task
381
382
  self._only_repr = only_repr
383
+ # Use the global MAX_ARTIFACT_SIZE constant if not specified
384
+ self._max_artifact_size = (
385
+ max_artifact_size if max_artifact_size is not None else MAX_ARTIFACT_SIZE
386
+ )
382
387
  self._graph = graph
383
388
  self._components = components
384
389
  self._page_title = page_title
@@ -394,9 +399,9 @@ class TaskInfoComponent(MetaflowCardComponent):
394
399
  a dictionary of form:
395
400
  dict(metadata = {},components= [])
396
401
  """
397
- task_data_dict = TaskToDict(only_repr=self._only_repr)(
398
- self._task, graph=self._graph
399
- )
402
+ task_data_dict = TaskToDict(
403
+ only_repr=self._only_repr, max_artifact_size=self._max_artifact_size
404
+ )(self._task, graph=self._graph)
400
405
  # ignore the name as an artifact
401
406
  if "name" in task_data_dict["data"]:
402
407
  del task_data_dict["data"]["name"]
@@ -693,10 +698,14 @@ class DefaultCard(MetaflowCard):
693
698
  **kwargs
694
699
  ):
695
700
  self._only_repr = True
701
+ # Default max artifact size uses the global MAX_ARTIFACT_SIZE constant (200MB)
702
+ self._max_artifact_size = MAX_ARTIFACT_SIZE
696
703
  self._graph = None if graph is None else transform_flow_graph(graph)
697
704
  self._flow = flow
698
705
  if "only_repr" in options:
699
706
  self._only_repr = options["only_repr"]
707
+ if "max_artifact_size" in options:
708
+ self._max_artifact_size = options["max_artifact_size"]
700
709
  self._components = components
701
710
 
702
711
  def render(self, task, runtime=False):
@@ -710,6 +719,7 @@ class DefaultCard(MetaflowCard):
710
719
  components=self._components,
711
720
  runtime=runtime,
712
721
  flow=self._flow,
722
+ max_artifact_size=self._max_artifact_size,
713
723
  ).render()
714
724
  pt = self._get_mustache()
715
725
  data_dict = dict(
@@ -15,6 +15,7 @@ from .renderer_tools import render_safely
15
15
  from .json_viewer import JSONViewer as _JSONViewer, YAMLViewer as _YAMLViewer
16
16
  import uuid
17
17
  import inspect
18
+ import textwrap
18
19
 
19
20
 
20
21
  def _warning_with_component(component, msg):
@@ -656,19 +657,38 @@ class Markdown(UserComponent):
656
657
  )
657
658
  ```
658
659
 
660
+ Multi-line strings with indentation are automatically dedented:
661
+ ```
662
+ current.card.append(
663
+ Markdown(f'''
664
+ # Header
665
+ - Item 1
666
+ - Item 2
667
+ ''')
668
+ )
669
+ ```
670
+
659
671
  Parameters
660
672
  ----------
661
673
  text : str
662
- Text formatted in Markdown.
674
+ Text formatted in Markdown. Leading whitespace common to all lines
675
+ is automatically removed to support indented multi-line strings.
663
676
  """
664
677
 
665
678
  REALTIME_UPDATABLE = True
666
679
 
680
+ @staticmethod
681
+ def _dedent_text(text):
682
+ """Remove common leading whitespace from all lines."""
683
+ if text is None:
684
+ return None
685
+ return textwrap.dedent(text)
686
+
667
687
  def update(self, text=None):
668
- self._text = text
688
+ self._text = self._dedent_text(text)
669
689
 
670
690
  def __init__(self, text=None):
671
- self._text = text
691
+ self._text = self._dedent_text(text)
672
692
 
673
693
  @with_default_component_id
674
694
  @render_safely
@@ -8,7 +8,9 @@ TypeResolvedObject = namedtuple("TypeResolvedObject", ["data", "is_image", "is_t
8
8
 
9
9
 
10
10
  TIME_FORMAT = "%Y-%m-%d %I:%M:%S %p"
11
- MAX_ARTIFACT_SIZE = 1 # in 1 MB
11
+ # Maximum artifact size to render in cards: 200MB (in bytes)
12
+ # Artifacts larger than this will be skipped during card rendering to avoid memory issues
13
+ MAX_ARTIFACT_SIZE = 256 * 1024 * 1024 # 256 MB = 268435456 bytes
12
14
 
13
15
 
14
16
  def _get_object_size(obj, seen=None):
@@ -44,7 +46,7 @@ def _full_classname(obj):
44
46
 
45
47
 
46
48
  class TaskToDict:
47
- def __init__(self, only_repr=False, runtime=False):
49
+ def __init__(self, only_repr=False, runtime=False, max_artifact_size=None):
48
50
  # this dictionary holds all the supported functions
49
51
  import reprlib
50
52
  import pprint
@@ -61,6 +63,10 @@ class TaskToDict:
61
63
  self._repr = r
62
64
  self._runtime = runtime
63
65
  self._only_repr = only_repr
66
+ # Use the global MAX_ARTIFACT_SIZE constant if not specified
67
+ self._max_artifact_size = (
68
+ max_artifact_size if max_artifact_size is not None else MAX_ARTIFACT_SIZE
69
+ )
64
70
  self._supported_types = {
65
71
  "tuple": self._parse_tuple,
66
72
  "NoneType": self._parse_nonetype,
@@ -110,6 +116,19 @@ class TaskToDict:
110
116
  task_data_dict = {}
111
117
  type_inferred_objects = {"images": {}, "tables": {}}
112
118
  for data in task:
119
+ # Check if artifact size exceeds the maximum allowed size
120
+ if data.size > self._max_artifact_size:
121
+ # Skip artifacts that are too large
122
+ task_data_dict[data.id] = dict(
123
+ type="skipped",
124
+ data=f"<artifact too large: {data.size} bytes, max: {self._max_artifact_size} bytes>",
125
+ large_object=True,
126
+ supported_type=False,
127
+ only_repr=self._only_repr,
128
+ name=data.id,
129
+ )
130
+ continue
131
+
113
132
  try:
114
133
  data_object = data.data
115
134
  task_data_dict[data.id] = self._convert_to_native_type(data_object)
@@ -241,7 +260,8 @@ class TaskToDict:
241
260
  supported_type = True
242
261
  type_parsing_func = self._supported_types[obj_type_name]
243
262
  data_obj = type_parsing_func(data_object)
244
- if _get_object_size(data_obj) * 1e-6 > MAX_ARTIFACT_SIZE:
263
+ # Secondary check: if the in-memory object size exceeds our limit, use repr instead
264
+ if _get_object_size(data_obj) > self._max_artifact_size:
245
265
  data_obj = rep.repr(data_obj)
246
266
  large_object = True
247
267
  else:
metaflow/runner/utils.py CHANGED
@@ -109,7 +109,6 @@ def read_from_fifo_when_ready(
109
109
  content = bytearray()
110
110
  poll = select.poll()
111
111
  poll.register(fifo_fd, select.POLLIN)
112
- max_timeout = 3 # Wait for 10 * 3 = 30 ms after last write
113
112
  while True:
114
113
  if check_process_exited(command_obj) and command_obj.process.returncode != 0:
115
114
  raise CalledProcessError(
@@ -137,15 +136,16 @@ def read_from_fifo_when_ready(
137
136
  else:
138
137
  # We had no events (just a timeout) and the read didn't return
139
138
  # an exception so the file is still open; we continue waiting for data
140
- # Unfortunately, on MacOS, it seems that even *after* the file is
141
- # closed on the other end, we still don't get a BlockingIOError so
142
- # we hack our way and timeout if there is no write in 30ms which is
143
- # a relative eternity for file writes.
144
- if content:
145
- if max_timeout <= 0:
146
- break
147
- max_timeout -= 1
148
- continue
139
+ # On some systems (notably MacOS), even after the file is closed on the
140
+ # other end, we may not get a BlockingIOError or proper EOF signal.
141
+ # Instead of using an arbitrary timeout, check if the writer process
142
+ # has actually exited. If it has and we have content, we can safely
143
+ # assume EOF. If the process is still running, continue waiting.
144
+ if content and check_process_exited(command_obj):
145
+ # Process has exited and we got an empty read with no poll events.
146
+ # This is EOF - break out to return the content we've collected.
147
+ break
148
+ # else: process is still running, continue waiting for more data
149
149
  except BlockingIOError:
150
150
  has_blocking_error = True
151
151
  if content:
metaflow/version.py CHANGED
@@ -1 +1 @@
1
- metaflow_version = "2.18.10"
1
+ metaflow_version = "2.18.12"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metaflow
3
- Version: 2.18.10
3
+ Version: 2.18.12
4
4
  Summary: Metaflow: More AI and ML, Less Engineering
5
5
  Author: Metaflow Developers
6
6
  Author-email: help@metaflow.org
@@ -26,7 +26,7 @@ License-File: LICENSE
26
26
  Requires-Dist: requests
27
27
  Requires-Dist: boto3
28
28
  Provides-Extra: stubs
29
- Requires-Dist: metaflow-stubs==2.18.10; extra == "stubs"
29
+ Requires-Dist: metaflow-stubs==2.18.12; extra == "stubs"
30
30
  Dynamic: author
31
31
  Dynamic: author-email
32
32
  Dynamic: classifier
@@ -36,7 +36,7 @@ metaflow/tuple_util.py,sha256=_G5YIEhuugwJ_f6rrZoelMFak3DqAR2tt_5CapS1XTY,830
36
36
  metaflow/unbounded_foreach.py,sha256=p184WMbrMJ3xKYHwewj27ZhRUsSj_kw1jlye5gA9xJk,387
37
37
  metaflow/util.py,sha256=g2SOU_CRzJLgDM_UGF9QDMANMAIHAsDRXE6S76_YzsY,14594
38
38
  metaflow/vendor.py,sha256=A82CGHfStZGDP5pQ5XzRjFkbN1ZC-vFmghXIrzMDDNg,5868
39
- metaflow/version.py,sha256=fm3PVktu1KSNr7dMY4-BletucOknAbjiLAaLr9y1JkU,29
39
+ metaflow/version.py,sha256=LEAeq12k2u6Mfx_BKRFo6XFbIXmlvtKvNKon7OjzR2k,29
40
40
  metaflow/_vendor/__init__.py,sha256=y_CiwUD3l4eAKvTVDZeqgVujMy31cAM1qjAB-HfI-9s,353
41
41
  metaflow/_vendor/typing_extensions.py,sha256=q9zxWa6p6CzF1zZvSkygSlklduHf_b3K7MCxGz7MJRc,134519
42
42
  metaflow/_vendor/zipp.py,sha256=ajztOH-9I7KA_4wqDYygtHa6xUBVZgFpmZ8FE74HHHI,8425
@@ -231,12 +231,12 @@ metaflow/plugins/airflow/sensors/s3_sensor.py,sha256=iDReG-7FKnumrtQg-HY6cCUAAqN
231
231
  metaflow/plugins/argo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
232
232
  metaflow/plugins/argo/argo_client.py,sha256=oT4ZrCyE7CYEbqNN0SfoZfSHd5fYW9XtuOrQEiUd1co,17230
233
233
  metaflow/plugins/argo/argo_events.py,sha256=_C1KWztVqgi3zuH57pInaE9OzABc2NnncC-zdwOMZ-w,5909
234
- metaflow/plugins/argo/argo_workflows.py,sha256=r__mx04QOPbpBEe2c7F23NKn93-KPWhmU7LCh0Gx2cw,216218
235
- metaflow/plugins/argo/argo_workflows_cli.py,sha256=-blfZp-kAS8oWFTarfou9gRyE4QCnnJwa-0g8QuE0zk,52280
234
+ metaflow/plugins/argo/argo_workflows.py,sha256=89C72toG6tzsix8oZ3wr5DBEn_88GjydEWzvcL3L1S0,217637
235
+ metaflow/plugins/argo/argo_workflows_cli.py,sha256=GRDsiE8QT9HEdeAUODtyyGiqePhShSkwJJ8tiPQwwiI,52992
236
236
  metaflow/plugins/argo/argo_workflows_decorator.py,sha256=CLSjPqFTGucZ2_dSQGAYkoWWUZBQ9TCBXul4rxhDj3w,8282
237
237
  metaflow/plugins/argo/argo_workflows_deployer.py,sha256=6kHxEnYXJwzNCM9swI8-0AckxtPWqwhZLerYkX8fxUM,4444
238
238
  metaflow/plugins/argo/argo_workflows_deployer_objects.py,sha256=ydBE-lP42eNKvep36nQdUBPS3rQQErvoA7rCgyp5M6I,14949
239
- metaflow/plugins/argo/capture_error.py,sha256=Ys9dscGrTpW-ZCirLBU0gD9qBM0BjxyxGlUMKcwewQc,1852
239
+ metaflow/plugins/argo/capture_error.py,sha256=9ggbGHyR9UBPswOqAHCbpE9kdXuV3uBYslKiybFxqhs,2042
240
240
  metaflow/plugins/argo/conditional_input_paths.py,sha256=Vtca74XbhnqAXgJJXKasLEa28jZbKBZPC5w4NAIOURc,1251
241
241
  metaflow/plugins/argo/exit_hooks.py,sha256=nh8IEkzAtQnbKVnh3N9CVnVKZB39Bjm3e0LFrACsLz8,6109
242
242
  metaflow/plugins/argo/generate_input_paths.py,sha256=loYsI6RFX9LlFsHb7Fe-mzlTTtRdySoOu7sYDy-uXK0,881
@@ -284,11 +284,11 @@ metaflow/plugins/cards/exception.py,sha256=2UqlNb-Kxpg6cuLu2sBEIPTIElwlVBsSpeCgD
284
284
  metaflow/plugins/cards/metadata.py,sha256=tACaw7_XNAICZ4A25celIbgxUF0CxHh7BBpFzKrMLTo,487
285
285
  metaflow/plugins/cards/card_modules/__init__.py,sha256=WI2IAsFiKGyqPrHtO9S9-MbyVtUTgWJNL4xjJaBErRo,3437
286
286
  metaflow/plugins/cards/card_modules/base.html,sha256=Y208ZKIZqEWWUcoBFTLTdWKAG0C8xH5lmyCRSjaN2FY,21004
287
- metaflow/plugins/cards/card_modules/basic.py,sha256=b6aBg7800CjjkQb0J_TOd3JujVR10X2QoXYdwiXFbkE,25831
287
+ metaflow/plugins/cards/card_modules/basic.py,sha256=bKU_b_Wfs2OC6me6kPp1Jm_SLvaJ4dkUCMAt2VLampk,26430
288
288
  metaflow/plugins/cards/card_modules/bundle.css,sha256=zlYjv5rt7lMqiQzd_OAe4QdQeM3J3YbwljnEghlbTaU,28052
289
289
  metaflow/plugins/cards/card_modules/card.py,sha256=6sbqP5mwf7QWvQvX2N_bC78H9ixuI5sQ8612Q5islys,4627
290
- metaflow/plugins/cards/card_modules/components.py,sha256=hF204MUyJ2DZXSPhEt7d23isjdEf4TGK8pzmVkmXyQ0,45574
291
- metaflow/plugins/cards/card_modules/convert_to_native_type.py,sha256=Vcjqn5rfC0kVMdhqDwsYEjknXTbkG_ppraQrQGaQY_E,16245
290
+ metaflow/plugins/cards/card_modules/components.py,sha256=z9IT9gVpI22hUhGtJbgcy5oMpGzPeTof_lEkOOfMa9Q,46150
291
+ metaflow/plugins/cards/card_modules/convert_to_native_type.py,sha256=opjGOvWg7trOqzhTRZ7h1cFlYrNj68Wn3_EyDTIKEvw,17320
292
292
  metaflow/plugins/cards/card_modules/json_viewer.py,sha256=DWOcQPk6DXbeGuYEqv1gGrQW1eMVYlCXv3kMsVLnhNc,7113
293
293
  metaflow/plugins/cards/card_modules/main.css,sha256=avu7BTB9qj0M8LvqNLUhikUFQhmAJhQQ7REcUgh9zMw,11725
294
294
  metaflow/plugins/cards/card_modules/main.js,sha256=wT4PhcwoFwVNOGVZYBkjqfYKROuPSPWGjS-zCQZErz8,1075727
@@ -384,7 +384,7 @@ metaflow/runner/metaflow_runner.py,sha256=uo3BzcAfZ67VT_f-TPe5ZHiWHn6uuojWusOMGk
384
384
  metaflow/runner/nbdeploy.py,sha256=Sp5w-6nCZwjHaRBHWxi8udya-RYnJOB76KNLjB4L7Gs,4166
385
385
  metaflow/runner/nbrun.py,sha256=LhJu-Teoi7wTkNxg0kpNPVXFxH_9P4lvtp0ysMEIFJ8,7299
386
386
  metaflow/runner/subprocess_manager.py,sha256=x-MtPpGGMQUkIbQ_oNOuR-45b91DFvsCJ0SPoFc0dF4,23028
387
- metaflow/runner/utils.py,sha256=fU4vPazBdi6ATAUW_DaBAQeVslRwrLT8Pn9s5wav3gg,10350
387
+ metaflow/runner/utils.py,sha256=x9EED11RZGf7J4OuK-cVuj8gxGlSjRQFSqqTehvBSjw,10588
388
388
  metaflow/sidecar/__init__.py,sha256=1mmNpmQ5puZCpRmmYlCOeieZ4108Su9XQ4_EqF1FGOU,131
389
389
  metaflow/sidecar/sidecar.py,sha256=EspKXvPPNiyRToaUZ51PS5TT_PzrBNAurn_wbFnmGr0,1334
390
390
  metaflow/sidecar/sidecar_messages.py,sha256=zPsCoYgDIcDkkvdC9MEpJTJ3y6TSGm2JWkRc4vxjbFA,1071
@@ -430,12 +430,12 @@ metaflow/user_decorators/mutable_flow.py,sha256=EywKTN3cnXPQF_s62wQaC4a4aH14j8oe
430
430
  metaflow/user_decorators/mutable_step.py,sha256=-BY0UDXf_RCAEnC5JlLzEXGdiw1KD9oSrSxS_SWaB9Y,16791
431
431
  metaflow/user_decorators/user_flow_decorator.py,sha256=2yDwZq9QGv9W-7kEuKwa8o4ZkTvuHJ5ESz7VVrGViAI,9890
432
432
  metaflow/user_decorators/user_step_decorator.py,sha256=4558NR8RJtN22OyTwCXO80bAMhMTaRGMoX12b1GMcPc,27232
433
- metaflow-2.18.10.data/data/share/metaflow/devtools/Makefile,sha256=TT4TCq8ALSfqYyGqDPocN5oPcZe2FqoCZxmGO1LmyCc,13760
434
- metaflow-2.18.10.data/data/share/metaflow/devtools/Tiltfile,sha256=b6l_fjDO0wtxOkO85lFvuf3HDa6wnzHhhBG8yv1kQqk,23949
435
- metaflow-2.18.10.data/data/share/metaflow/devtools/pick_services.sh,sha256=PGjQeDIigFHeoQ0asmYNdYDPIOdeYy1UYvkw2wdN4zg,2209
436
- metaflow-2.18.10.dist-info/licenses/LICENSE,sha256=nl_Lt5v9VvJ-5lWJDT4ddKAG-VZ-2IaLmbzpgYDz2hU,11343
437
- metaflow-2.18.10.dist-info/METADATA,sha256=EpxLRWGGk1VpW6VbbCa0CGQnVsoaTy4kXEPib4uCsNU,6743
438
- metaflow-2.18.10.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
439
- metaflow-2.18.10.dist-info/entry_points.txt,sha256=RvEq8VFlgGe_FfqGOZi0D7ze1hLD0pAtXeNyGfzc_Yc,103
440
- metaflow-2.18.10.dist-info/top_level.txt,sha256=v1pDHoWaSaKeuc5fKTRSfsXCKSdW1zvNVmvA-i0if3o,9
441
- metaflow-2.18.10.dist-info/RECORD,,
433
+ metaflow-2.18.12.data/data/share/metaflow/devtools/Makefile,sha256=TT4TCq8ALSfqYyGqDPocN5oPcZe2FqoCZxmGO1LmyCc,13760
434
+ metaflow-2.18.12.data/data/share/metaflow/devtools/Tiltfile,sha256=b6l_fjDO0wtxOkO85lFvuf3HDa6wnzHhhBG8yv1kQqk,23949
435
+ metaflow-2.18.12.data/data/share/metaflow/devtools/pick_services.sh,sha256=PGjQeDIigFHeoQ0asmYNdYDPIOdeYy1UYvkw2wdN4zg,2209
436
+ metaflow-2.18.12.dist-info/licenses/LICENSE,sha256=nl_Lt5v9VvJ-5lWJDT4ddKAG-VZ-2IaLmbzpgYDz2hU,11343
437
+ metaflow-2.18.12.dist-info/METADATA,sha256=O2fzkU976nnqO8o9Ufxng-zphV6LCS3qR9u-zbHSZMg,6743
438
+ metaflow-2.18.12.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
439
+ metaflow-2.18.12.dist-info/entry_points.txt,sha256=RvEq8VFlgGe_FfqGOZi0D7ze1hLD0pAtXeNyGfzc_Yc,103
440
+ metaflow-2.18.12.dist-info/top_level.txt,sha256=v1pDHoWaSaKeuc5fKTRSfsXCKSdW1zvNVmvA-i0if3o,9
441
+ metaflow-2.18.12.dist-info/RECORD,,