metaflow 2.12.19__tar.gz → 2.12.20__tar.gz

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 (361) hide show
  1. {metaflow-2.12.19/metaflow.egg-info → metaflow-2.12.20}/PKG-INFO +2 -2
  2. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/metaflow_current.py +3 -1
  3. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/argo/argo_workflows.py +10 -1
  4. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/batch/batch_client.py +3 -0
  5. metaflow-2.12.20/metaflow/plugins/kubernetes/kube_utils.py +25 -0
  6. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/kubernetes/kubernetes.py +3 -0
  7. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/kubernetes/kubernetes_cli.py +84 -1
  8. metaflow-2.12.20/metaflow/plugins/kubernetes/kubernetes_client.py +164 -0
  9. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/kubernetes/kubernetes_decorator.py +4 -0
  10. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/parallel_decorator.py +4 -0
  11. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/pypi/bootstrap.py +2 -0
  12. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/pypi/conda_decorator.py +6 -0
  13. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/runner/click_api.py +13 -1
  14. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/runner/deployer.py +9 -2
  15. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/runner/metaflow_runner.py +4 -2
  16. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/runner/subprocess_manager.py +8 -3
  17. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/runner/utils.py +19 -2
  18. metaflow-2.12.20/metaflow/version.py +1 -0
  19. {metaflow-2.12.19 → metaflow-2.12.20/metaflow.egg-info}/PKG-INFO +2 -2
  20. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow.egg-info/SOURCES.txt +1 -0
  21. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow.egg-info/requires.txt +1 -1
  22. metaflow-2.12.19/metaflow/plugins/kubernetes/kubernetes_client.py +0 -67
  23. metaflow-2.12.19/metaflow/version.py +0 -1
  24. {metaflow-2.12.19 → metaflow-2.12.20}/LICENSE +0 -0
  25. {metaflow-2.12.19 → metaflow-2.12.20}/MANIFEST.in +0 -0
  26. {metaflow-2.12.19 → metaflow-2.12.20}/README.md +0 -0
  27. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/R.py +0 -0
  28. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/__init__.py +0 -0
  29. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/__init__.py +0 -0
  30. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/__init__.py +0 -0
  31. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/_bashcomplete.py +0 -0
  32. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/_compat.py +0 -0
  33. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/_termui_impl.py +0 -0
  34. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/_textwrap.py +0 -0
  35. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/_unicodefun.py +0 -0
  36. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/_winconsole.py +0 -0
  37. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/core.py +0 -0
  38. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/decorators.py +0 -0
  39. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/exceptions.py +0 -0
  40. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/formatting.py +0 -0
  41. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/globals.py +0 -0
  42. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/parser.py +0 -0
  43. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/termui.py +0 -0
  44. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/testing.py +0 -0
  45. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/types.py +0 -0
  46. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/click/utils.py +0 -0
  47. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/__init__.py +0 -0
  48. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_adapters.py +0 -0
  49. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_collections.py +0 -0
  50. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_compat.py +0 -0
  51. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_functools.py +0 -0
  52. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_itertools.py +0 -0
  53. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_meta.py +0 -0
  54. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_text.py +0 -0
  55. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/py.typed +0 -0
  56. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/__init__.py +0 -0
  57. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/_elffile.py +0 -0
  58. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/_manylinux.py +0 -0
  59. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/_musllinux.py +0 -0
  60. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/_parser.py +0 -0
  61. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/_structures.py +0 -0
  62. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/_tokenizer.py +0 -0
  63. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/markers.py +0 -0
  64. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/py.typed +0 -0
  65. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/requirements.py +0 -0
  66. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/specifiers.py +0 -0
  67. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/tags.py +0 -0
  68. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/utils.py +0 -0
  69. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/packaging/version.py +0 -0
  70. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/__init__.py +0 -0
  71. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_checkers.py +0 -0
  72. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_config.py +0 -0
  73. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_decorators.py +0 -0
  74. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_exceptions.py +0 -0
  75. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_functions.py +0 -0
  76. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_importhook.py +0 -0
  77. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_memo.py +0 -0
  78. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_pytest_plugin.py +0 -0
  79. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_suppression.py +0 -0
  80. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_transformer.py +0 -0
  81. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_union_transformer.py +0 -0
  82. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_utils.py +0 -0
  83. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typeguard/py.typed +0 -0
  84. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/typing_extensions.py +0 -0
  85. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_5/__init__.py +0 -0
  86. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_5/importlib_metadata/__init__.py +0 -0
  87. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_5/importlib_metadata/_compat.py +0 -0
  88. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_5/zipp.py +0 -0
  89. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/__init__.py +0 -0
  90. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/__init__.py +0 -0
  91. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_adapters.py +0 -0
  92. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_collections.py +0 -0
  93. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_compat.py +0 -0
  94. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_functools.py +0 -0
  95. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_itertools.py +0 -0
  96. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_meta.py +0 -0
  97. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_text.py +0 -0
  98. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/py.typed +0 -0
  99. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/typing_extensions.py +0 -0
  100. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/v3_6/zipp.py +0 -0
  101. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/_vendor/zipp.py +0 -0
  102. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cards.py +0 -0
  103. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cli.py +0 -0
  104. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cli_args.py +0 -0
  105. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/client/__init__.py +0 -0
  106. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/client/core.py +0 -0
  107. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/client/filecache.py +0 -0
  108. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/clone_util.py +0 -0
  109. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cmd/__init__.py +0 -0
  110. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cmd/configure_cmd.py +0 -0
  111. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cmd/develop/__init__.py +0 -0
  112. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cmd/develop/stub_generator.py +0 -0
  113. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cmd/develop/stubs.py +0 -0
  114. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cmd/main_cli.py +0 -0
  115. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cmd/tutorials_cmd.py +0 -0
  116. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cmd/util.py +0 -0
  117. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/cmd_with_io.py +0 -0
  118. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/datastore/__init__.py +0 -0
  119. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/datastore/content_addressed_store.py +0 -0
  120. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/datastore/datastore_set.py +0 -0
  121. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/datastore/datastore_storage.py +0 -0
  122. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/datastore/exceptions.py +0 -0
  123. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/datastore/flow_datastore.py +0 -0
  124. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/datastore/inputs.py +0 -0
  125. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/datastore/task_datastore.py +0 -0
  126. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/debug.py +0 -0
  127. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/decorators.py +0 -0
  128. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/event_logger.py +0 -0
  129. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/events.py +0 -0
  130. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/exception.py +0 -0
  131. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/extension_support/__init__.py +0 -0
  132. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/extension_support/_empty_file.py +0 -0
  133. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/extension_support/cmd.py +0 -0
  134. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/extension_support/integrations.py +0 -0
  135. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/extension_support/plugins.py +0 -0
  136. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/flowspec.py +0 -0
  137. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/graph.py +0 -0
  138. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/includefile.py +0 -0
  139. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/integrations.py +0 -0
  140. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/lint.py +0 -0
  141. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/metadata/__init__.py +0 -0
  142. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/metadata/heartbeat.py +0 -0
  143. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/metadata/metadata.py +0 -0
  144. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/metadata/util.py +0 -0
  145. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/metaflow_config.py +0 -0
  146. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/metaflow_config_funcs.py +0 -0
  147. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/metaflow_environment.py +0 -0
  148. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/metaflow_profile.py +0 -0
  149. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/metaflow_version.py +0 -0
  150. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/mflog/__init__.py +0 -0
  151. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/mflog/mflog.py +0 -0
  152. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/mflog/save_logs.py +0 -0
  153. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/mflog/save_logs_periodically.py +0 -0
  154. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/mflog/tee.py +0 -0
  155. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/monitor.py +0 -0
  156. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/multicore_utils.py +0 -0
  157. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/package.py +0 -0
  158. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/parameters.py +0 -0
  159. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/__init__.py +0 -0
  160. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/__init__.py +0 -0
  161. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/airflow.py +0 -0
  162. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/airflow_cli.py +0 -0
  163. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/airflow_decorator.py +0 -0
  164. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/airflow_utils.py +0 -0
  165. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/dag.py +0 -0
  166. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/exception.py +0 -0
  167. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/plumbing/__init__.py +0 -0
  168. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/plumbing/set_parameters.py +0 -0
  169. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/sensors/__init__.py +0 -0
  170. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/sensors/base_sensor.py +0 -0
  171. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/sensors/external_task_sensor.py +0 -0
  172. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/airflow/sensors/s3_sensor.py +0 -0
  173. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/argo/__init__.py +0 -0
  174. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/argo/argo_client.py +0 -0
  175. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/argo/argo_events.py +0 -0
  176. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/argo/argo_workflows_cli.py +0 -0
  177. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/argo/argo_workflows_decorator.py +0 -0
  178. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/argo/argo_workflows_deployer.py +0 -0
  179. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/argo/capture_error.py +0 -0
  180. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/argo/daemon.py +0 -0
  181. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/argo/generate_input_paths.py +0 -0
  182. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/argo/jobset_input_paths.py +0 -0
  183. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/__init__.py +0 -0
  184. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/aws_client.py +0 -0
  185. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/aws_utils.py +0 -0
  186. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/batch/__init__.py +0 -0
  187. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/batch/batch.py +0 -0
  188. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/batch/batch_cli.py +0 -0
  189. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/batch/batch_decorator.py +0 -0
  190. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/secrets_manager/__init__.py +0 -0
  191. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/secrets_manager/aws_secrets_manager_secrets_provider.py +0 -0
  192. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/__init__.py +0 -0
  193. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/dynamo_db_client.py +0 -0
  194. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/event_bridge_client.py +0 -0
  195. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/production_token.py +0 -0
  196. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/schedule_decorator.py +0 -0
  197. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/set_batch_environment.py +0 -0
  198. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/step_functions.py +0 -0
  199. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/step_functions_cli.py +0 -0
  200. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/step_functions_client.py +0 -0
  201. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/step_functions_decorator.py +0 -0
  202. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/step_functions_deployer.py +0 -0
  203. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/azure/__init__.py +0 -0
  204. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/azure/azure_credential.py +0 -0
  205. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/azure/azure_exceptions.py +0 -0
  206. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/azure/azure_secret_manager_secrets_provider.py +0 -0
  207. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/azure/azure_tail.py +0 -0
  208. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/azure/azure_utils.py +0 -0
  209. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/azure/blob_service_client_factory.py +0 -0
  210. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/azure/includefile_support.py +0 -0
  211. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/__init__.py +0 -0
  212. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_cli.py +0 -0
  213. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_client.py +0 -0
  214. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_creator.py +0 -0
  215. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_datastore.py +0 -0
  216. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_decorator.py +0 -0
  217. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/__init__.py +0 -0
  218. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/base.html +0 -0
  219. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/basic.py +0 -0
  220. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/bundle.css +0 -0
  221. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/card.py +0 -0
  222. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/chevron/__init__.py +0 -0
  223. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/chevron/main.py +0 -0
  224. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/chevron/metadata.py +0 -0
  225. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/chevron/renderer.py +0 -0
  226. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/chevron/tokenizer.py +0 -0
  227. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/components.py +0 -0
  228. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/convert_to_native_type.py +0 -0
  229. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/main.js +0 -0
  230. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/renderer_tools.py +0 -0
  231. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/test_cards.py +0 -0
  232. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_resolver.py +0 -0
  233. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_server.py +0 -0
  234. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/card_viewer/viewer.html +0 -0
  235. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/component_serializer.py +0 -0
  236. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/cards/exception.py +0 -0
  237. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/catch_decorator.py +0 -0
  238. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datastores/__init__.py +0 -0
  239. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datastores/azure_storage.py +0 -0
  240. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datastores/gs_storage.py +0 -0
  241. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datastores/local_storage.py +0 -0
  242. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datastores/s3_storage.py +0 -0
  243. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datatools/__init__.py +0 -0
  244. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datatools/local.py +0 -0
  245. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datatools/s3/__init__.py +0 -0
  246. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datatools/s3/s3.py +0 -0
  247. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datatools/s3/s3op.py +0 -0
  248. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datatools/s3/s3tail.py +0 -0
  249. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/datatools/s3/s3util.py +0 -0
  250. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/debug_logger.py +0 -0
  251. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/debug_monitor.py +0 -0
  252. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/__init__.py +0 -0
  253. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/client.py +0 -0
  254. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/client_modules.py +0 -0
  255. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/communication/__init__.py +0 -0
  256. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/communication/bytestream.py +0 -0
  257. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/communication/channel.py +0 -0
  258. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/communication/socket_bytestream.py +0 -0
  259. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/communication/utils.py +0 -0
  260. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/configurations/emulate_test_lib/__init__.py +0 -0
  261. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/configurations/emulate_test_lib/overrides.py +0 -0
  262. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/configurations/emulate_test_lib/server_mappings.py +0 -0
  263. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/configurations/test_lib_impl/__init__.py +0 -0
  264. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/configurations/test_lib_impl/test_lib.py +0 -0
  265. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/consts.py +0 -0
  266. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/data_transferer.py +0 -0
  267. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/exception_transferer.py +0 -0
  268. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/override_decorators.py +0 -0
  269. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/server.py +0 -0
  270. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/stub.py +0 -0
  271. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/env_escape/utils.py +0 -0
  272. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/environment_decorator.py +0 -0
  273. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/events_decorator.py +0 -0
  274. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/frameworks/__init__.py +0 -0
  275. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/frameworks/pytorch.py +0 -0
  276. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/gcp/__init__.py +0 -0
  277. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/gcp/gcp_secret_manager_secrets_provider.py +0 -0
  278. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/gcp/gs_exceptions.py +0 -0
  279. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/gcp/gs_storage_client_factory.py +0 -0
  280. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/gcp/gs_tail.py +0 -0
  281. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/gcp/gs_utils.py +0 -0
  282. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/gcp/includefile_support.py +0 -0
  283. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/kubernetes/__init__.py +0 -0
  284. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/kubernetes/kubernetes_job.py +0 -0
  285. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/kubernetes/kubernetes_jobsets.py +0 -0
  286. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/logs_cli.py +0 -0
  287. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/metadata/__init__.py +0 -0
  288. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/metadata/local.py +0 -0
  289. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/metadata/service.py +0 -0
  290. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/package_cli.py +0 -0
  291. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/project_decorator.py +0 -0
  292. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/pypi/__init__.py +0 -0
  293. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/pypi/conda_environment.py +0 -0
  294. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/pypi/micromamba.py +0 -0
  295. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/pypi/pip.py +0 -0
  296. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/pypi/pypi_decorator.py +0 -0
  297. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/pypi/pypi_environment.py +0 -0
  298. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/pypi/utils.py +0 -0
  299. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/resources_decorator.py +0 -0
  300. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/retry_decorator.py +0 -0
  301. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/secrets/__init__.py +0 -0
  302. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/secrets/inline_secrets_provider.py +0 -0
  303. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/secrets/secrets_decorator.py +0 -0
  304. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/storage_executor.py +0 -0
  305. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/tag_cli.py +0 -0
  306. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/test_unbounded_foreach_decorator.py +0 -0
  307. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/plugins/timeout_decorator.py +0 -0
  308. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/procpoll.py +0 -0
  309. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/py.typed +0 -0
  310. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/pylint_wrapper.py +0 -0
  311. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/runner/__init__.py +0 -0
  312. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/runner/nbdeploy.py +0 -0
  313. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/runner/nbrun.py +0 -0
  314. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/runtime.py +0 -0
  315. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/sidecar/__init__.py +0 -0
  316. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/sidecar/sidecar.py +0 -0
  317. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/sidecar/sidecar_messages.py +0 -0
  318. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/sidecar/sidecar_subprocess.py +0 -0
  319. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/sidecar/sidecar_worker.py +0 -0
  320. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/system/__init__.py +0 -0
  321. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/system/system_logger.py +0 -0
  322. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/system/system_monitor.py +0 -0
  323. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/system/system_utils.py +0 -0
  324. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tagging_util.py +0 -0
  325. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/task.py +0 -0
  326. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tracing/__init__.py +0 -0
  327. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tracing/propagator.py +0 -0
  328. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tracing/span_exporter.py +0 -0
  329. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tracing/tracing_modules.py +0 -0
  330. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tuple_util.py +0 -0
  331. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/00-helloworld/README.md +0 -0
  332. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/00-helloworld/helloworld.py +0 -0
  333. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/01-playlist/README.md +0 -0
  334. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/01-playlist/movies.csv +0 -0
  335. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/01-playlist/playlist.ipynb +0 -0
  336. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/01-playlist/playlist.py +0 -0
  337. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/02-statistics/README.md +0 -0
  338. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/02-statistics/movies.csv +0 -0
  339. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/02-statistics/stats.ipynb +0 -0
  340. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/02-statistics/stats.py +0 -0
  341. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/03-playlist-redux/README.md +0 -0
  342. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/03-playlist-redux/playlist.py +0 -0
  343. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/04-playlist-plus/README.md +0 -0
  344. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/04-playlist-plus/playlist.py +0 -0
  345. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/05-hello-cloud/README.md +0 -0
  346. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/05-hello-cloud/hello-cloud.ipynb +0 -0
  347. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/05-hello-cloud/hello-cloud.py +0 -0
  348. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/06-statistics-redux/README.md +0 -0
  349. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/06-statistics-redux/stats.ipynb +0 -0
  350. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/07-worldview/README.md +0 -0
  351. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/07-worldview/worldview.ipynb +0 -0
  352. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/08-autopilot/README.md +0 -0
  353. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/tutorials/08-autopilot/autopilot.ipynb +0 -0
  354. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/unbounded_foreach.py +0 -0
  355. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/util.py +0 -0
  356. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow/vendor.py +0 -0
  357. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow.egg-info/dependency_links.txt +0 -0
  358. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow.egg-info/entry_points.txt +0 -0
  359. {metaflow-2.12.19 → metaflow-2.12.20}/metaflow.egg-info/top_level.txt +0 -0
  360. {metaflow-2.12.19 → metaflow-2.12.20}/setup.cfg +0 -0
  361. {metaflow-2.12.19 → metaflow-2.12.20}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: metaflow
