metaflow 2.17.4__py2.py3-none-any.whl → 2.18.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.
metaflow/lint.py CHANGED
@@ -416,3 +416,25 @@ def check_nested_foreach(graph):
416
416
  if node.type == "foreach":
417
417
  if any(graph[p].type == "foreach" for p in node.split_parents):
418
418
  raise LintWarn(msg.format(node), node.func_lineno, node.source_file)
419
+
420
+
421
+ @linter.ensure_static_graph
422
+ @linter.check
423
+ def check_ambiguous_joins(graph):
424
+ for node in graph:
425
+ if node.type == "join":
426
+ problematic_parents = [
427
+ p_name
428
+ for p_name in node.in_funcs
429
+ if graph[p_name].type == "split-switch"
430
+ ]
431
+ if problematic_parents:
432
+ msg = (
433
+ "A conditional path cannot lead directly to a join step.\n"
434
+ "In your conditional step(s) {parents}, one or more of the possible paths transition directly to the join step {join_name}.\n"
435
+ "As a workaround, please introduce an intermediate, unconditional step on that specific path before joining."
436
+ ).format(
437
+ parents=", ".join("*%s*" % p for p in problematic_parents),
438
+ join_name="*%s*" % node.name,
439
+ )
440
+ raise LintWarn(msg, node.func_lineno, node.source_file)
@@ -926,6 +926,7 @@ class ArgoWorkflows(object):
926
926
  self.conditional_nodes = set()
927
927
  self.conditional_join_nodes = set()
928
928
  self.matching_conditional_join_dict = {}
929
+ self.recursive_nodes = set()
929
930
 
930
931
  node_conditional_parents = {}
931
932
  node_conditional_branches = {}
@@ -948,6 +949,12 @@ class ArgoWorkflows(object):
948
949
  )
949
950
  node_conditional_parents[node.name] = conditional_parents
950
951
 
952
+ # check for recursion. this split is recursive if any of its out functions are itself.
953
+ if any(
954
+ out_func for out_func in node.out_funcs if out_func == node.name
955
+ ):
956
+ self.recursive_nodes.add(node.name)
957
+
951
958
  if conditional_parents and not node.type == "split-switch":
952
959
  node_conditional_parents[node.name] = conditional_parents
953
960
  conditional_branch = conditional_branch + [node.name]
@@ -1033,6 +1040,9 @@ class ArgoWorkflows(object):
1033
1040
  def _is_conditional_join_node(self, node):
1034
1041
  return node.name in self.conditional_join_nodes
1035
1042
 
1043
+ def _is_recursive_node(self, node):
1044
+ return node.name in self.recursive_nodes
1045
+
1036
1046
  def _matching_conditional_join(self, node):
1037
1047
  return self.matching_conditional_join_dict.get(node.name, None)
1038
1048
 
@@ -1044,6 +1054,7 @@ class ArgoWorkflows(object):
1044
1054
  templates=None,
1045
1055
  dag_tasks=None,
1046
1056
  parent_foreach=None,
1057
+ seen=None,
1047
1058
  ): # Returns Tuple[List[Template], List[DAGTask]]
1048
1059
  """ """
1049
1060
  # Every for-each node results in a separate subDAG and an equivalent
@@ -1053,6 +1064,8 @@ class ArgoWorkflows(object):
1053
1064
  # of the for-each node.
1054
1065
 
1055
1066
  # Emit if we have reached the end of the sub workflow
1067
+ if seen is None:
1068
+ seen = []
1056
1069
  if dag_tasks is None:
1057
1070
  dag_tasks = []
1058
1071
  if templates is None:
@@ -1060,6 +1073,13 @@ class ArgoWorkflows(object):
1060
1073
 
1061
1074
  if exit_node is not None and exit_node is node.name:
1062
1075
  return templates, dag_tasks
1076
+ if node.name in seen:
1077
+ return templates, dag_tasks
1078
+
1079
+ seen.append(node.name)
1080
+
1081
+ # helper variable for recursive conditional inputs
1082
+ has_foreach_inputs = False
1063
1083
  if node.name == "start":
1064
1084
  # Start node has no dependencies.
1065
1085
  dag_task = DAGTask(self._sanitize(node.name)).template(
@@ -1073,9 +1093,10 @@ class ArgoWorkflows(object):
1073
1093
  # vs what is a "num_parallel" based foreach (i.e. something that follows gang semantics.)
1074
1094
  # A `regular` foreach is basically any arbitrary kind of foreach.
1075
1095
  ):
