metaflow 2.12.18__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.
- {metaflow-2.12.18/metaflow.egg-info → metaflow-2.12.20}/PKG-INFO +2 -2
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/metaflow_current.py +3 -1
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/argo/argo_workflows.py +10 -1
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/batch/batch_client.py +3 -0
- metaflow-2.12.20/metaflow/plugins/kubernetes/kube_utils.py +25 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/kubernetes/kubernetes.py +5 -2
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/kubernetes/kubernetes_cli.py +84 -1
- metaflow-2.12.20/metaflow/plugins/kubernetes/kubernetes_client.py +164 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/kubernetes/kubernetes_decorator.py +4 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/kubernetes/kubernetes_jobsets.py +0 -2
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/parallel_decorator.py +4 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/pypi/bootstrap.py +2 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/pypi/conda_decorator.py +24 -1
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/pypi/pypi_decorator.py +18 -1
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/runner/click_api.py +13 -1
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/runner/deployer.py +9 -2
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/runner/metaflow_runner.py +4 -2
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/runner/subprocess_manager.py +8 -3
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/runner/utils.py +19 -2
- metaflow-2.12.20/metaflow/version.py +1 -0
- {metaflow-2.12.18 → metaflow-2.12.20/metaflow.egg-info}/PKG-INFO +2 -2
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow.egg-info/SOURCES.txt +1 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow.egg-info/requires.txt +1 -1
- metaflow-2.12.18/metaflow/plugins/kubernetes/kubernetes_client.py +0 -67
- metaflow-2.12.18/metaflow/version.py +0 -1
- {metaflow-2.12.18 → metaflow-2.12.20}/LICENSE +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/MANIFEST.in +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/README.md +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/R.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/_bashcomplete.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/_compat.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/_termui_impl.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/_textwrap.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/_unicodefun.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/_winconsole.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/core.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/decorators.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/exceptions.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/formatting.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/globals.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/parser.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/termui.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/testing.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/types.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/click/utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_adapters.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_collections.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_compat.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_functools.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_itertools.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_meta.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/_text.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/importlib_metadata/py.typed +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/_elffile.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/_manylinux.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/_musllinux.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/_parser.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/_structures.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/_tokenizer.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/markers.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/py.typed +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/requirements.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/specifiers.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/tags.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/packaging/version.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_checkers.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_config.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_decorators.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_exceptions.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_functions.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_importhook.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_memo.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_pytest_plugin.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_suppression.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_transformer.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_union_transformer.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/_utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typeguard/py.typed +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/typing_extensions.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_5/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_5/importlib_metadata/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_5/importlib_metadata/_compat.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_5/zipp.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_adapters.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_collections.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_compat.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_functools.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_itertools.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_meta.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/_text.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/importlib_metadata/py.typed +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/typing_extensions.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/v3_6/zipp.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/_vendor/zipp.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cards.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cli.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cli_args.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/client/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/client/core.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/client/filecache.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/clone_util.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cmd/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cmd/configure_cmd.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cmd/develop/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cmd/develop/stub_generator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cmd/develop/stubs.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cmd/main_cli.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cmd/tutorials_cmd.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cmd/util.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/cmd_with_io.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/datastore/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/datastore/content_addressed_store.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/datastore/datastore_set.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/datastore/datastore_storage.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/datastore/exceptions.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/datastore/flow_datastore.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/datastore/inputs.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/datastore/task_datastore.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/debug.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/decorators.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/event_logger.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/events.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/exception.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/extension_support/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/extension_support/_empty_file.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/extension_support/cmd.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/extension_support/integrations.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/extension_support/plugins.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/flowspec.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/graph.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/includefile.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/integrations.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/lint.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/metadata/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/metadata/heartbeat.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/metadata/metadata.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/metadata/util.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/metaflow_config.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/metaflow_config_funcs.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/metaflow_environment.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/metaflow_profile.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/metaflow_version.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/mflog/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/mflog/mflog.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/mflog/save_logs.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/mflog/save_logs_periodically.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/mflog/tee.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/monitor.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/multicore_utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/package.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/parameters.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/airflow.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/airflow_cli.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/airflow_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/airflow_utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/dag.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/exception.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/plumbing/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/plumbing/set_parameters.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/sensors/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/sensors/base_sensor.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/sensors/external_task_sensor.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/airflow/sensors/s3_sensor.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/argo/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/argo/argo_client.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/argo/argo_events.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/argo/argo_workflows_cli.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/argo/argo_workflows_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/argo/argo_workflows_deployer.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/argo/capture_error.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/argo/daemon.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/argo/generate_input_paths.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/argo/jobset_input_paths.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/aws_client.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/aws_utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/batch/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/batch/batch.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/batch/batch_cli.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/batch/batch_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/secrets_manager/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/secrets_manager/aws_secrets_manager_secrets_provider.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/dynamo_db_client.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/event_bridge_client.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/production_token.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/schedule_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/set_batch_environment.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/step_functions.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/step_functions_cli.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/step_functions_client.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/step_functions_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/aws/step_functions/step_functions_deployer.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/azure/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/azure/azure_credential.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/azure/azure_exceptions.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/azure/azure_secret_manager_secrets_provider.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/azure/azure_tail.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/azure/azure_utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/azure/blob_service_client_factory.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/azure/includefile_support.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_cli.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_client.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_creator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_datastore.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/base.html +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/basic.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/bundle.css +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/card.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/chevron/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/chevron/main.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/chevron/metadata.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/chevron/renderer.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/chevron/tokenizer.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/components.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/convert_to_native_type.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/main.js +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/renderer_tools.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_modules/test_cards.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_resolver.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_server.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/card_viewer/viewer.html +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/component_serializer.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/cards/exception.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/catch_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datastores/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datastores/azure_storage.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datastores/gs_storage.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datastores/local_storage.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datastores/s3_storage.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datatools/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datatools/local.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datatools/s3/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datatools/s3/s3.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datatools/s3/s3op.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datatools/s3/s3tail.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/datatools/s3/s3util.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/debug_logger.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/debug_monitor.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/client.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/client_modules.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/communication/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/communication/bytestream.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/communication/channel.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/communication/socket_bytestream.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/communication/utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/configurations/emulate_test_lib/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/configurations/emulate_test_lib/overrides.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/configurations/emulate_test_lib/server_mappings.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/configurations/test_lib_impl/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/configurations/test_lib_impl/test_lib.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/consts.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/data_transferer.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/exception_transferer.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/override_decorators.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/server.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/stub.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/env_escape/utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/environment_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/events_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/frameworks/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/frameworks/pytorch.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/gcp/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/gcp/gcp_secret_manager_secrets_provider.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/gcp/gs_exceptions.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/gcp/gs_storage_client_factory.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/gcp/gs_tail.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/gcp/gs_utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/gcp/includefile_support.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/kubernetes/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/kubernetes/kubernetes_job.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/logs_cli.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/metadata/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/metadata/local.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/metadata/service.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/package_cli.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/project_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/pypi/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/pypi/conda_environment.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/pypi/micromamba.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/pypi/pip.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/pypi/pypi_environment.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/pypi/utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/resources_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/retry_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/secrets/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/secrets/inline_secrets_provider.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/secrets/secrets_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/storage_executor.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/tag_cli.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/test_unbounded_foreach_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/plugins/timeout_decorator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/procpoll.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/py.typed +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/pylint_wrapper.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/runner/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/runner/nbdeploy.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/runner/nbrun.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/runtime.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/sidecar/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/sidecar/sidecar.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/sidecar/sidecar_messages.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/sidecar/sidecar_subprocess.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/sidecar/sidecar_worker.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/system/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/system/system_logger.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/system/system_monitor.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/system/system_utils.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tagging_util.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/task.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tracing/__init__.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tracing/propagator.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tracing/span_exporter.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tracing/tracing_modules.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tuple_util.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/00-helloworld/README.md +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/00-helloworld/helloworld.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/01-playlist/README.md +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/01-playlist/movies.csv +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/01-playlist/playlist.ipynb +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/01-playlist/playlist.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/02-statistics/README.md +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/02-statistics/movies.csv +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/02-statistics/stats.ipynb +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/02-statistics/stats.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/03-playlist-redux/README.md +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/03-playlist-redux/playlist.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/04-playlist-plus/README.md +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/04-playlist-plus/playlist.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/05-hello-cloud/README.md +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/05-hello-cloud/hello-cloud.ipynb +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/05-hello-cloud/hello-cloud.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/06-statistics-redux/README.md +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/06-statistics-redux/stats.ipynb +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/07-worldview/README.md +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/07-worldview/worldview.ipynb +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/08-autopilot/README.md +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/tutorials/08-autopilot/autopilot.ipynb +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/unbounded_foreach.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/util.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow/vendor.py +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow.egg-info/dependency_links.txt +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow.egg-info/entry_points.txt +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/metaflow.egg-info/top_level.txt +0 -0
- {metaflow-2.12.18 → metaflow-2.12.20}/setup.cfg +0 -0
- {metaflow-2.12.18 → 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.
|
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.
|
29
|
+
Requires-Dist: metaflow-stubs==2.12.20; extra == "stubs"
|
30
30
|
|
31
31
|

|
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(
|
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
|
@@ -698,7 +701,7 @@ class Kubernetes(object):
|
|
698
701
|
t = time.time()
|
699
702
|
time.sleep(update_delay(time.time() - start_time))
|
700
703
|
|
701
|
-
|
704
|
+
prefix = lambda: b"[%s] " % util.to_bytes(self._job.id)
|
702
705
|
|
703
706
|
stdout_tail = get_log_tailer(stdout_location, self._datastore.TYPE)
|
704
707
|
stderr_tail = get_log_tailer(stderr_location, self._datastore.TYPE)
|
@@ -708,7 +711,7 @@ class Kubernetes(object):
|
|
708
711
|
|
709
712
|
# 2) Tail logs until the job has finished
|
710
713
|
tail_logs(
|
711
|
-
prefix=
|
714
|
+
prefix=prefix(),
|
712
715
|
stdout_tail=stdout_tail,
|
713
716
|
stderr_tail=stderr_tail,
|
714
717
|
echo=echo,
|
@@ -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,
|
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
|
@@ -571,10 +571,8 @@ class JobSetSpec(object):
|
|
571
571
|
namespace=self._kwargs["namespace"],
|
572
572
|
),
|
573
573
|
spec=client.V1PodSpec(
|
574
|
-
## --- jobset require podspec deets start----
|
575
574
|
subdomain=self._kwargs["subdomain"],
|
576
575
|
set_hostname_as_fqdn=True,
|
577
|
-
## --- jobset require podspec deets end ----
|
578
576
|
# Timeout is set on the pod and not the job (important!)
|
579
577
|
active_deadline_seconds=self._kwargs[
|
580
578
|
"timeout_in_seconds"
|
@@ -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
|
)
|
@@ -50,6 +50,9 @@ class CondaStepDecorator(StepDecorator):
|
|
50
50
|
# conda channels, users can specify channel::package as the package name.
|
51
51
|
|
52
52
|
def __init__(self, attributes=None, statically_defined=False):
|
53
|
+
self._user_defined_attributes = (
|
54
|
+
attributes.copy() if attributes is not None else {}
|
55
|
+
)
|
53
56
|
super(CondaStepDecorator, self).__init__(attributes, statically_defined)
|
54
57
|
|
55
58
|
# Support legacy 'libraries=' attribute for the decorator.
|
@@ -59,6 +62,9 @@ class CondaStepDecorator(StepDecorator):
|
|
59
62
|
}
|
60
63
|
del self.attributes["libraries"]
|
61
64
|
|
65
|
+
def is_attribute_user_defined(self, name):
|
66
|
+
return name in self._user_defined_attributes
|
67
|
+
|
62
68
|
def step_init(self, flow, graph, step, decos, environment, flow_datastore, logger):
|
63
69
|
# The init_environment hook for Environment creates the relevant virtual
|
64
70
|
# environments. The step_init hook sets up the relevant state for that hook to
|
@@ -71,11 +77,16 @@ class CondaStepDecorator(StepDecorator):
|
|
71
77
|
|
72
78
|
# Support flow-level decorator.
|
73
79
|
if "conda_base" in self.flow._flow_decorators:
|
74
|
-
|
80
|
+
conda_base = self.flow._flow_decorators["conda_base"][0]
|
81
|
+
super_attributes = conda_base.attributes
|
75
82
|
self.attributes["packages"] = {
|
76
83
|
**super_attributes["packages"],
|
77
84
|
**self.attributes["packages"],
|
78
85
|
}
|
86
|
+
self._user_defined_attributes = {
|
87
|
+
**self._user_defined_attributes,
|
88
|
+
**conda_base._user_defined_attributes,
|
89
|
+
}
|
79
90
|
self.attributes["python"] = (
|
80
91
|
self.attributes["python"] or super_attributes["python"]
|
81
92
|
)
|
@@ -322,6 +333,9 @@ class CondaFlowDecorator(FlowDecorator):
|
|
322
333
|
}
|
323
334
|
|
324
335
|
def __init__(self, attributes=None, statically_defined=False):
|
336
|
+
self._user_defined_attributes = (
|
337
|
+
attributes.copy() if attributes is not None else {}
|
338
|
+
)
|
325
339
|
super(CondaFlowDecorator, self).__init__(attributes, statically_defined)
|
326
340
|
|
327
341
|
# Support legacy 'libraries=' attribute for the decorator.
|
@@ -333,9 +347,18 @@ class CondaFlowDecorator(FlowDecorator):
|
|
333
347
|
if self.attributes["python"]:
|
334
348
|
self.attributes["python"] = str(self.attributes["python"])
|
335
349
|
|
350
|
+
def is_attribute_user_defined(self, name):
|
351
|
+
return name in self._user_defined_attributes
|
352
|
+
|
336
353
|
def flow_init(
|
337
354
|
self, flow, graph, environment, flow_datastore, metadata, logger, echo, options
|
338
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
|
+
|
339
362
|
# @conda uses a conda environment to create a virtual environment.
|
340
363
|
# The conda environment can be created through micromamba.
|
341
364
|
_supported_virtual_envs = ["conda"]
|
@@ -40,7 +40,12 @@ class PyPIStepDecorator(StepDecorator):
|
|
40
40
|
|
41
41
|
# Support flow-level decorator
|
42
42
|
if "pypi_base" in self.flow._flow_decorators:
|
43
|
-
|
43
|
+
pypi_base = self.flow._flow_decorators["pypi_base"][0]
|
44
|
+
super_attributes = pypi_base.attributes
|
45
|
+
self._user_defined_attributes = {
|
46
|
+
**self._user_defined_attributes,
|
47
|
+
**pypi_base._user_defined_attributes,
|
48
|
+
}
|
44
49
|
self.attributes["packages"] = {
|
45
50
|
**super_attributes["packages"],
|
46
51
|
**self.attributes["packages"],
|
@@ -93,6 +98,12 @@ class PyPIStepDecorator(StepDecorator):
|
|
93
98
|
),
|
94
99
|
)
|
95
100
|
)
|
101
|
+
# TODO: This code snippet can be done away with by altering the constructor of
|
102
|
+
# MetaflowEnvironment. A good first-task exercise.
|
103
|
+
# Avoid circular import
|
104
|
+
from metaflow.plugins.datastores.local_storage import LocalStorage
|
105
|
+
|
106
|
+
environment.set_local_root(LocalStorage.get_datastore_root_from_config(logger))
|
96
107
|
|
97
108
|
def is_attribute_user_defined(self, name):
|
98
109
|
return name in self._user_defined_attributes
|
@@ -117,6 +128,12 @@ class PyPIFlowDecorator(FlowDecorator):
|
|
117
128
|
name = "pypi_base"
|
118
129
|
defaults = {"packages": {}, "python": None, "disabled": None}
|
119
130
|
|
131
|
+
def __init__(self, attributes=None, statically_defined=False):
|
132
|
+
self._user_defined_attributes = (
|
133
|
+
attributes.copy() if attributes is not None else {}
|
134
|
+
)
|
135
|
+
super().__init__(attributes, statically_defined)
|
136
|
+
|
120
137
|
def flow_init(
|
121
138
|
self, flow, graph, environment, flow_datastore, metadata, logger, echo, options
|
122
139
|
):
|
@@ -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:
|
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)
|