3
- Version: 2.12.19
3
+ Version: 2.12.20
4
4
  Summary: Metaflow: More Data Science, 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.12.19; extra == "stubs"
29
+ Requires-Dist: metaflow-stubs==2.12.20; extra == "stubs"
30
30
 
31
31
  ![Metaflow_Logo_Horizontal_FullColor_Ribbon_Dark_RGB](https://user-images.githubusercontent.com/763451/89453116-96a57e00-d713-11ea-9fa6-82b29d4d6eff.png)
32
32
 
@@ -4,7 +4,9 @@ from typing import Any, Optional, TYPE_CHECKING
4
4
 
5
5
  from metaflow.metaflow_config import TEMPDIR
6
6
 
7
- Parallel = namedtuple("Parallel", ["main_ip", "num_nodes", "node_index"])
7
+ Parallel = namedtuple(
8
+ "Parallel", ["main_ip", "num_nodes", "node_index", "control_task_id"]
9
+ )
8
10
 
9
11
  if TYPE_CHECKING:
10
12
  import metaflow
@@ -1905,6 +1905,12 @@ class ArgoWorkflows(object):
1905
1905
  jobset.environment_variable(
1906
1906
  "MF_WORLD_SIZE", "{{inputs.parameters.num-parallel}}"
1907
1907
  )
1908
+ # We need this task-id set so that all the nodes are aware of the control
1909
+ # task's task-id. These "MF_" variables populate the `current.parallel` namedtuple
1910
+ jobset.environment_variable(
1911
+ "MF_PARALLEL_CONTROL_TASK_ID",
1912
+ "control-{{inputs.parameters.task-id-entropy}}-0",
1913
+ )
1908
1914
  # for k, v in .items():
1909
1915
  jobset.environment_variables_from_selectors(
1910
1916
  {
@@ -2552,8 +2558,8 @@ class ArgoWorkflows(object):
2552
2558
  cmd_str = " && ".join([init_cmds, heartbeat_cmds])
2553
2559
  cmds = shlex.split('bash -c "%s"' % cmd_str)
2554
2560
 
2555
- # TODO: Check that this is the minimal env.
2556
2561
  # Env required for sending heartbeats to the metadata service, nothing extra.
2562
+ # prod token / runtime info is required to correctly register flow branches
2557
2563
  env = {
2558
2564
  # These values are needed by Metaflow to set it's internal
2559
2565
  # state appropriately.
@@ -2565,7 +2571,10 @@ class ArgoWorkflows(object):
2565
2571
  "METAFLOW_USER": "argo-workflows",
2566
2572
  "METAFLOW_DEFAULT_DATASTORE": self.flow_datastore.TYPE,
2567
2573
  "METAFLOW_DEFAULT_METADATA": DEFAULT_METADATA,
2574
+ "METAFLOW_KUBERNETES_WORKLOAD": 1,
2575
+ "METAFLOW_RUNTIME_ENVIRONMENT": "kubernetes",
2568
2576
  "METAFLOW_OWNER": self.username,
2577
+ "METAFLOW_PRODUCTION_TOKEN": self.production_token,
2569
2578
  }
2570
2579
  # support Metaflow sandboxes
2571
2580
  env["METAFLOW_INIT_SCRIPT"] = KUBERNETES_SANDBOX_INIT_SCRIPT
@@ -89,6 +89,9 @@ class BatchJob(object):
89
89
  # Multinode
90
90
  if getattr(self, "num_parallel", 0) >= 1:
91
91
  num_nodes = self.num_parallel
92
+ # We need this task-id set so that all the nodes are aware of the control
93
+ # task's task-id. These "MF_" variables populate the `current.parallel` namedtuple
94
+ self.environment_variable("MF_PARALLEL_CONTROL_TASK_ID", self._task_id)
92
95
  main_task_override = copy.deepcopy(self.payload["containerOverrides"])
93
96
 
94
97
  # main
@@ -0,0 +1,25 @@
1
+ from metaflow.exception import CommandException
2
+ from metaflow.util import get_username, get_latest_run_id
3
+
4
+
5
+ def parse_cli_options(flow_name, run_id, user, my_runs, echo):
6
+ if user and my_runs:
7
+ raise CommandException("--user and --my-runs are mutually exclusive.")
8
+
9
+ if run_id and my_runs:
10
+ raise CommandException("--run_id and --my-runs are mutually exclusive.")
11
+
12
+ if my_runs:
13
+ user = get_username()
14
+
15
+ latest_run = True
16
+
17
+ if user and not run_id:
18
+ latest_run = False
19
+
20
+ if not run_id and latest_run:
21
+ run_id = get_latest_run_id(echo, flow_name)
22
+ if run_id is None:
23
+ raise CommandException("A previous run id was not found. Specify --run-id.")
24
+
25
+ return flow_name, run_id, user
@@ -401,6 +401,9 @@ class Kubernetes(object):
401
401
  .label("app.kubernetes.io/name", "metaflow-task")
402
402
  .label("app.kubernetes.io/part-of", "metaflow")
403
403
  )
404
+ # We need this task-id set so that all the nodes are aware of the control
405
+ # task's task-id. These "MF_" variables populate the `current.parallel` namedtuple
406
+ jobset.environment_variable("MF_PARALLEL_CONTROL_TASK_ID", str(task_id))
404
407
 
405
408
  ## ----------- control/worker specific values START here -----------
406
409
  # We will now set the appropriate command for the control/worker job
@@ -3,10 +3,12 @@ import sys
3
3
  import time
4
4
  import traceback
5
5
 
6
+ from metaflow.plugins.kubernetes.kube_utils import parse_cli_options
7
+ from metaflow.plugins.kubernetes.kubernetes_client import KubernetesClient
6
8
  import metaflow.tracing as tracing
7
9
  from metaflow import JSONTypeClass, util
8
10
  from metaflow._vendor import click
9
- from metaflow.exception import METAFLOW_EXIT_DISALLOW_RETRY, CommandException
11
+ from metaflow.exception import METAFLOW_EXIT_DISALLOW_RETRY, MetaflowException
10
12
  from metaflow.metadata.util import sync_local_metadata_from_datastore
11
13
  from metaflow.metaflow_config import DATASTORE_LOCAL_DIR, KUBERNETES_LABELS
12
14
  from metaflow.mflog import TASK_LOG_SOURCE
@@ -305,3 +307,84 @@ def step(
305
307
  sys.exit(METAFLOW_EXIT_DISALLOW_RETRY)
306
308
  finally:
307
309
  _sync_metadata()
310
+
311
+
312
+ @kubernetes.command(help="List unfinished Kubernetes tasks of this flow.")
313
+ @click.option(
314
+ "--my-runs",
315
+ default=False,
316
+ is_flag=True,
317
+ help="List all my unfinished tasks.",
318
+ )
319
+ @click.option("--user", default=None, help="List unfinished tasks for the given user.")
320
+ @click.option(
321
+ "--run-id",
322
+ default=None,
323
+ help="List unfinished tasks corresponding to the run id.",
324
+ )
325
+ @click.pass_obj
326
+ def list(obj, run_id, user, my_runs):
327
+ flow_name, run_id, user = parse_cli_options(
328
+ obj.flow.name, run_id, user, my_runs, obj.echo
329
+ )
330
+ kube_client = KubernetesClient()
331
+ pods = kube_client.list(obj.flow.name, run_id, user)
332
+
333
+ def format_timestamp(timestamp=None):
334
+ if timestamp is None:
335
+ return "-"
336
+ return timestamp.strftime("%Y-%m-%d %H:%M:%S")
337
+
338
+ for pod in pods:
339
+ obj.echo(
340
+ "Run: *{run_id}* "
341
+ "Pod: *{pod_id}* "
342
+ "Started At: {startedAt} "
343
+ "Status: *{status}*".format(
344
+ run_id=pod.metadata.annotations.get(
345
+ "metaflow/run_id",
346
+ pod.metadata.labels.get("workflows.argoproj.io/workflow"),
347
+ ),
348
+ pod_id=pod.metadata.name,
349
+ startedAt=format_timestamp(pod.status.start_time),
350
+ status=pod.status.phase,
351
+ )
352
+ )
353
+
354
+ if not pods:
355
+ obj.echo("No active Kubernetes pods found.")
356
+
357
+
358
+ @kubernetes.command(
359
+ help="Terminate unfinished Kubernetes tasks of this flow. Killed pods may result in newer attempts when using @retry."
360
+ )
361
+ @click.option(
362
+ "--my-runs",
363
+ default=False,
364
+ is_flag=True,
365
+ help="Kill all my unfinished tasks.",
366
+ )
367
+ @click.option(
368
+ "--user",
369
+ default=None,
370
+ help="Terminate unfinished tasks for the given user.",
371
+ )
372
+ @click.option(
373
+ "--run-id",
374
+ default=None,
375
+ help="Terminate unfinished tasks corresponding to the run id.",
376
+ )
377
+ @click.pass_obj
378
+ def kill(obj, run_id, user, my_runs):
379
+ flow_name, run_id, user = parse_cli_options(
380
+ obj.flow.name, run_id, user, my_runs, obj.echo
381
+ )
382
+
383
+ if run_id is not None and run_id.startswith("argo-") or user == "argo-workflows":
384
+ raise MetaflowException(
385
+ "Killing pods launched by Argo Workflows is not supported. "
386
+ "Use *argo-workflows terminate* instead."
387
+ )
388
+
389
+ kube_client = KubernetesClient()
390
+ kube_client.kill_pods(flow_name, run_id, user, obj.echo)
@@ -0,0 +1,164 @@
1
+ from concurrent.futures import ThreadPoolExecutor
2
+ import os
3
+ import sys
4
+ import time
5
+
6
+ from metaflow.exception import MetaflowException
7
+ from metaflow.metaflow_config import KUBERNETES_NAMESPACE
8
+
9
+ from .kubernetes_job import KubernetesJob, KubernetesJobSet
10
+
11
+ CLIENT_REFRESH_INTERVAL_SECONDS = 300
12
+
13
+
14
+ class KubernetesClientException(MetaflowException):
15
+ headline = "Kubernetes client error"
16
+
17
+
18
+ class KubernetesClient(object):
19
+ def __init__(self):
20
+ try:
21
+ # Kubernetes is a soft dependency.
22
+ from kubernetes import client, config
23
+ except (NameError, ImportError):
24
+ raise KubernetesClientException(
25
+ "Could not import module 'kubernetes'.\n\nInstall Kubernetes "
26
+ "Python package (https://pypi.org/project/kubernetes/) first.\n"
27
+ "You can install the module by executing - "
28
+ "%s -m pip install kubernetes\n"
29
+ "or equivalent through your favorite Python package manager."
30
+ % sys.executable
31
+ )
32
+ self._refresh_client()
33
+ self._namespace = KUBERNETES_NAMESPACE
34
+
35
+ def _refresh_client(self):
36
+ from kubernetes import client, config
37
+
38
+ if os.getenv("KUBECONFIG"):
39
+ # There are cases where we're running inside a pod, but can't use
40
+ # the kubernetes client for that pod's cluster: for example when
41
+ # running in Bitbucket Cloud or other CI system.
42
+ # In this scenario, the user can set a KUBECONFIG environment variable
43
+ # to load the kubeconfig, regardless of whether we're in a pod or not.
44
+ config.load_kube_config()
45
+ elif os.getenv("KUBERNETES_SERVICE_HOST"):
46
+ # We are inside a pod, authenticate via ServiceAccount assigned to us
47
+ config.load_incluster_config()
48
+ else:
49
+ # Default to using kubeconfig, likely $HOME/.kube/config
50
+ # TODO (savin):
51
+ # 1. Support generating kubeconfig on the fly using boto3
52
+ # 2. Support auth via OIDC - https://docs.aws.amazon.com/eks/latest/userguide/authenticate-oidc-identity-provider.html
53
+ config.load_kube_config()
54
+ self._client = client
55
+ self._client_refresh_timestamp = time.time()
56
+
57
+ def get(self):
58
+ if (
59
+ time.time() - self._client_refresh_timestamp
60
+ > CLIENT_REFRESH_INTERVAL_SECONDS
61
+ ):
62
+ self._refresh_client()
63
+
64
+ return self._client
65
+
66
+ def _find_active_pods(self, flow_name, run_id=None, user=None):
67
+ def _request(_continue=None):
68
+ # handle paginated responses
69
+ return self._client.CoreV1Api().list_namespaced_pod(
70
+ namespace=self._namespace,
71
+ # limited selector support for K8S api. We want to cover multiple statuses: Running / Pending / Unknown
72
+ field_selector="status.phase!=Succeeded,status.phase!=Failed",
73
+ limit=1000,
74
+ _continue=_continue,
75
+ )
76
+
77
+ results = _request()
78
+
79
+ if run_id is not None:
80
+ # handle argo prefixes in run_id
81
+ run_id = run_id[run_id.startswith("argo-") and len("argo-") :]
82
+
83
+ while results.metadata._continue or results.items:
84
+ for pod in results.items:
85
+ match = (
86
+ # arbitrary pods might have no annotations at all.
87
+ pod.metadata.annotations
88
+ and pod.metadata.labels
89
+ and (
90
+ run_id is None
91
+ or (pod.metadata.annotations.get("metaflow/run_id") == run_id)
92
+ # we want to also match pods launched by argo-workflows
93
+ or (
94
+ pod.metadata.labels.get("workflows.argoproj.io/workflow")
95
+ == run_id
96
+ )
97
+ )
98
+ and (
99
+ user is None
100
+ or pod.metadata.annotations.get("metaflow/user") == user
101
+ )
102
+ and (
103
+ pod.metadata.annotations.get("metaflow/flow_name") == flow_name
104
+ )
105
+ )
106
+ if match:
107
+ yield pod
108
+ if not results.metadata._continue:
109
+ break
110
+ results = _request(results.metadata._continue)
111
+
112
+ def list(self, flow_name, run_id, user):
113
+ results = self._find_active_pods(flow_name, run_id, user)
114
+
115
+ return list(results)
116
+
117
+ def kill_pods(self, flow_name, run_id, user, echo):
118
+ from kubernetes.stream import stream
119
+
120
+ api_instance = self._client.CoreV1Api()
121
+ job_api = self._client.BatchV1Api()
122
+ pods = self._find_active_pods(flow_name, run_id, user)
123
+
124
+ def _kill_pod(pod):
125
+ echo("Killing Kubernetes pod %s\n" % pod.metadata.name)
126
+ try:
127
+ stream(
128
+ api_instance.connect_get_namespaced_pod_exec,
129
+ name=pod.metadata.name,
130
+ namespace=pod.metadata.namespace,
131
+ command=[
132
+ "/bin/sh",
133
+ "-c",
134
+ "/sbin/killall5",
135
+ ],
136
+ stderr=True,
137
+ stdin=False,
138
+ stdout=True,
139
+ tty=False,
140
+ )
141
+ except Exception:
142
+ # best effort kill for pod can fail.
143
+ try:
144
+ job_name = pod.metadata.labels.get("job-name", None)
145
+ if job_name is None:
146
+ raise Exception("Could not determine job name")
147
+
148
+ job_api.patch_namespaced_job(
149
+ name=job_name,
150
+ namespace=pod.metadata.namespace,
151
+ field_manager="metaflow",
152
+ body={"spec": {"parallelism": 0}},
153
+ )
154
+ except Exception as e:
155
+ echo("failed to kill pod %s - %s" % (pod.metadata.name, str(e)))
156
+
157
+ with ThreadPoolExecutor() as executor:
158
+ executor.map(_kill_pod, list(pods))
159
+
160
+ def jobset(self, **kwargs):
161
+ return KubernetesJobSet(self, **kwargs)
162
+
163
+ def job(self, **kwargs):
164
+ return KubernetesJob(self, **kwargs)
@@ -70,6 +70,10 @@ class KubernetesDecorator(StepDecorator):
70
70
  Kubernetes secrets to use when launching pod in Kubernetes. These
71
71
  secrets are in addition to the ones defined in `METAFLOW_KUBERNETES_SECRETS`
72
72
  in Metaflow configuration.
73
+ node_selector: Union[Dict[str,str], str], optional, default None
74
+ Kubernetes node selector(s) to apply to the pod running the task.
75
+ Can be passed in as a comma separated string of values e.g. "kubernetes.io/os=linux,kubernetes.io/arch=amd64"
76
+ or as a dictionary {"kubernetes.io/os": "linux", "kubernetes.io/arch": "amd64"}
73
77
  namespace : str, default METAFLOW_KUBERNETES_NAMESPACE
74
78
  Kubernetes namespace to use when launching pod in Kubernetes.
75
79
  gpu : int, optional, default None
@@ -24,6 +24,8 @@ class ParallelDecorator(StepDecorator):
24
24
  The total number of tasks created by @parallel
25
25
  - node_index : int
26
26
  The index of the current task in all the @parallel tasks.
27
+ - control_task_id : Optional[str]
28
+ The task ID of the control task. Available to all tasks.
27
29
 
28
30
  is_parallel -> bool
29
31
  True if the current step is a @parallel step.
@@ -67,6 +69,7 @@ class ParallelDecorator(StepDecorator):
67
69
  main_ip=os.environ.get("MF_PARALLEL_MAIN_IP", "127.0.0.1"),
68
70
  num_nodes=int(os.environ.get("MF_PARALLEL_NUM_NODES", "1")),
69
71
  node_index=int(os.environ.get("MF_PARALLEL_NODE_INDEX", "0")),
72
+ control_task_id=os.environ.get("MF_PARALLEL_CONTROL_TASK_ID", None),
70
73
  )
71
74
  ),
72
75
  )