1096
+ # helper variable for recursive conditional inputs
1097
+ has_foreach_inputs = True
1076
1098
  # Child of a foreach node needs input-paths as well as split-index
1077
1099
  # This child is the first node of the sub workflow and has no dependency
1078
-
1079
1100
  parameters = [
1080
1101
  Parameter("input-paths").value("{{inputs.parameters.input-paths}}"),
1081
1102
  Parameter("split-index").value("{{inputs.parameters.split-index}}"),
@@ -1253,6 +1274,7 @@ class ArgoWorkflows(object):
1253
1274
  templates,
1254
1275
  dag_tasks,
1255
1276
  parent_foreach,
1277
+ seen,
1256
1278
  )
1257
1279
  return _visit(
1258
1280
  self.graph[node.matching_join],
@@ -1260,8 +1282,102 @@ class ArgoWorkflows(object):
1260
1282
  templates,
1261
1283
  dag_tasks,
1262
1284
  parent_foreach,
1285
+ seen,
1263
1286
  )
1264
1287
  elif node.type == "split-switch":
1288
+ if self._is_recursive_node(node):
1289
+ # we need an additional recursive template if the step is recursive
1290
+ # NOTE: in the recursive case, the original step is renamed in the container templates to 'recursive-<step_name>'
1291
+ # so that we do not have to touch the step references in the DAG.
1292
+ #
1293
+ # NOTE: The way that recursion in Argo Workflows is achieved is with the following structure:
1294
+ # - the usual 'example-step' template which would match example_step in flow code is renamed to 'recursive-example-step'
1295
+ # - templates has another template with the original task name: 'example-step'
1296
+ # - the template 'example-step' in turn has steps
1297
+ # - 'example-step-internal' which uses the metaflow step executing template 'recursive-example-step'
1298
+ # - 'example-step-recursion' which calls the parent template 'example-step' if switch-step output from 'example-step-internal' matches the condition.
1299
+ sanitized_name = self._sanitize(node.name)
1300
+ templates.append(
1301
+ Template(sanitized_name)
1302
+ .steps(
1303
+ [
1304
+ WorkflowStep()
1305
+ .name("%s-internal" % sanitized_name)
1306
+ .template("recursive-%s" % sanitized_name)
1307
+ .arguments(
1308
+ Arguments().parameters(
1309
+ [
1310
+ Parameter("input-paths").value(
1311
+ "{{inputs.parameters.input-paths}}"
1312
+ )
1313
+ ]
1314
+ # Add the additional inputs required by specific node types.
1315
+ # We do not need to cover joins or @parallel, as a split-switch step can not be either one of these.
1316
+ + (
1317
+ [
1318
+ Parameter("split-index").value(
1319
+ "{{inputs.parameters.split-index}}"
1320
+ )
1321
+ ]
1322
+ if has_foreach_inputs
1323
+ else []
1324
+ )
1325
+ )
1326
+ )
1327
+ ]
1328
+ )
1329
+ .steps(
1330
+ [
1331
+ WorkflowStep()
1332
+ .name("%s-recursion" % sanitized_name)
1333
+ .template(sanitized_name)
1334
+ .when(
1335
+ "{{steps.%s-internal.outputs.parameters.switch-step}}==%s"
1336
+ % (sanitized_name, node.name)
1337
+ )
1338
+ .arguments(
1339
+ Arguments().parameters(
1340
+ [
1341
+ Parameter("input-paths").value(
1342
+ "argo-{{workflow.name}}/%s/{{steps.%s-internal.outputs.parameters.task-id}}"
1343
+ % (node.name, sanitized_name)
1344
+ )
1345
+ ]
1346
+ + (
1347
+ [
1348
+ Parameter("split-index").value(
1349
+ "{{inputs.parameters.split-index}}"
1350
+ )
1351
+ ]
1352
+ if has_foreach_inputs
1353
+ else []
1354
+ )
1355
+ )
1356
+ ),
1357
+ ]
1358
+ )
1359
+ .inputs(Inputs().parameters(parameters))
1360
+ .outputs(
1361
+ # NOTE: We try to read the output parameters from the recursive template call first (<step>-recursion), and the internal step second (<step>-internal).
1362
+ # This guarantees that we always get the output parameters of the last recursive step that executed.
1363
+ Outputs().parameters(
1364
+ [
1365
+ Parameter("task-id").valueFrom(
1366
+ {
1367
+ "expression": "(steps['%s-recursion']?.outputs ?? steps['%s-internal']?.outputs).parameters['task-id']"
1368
+ % (sanitized_name, sanitized_name)
1369
+ }
1370
+ ),
1371
+ Parameter("switch-step").valueFrom(
1372
+ {
1373
+ "expression": "(steps['%s-recursion']?.outputs ?? steps['%s-internal']?.outputs).parameters['switch-step']"
1374
+ % (sanitized_name, sanitized_name)
1375
+ }
1376
+ ),
1377
+ ]
1378
+ )
1379
+ )
1380
+ )
1265
1381
  for n in node.out_funcs:
1266
1382
  _visit(
1267
1383
  self.graph[n],
@@ -1269,6 +1385,7 @@ class ArgoWorkflows(object):
1269
1385
  templates,
1270
1386
  dag_tasks,
1271
1387
  parent_foreach,
1388
+ seen,
1272
1389
  )
1273
1390
 
1274
1391
  return _visit(
@@ -1277,6 +1394,7 @@ class ArgoWorkflows(object):
1277
1394
  templates,
1278
1395
  dag_tasks,
1279
1396
  parent_foreach,
1397
+ seen,
1280
1398
  )
1281
1399
  # For foreach nodes generate a new sub DAGTemplate
1282
1400
  # We do this for "regular" foreaches (ie. `self.next(self.a, foreach=)`)
@@ -1367,6 +1485,7 @@ class ArgoWorkflows(object):
1367
1485
  templates,
1368
1486
  [],
1369
1487
  node.name,
1488
+ seen,
1370
1489
  )
1371
1490
 
1372
1491
  # How do foreach's work on Argo:
@@ -1500,6 +1619,7 @@ class ArgoWorkflows(object):
1500
1619
  templates,
1501
1620
  dag_tasks,
1502
1621
  parent_foreach,
1622
+ seen,
1503
1623
  )
1504
1624
  # For linear nodes continue traversing to the next node
1505
1625
  if node.type in ("linear", "join", "start"):
@@ -1509,6 +1629,7 @@ class ArgoWorkflows(object):
1509
1629
  templates,
1510
1630
  dag_tasks,
1511
1631
  parent_foreach,
1632
+ seen,
1512
1633
  )
1513
1634
  else:
1514
1635
  raise ArgoWorkflowsException(
@@ -1773,8 +1894,10 @@ class ArgoWorkflows(object):
1773
1894
  # foreach-joins straight out of conditional branches are not yet supported
1774
1895
  if self._is_conditional_join_node(node):
1775
1896
  raise ArgoWorkflowsException(
1776
- "Conditionals steps that transition directly into a join step are not currently supported. "
1777
- "As a workaround, you can add a normal step after the conditional steps that transitions to a join step."
1897
+ "Conditional steps inside a foreach that transition directly into a join step are not currently supported.\n"
1898
+ "As a workaround, add a common step after the conditional steps %s "
1899
+ "that will transition to a join."
1900
+ % ", ".join("*%s*" % f for f in node.in_funcs)
1778
1901
  )
1779
1902
  # Set aggregated input-paths for a for-each join
1780
1903
  foreach_step = next(
@@ -2290,8 +2413,13 @@ class ArgoWorkflows(object):
2290
2413
  )
2291
2414
  )
2292
2415
  else:
2416
+ template_name = self._sanitize(node.name)
2417
+ if self._is_recursive_node(node):
2418
+ # The recursive template has the original step name,
2419
+ # this becomes a template within the recursive ones 'steps'
2420
+ template_name = self._sanitize("recursive-%s" % node.name)
2293
2421
  yield (
2294
- Template(self._sanitize(node.name))
2422
+ Template(template_name)
2295
2423
  # Set @timeout values
2296
2424
  .active_deadline_seconds(run_time_limit)
2297
2425
  # Set service account
@@ -3750,6 +3878,10 @@ class WorkflowStep(object):
3750
3878
  self.payload["template"] = str(template)
3751
3879
  return self
3752
3880
 
3881
+ def arguments(self, arguments):
3882
+ self.payload["arguments"] = arguments.to_json()
3883
+ return self
3884
+
3753
3885
  def when(self, condition):
3754
3886
  self.payload["when"] = str(condition)
3755
3887
  return self
@@ -60,7 +60,7 @@ def list(obj, archive=False):
60
60
  @click.pass_obj
61
61
  def save(obj, path):
62
62
  with open(path, "wb") as f:
63
- f.write(obj.package.blob())
63
+ f.write(obj.package.blob)
64
64
  obj.echo(
65
65
  "Code package saved in *%s* with metadata: %s"
66
66
  % (path, obj.package.package_metadata),
metaflow/task.py CHANGED
@@ -121,8 +121,10 @@ class MetaflowTask(object):
121
121
  r = w.post_step(orig_step_func.name, self.flow, raised_exception)
122
122
  except Exception as ex:
123
123
  r = ex
124
- if r is None or isinstance(r, Exception):
124
+ if r is None:
125
125
  raised_exception = None
126
+ elif isinstance(r, Exception):
127
+ raised_exception = r
126
128
  elif isinstance(r, tuple):
127
129
  if len(r) == 2:
128
130
  raised_exception, fake_next_call_args = r
@@ -271,6 +271,9 @@ class ConfigValue(collections.abc.Mapping, dict):
271
271
  v = obj
272
272
  return v
273
273
 
274
+ def __reduce__(self):
275
+ return (self.__class__, (self.to_dict(),))
276
+
274
277
 
275
278
  class DelayEvaluator(collections.abc.Mapping):
276
279
  """
@@ -484,7 +487,6 @@ class Config(Parameter, collections.abc.Mapping):
484
487
  parser: Optional[Union[str, Callable[[str], Dict[Any, Any]]]] = None,
485
488
  **kwargs: Dict[str, str]
486
489
  ):
487
-
488
490
  if default is not None and default_value is not None:
489
491
  raise MetaflowException(
490
492
  "For config '%s', you can only specify default or default_value, not both"
metaflow/version.py CHANGED
@@ -1 +1 @@
1
- metaflow_version = "2.17.4"
1
+ metaflow_version = "2.18.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metaflow
3
- Version: 2.17.4
3
+ Version: 2.18.0
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.17.4; extra == "stubs"
29
+ Requires-Dist: metaflow-stubs==2.18.0; extra == "stubs"
30
30
  Dynamic: author
31
31
  Dynamic: author-email
32
32
  Dynamic: classifier
@@ -14,7 +14,7 @@ metaflow/flowspec.py,sha256=9wsO2_QoO_VHKusKdpslfbwQREOwf0fAzF-DSEA0iZ8,41968
14
14
  metaflow/graph.py,sha256=UOeClj-JeORRlZWOQMI1CirkrCpTvVWvRcSwODCajMg,19263
15
15
  metaflow/includefile.py,sha256=RtISGl1V48qjkJBakUZ9yPpHV102h7pOIFiKP8PLHpc,20927
16
16
  metaflow/integrations.py,sha256=LlsaoePRg03DjENnmLxZDYto3NwWc9z_PtU6nJxLldg,1480
17
- metaflow/lint.py,sha256=dvgpMZoF506yJerCHHUu7A-nTVry95Fmr8Q3bPEaJCs,14374
17
+ metaflow/lint.py,sha256=A2NdUq_MnQal_RUCMC8ZOSR0VYZGyi2mSgwPQB0UzQo,15343
18
18
  metaflow/meta_files.py,sha256=vlgJHI8GJUKzXoxdrVoH8yyCF5bhFgwYemUgnyd1wgM,342
19
19
  metaflow/metaflow_config.py,sha256=lsdfr_1eS4cP6g1OgLWePKzUIypUGVjNxffRhKlFWfA,24102
20
20
  metaflow/metaflow_config_funcs.py,sha256=5GlvoafV6SxykwfL8D12WXSfwjBN_NsyuKE_Q3gjGVE,6738
@@ -31,12 +31,12 @@ metaflow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
31
  metaflow/pylint_wrapper.py,sha256=tJjmdsgtbHTCqg_oA6fV6SbWq_3V5XUgE9xH0zJ1CGU,3004
32
32
  metaflow/runtime.py,sha256=3R44AFI04LWahbfa2v0yDYIWHIz6sau26p1SnzYFNew,86888
33
33
  metaflow/tagging_util.py,sha256=ctyf0Q1gBi0RyZX6J0e9DQGNkNHblV_CITfy66axXB4,2346
34
- metaflow/task.py,sha256=keErPaNH5gNko6V1saDT-qsICKu4EROau9DiCu4riHU,39192
34
+ metaflow/task.py,sha256=jnh_qteVIW0sP3Y2MBfJR2eEv_MGnOW1quPO_1OltH0,39244
35
35
  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=-kkCVrHWQPhCpJvbbJKGFXeit8uBl_Mos2kWpMTu48E,28
39
+ metaflow/version.py,sha256=GQnbrtyPirqYpqhPvarOOi5VzV-a2pEEafFGrBt3LNo,28
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
@@ -205,7 +205,7 @@ metaflow/plugins/debug_monitor.py,sha256=Md5X_sDOSssN9pt2D8YcaIjTK5JaQD55UAYTcF6
205
205
  metaflow/plugins/environment_decorator.py,sha256=6m9j2B77d-Ja_l_9CTJ__0O6aB2a8Qt_lAZu6UjAcUA,587
206
206
  metaflow/plugins/events_decorator.py,sha256=T_YSK-DlgZhd3ge9PlpTRNaMi15GK0tKZMZl1NdV9DQ,24403
207
207
  metaflow/plugins/logs_cli.py,sha256=77W5UNagU2mOKSMMvrQxQmBLRzvmjK-c8dWxd-Ygbqs,11410
208
- metaflow/plugins/package_cli.py,sha256=4OIBmuSSmQ6utWbeMln9HzQXnC9UYm3SilsHzf_sqbo,2002
208
+ metaflow/plugins/package_cli.py,sha256=GOxKJs9Wt0x9VtcTJ2EG_wj6pWnlS0XBFAyHpCzzuvs,2000
209
209
  metaflow/plugins/parallel_decorator.py,sha256=wtR_3eRIP3eV7fBIm15oouRjmHBFZ9OklxdaNvttLEQ,9702
210
210
  metaflow/plugins/project_decorator.py,sha256=uhwsguEj7OM_E2OnY1ap3MoGocQHeywuJSa-qPuWn-U,7592
211
211
  metaflow/plugins/resources_decorator.py,sha256=AtoOwg4mHYHYthg-CAfbfam-QiT0ViuDLDoukoDvF6Q,1347
@@ -230,7 +230,7 @@ metaflow/plugins/airflow/sensors/s3_sensor.py,sha256=iDReG-7FKnumrtQg-HY6cCUAAqN
230
230
  metaflow/plugins/argo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
231
231
  metaflow/plugins/argo/argo_client.py,sha256=jLz0FjCTBvFLZt-8lZcMQhDcInhgEcGdPrU2Gvh67zA,17080
232
232
  metaflow/plugins/argo/argo_events.py,sha256=_C1KWztVqgi3zuH57pInaE9OzABc2NnncC-zdwOMZ-w,5909
233
- metaflow/plugins/argo/argo_workflows.py,sha256=iSwLp-LA868pHE8C-ltW-J_W_qpP59UjFtqjXEj3lyI,200184
233
+ metaflow/plugins/argo/argo_workflows.py,sha256=URF89Inj4gXQJ5p4_nFPTQihj-LlQZP0yq38kIlmhKU,207599
234
234
  metaflow/plugins/argo/argo_workflows_cli.py,sha256=L5KwcT6Vd4HqAXFCPGmHUONgM2eOCTbvxdoIs6CQchw,51877
235
235
  metaflow/plugins/argo/argo_workflows_decorator.py,sha256=CLSjPqFTGucZ2_dSQGAYkoWWUZBQ9TCBXul4rxhDj3w,8282
236
236
  metaflow/plugins/argo/argo_workflows_deployer.py,sha256=6kHxEnYXJwzNCM9swI8-0AckxtPWqwhZLerYkX8fxUM,4444
@@ -421,19 +421,19 @@ metaflow/tutorials/08-autopilot/README.md,sha256=GnePFp_q76jPs991lMUqfIIh5zSorIe
421
421
  metaflow/tutorials/08-autopilot/autopilot.ipynb,sha256=DQoJlILV7Mq9vfPBGW-QV_kNhWPjS5n6SJLqePjFYLY,3191
422
422
  metaflow/user_configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
423
423
  metaflow/user_configs/config_options.py,sha256=d3hKA6WRPe21PdTl7sBnxIp5sE6zBpRtgAGx7hWkkfw,21380
424
- metaflow/user_configs/config_parameters.py,sha256=Loa5wu3vIs0SLyGhbOo8b88nWgCuZ09k24EqC_lI7n4,20890
424
+ metaflow/user_configs/config_parameters.py,sha256=1KZC1x7i-M-PfscIEOMUJ5NT2HTzFsB0HtNMTp_8hqE,20967
425
425
  metaflow/user_decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
426
426
  metaflow/user_decorators/common.py,sha256=0u9NRLQ95TfJCjWVEOGT4MJ9WoQgAMBM9kJ2gJGlVjk,5362
427
427
  metaflow/user_decorators/mutable_flow.py,sha256=EywKTN3cnXPQF_s62wQaC4a4aH14j8oeqzD3yZaiDxw,19467
428
428
  metaflow/user_decorators/mutable_step.py,sha256=-BY0UDXf_RCAEnC5JlLzEXGdiw1KD9oSrSxS_SWaB9Y,16791
429
429
  metaflow/user_decorators/user_flow_decorator.py,sha256=2yDwZq9QGv9W-7kEuKwa8o4ZkTvuHJ5ESz7VVrGViAI,9890
430
430
  metaflow/user_decorators/user_step_decorator.py,sha256=4558NR8RJtN22OyTwCXO80bAMhMTaRGMoX12b1GMcPc,27232
431
- metaflow-2.17.4.data/data/share/metaflow/devtools/Makefile,sha256=TT4TCq8ALSfqYyGqDPocN5oPcZe2FqoCZxmGO1LmyCc,13760
432
- metaflow-2.17.4.data/data/share/metaflow/devtools/Tiltfile,sha256=Ty5p6AD3MwJAcAnOGv4yMz8fExAsnNQ11r8whK6uzzw,21381
433
- metaflow-2.17.4.data/data/share/metaflow/devtools/pick_services.sh,sha256=DCnrMXwtApfx3B4S-YiZESMyAFHbXa3VuNL0MxPLyiE,2196
434
- metaflow-2.17.4.dist-info/licenses/LICENSE,sha256=nl_Lt5v9VvJ-5lWJDT4ddKAG-VZ-2IaLmbzpgYDz2hU,11343
435
- metaflow-2.17.4.dist-info/METADATA,sha256=fQRSl2xh3xdKu73eEo8LVKxaDwWTQJxk72v0LWzMHAs,6740
436
- metaflow-2.17.4.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
437
- metaflow-2.17.4.dist-info/entry_points.txt,sha256=RvEq8VFlgGe_FfqGOZi0D7ze1hLD0pAtXeNyGfzc_Yc,103
438
- metaflow-2.17.4.dist-info/top_level.txt,sha256=v1pDHoWaSaKeuc5fKTRSfsXCKSdW1zvNVmvA-i0if3o,9
439
- metaflow-2.17.4.dist-info/RECORD,,
431
+ metaflow-2.18.0.data/data/share/metaflow/devtools/Makefile,sha256=TT4TCq8ALSfqYyGqDPocN5oPcZe2FqoCZxmGO1LmyCc,13760
432
+ metaflow-2.18.0.data/data/share/metaflow/devtools/Tiltfile,sha256=Ty5p6AD3MwJAcAnOGv4yMz8fExAsnNQ11r8whK6uzzw,21381
433
+ metaflow-2.18.0.data/data/share/metaflow/devtools/pick_services.sh,sha256=DCnrMXwtApfx3B4S-YiZESMyAFHbXa3VuNL0MxPLyiE,2196
434
+ metaflow-2.18.0.dist-info/licenses/LICENSE,sha256=nl_Lt5v9VvJ-5lWJDT4ddKAG-VZ-2IaLmbzpgYDz2hU,11343
435
+ metaflow-2.18.0.dist-info/METADATA,sha256=Ic26QTgdp3FKW3w-l43idt6wchjKZWHfNrcN5bCUyeE,6740
436
+ metaflow-2.18.0.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
437
+ metaflow-2.18.0.dist-info/entry_points.txt,sha256=RvEq8VFlgGe_FfqGOZi0D7ze1hLD0pAtXeNyGfzc_Yc,103
438
+ metaflow-2.18.0.dist-info/top_level.txt,sha256=v1pDHoWaSaKeuc5fKTRSfsXCKSdW1zvNVmvA-i0if3o,9
439
+ metaflow-2.18.0.dist-info/RECORD,,