@@ -177,6 +180,7 @@ def _local_multinode_control_task_step_func(
177
180
  num_parallel = foreach_iter.num_parallel
178
181
  os.environ["MF_PARALLEL_NUM_NODES"] = str(num_parallel)
179
182
  os.environ["MF_PARALLEL_MAIN_IP"] = "127.0.0.1"
183
+ os.environ["MF_PARALLEL_CONTROL_TASK_ID"] = str(current.task_id)
180
184
 
181
185
  run_id = current.run_id
182
186
  step_name = current.step_name
@@ -103,6 +103,7 @@ if __name__ == "__main__":
103
103
  echo "@EXPLICIT" > "$tmpfile";
104
104
  ls -d {conda_pkgs_dir}/*/* >> "$tmpfile";
105
105
  export PATH=$PATH:$(pwd)/micromamba;
106
+ export CONDA_PKGS_DIRS=$(pwd)/micromamba/pkgs;
106
107
  micromamba create --yes --offline --no-deps --safety-checks=disabled --no-extra-safety-checks --prefix {prefix} --file "$tmpfile";
107
108
  rm "$tmpfile"''',
108
109
  ]
@@ -123,6 +124,7 @@ if __name__ == "__main__":
123
124
  [
124
125
  f"""set -e;
125
126
  export PATH=$PATH:$(pwd)/micromamba;
127
+ export CONDA_PKGS_DIRS=$(pwd)/micromamba/pkgs;
126
128
  micromamba run --prefix {prefix} python -m pip --disable-pip-version-check install --root-user-action=ignore --no-compile {pypi_pkgs_dir}/*.whl --no-user"""
127
129
  ]
128
130
  )
@@ -353,6 +353,12 @@ class CondaFlowDecorator(FlowDecorator):
353
353
  def flow_init(
354
354
  self, flow, graph, environment, flow_datastore, metadata, logger, echo, options
355
355
  ):
356
+ # NOTE: Important for extensions implementing custom virtual environments.
357
+ # Without this steps will not have an implicit conda step decorator on them unless the environment adds one in its decospecs.
358
+ from metaflow import decorators
359
+
360
+ decorators._attach_decorators(flow, ["conda"])
361
+
356
362
  # @conda uses a conda environment to create a virtual environment.
357
363
  # The conda environment can be created through micromamba.
358
364
  _supported_virtual_envs = ["conda"]
@@ -1,3 +1,4 @@
1
+ import os
1
2
  import sys
2
3
 
3
4
  if sys.version_info < (3, 7):
@@ -12,6 +13,7 @@ import importlib
12
13
  import inspect
13
14
  import itertools
14
15
  import uuid
16
+ import json
15
17
  from collections import OrderedDict
16
18
  from typing import Any, Callable, Dict, List, Optional
17
19
  from typing import OrderedDict as TOrderedDict
@@ -37,6 +39,9 @@ from metaflow.exception import MetaflowException
37
39
  from metaflow.includefile import FilePathClass
38
40
  from metaflow.parameters import JSONTypeClass, flow_context
39
41
 
42
+ # Define a recursive type alias for JSON
43
+ JSON = Union[Dict[str, "JSON"], List["JSON"], str, int, float, bool, None]
44
+
40
45
  click_to_python_types = {
41
46
  StringParamType: str,
42
47
  IntParamType: int,
@@ -48,7 +53,7 @@ click_to_python_types = {
48
53
  Tuple: tuple,
49
54
  Choice: str,
50
55
  File: str,
51
- JSONTypeClass: str,
56
+ JSONTypeClass: JSON,
52
57
  FilePathClass: str,
53
58
  }
54
59
 
@@ -82,6 +87,11 @@ def _method_sanity_check(
82
87
  % (supplied_k, annotations[supplied_k], defaults[supplied_k])
83
88
  )
84
89
 
90
+ # because Click expects stringified JSON..
91
+ supplied_v = (
92
+ json.dumps(supplied_v) if annotations[supplied_k] == JSON else supplied_v
93
+ )
94
+
85
95
  if supplied_k in possible_arg_params:
86
96
  cli_name = possible_arg_params[supplied_k].opts[0].strip("-")
87
97
  method_params["args"][cli_name] = supplied_v
@@ -142,6 +152,8 @@ loaded_modules = {}
142
152
 
143
153
 
144
154
  def extract_flow_class_from_file(flow_file: str) -> FlowSpec:
155
+ if not os.path.exists(flow_file):
156
+ raise FileNotFoundError("Flow file not present at '%s'" % flow_file)
145
157
  # Check if the module has already been loaded
146
158
  if flow_file in loaded_modules:
147
159
  module = loaded_modules[flow_file]
@@ -5,6 +5,8 @@ import time
5
5
  import importlib
6
6
  import functools
7
7
  import tempfile
8
+
9
+ from subprocess import CalledProcessError
8
10
  from typing import Optional, Dict, ClassVar
9
11
 
10
12
  from metaflow.exception import MetaflowNotFound
@@ -25,6 +27,8 @@ def handle_timeout(
25
27
  Temporary file that stores runner attribute data.
26
28
  command_obj : CommandManager
27
29
  Command manager object that encapsulates the running command details.
30
+ file_read_timeout : int
31
+ Timeout for reading the file.
28
32
 
29
33
  Returns
30
34
  -------
@@ -39,10 +43,10 @@ def handle_timeout(
39
43
  """
40
44
  try:
41
45
  content = read_from_file_when_ready(
42
- tfp_runner_attribute.name, timeout=file_read_timeout
46
+ tfp_runner_attribute.name, command_obj, timeout=file_read_timeout
43
47
  )
44
48
  return content
45
- except TimeoutError as e:
49
+ except (CalledProcessError, TimeoutError) as e:
46
50
  stdout_log = open(command_obj.log_files["stdout"]).read()
47
51
  stderr_log = open(command_obj.log_files["stderr"]).read()
48
52
  command = " ".join(command_obj.command)
@@ -397,6 +401,9 @@ class DeployerImpl(object):
397
401
  self.name = content.get("name")
398
402
  self.flow_name = content.get("flow_name")
399
403
  self.metadata = content.get("metadata")
404
+ # Additional info is used to pass additional deployer specific information.
405
+ # It is used in non-OSS deployers (extensions).
406
+ self.additional_info = content.get("additional_info", {})
400
407
 
401
408
  if command_obj.process.returncode == 0:
402
409
  deployed_flow = DeployedFlow(deployer=self)
@@ -2,6 +2,8 @@ import importlib
2
2
  import os
3
3
  import sys
4
4
  import tempfile
5
+
6
+ from subprocess import CalledProcessError
5
7
  from typing import Dict, Iterator, Optional, Tuple
6
8
 
7
9
  from metaflow import Run, metadata
@@ -275,13 +277,13 @@ class Runner(object):
275
277
 
276
278
  # Set the correct metadata from the runner_attribute file corresponding to this run.
277
279
  content = read_from_file_when_ready(
278
- tfp_runner_attribute.name, timeout=self.file_read_timeout
280
+ tfp_runner_attribute.name, command_obj, timeout=self.file_read_timeout
279
281
  )
280
282
  metadata_for_flow, pathspec = content.rsplit(":", maxsplit=1)
281
283
  metadata(metadata_for_flow)
282
284
  run_object = Run(pathspec, _namespace_check=False)
283
285
  return ExecutingRun(self, command_obj, run_object)
284
- except TimeoutError as e:
286
+ except (CalledProcessError, TimeoutError) as e:
285
287
  stdout_log = open(command_obj.log_files["stdout"]).read()
286
288
  stderr_log = open(command_obj.log_files["stderr"]).read()
287
289
  command = " ".join(command_obj.command)
@@ -1,18 +1,22 @@
1
1
  import asyncio
2
2
  import os
3
+ import time
3
4
  import shutil
4
5
  import signal
5
6
  import subprocess
6
7
  import sys
7
8
  import tempfile
8
9
  import threading
9
- import time
10
10
  from typing import Callable, Dict, Iterator, List, Optional, Tuple
11
11
 
12
12
 
13
13
  def kill_process_and_descendants(pid, termination_timeout):
14
+ # TODO: there's a race condition that new descendants might
15
+ # spawn b/w the invocations of 'pkill' and 'kill'.
16
+ # Needs to be fixed in future.
14
17
  try:
15
18
  subprocess.check_call(["pkill", "-TERM", "-P", str(pid)])
19
+ subprocess.check_call(["kill", "-TERM", str(pid)])
16
20
  except subprocess.CalledProcessError:
17
21
  pass
18
22
 
@@ -20,6 +24,7 @@ def kill_process_and_descendants(pid, termination_timeout):
20
24
 
21
25
  try:
22
26
  subprocess.check_call(["pkill", "-KILL", "-P", str(pid)])
27
+ subprocess.check_call(["kill", "-KILL", str(pid)])
23
28
  except subprocess.CalledProcessError:
24
29
  pass
25
30
 
@@ -436,13 +441,13 @@ class CommandManager(object):
436
441
  if self.run_called:
437
442
  shutil.rmtree(self.temp_dir, ignore_errors=True)
438
443
 
439
- async def kill(self, termination_timeout: float = 1):
444
+ async def kill(self, termination_timeout: float = 5):
440
445
  """
441
446
  Kill the subprocess and its descendants.
442
447
 
443
448
  Parameters
444
449
  ----------
445
- termination_timeout : float, default 1
450
+ termination_timeout : float, default 5
446
451
  The time to wait after sending a SIGTERM to the process and its descendants
447
452
  before sending a SIGKILL.
448
453
  """
@@ -1,7 +1,12 @@
1
1
  import os
2
2
  import ast
3
3
  import time
4
- from typing import Dict
4
+
5
+ from subprocess import CalledProcessError
6
+ from typing import Dict, TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ from .subprocess_manager import CommandManager
5
10
 
6
11
 
7
12
  def get_current_cell(ipython):
@@ -35,11 +40,23 @@ def clear_and_set_os_environ(env: Dict):
35
40
  os.environ.update(env)
36
41
 
37
42
 
38
- def read_from_file_when_ready(file_path: str, timeout: float = 5):
43
+ def read_from_file_when_ready(
44
+ file_path: str, command_obj: "CommandManager", timeout: float = 5
45
+ ):
39
46
  start_time = time.time()
40
47
  with open(file_path, "r", encoding="utf-8") as file_pointer:
41
48
  content = file_pointer.read()
42
49
  while not content:
50
+ if command_obj.process.poll() is not None:
51
+ # Check to make sure the file hasn't been read yet to avoid a race
52
+ # where the file is written between the end of this while loop and the
53
+ # poll call above.
54
+ content = file_pointer.read()
55
+ if content:
56
+ break
57
+ raise CalledProcessError(
58
+ command_obj.process.returncode, command_obj.command
59
+ )
43
60
  if time.time() - start_time > timeout:
44
61
  raise TimeoutError(
45
62
  "Timeout while waiting for file content from '%s'" % file_path
@@ -0,0 +1 @@
1
+ metaflow_version = "2.12.20"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: metaflow
3
- Version: 2.12.19
3
+ Version: 2.12.20
4
4
  Summary: Metaflow: More Data Science, 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.12.19; extra == "stubs"
29
+ Requires-Dist: metaflow-stubs==2.12.20; extra == "stubs"
30
30
 
31
31
  ![Metaflow_Logo_Horizontal_FullColor_Ribbon_Dark_RGB](https://user-images.githubusercontent.com/763451/89453116-96a57e00-d713-11ea-9fa6-82b29d4d6eff.png)
32
32