genesis-flow 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- genesis_flow-1.0.0.dist-info/METADATA +822 -0
- genesis_flow-1.0.0.dist-info/RECORD +645 -0
- genesis_flow-1.0.0.dist-info/WHEEL +5 -0
- genesis_flow-1.0.0.dist-info/entry_points.txt +19 -0
- genesis_flow-1.0.0.dist-info/licenses/LICENSE.txt +202 -0
- genesis_flow-1.0.0.dist-info/top_level.txt +1 -0
- mlflow/__init__.py +367 -0
- mlflow/__main__.py +3 -0
- mlflow/ag2/__init__.py +56 -0
- mlflow/ag2/ag2_logger.py +294 -0
- mlflow/anthropic/__init__.py +40 -0
- mlflow/anthropic/autolog.py +129 -0
- mlflow/anthropic/chat.py +144 -0
- mlflow/artifacts/__init__.py +268 -0
- mlflow/autogen/__init__.py +144 -0
- mlflow/autogen/chat.py +142 -0
- mlflow/azure/__init__.py +26 -0
- mlflow/azure/auth_handler.py +257 -0
- mlflow/azure/client.py +319 -0
- mlflow/azure/config.py +120 -0
- mlflow/azure/connection_factory.py +340 -0
- mlflow/azure/exceptions.py +27 -0
- mlflow/azure/stores.py +327 -0
- mlflow/azure/utils.py +183 -0
- mlflow/bedrock/__init__.py +45 -0
- mlflow/bedrock/_autolog.py +202 -0
- mlflow/bedrock/chat.py +122 -0
- mlflow/bedrock/stream.py +160 -0
- mlflow/bedrock/utils.py +43 -0
- mlflow/cli.py +707 -0
- mlflow/client.py +12 -0
- mlflow/config/__init__.py +56 -0
- mlflow/crewai/__init__.py +79 -0
- mlflow/crewai/autolog.py +253 -0
- mlflow/crewai/chat.py +29 -0
- mlflow/data/__init__.py +75 -0
- mlflow/data/artifact_dataset_sources.py +170 -0
- mlflow/data/code_dataset_source.py +40 -0
- mlflow/data/dataset.py +123 -0
- mlflow/data/dataset_registry.py +168 -0
- mlflow/data/dataset_source.py +110 -0
- mlflow/data/dataset_source_registry.py +219 -0
- mlflow/data/delta_dataset_source.py +167 -0
- mlflow/data/digest_utils.py +108 -0
- mlflow/data/evaluation_dataset.py +562 -0
- mlflow/data/filesystem_dataset_source.py +81 -0
- mlflow/data/http_dataset_source.py +145 -0
- mlflow/data/huggingface_dataset.py +258 -0
- mlflow/data/huggingface_dataset_source.py +118 -0
- mlflow/data/meta_dataset.py +104 -0
- mlflow/data/numpy_dataset.py +223 -0
- mlflow/data/pandas_dataset.py +231 -0
- mlflow/data/polars_dataset.py +352 -0
- mlflow/data/pyfunc_dataset_mixin.py +31 -0
- mlflow/data/schema.py +76 -0
- mlflow/data/sources.py +1 -0
- mlflow/data/spark_dataset.py +406 -0
- mlflow/data/spark_dataset_source.py +74 -0
- mlflow/data/spark_delta_utils.py +118 -0
- mlflow/data/tensorflow_dataset.py +350 -0
- mlflow/data/uc_volume_dataset_source.py +81 -0
- mlflow/db.py +27 -0
- mlflow/dspy/__init__.py +17 -0
- mlflow/dspy/autolog.py +197 -0
- mlflow/dspy/callback.py +398 -0
- mlflow/dspy/constant.py +1 -0
- mlflow/dspy/load.py +93 -0
- mlflow/dspy/save.py +393 -0
- mlflow/dspy/util.py +109 -0
- mlflow/dspy/wrapper.py +226 -0
- mlflow/entities/__init__.py +104 -0
- mlflow/entities/_mlflow_object.py +52 -0
- mlflow/entities/assessment.py +545 -0
- mlflow/entities/assessment_error.py +80 -0
- mlflow/entities/assessment_source.py +141 -0
- mlflow/entities/dataset.py +92 -0
- mlflow/entities/dataset_input.py +51 -0
- mlflow/entities/dataset_summary.py +62 -0
- mlflow/entities/document.py +48 -0
- mlflow/entities/experiment.py +109 -0
- mlflow/entities/experiment_tag.py +35 -0
- mlflow/entities/file_info.py +45 -0
- mlflow/entities/input_tag.py +35 -0
- mlflow/entities/lifecycle_stage.py +35 -0
- mlflow/entities/logged_model.py +228 -0
- mlflow/entities/logged_model_input.py +26 -0
- mlflow/entities/logged_model_output.py +32 -0
- mlflow/entities/logged_model_parameter.py +46 -0
- mlflow/entities/logged_model_status.py +74 -0
- mlflow/entities/logged_model_tag.py +33 -0
- mlflow/entities/metric.py +200 -0
- mlflow/entities/model_registry/__init__.py +29 -0
- mlflow/entities/model_registry/_model_registry_entity.py +13 -0
- mlflow/entities/model_registry/model_version.py +243 -0
- mlflow/entities/model_registry/model_version_deployment_job_run_state.py +44 -0
- mlflow/entities/model_registry/model_version_deployment_job_state.py +70 -0
- mlflow/entities/model_registry/model_version_search.py +25 -0
- mlflow/entities/model_registry/model_version_stages.py +25 -0
- mlflow/entities/model_registry/model_version_status.py +35 -0
- mlflow/entities/model_registry/model_version_tag.py +35 -0
- mlflow/entities/model_registry/prompt.py +73 -0
- mlflow/entities/model_registry/prompt_version.py +244 -0
- mlflow/entities/model_registry/registered_model.py +175 -0
- mlflow/entities/model_registry/registered_model_alias.py +35 -0
- mlflow/entities/model_registry/registered_model_deployment_job_state.py +39 -0
- mlflow/entities/model_registry/registered_model_search.py +25 -0
- mlflow/entities/model_registry/registered_model_tag.py +35 -0
- mlflow/entities/multipart_upload.py +74 -0
- mlflow/entities/param.py +49 -0
- mlflow/entities/run.py +97 -0
- mlflow/entities/run_data.py +84 -0
- mlflow/entities/run_info.py +188 -0
- mlflow/entities/run_inputs.py +59 -0
- mlflow/entities/run_outputs.py +43 -0
- mlflow/entities/run_status.py +41 -0
- mlflow/entities/run_tag.py +36 -0
- mlflow/entities/source_type.py +31 -0
- mlflow/entities/span.py +774 -0
- mlflow/entities/span_event.py +96 -0
- mlflow/entities/span_status.py +102 -0
- mlflow/entities/trace.py +317 -0
- mlflow/entities/trace_data.py +71 -0
- mlflow/entities/trace_info.py +220 -0
- mlflow/entities/trace_info_v2.py +162 -0
- mlflow/entities/trace_location.py +173 -0
- mlflow/entities/trace_state.py +39 -0
- mlflow/entities/trace_status.py +68 -0
- mlflow/entities/view_type.py +51 -0
- mlflow/environment_variables.py +866 -0
- mlflow/evaluation/__init__.py +16 -0
- mlflow/evaluation/assessment.py +369 -0
- mlflow/evaluation/evaluation.py +411 -0
- mlflow/evaluation/evaluation_tag.py +61 -0
- mlflow/evaluation/fluent.py +48 -0
- mlflow/evaluation/utils.py +201 -0
- mlflow/exceptions.py +213 -0
- mlflow/experiments.py +140 -0
- mlflow/gemini/__init__.py +81 -0
- mlflow/gemini/autolog.py +186 -0
- mlflow/gemini/chat.py +261 -0
- mlflow/genai/__init__.py +71 -0
- mlflow/genai/datasets/__init__.py +67 -0
- mlflow/genai/datasets/evaluation_dataset.py +131 -0
- mlflow/genai/evaluation/__init__.py +3 -0
- mlflow/genai/evaluation/base.py +411 -0
- mlflow/genai/evaluation/constant.py +23 -0
- mlflow/genai/evaluation/utils.py +244 -0
- mlflow/genai/judges/__init__.py +21 -0
- mlflow/genai/judges/databricks.py +404 -0
- mlflow/genai/label_schemas/__init__.py +153 -0
- mlflow/genai/label_schemas/label_schemas.py +209 -0
- mlflow/genai/labeling/__init__.py +159 -0
- mlflow/genai/labeling/labeling.py +250 -0
- mlflow/genai/optimize/__init__.py +13 -0
- mlflow/genai/optimize/base.py +198 -0
- mlflow/genai/optimize/optimizers/__init__.py +4 -0
- mlflow/genai/optimize/optimizers/base_optimizer.py +38 -0
- mlflow/genai/optimize/optimizers/dspy_mipro_optimizer.py +221 -0
- mlflow/genai/optimize/optimizers/dspy_optimizer.py +91 -0
- mlflow/genai/optimize/optimizers/utils/dspy_mipro_callback.py +76 -0
- mlflow/genai/optimize/optimizers/utils/dspy_mipro_utils.py +18 -0
- mlflow/genai/optimize/types.py +75 -0
- mlflow/genai/optimize/util.py +30 -0
- mlflow/genai/prompts/__init__.py +206 -0
- mlflow/genai/scheduled_scorers.py +431 -0
- mlflow/genai/scorers/__init__.py +26 -0
- mlflow/genai/scorers/base.py +492 -0
- mlflow/genai/scorers/builtin_scorers.py +765 -0
- mlflow/genai/scorers/scorer_utils.py +138 -0
- mlflow/genai/scorers/validation.py +165 -0
- mlflow/genai/utils/data_validation.py +146 -0
- mlflow/genai/utils/enum_utils.py +23 -0
- mlflow/genai/utils/trace_utils.py +211 -0
- mlflow/groq/__init__.py +42 -0
- mlflow/groq/_groq_autolog.py +74 -0
- mlflow/johnsnowlabs/__init__.py +888 -0
- mlflow/langchain/__init__.py +24 -0
- mlflow/langchain/api_request_parallel_processor.py +330 -0
- mlflow/langchain/autolog.py +147 -0
- mlflow/langchain/chat_agent_langgraph.py +340 -0
- mlflow/langchain/constant.py +1 -0
- mlflow/langchain/constants.py +1 -0
- mlflow/langchain/databricks_dependencies.py +444 -0
- mlflow/langchain/langchain_tracer.py +597 -0
- mlflow/langchain/model.py +919 -0
- mlflow/langchain/output_parsers.py +142 -0
- mlflow/langchain/retriever_chain.py +153 -0
- mlflow/langchain/runnables.py +527 -0
- mlflow/langchain/utils/chat.py +402 -0
- mlflow/langchain/utils/logging.py +671 -0
- mlflow/langchain/utils/serialization.py +36 -0
- mlflow/legacy_databricks_cli/__init__.py +0 -0
- mlflow/legacy_databricks_cli/configure/__init__.py +0 -0
- mlflow/legacy_databricks_cli/configure/provider.py +482 -0
- mlflow/litellm/__init__.py +175 -0
- mlflow/llama_index/__init__.py +22 -0
- mlflow/llama_index/autolog.py +55 -0
- mlflow/llama_index/chat.py +43 -0
- mlflow/llama_index/constant.py +1 -0
- mlflow/llama_index/model.py +577 -0
- mlflow/llama_index/pyfunc_wrapper.py +332 -0
- mlflow/llama_index/serialize_objects.py +188 -0
- mlflow/llama_index/tracer.py +561 -0
- mlflow/metrics/__init__.py +479 -0
- mlflow/metrics/base.py +39 -0
- mlflow/metrics/genai/__init__.py +25 -0
- mlflow/metrics/genai/base.py +101 -0
- mlflow/metrics/genai/genai_metric.py +771 -0
- mlflow/metrics/genai/metric_definitions.py +450 -0
- mlflow/metrics/genai/model_utils.py +371 -0
- mlflow/metrics/genai/prompt_template.py +68 -0
- mlflow/metrics/genai/prompts/__init__.py +0 -0
- mlflow/metrics/genai/prompts/v1.py +422 -0
- mlflow/metrics/genai/utils.py +6 -0
- mlflow/metrics/metric_definitions.py +619 -0
- mlflow/mismatch.py +34 -0
- mlflow/mistral/__init__.py +34 -0
- mlflow/mistral/autolog.py +71 -0
- mlflow/mistral/chat.py +135 -0
- mlflow/ml_package_versions.py +452 -0
- mlflow/models/__init__.py +97 -0
- mlflow/models/auth_policy.py +83 -0
- mlflow/models/cli.py +354 -0
- mlflow/models/container/__init__.py +294 -0
- mlflow/models/container/scoring_server/__init__.py +0 -0
- mlflow/models/container/scoring_server/nginx.conf +39 -0
- mlflow/models/dependencies_schemas.py +287 -0
- mlflow/models/display_utils.py +158 -0
- mlflow/models/docker_utils.py +211 -0
- mlflow/models/evaluation/__init__.py +23 -0
- mlflow/models/evaluation/_shap_patch.py +64 -0
- mlflow/models/evaluation/artifacts.py +194 -0
- mlflow/models/evaluation/base.py +1811 -0
- mlflow/models/evaluation/calibration_curve.py +109 -0
- mlflow/models/evaluation/default_evaluator.py +996 -0
- mlflow/models/evaluation/deprecated.py +23 -0
- mlflow/models/evaluation/evaluator_registry.py +80 -0
- mlflow/models/evaluation/evaluators/classifier.py +704 -0
- mlflow/models/evaluation/evaluators/default.py +233 -0
- mlflow/models/evaluation/evaluators/regressor.py +96 -0
- mlflow/models/evaluation/evaluators/shap.py +296 -0
- mlflow/models/evaluation/lift_curve.py +178 -0
- mlflow/models/evaluation/utils/metric.py +123 -0
- mlflow/models/evaluation/utils/trace.py +179 -0
- mlflow/models/evaluation/validation.py +434 -0
- mlflow/models/flavor_backend.py +93 -0
- mlflow/models/flavor_backend_registry.py +53 -0
- mlflow/models/model.py +1639 -0
- mlflow/models/model_config.py +150 -0
- mlflow/models/notebook_resources/agent_evaluation_template.html +235 -0
- mlflow/models/notebook_resources/eval_with_dataset_example.py +22 -0
- mlflow/models/notebook_resources/eval_with_synthetic_example.py +22 -0
- mlflow/models/python_api.py +369 -0
- mlflow/models/rag_signatures.py +128 -0
- mlflow/models/resources.py +321 -0
- mlflow/models/signature.py +662 -0
- mlflow/models/utils.py +2054 -0
- mlflow/models/wheeled_model.py +280 -0
- mlflow/openai/__init__.py +57 -0
- mlflow/openai/_agent_tracer.py +364 -0
- mlflow/openai/api_request_parallel_processor.py +131 -0
- mlflow/openai/autolog.py +509 -0
- mlflow/openai/constant.py +1 -0
- mlflow/openai/model.py +824 -0
- mlflow/openai/utils/chat_schema.py +367 -0
- mlflow/optuna/__init__.py +3 -0
- mlflow/optuna/storage.py +646 -0
- mlflow/plugins/__init__.py +72 -0
- mlflow/plugins/base.py +358 -0
- mlflow/plugins/builtin/__init__.py +24 -0
- mlflow/plugins/builtin/pytorch_plugin.py +150 -0
- mlflow/plugins/builtin/sklearn_plugin.py +158 -0
- mlflow/plugins/builtin/transformers_plugin.py +187 -0
- mlflow/plugins/cli.py +321 -0
- mlflow/plugins/discovery.py +340 -0
- mlflow/plugins/manager.py +465 -0
- mlflow/plugins/registry.py +316 -0
- mlflow/plugins/templates/framework_plugin_template.py +329 -0
- mlflow/prompt/constants.py +20 -0
- mlflow/prompt/promptlab_model.py +197 -0
- mlflow/prompt/registry_utils.py +248 -0
- mlflow/promptflow/__init__.py +495 -0
- mlflow/protos/__init__.py +0 -0
- mlflow/protos/assessments_pb2.py +174 -0
- mlflow/protos/databricks_artifacts_pb2.py +489 -0
- mlflow/protos/databricks_filesystem_service_pb2.py +196 -0
- mlflow/protos/databricks_managed_catalog_messages_pb2.py +95 -0
- mlflow/protos/databricks_managed_catalog_service_pb2.py +86 -0
- mlflow/protos/databricks_pb2.py +267 -0
- mlflow/protos/databricks_trace_server_pb2.py +374 -0
- mlflow/protos/databricks_uc_registry_messages_pb2.py +1249 -0
- mlflow/protos/databricks_uc_registry_service_pb2.py +170 -0
- mlflow/protos/facet_feature_statistics_pb2.py +296 -0
- mlflow/protos/internal_pb2.py +77 -0
- mlflow/protos/mlflow_artifacts_pb2.py +336 -0
- mlflow/protos/model_registry_pb2.py +1073 -0
- mlflow/protos/scalapb/__init__.py +0 -0
- mlflow/protos/scalapb/scalapb_pb2.py +104 -0
- mlflow/protos/service_pb2.py +2600 -0
- mlflow/protos/unity_catalog_oss_messages_pb2.py +457 -0
- mlflow/protos/unity_catalog_oss_service_pb2.py +130 -0
- mlflow/protos/unity_catalog_prompt_messages_pb2.py +447 -0
- mlflow/protos/unity_catalog_prompt_messages_pb2_grpc.py +24 -0
- mlflow/protos/unity_catalog_prompt_service_pb2.py +164 -0
- mlflow/protos/unity_catalog_prompt_service_pb2_grpc.py +785 -0
- mlflow/py.typed +0 -0
- mlflow/pydantic_ai/__init__.py +57 -0
- mlflow/pydantic_ai/autolog.py +173 -0
- mlflow/pyfunc/__init__.py +3844 -0
- mlflow/pyfunc/_mlflow_pyfunc_backend_predict.py +61 -0
- mlflow/pyfunc/backend.py +523 -0
- mlflow/pyfunc/context.py +78 -0
- mlflow/pyfunc/dbconnect_artifact_cache.py +144 -0
- mlflow/pyfunc/loaders/__init__.py +7 -0
- mlflow/pyfunc/loaders/chat_agent.py +117 -0
- mlflow/pyfunc/loaders/chat_model.py +125 -0
- mlflow/pyfunc/loaders/code_model.py +31 -0
- mlflow/pyfunc/loaders/responses_agent.py +112 -0
- mlflow/pyfunc/mlserver.py +46 -0
- mlflow/pyfunc/model.py +1473 -0
- mlflow/pyfunc/scoring_server/__init__.py +604 -0
- mlflow/pyfunc/scoring_server/app.py +7 -0
- mlflow/pyfunc/scoring_server/client.py +146 -0
- mlflow/pyfunc/spark_model_cache.py +48 -0
- mlflow/pyfunc/stdin_server.py +44 -0
- mlflow/pyfunc/utils/__init__.py +3 -0
- mlflow/pyfunc/utils/data_validation.py +224 -0
- mlflow/pyfunc/utils/environment.py +22 -0
- mlflow/pyfunc/utils/input_converter.py +47 -0
- mlflow/pyfunc/utils/serving_data_parser.py +11 -0
- mlflow/pytorch/__init__.py +1171 -0
- mlflow/pytorch/_lightning_autolog.py +580 -0
- mlflow/pytorch/_pytorch_autolog.py +50 -0
- mlflow/pytorch/pickle_module.py +35 -0
- mlflow/rfunc/__init__.py +42 -0
- mlflow/rfunc/backend.py +134 -0
- mlflow/runs.py +89 -0
- mlflow/server/__init__.py +302 -0
- mlflow/server/auth/__init__.py +1224 -0
- mlflow/server/auth/__main__.py +4 -0
- mlflow/server/auth/basic_auth.ini +6 -0
- mlflow/server/auth/cli.py +11 -0
- mlflow/server/auth/client.py +537 -0
- mlflow/server/auth/config.py +34 -0
- mlflow/server/auth/db/__init__.py +0 -0
- mlflow/server/auth/db/cli.py +18 -0
- mlflow/server/auth/db/migrations/__init__.py +0 -0
- mlflow/server/auth/db/migrations/alembic.ini +110 -0
- mlflow/server/auth/db/migrations/env.py +76 -0
- mlflow/server/auth/db/migrations/versions/8606fa83a998_initial_migration.py +51 -0
- mlflow/server/auth/db/migrations/versions/__init__.py +0 -0
- mlflow/server/auth/db/models.py +67 -0
- mlflow/server/auth/db/utils.py +37 -0
- mlflow/server/auth/entities.py +165 -0
- mlflow/server/auth/logo.py +14 -0
- mlflow/server/auth/permissions.py +65 -0
- mlflow/server/auth/routes.py +18 -0
- mlflow/server/auth/sqlalchemy_store.py +263 -0
- mlflow/server/graphql/__init__.py +0 -0
- mlflow/server/graphql/autogenerated_graphql_schema.py +353 -0
- mlflow/server/graphql/graphql_custom_scalars.py +24 -0
- mlflow/server/graphql/graphql_errors.py +15 -0
- mlflow/server/graphql/graphql_no_batching.py +89 -0
- mlflow/server/graphql/graphql_schema_extensions.py +74 -0
- mlflow/server/handlers.py +3217 -0
- mlflow/server/prometheus_exporter.py +17 -0
- mlflow/server/validation.py +30 -0
- mlflow/shap/__init__.py +691 -0
- mlflow/sklearn/__init__.py +1994 -0
- mlflow/sklearn/utils.py +1041 -0
- mlflow/smolagents/__init__.py +66 -0
- mlflow/smolagents/autolog.py +139 -0
- mlflow/smolagents/chat.py +29 -0
- mlflow/store/__init__.py +10 -0
- mlflow/store/_unity_catalog/__init__.py +1 -0
- mlflow/store/_unity_catalog/lineage/__init__.py +1 -0
- mlflow/store/_unity_catalog/lineage/constants.py +2 -0
- mlflow/store/_unity_catalog/registry/__init__.py +6 -0
- mlflow/store/_unity_catalog/registry/prompt_info.py +75 -0
- mlflow/store/_unity_catalog/registry/rest_store.py +1740 -0
- mlflow/store/_unity_catalog/registry/uc_oss_rest_store.py +507 -0
- mlflow/store/_unity_catalog/registry/utils.py +121 -0
- mlflow/store/artifact/__init__.py +0 -0
- mlflow/store/artifact/artifact_repo.py +472 -0
- mlflow/store/artifact/artifact_repository_registry.py +154 -0
- mlflow/store/artifact/azure_blob_artifact_repo.py +275 -0
- mlflow/store/artifact/azure_data_lake_artifact_repo.py +295 -0
- mlflow/store/artifact/cli.py +141 -0
- mlflow/store/artifact/cloud_artifact_repo.py +332 -0
- mlflow/store/artifact/databricks_artifact_repo.py +729 -0
- mlflow/store/artifact/databricks_artifact_repo_resources.py +301 -0
- mlflow/store/artifact/databricks_logged_model_artifact_repo.py +93 -0
- mlflow/store/artifact/databricks_models_artifact_repo.py +216 -0
- mlflow/store/artifact/databricks_sdk_artifact_repo.py +134 -0
- mlflow/store/artifact/databricks_sdk_models_artifact_repo.py +97 -0
- mlflow/store/artifact/dbfs_artifact_repo.py +240 -0
- mlflow/store/artifact/ftp_artifact_repo.py +132 -0
- mlflow/store/artifact/gcs_artifact_repo.py +296 -0
- mlflow/store/artifact/hdfs_artifact_repo.py +209 -0
- mlflow/store/artifact/http_artifact_repo.py +218 -0
- mlflow/store/artifact/local_artifact_repo.py +142 -0
- mlflow/store/artifact/mlflow_artifacts_repo.py +94 -0
- mlflow/store/artifact/models_artifact_repo.py +259 -0
- mlflow/store/artifact/optimized_s3_artifact_repo.py +356 -0
- mlflow/store/artifact/presigned_url_artifact_repo.py +173 -0
- mlflow/store/artifact/r2_artifact_repo.py +70 -0
- mlflow/store/artifact/runs_artifact_repo.py +265 -0
- mlflow/store/artifact/s3_artifact_repo.py +330 -0
- mlflow/store/artifact/sftp_artifact_repo.py +141 -0
- mlflow/store/artifact/uc_volume_artifact_repo.py +76 -0
- mlflow/store/artifact/unity_catalog_models_artifact_repo.py +168 -0
- mlflow/store/artifact/unity_catalog_oss_models_artifact_repo.py +168 -0
- mlflow/store/artifact/utils/__init__.py +0 -0
- mlflow/store/artifact/utils/models.py +148 -0
- mlflow/store/db/__init__.py +0 -0
- mlflow/store/db/base_sql_model.py +3 -0
- mlflow/store/db/db_types.py +10 -0
- mlflow/store/db/utils.py +314 -0
- mlflow/store/db_migrations/__init__.py +0 -0
- mlflow/store/db_migrations/alembic.ini +74 -0
- mlflow/store/db_migrations/env.py +84 -0
- mlflow/store/db_migrations/versions/0584bdc529eb_add_cascading_deletion_to_datasets_from_experiments.py +88 -0
- mlflow/store/db_migrations/versions/0a8213491aaa_drop_duplicate_killed_constraint.py +49 -0
- mlflow/store/db_migrations/versions/0c779009ac13_add_deleted_time_field_to_runs_table.py +24 -0
- mlflow/store/db_migrations/versions/181f10493468_allow_nulls_for_metric_values.py +35 -0
- mlflow/store/db_migrations/versions/27a6a02d2cf1_add_model_version_tags_table.py +38 -0
- mlflow/store/db_migrations/versions/2b4d017a5e9b_add_model_registry_tables_to_db.py +77 -0
- mlflow/store/db_migrations/versions/2d6e25af4d3e_increase_max_param_val_length.py +33 -0
- mlflow/store/db_migrations/versions/3500859a5d39_add_model_aliases_table.py +50 -0
- mlflow/store/db_migrations/versions/39d1c3be5f05_add_is_nan_constraint_for_metrics_tables_if_necessary.py +41 -0
- mlflow/store/db_migrations/versions/400f98739977_add_logged_model_tables.py +123 -0
- mlflow/store/db_migrations/versions/4465047574b1_increase_max_dataset_schema_size.py +38 -0
- mlflow/store/db_migrations/versions/451aebb31d03_add_metric_step.py +35 -0
- mlflow/store/db_migrations/versions/5b0e9adcef9c_add_cascade_deletion_to_trace_tables_fk.py +40 -0
- mlflow/store/db_migrations/versions/6953534de441_add_step_to_inputs_table.py +25 -0
- mlflow/store/db_migrations/versions/728d730b5ebd_add_registered_model_tags_table.py +38 -0
- mlflow/store/db_migrations/versions/7ac759974ad8_update_run_tags_with_larger_limit.py +36 -0
- mlflow/store/db_migrations/versions/7f2a7d5fae7d_add_datasets_inputs_input_tags_tables.py +82 -0
- mlflow/store/db_migrations/versions/84291f40a231_add_run_link_to_model_version.py +26 -0
- mlflow/store/db_migrations/versions/867495a8f9d4_add_trace_tables.py +90 -0
- mlflow/store/db_migrations/versions/89d4b8295536_create_latest_metrics_table.py +169 -0
- mlflow/store/db_migrations/versions/90e64c465722_migrate_user_column_to_tags.py +64 -0
- mlflow/store/db_migrations/versions/97727af70f4d_creation_time_last_update_time_experiments.py +25 -0
- mlflow/store/db_migrations/versions/__init__.py +0 -0
- mlflow/store/db_migrations/versions/a8c4a736bde6_allow_nulls_for_run_id.py +27 -0
- mlflow/store/db_migrations/versions/acf3f17fdcc7_add_storage_location_field_to_model_.py +29 -0
- mlflow/store/db_migrations/versions/bd07f7e963c5_create_index_on_run_uuid.py +26 -0
- mlflow/store/db_migrations/versions/bda7b8c39065_increase_model_version_tag_value_limit.py +38 -0
- mlflow/store/db_migrations/versions/c48cb773bb87_reset_default_value_for_is_nan_in_metrics_table_for_mysql.py +41 -0
- mlflow/store/db_migrations/versions/cbc13b556ace_add_v3_trace_schema_columns.py +31 -0
- mlflow/store/db_migrations/versions/cc1f77228345_change_param_value_length_to_500.py +34 -0
- mlflow/store/db_migrations/versions/cfd24bdc0731_update_run_status_constraint_with_killed.py +78 -0
- mlflow/store/db_migrations/versions/df50e92ffc5e_add_experiment_tags_table.py +38 -0
- mlflow/store/db_migrations/versions/f5a4f2784254_increase_run_tag_value_limit.py +36 -0
- mlflow/store/entities/__init__.py +3 -0
- mlflow/store/entities/paged_list.py +18 -0
- mlflow/store/model_registry/__init__.py +10 -0
- mlflow/store/model_registry/abstract_store.py +1081 -0
- mlflow/store/model_registry/base_rest_store.py +44 -0
- mlflow/store/model_registry/databricks_workspace_model_registry_rest_store.py +37 -0
- mlflow/store/model_registry/dbmodels/__init__.py +0 -0
- mlflow/store/model_registry/dbmodels/models.py +206 -0
- mlflow/store/model_registry/file_store.py +1091 -0
- mlflow/store/model_registry/rest_store.py +481 -0
- mlflow/store/model_registry/sqlalchemy_store.py +1286 -0
- mlflow/store/tracking/__init__.py +23 -0
- mlflow/store/tracking/abstract_store.py +816 -0
- mlflow/store/tracking/dbmodels/__init__.py +0 -0
- mlflow/store/tracking/dbmodels/initial_models.py +243 -0
- mlflow/store/tracking/dbmodels/models.py +1073 -0
- mlflow/store/tracking/file_store.py +2438 -0
- mlflow/store/tracking/postgres_managed_identity.py +146 -0
- mlflow/store/tracking/rest_store.py +1131 -0
- mlflow/store/tracking/sqlalchemy_store.py +2785 -0
- mlflow/system_metrics/__init__.py +61 -0
- mlflow/system_metrics/metrics/__init__.py +0 -0
- mlflow/system_metrics/metrics/base_metrics_monitor.py +32 -0
- mlflow/system_metrics/metrics/cpu_monitor.py +23 -0
- mlflow/system_metrics/metrics/disk_monitor.py +21 -0
- mlflow/system_metrics/metrics/gpu_monitor.py +71 -0
- mlflow/system_metrics/metrics/network_monitor.py +34 -0
- mlflow/system_metrics/metrics/rocm_monitor.py +123 -0
- mlflow/system_metrics/system_metrics_monitor.py +198 -0
- mlflow/tracing/__init__.py +16 -0
- mlflow/tracing/assessment.py +356 -0
- mlflow/tracing/client.py +531 -0
- mlflow/tracing/config.py +125 -0
- mlflow/tracing/constant.py +105 -0
- mlflow/tracing/destination.py +81 -0
- mlflow/tracing/display/__init__.py +40 -0
- mlflow/tracing/display/display_handler.py +196 -0
- mlflow/tracing/export/async_export_queue.py +186 -0
- mlflow/tracing/export/inference_table.py +138 -0
- mlflow/tracing/export/mlflow_v3.py +137 -0
- mlflow/tracing/export/utils.py +70 -0
- mlflow/tracing/fluent.py +1417 -0
- mlflow/tracing/processor/base_mlflow.py +199 -0
- mlflow/tracing/processor/inference_table.py +175 -0
- mlflow/tracing/processor/mlflow_v3.py +47 -0
- mlflow/tracing/processor/otel.py +73 -0
- mlflow/tracing/provider.py +487 -0
- mlflow/tracing/trace_manager.py +200 -0
- mlflow/tracing/utils/__init__.py +616 -0
- mlflow/tracing/utils/artifact_utils.py +28 -0
- mlflow/tracing/utils/copy.py +55 -0
- mlflow/tracing/utils/environment.py +55 -0
- mlflow/tracing/utils/exception.py +21 -0
- mlflow/tracing/utils/once.py +35 -0
- mlflow/tracing/utils/otlp.py +63 -0
- mlflow/tracing/utils/processor.py +54 -0
- mlflow/tracing/utils/search.py +292 -0
- mlflow/tracing/utils/timeout.py +250 -0
- mlflow/tracing/utils/token.py +19 -0
- mlflow/tracing/utils/truncation.py +124 -0
- mlflow/tracing/utils/warning.py +76 -0
- mlflow/tracking/__init__.py +39 -0
- mlflow/tracking/_model_registry/__init__.py +1 -0
- mlflow/tracking/_model_registry/client.py +764 -0
- mlflow/tracking/_model_registry/fluent.py +853 -0
- mlflow/tracking/_model_registry/registry.py +67 -0
- mlflow/tracking/_model_registry/utils.py +251 -0
- mlflow/tracking/_tracking_service/__init__.py +0 -0
- mlflow/tracking/_tracking_service/client.py +883 -0
- mlflow/tracking/_tracking_service/registry.py +56 -0
- mlflow/tracking/_tracking_service/utils.py +275 -0
- mlflow/tracking/artifact_utils.py +179 -0
- mlflow/tracking/client.py +5900 -0
- mlflow/tracking/context/__init__.py +0 -0
- mlflow/tracking/context/abstract_context.py +35 -0
- mlflow/tracking/context/databricks_cluster_context.py +15 -0
- mlflow/tracking/context/databricks_command_context.py +15 -0
- mlflow/tracking/context/databricks_job_context.py +49 -0
- mlflow/tracking/context/databricks_notebook_context.py +41 -0
- mlflow/tracking/context/databricks_repo_context.py +43 -0
- mlflow/tracking/context/default_context.py +51 -0
- mlflow/tracking/context/git_context.py +32 -0
- mlflow/tracking/context/registry.py +98 -0
- mlflow/tracking/context/system_environment_context.py +15 -0
- mlflow/tracking/default_experiment/__init__.py +1 -0
- mlflow/tracking/default_experiment/abstract_context.py +43 -0
- mlflow/tracking/default_experiment/databricks_notebook_experiment_provider.py +44 -0
- mlflow/tracking/default_experiment/registry.py +75 -0
- mlflow/tracking/fluent.py +3595 -0
- mlflow/tracking/metric_value_conversion_utils.py +93 -0
- mlflow/tracking/multimedia.py +206 -0
- mlflow/tracking/registry.py +86 -0
- mlflow/tracking/request_auth/__init__.py +0 -0
- mlflow/tracking/request_auth/abstract_request_auth_provider.py +34 -0
- mlflow/tracking/request_auth/registry.py +60 -0
- mlflow/tracking/request_header/__init__.py +0 -0
- mlflow/tracking/request_header/abstract_request_header_provider.py +36 -0
- mlflow/tracking/request_header/databricks_request_header_provider.py +38 -0
- mlflow/tracking/request_header/default_request_header_provider.py +17 -0
- mlflow/tracking/request_header/registry.py +79 -0
- mlflow/transformers/__init__.py +2982 -0
- mlflow/transformers/flavor_config.py +258 -0
- mlflow/transformers/hub_utils.py +83 -0
- mlflow/transformers/llm_inference_utils.py +468 -0
- mlflow/transformers/model_io.py +301 -0
- mlflow/transformers/peft.py +51 -0
- mlflow/transformers/signature.py +183 -0
- mlflow/transformers/torch_utils.py +55 -0
- mlflow/types/__init__.py +21 -0
- mlflow/types/agent.py +270 -0
- mlflow/types/chat.py +240 -0
- mlflow/types/llm.py +935 -0
- mlflow/types/responses.py +139 -0
- mlflow/types/responses_helpers.py +416 -0
- mlflow/types/schema.py +1505 -0
- mlflow/types/type_hints.py +647 -0
- mlflow/types/utils.py +753 -0
- mlflow/utils/__init__.py +283 -0
- mlflow/utils/_capture_modules.py +256 -0
- mlflow/utils/_capture_transformers_modules.py +75 -0
- mlflow/utils/_spark_utils.py +201 -0
- mlflow/utils/_unity_catalog_oss_utils.py +97 -0
- mlflow/utils/_unity_catalog_utils.py +479 -0
- mlflow/utils/annotations.py +218 -0
- mlflow/utils/arguments_utils.py +16 -0
- mlflow/utils/async_logging/__init__.py +1 -0
- mlflow/utils/async_logging/async_artifacts_logging_queue.py +258 -0
- mlflow/utils/async_logging/async_logging_queue.py +366 -0
- mlflow/utils/async_logging/run_artifact.py +38 -0
- mlflow/utils/async_logging/run_batch.py +58 -0
- mlflow/utils/async_logging/run_operations.py +49 -0
- mlflow/utils/autologging_utils/__init__.py +737 -0
- mlflow/utils/autologging_utils/client.py +432 -0
- mlflow/utils/autologging_utils/config.py +33 -0
- mlflow/utils/autologging_utils/events.py +294 -0
- mlflow/utils/autologging_utils/logging_and_warnings.py +328 -0
- mlflow/utils/autologging_utils/metrics_queue.py +71 -0
- mlflow/utils/autologging_utils/safety.py +1104 -0
- mlflow/utils/autologging_utils/versioning.py +95 -0
- mlflow/utils/checkpoint_utils.py +206 -0
- mlflow/utils/class_utils.py +6 -0
- mlflow/utils/cli_args.py +257 -0
- mlflow/utils/conda.py +354 -0
- mlflow/utils/credentials.py +231 -0
- mlflow/utils/data_utils.py +17 -0
- mlflow/utils/databricks_utils.py +1436 -0
- mlflow/utils/docstring_utils.py +477 -0
- mlflow/utils/doctor.py +133 -0
- mlflow/utils/download_cloud_file_chunk.py +43 -0
- mlflow/utils/env_manager.py +16 -0
- mlflow/utils/env_pack.py +131 -0
- mlflow/utils/environment.py +1009 -0
- mlflow/utils/exception_utils.py +14 -0
- mlflow/utils/file_utils.py +978 -0
- mlflow/utils/git_utils.py +77 -0
- mlflow/utils/gorilla.py +797 -0
- mlflow/utils/import_hooks/__init__.py +363 -0
- mlflow/utils/lazy_load.py +51 -0
- mlflow/utils/logging_utils.py +168 -0
- mlflow/utils/mime_type_utils.py +58 -0
- mlflow/utils/mlflow_tags.py +103 -0
- mlflow/utils/model_utils.py +486 -0
- mlflow/utils/name_utils.py +346 -0
- mlflow/utils/nfs_on_spark.py +62 -0
- mlflow/utils/openai_utils.py +164 -0
- mlflow/utils/os.py +12 -0
- mlflow/utils/oss_registry_utils.py +29 -0
- mlflow/utils/plugins.py +17 -0
- mlflow/utils/process.py +182 -0
- mlflow/utils/promptlab_utils.py +146 -0
- mlflow/utils/proto_json_utils.py +743 -0
- mlflow/utils/pydantic_utils.py +54 -0
- mlflow/utils/request_utils.py +279 -0
- mlflow/utils/requirements_utils.py +704 -0
- mlflow/utils/rest_utils.py +673 -0
- mlflow/utils/search_logged_model_utils.py +127 -0
- mlflow/utils/search_utils.py +2111 -0
- mlflow/utils/secure_loading.py +221 -0
- mlflow/utils/security_validation.py +384 -0
- mlflow/utils/server_cli_utils.py +61 -0
- mlflow/utils/spark_utils.py +15 -0
- mlflow/utils/string_utils.py +138 -0
- mlflow/utils/thread_utils.py +63 -0
- mlflow/utils/time.py +54 -0
- mlflow/utils/timeout.py +42 -0
- mlflow/utils/uri.py +572 -0
- mlflow/utils/validation.py +662 -0
- mlflow/utils/virtualenv.py +458 -0
- mlflow/utils/warnings_utils.py +25 -0
- mlflow/utils/yaml_utils.py +179 -0
- mlflow/version.py +24 -0
@@ -0,0 +1,458 @@
|
|
1
|
+
import logging
|
2
|
+
import os
|
3
|
+
import re
|
4
|
+
import shutil
|
5
|
+
import sys
|
6
|
+
import tempfile
|
7
|
+
import uuid
|
8
|
+
from pathlib import Path
|
9
|
+
from typing import Literal, Optional
|
10
|
+
|
11
|
+
from packaging.version import Version
|
12
|
+
|
13
|
+
import mlflow
|
14
|
+
from mlflow.environment_variables import _MLFLOW_TESTING, MLFLOW_ENV_ROOT
|
15
|
+
from mlflow.exceptions import MlflowException
|
16
|
+
from mlflow.models.model import MLMODEL_FILE_NAME, Model
|
17
|
+
from mlflow.utils import env_manager as em
|
18
|
+
from mlflow.utils.conda import _PIP_CACHE_DIR
|
19
|
+
from mlflow.utils.databricks_utils import is_in_databricks_runtime
|
20
|
+
from mlflow.utils.environment import (
|
21
|
+
_CONDA_ENV_FILE_NAME,
|
22
|
+
_PYTHON_ENV_FILE_NAME,
|
23
|
+
_REQUIREMENTS_FILE_NAME,
|
24
|
+
_get_mlflow_env_name,
|
25
|
+
_PythonEnv,
|
26
|
+
)
|
27
|
+
from mlflow.utils.file_utils import remove_on_error
|
28
|
+
from mlflow.utils.os import is_windows
|
29
|
+
from mlflow.utils.process import _exec_cmd, _join_commands
|
30
|
+
from mlflow.utils.requirements_utils import _parse_requirements
|
31
|
+
|
32
|
+
_logger = logging.getLogger(__name__)
|
33
|
+
|
34
|
+
|
35
|
+
def _get_mlflow_virtualenv_root():
|
36
|
+
"""
|
37
|
+
Returns the root directory to store virtualenv environments created by MLflow.
|
38
|
+
"""
|
39
|
+
return MLFLOW_ENV_ROOT.get()
|
40
|
+
|
41
|
+
|
42
|
+
_DATABRICKS_PYENV_BIN_PATH = "/databricks/.pyenv/bin/pyenv"
|
43
|
+
|
44
|
+
|
45
|
+
def _is_pyenv_available():
|
46
|
+
"""
|
47
|
+
Returns True if pyenv is available, otherwise False.
|
48
|
+
"""
|
49
|
+
return _get_pyenv_bin_path() is not None
|
50
|
+
|
51
|
+
|
52
|
+
def _validate_pyenv_is_available():
|
53
|
+
"""
|
54
|
+
Validates pyenv is available. If not, throws an `MlflowException` with a brief instruction on
|
55
|
+
how to install pyenv.
|
56
|
+
"""
|
57
|
+
url = (
|
58
|
+
"https://github.com/pyenv/pyenv#installation"
|
59
|
+
if not is_windows()
|
60
|
+
else "https://github.com/pyenv-win/pyenv-win#installation"
|
61
|
+
)
|
62
|
+
if not _is_pyenv_available():
|
63
|
+
raise MlflowException(
|
64
|
+
f"Could not find the pyenv binary. See {url} for installation instructions."
|
65
|
+
)
|
66
|
+
|
67
|
+
|
68
|
+
def _is_virtualenv_available():
|
69
|
+
"""
|
70
|
+
Returns True if virtualenv is available, otherwise False.
|
71
|
+
"""
|
72
|
+
return shutil.which("virtualenv") is not None
|
73
|
+
|
74
|
+
|
75
|
+
def _validate_virtualenv_is_available():
|
76
|
+
"""
|
77
|
+
Validates virtualenv is available. If not, throws an `MlflowException` with a brief instruction
|
78
|
+
on how to install virtualenv.
|
79
|
+
"""
|
80
|
+
if not _is_virtualenv_available():
|
81
|
+
raise MlflowException(
|
82
|
+
"Could not find the virtualenv binary. Run `pip install virtualenv` to install "
|
83
|
+
"virtualenv."
|
84
|
+
)
|
85
|
+
|
86
|
+
|
87
|
+
_SEMANTIC_VERSION_REGEX = re.compile(r"^([0-9]+)\.([0-9]+)\.([0-9]+)$")
|
88
|
+
|
89
|
+
|
90
|
+
def _get_pyenv_bin_path():
|
91
|
+
if os.path.exists(_DATABRICKS_PYENV_BIN_PATH):
|
92
|
+
return _DATABRICKS_PYENV_BIN_PATH
|
93
|
+
return shutil.which("pyenv")
|
94
|
+
|
95
|
+
|
96
|
+
def _find_latest_installable_python_version(version_prefix):
|
97
|
+
"""
|
98
|
+
Find the latest installable python version that matches the given version prefix
|
99
|
+
from the output of `pyenv install --list`. For example, `version_prefix("3.8")` returns '3.8.x'
|
100
|
+
where 'x' represents the latest micro version in 3.8.
|
101
|
+
"""
|
102
|
+
lines = _exec_cmd(
|
103
|
+
[_get_pyenv_bin_path(), "install", "--list"],
|
104
|
+
capture_output=True,
|
105
|
+
shell=is_windows(),
|
106
|
+
).stdout.splitlines()
|
107
|
+
semantic_versions = filter(_SEMANTIC_VERSION_REGEX.match, map(str.strip, lines))
|
108
|
+
matched = [v for v in semantic_versions if v.startswith(version_prefix)]
|
109
|
+
if not matched:
|
110
|
+
raise MlflowException(f"Could not find python version that matches {version_prefix}")
|
111
|
+
return sorted(matched, key=Version)[-1]
|
112
|
+
|
113
|
+
|
114
|
+
def _install_python(version, pyenv_root=None, capture_output=False):
|
115
|
+
"""Installs a specified version of python with pyenv and returns a path to the installed python
|
116
|
+
binary.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
version: Python version to install.
|
120
|
+
pyenv_root: The value of the "PYENV_ROOT" environment variable used when running
|
121
|
+
`pyenv install` which installs python in `{PYENV_ROOT}/versions/{version}`.
|
122
|
+
capture_output: Set the `capture_output` argument when calling `_exec_cmd`.
|
123
|
+
|
124
|
+
Returns:
|
125
|
+
Path to the installed python binary.
|
126
|
+
"""
|
127
|
+
version = (
|
128
|
+
version
|
129
|
+
if _SEMANTIC_VERSION_REGEX.match(version)
|
130
|
+
else _find_latest_installable_python_version(version)
|
131
|
+
)
|
132
|
+
_logger.info("Installing python %s if it does not exist", version)
|
133
|
+
# pyenv-win doesn't support `--skip-existing` but its behavior is enabled by default
|
134
|
+
# https://github.com/pyenv-win/pyenv-win/pull/314
|
135
|
+
pyenv_install_options = ("--skip-existing",) if not is_windows() else ()
|
136
|
+
extra_env = {"PYENV_ROOT": pyenv_root} if pyenv_root else None
|
137
|
+
pyenv_bin_path = _get_pyenv_bin_path()
|
138
|
+
_exec_cmd(
|
139
|
+
[pyenv_bin_path, "install", *pyenv_install_options, version],
|
140
|
+
capture_output=capture_output,
|
141
|
+
# Windows fails to find pyenv and throws `FileNotFoundError` without `shell=True`
|
142
|
+
shell=is_windows(),
|
143
|
+
extra_env=extra_env,
|
144
|
+
)
|
145
|
+
|
146
|
+
if not is_windows():
|
147
|
+
if pyenv_root is None:
|
148
|
+
pyenv_root = _exec_cmd([pyenv_bin_path, "root"], capture_output=True).stdout.strip()
|
149
|
+
path_to_bin = ("bin", "python")
|
150
|
+
else:
|
151
|
+
# pyenv-win doesn't provide the `pyenv root` command
|
152
|
+
pyenv_root = os.getenv("PYENV_ROOT")
|
153
|
+
if pyenv_root is None:
|
154
|
+
raise MlflowException("Environment variable 'PYENV_ROOT' must be set")
|
155
|
+
path_to_bin = ("python.exe",)
|
156
|
+
return Path(pyenv_root).joinpath("versions", version, *path_to_bin)
|
157
|
+
|
158
|
+
|
159
|
+
def _get_conda_env_file(model_config):
|
160
|
+
from mlflow.pyfunc import _extract_conda_env
|
161
|
+
|
162
|
+
for flavor, config in model_config.flavors.items():
|
163
|
+
if flavor == mlflow.pyfunc.FLAVOR_NAME:
|
164
|
+
env = config.get(mlflow.pyfunc.ENV)
|
165
|
+
if env:
|
166
|
+
return _extract_conda_env(env)
|
167
|
+
return _CONDA_ENV_FILE_NAME
|
168
|
+
|
169
|
+
|
170
|
+
def _get_python_env_file(model_config):
|
171
|
+
from mlflow.pyfunc import EnvType
|
172
|
+
|
173
|
+
for flavor, config in model_config.flavors.items():
|
174
|
+
if flavor == mlflow.pyfunc.FLAVOR_NAME:
|
175
|
+
env = config.get(mlflow.pyfunc.ENV)
|
176
|
+
if isinstance(env, dict):
|
177
|
+
# Models saved in MLflow >= 2.0 use a dictionary for the pyfunc flavor
|
178
|
+
# `env` config, where the keys are different environment managers (e.g.
|
179
|
+
# conda, virtualenv) and the values are corresponding environment paths
|
180
|
+
return env[EnvType.VIRTUALENV]
|
181
|
+
return _PYTHON_ENV_FILE_NAME
|
182
|
+
|
183
|
+
|
184
|
+
def _get_python_env(local_model_path):
|
185
|
+
"""Constructs `_PythonEnv` from the model artifacts stored in `local_model_path`. If
|
186
|
+
`python_env.yaml` is available, use it, otherwise extract model dependencies from `conda.yaml`.
|
187
|
+
If `conda.yaml` contains conda dependencies except `python`, `pip`, `setuptools`, and, `wheel`,
|
188
|
+
an `MlflowException` is thrown because conda dependencies cannot be installed in a virtualenv
|
189
|
+
environment.
|
190
|
+
|
191
|
+
Args:
|
192
|
+
local_model_path: Local directory containing the model artifacts.
|
193
|
+
|
194
|
+
Returns:
|
195
|
+
`_PythonEnv` instance.
|
196
|
+
|
197
|
+
"""
|
198
|
+
model_config = Model.load(local_model_path / MLMODEL_FILE_NAME)
|
199
|
+
python_env_file = local_model_path / _get_python_env_file(model_config)
|
200
|
+
conda_env_file = local_model_path / _get_conda_env_file(model_config)
|
201
|
+
requirements_file = local_model_path / _REQUIREMENTS_FILE_NAME
|
202
|
+
|
203
|
+
if python_env_file.exists():
|
204
|
+
return _PythonEnv.from_yaml(python_env_file)
|
205
|
+
else:
|
206
|
+
_logger.info(
|
207
|
+
"This model is missing %s, which is because it was logged in an older version"
|
208
|
+
"of MLflow (< 1.26.0) that does not support restoring a model environment with "
|
209
|
+
"virtualenv. Attempting to extract model dependencies from %s and %s instead.",
|
210
|
+
_PYTHON_ENV_FILE_NAME,
|
211
|
+
_REQUIREMENTS_FILE_NAME,
|
212
|
+
_CONDA_ENV_FILE_NAME,
|
213
|
+
)
|
214
|
+
if requirements_file.exists():
|
215
|
+
deps = _PythonEnv.get_dependencies_from_conda_yaml(conda_env_file)
|
216
|
+
return _PythonEnv(
|
217
|
+
python=deps["python"],
|
218
|
+
build_dependencies=deps["build_dependencies"],
|
219
|
+
dependencies=[f"-r {_REQUIREMENTS_FILE_NAME}"],
|
220
|
+
)
|
221
|
+
else:
|
222
|
+
return _PythonEnv.from_conda_yaml(conda_env_file)
|
223
|
+
|
224
|
+
|
225
|
+
def _get_virtualenv_name(python_env, work_dir_path, env_id=None):
|
226
|
+
requirements = _parse_requirements(
|
227
|
+
python_env.dependencies,
|
228
|
+
is_constraint=False,
|
229
|
+
base_dir=work_dir_path,
|
230
|
+
)
|
231
|
+
return _get_mlflow_env_name(
|
232
|
+
str(python_env) + "".join(map(str, sorted(requirements))) + (env_id or "")
|
233
|
+
)
|
234
|
+
|
235
|
+
|
236
|
+
def _get_virtualenv_activate_cmd(env_dir: Path) -> str:
|
237
|
+
# Created a command to activate the environment
|
238
|
+
paths = ("bin", "activate") if not is_windows() else ("Scripts", "activate.bat")
|
239
|
+
activate_cmd = env_dir.joinpath(*paths)
|
240
|
+
return f"source {activate_cmd}" if not is_windows() else str(activate_cmd)
|
241
|
+
|
242
|
+
|
243
|
+
def _create_virtualenv(
|
244
|
+
local_model_path: Path,
|
245
|
+
python_env: _PythonEnv,
|
246
|
+
env_dir: Path,
|
247
|
+
pyenv_root_dir: Optional[str] = None,
|
248
|
+
env_manager: Literal["virtualenv", "uv"] = em.UV,
|
249
|
+
extra_env: Optional[dict[str, str]] = None,
|
250
|
+
capture_output: bool = False,
|
251
|
+
pip_requirements_override: Optional[list[str]] = None,
|
252
|
+
):
|
253
|
+
if env_manager not in {em.VIRTUALENV, em.UV}:
|
254
|
+
raise MlflowException.invalid_parameter_value(
|
255
|
+
f"Invalid value for `env_manager`: {env_manager}. "
|
256
|
+
f"Must be one of `{em.VIRTUALENV}, {em.UV}`"
|
257
|
+
)
|
258
|
+
|
259
|
+
activate_cmd = _get_virtualenv_activate_cmd(env_dir)
|
260
|
+
if env_dir.exists():
|
261
|
+
_logger.info(f"Environment {env_dir} already exists")
|
262
|
+
return activate_cmd
|
263
|
+
|
264
|
+
if env_manager == em.VIRTUALENV:
|
265
|
+
python_bin_path = _install_python(
|
266
|
+
python_env.python, pyenv_root=pyenv_root_dir, capture_output=capture_output
|
267
|
+
)
|
268
|
+
_logger.info(f"Creating a new environment in {env_dir} with {python_bin_path}")
|
269
|
+
env_creation_cmd = [
|
270
|
+
sys.executable,
|
271
|
+
"-m",
|
272
|
+
"virtualenv",
|
273
|
+
"--python",
|
274
|
+
python_bin_path,
|
275
|
+
env_dir,
|
276
|
+
]
|
277
|
+
install_deps_cmd_prefix = "python -m pip install"
|
278
|
+
elif env_manager == em.UV:
|
279
|
+
_logger.info(
|
280
|
+
f"Creating a new environment in {env_dir} with python "
|
281
|
+
f"version {python_env.python} using uv"
|
282
|
+
)
|
283
|
+
env_creation_cmd = ["uv", "venv", env_dir, f"--python={python_env.python}"]
|
284
|
+
install_deps_cmd_prefix = "uv pip install --prerelease=allow"
|
285
|
+
if _MLFLOW_TESTING.get():
|
286
|
+
os.environ["RUST_LOG"] = "uv=debug"
|
287
|
+
with remove_on_error(
|
288
|
+
env_dir,
|
289
|
+
onerror=lambda e: _logger.warning(
|
290
|
+
"Encountered an unexpected error: %s while creating a virtualenv environment in %s, "
|
291
|
+
"removing the environment directory...",
|
292
|
+
repr(e),
|
293
|
+
env_dir,
|
294
|
+
),
|
295
|
+
):
|
296
|
+
_exec_cmd(
|
297
|
+
env_creation_cmd,
|
298
|
+
capture_output=capture_output,
|
299
|
+
)
|
300
|
+
|
301
|
+
_logger.info("Installing dependencies")
|
302
|
+
for deps in filter(None, [python_env.build_dependencies, python_env.dependencies]):
|
303
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
304
|
+
# Create a temporary requirements file in the model directory to resolve the
|
305
|
+
# references in it correctly. To do this, we must first symlink or copy the model
|
306
|
+
# directory's contents to a temporary location for compatibility with deployment
|
307
|
+
# tools that store models in a read-only mount
|
308
|
+
try:
|
309
|
+
for model_item in os.listdir(local_model_path):
|
310
|
+
os.symlink(
|
311
|
+
src=os.path.join(local_model_path, model_item),
|
312
|
+
dst=os.path.join(tmpdir, model_item),
|
313
|
+
)
|
314
|
+
except Exception as e:
|
315
|
+
_logger.warning(
|
316
|
+
"Failed to symlink model directory during dependency installation"
|
317
|
+
" Copying instead. Exception: %s",
|
318
|
+
e,
|
319
|
+
)
|
320
|
+
_copy_model_to_writeable_destination(local_model_path, tmpdir)
|
321
|
+
|
322
|
+
tmp_req_file = f"requirements.{uuid.uuid4().hex}.txt"
|
323
|
+
Path(tmpdir).joinpath(tmp_req_file).write_text("\n".join(deps))
|
324
|
+
cmd = _join_commands(activate_cmd, f"{install_deps_cmd_prefix} -r {tmp_req_file}")
|
325
|
+
_exec_cmd(cmd, capture_output=capture_output, cwd=tmpdir, extra_env=extra_env)
|
326
|
+
|
327
|
+
if pip_requirements_override:
|
328
|
+
_logger.info(
|
329
|
+
"Installing additional dependencies specified by "
|
330
|
+
f"pip_requirements_override: {pip_requirements_override}"
|
331
|
+
)
|
332
|
+
cmd = _join_commands(
|
333
|
+
activate_cmd,
|
334
|
+
f"{install_deps_cmd_prefix} --quiet {' '.join(pip_requirements_override)}",
|
335
|
+
)
|
336
|
+
_exec_cmd(cmd, capture_output=capture_output, extra_env=extra_env)
|
337
|
+
|
338
|
+
return activate_cmd
|
339
|
+
|
340
|
+
|
341
|
+
def _copy_model_to_writeable_destination(model_src, dst):
|
342
|
+
"""
|
343
|
+
Copies the specified `model_src` directory, which may be read-only, to the writeable `dst`
|
344
|
+
directory.
|
345
|
+
"""
|
346
|
+
os.makedirs(dst, exist_ok=True)
|
347
|
+
for model_item in os.listdir(model_src):
|
348
|
+
# Copy individual files and subdirectories, rather than using `shutil.copytree()`
|
349
|
+
# because `shutil.copytree()` will apply the permissions from the source directory,
|
350
|
+
# which may be read-only
|
351
|
+
copy_fn = shutil.copytree if os.path.isdir(model_item) else shutil.copy2
|
352
|
+
|
353
|
+
copy_fn(
|
354
|
+
src=os.path.join(model_src, model_item),
|
355
|
+
dst=os.path.join(dst, model_item),
|
356
|
+
)
|
357
|
+
|
358
|
+
|
359
|
+
def _get_virtualenv_extra_env_vars(env_root_dir=None):
|
360
|
+
extra_env = {
|
361
|
+
# PIP_NO_INPUT=1 makes pip run in non-interactive mode,
|
362
|
+
# otherwise pip might prompt "yes or no" and ask stdin input
|
363
|
+
"PIP_NO_INPUT": "1",
|
364
|
+
}
|
365
|
+
if env_root_dir is not None:
|
366
|
+
# Note: Both conda pip and virtualenv can use the pip cache directory.
|
367
|
+
extra_env["PIP_CACHE_DIR"] = os.path.join(env_root_dir, _PIP_CACHE_DIR)
|
368
|
+
return extra_env
|
369
|
+
|
370
|
+
|
371
|
+
_VIRTUALENV_ENVS_DIR = "virtualenv_envs"
|
372
|
+
_PYENV_ROOT_DIR = "pyenv_root"
|
373
|
+
|
374
|
+
|
375
|
+
def _get_or_create_virtualenv( # noqa: D417
|
376
|
+
local_model_path,
|
377
|
+
env_id=None,
|
378
|
+
env_root_dir=None,
|
379
|
+
capture_output=False,
|
380
|
+
pip_requirements_override: Optional[list[str]] = None,
|
381
|
+
env_manager: Literal["virtualenv", "uv"] = em.UV,
|
382
|
+
):
|
383
|
+
"""Restores an MLflow model's environment in a virtual environment and returns a command
|
384
|
+
to activate it.
|
385
|
+
|
386
|
+
Args:
|
387
|
+
local_model_path: Local directory containing the model artifacts.
|
388
|
+
env_id: Optional string that is added to the contents of the yaml file before
|
389
|
+
calculating the hash. It can be used to distinguish environments that have the
|
390
|
+
same conda dependencies but are supposed to be different based on the context.
|
391
|
+
For example, when serving the model we may install additional dependencies to the
|
392
|
+
environment after the environment has been activated.
|
393
|
+
pip_requirements_override: If specified, install the specified python dependencies to
|
394
|
+
the environment (upgrade if already installed).
|
395
|
+
env_manager: Specifies the environment manager to use to create the environment.
|
396
|
+
Defaults to "uv".
|
397
|
+
|
398
|
+
.. tip::
|
399
|
+
It is highly recommended to use "uv" as it has significant performance improvements
|
400
|
+
over "virtualenv".
|
401
|
+
|
402
|
+
Returns:
|
403
|
+
Command to activate the created virtual environment
|
404
|
+
(e.g. "source /path/to/bin/activate").
|
405
|
+
|
406
|
+
"""
|
407
|
+
if env_manager == em.VIRTUALENV:
|
408
|
+
_validate_pyenv_is_available()
|
409
|
+
_validate_virtualenv_is_available()
|
410
|
+
|
411
|
+
local_model_path = Path(local_model_path)
|
412
|
+
python_env = _get_python_env(local_model_path)
|
413
|
+
|
414
|
+
pyenv_root_dir = None
|
415
|
+
if env_root_dir is None:
|
416
|
+
virtual_envs_root_path = Path(_get_mlflow_virtualenv_root())
|
417
|
+
else:
|
418
|
+
virtual_envs_root_path = Path(env_root_dir) / _VIRTUALENV_ENVS_DIR
|
419
|
+
if env_manager == em.VIRTUALENV:
|
420
|
+
pyenv_root_path = Path(env_root_dir) / _PYENV_ROOT_DIR
|
421
|
+
pyenv_root_path.mkdir(parents=True, exist_ok=True)
|
422
|
+
pyenv_root_dir = str(pyenv_root_path)
|
423
|
+
|
424
|
+
virtual_envs_root_path.mkdir(parents=True, exist_ok=True)
|
425
|
+
env_name = _get_virtualenv_name(python_env, local_model_path, env_id)
|
426
|
+
env_dir = virtual_envs_root_path / env_name
|
427
|
+
try:
|
428
|
+
env_dir.exists()
|
429
|
+
except PermissionError:
|
430
|
+
if is_in_databricks_runtime():
|
431
|
+
# Updating env_name only doesn't work because the cluster may not have
|
432
|
+
# permission to access the original virtual_envs_root_path
|
433
|
+
virtual_envs_root_path = (
|
434
|
+
Path(env_root_dir) / f"{_VIRTUALENV_ENVS_DIR}_{uuid.uuid4().hex[:8]}"
|
435
|
+
)
|
436
|
+
virtual_envs_root_path.mkdir(parents=True, exist_ok=True)
|
437
|
+
env_dir = virtual_envs_root_path / env_name
|
438
|
+
else:
|
439
|
+
_logger.warning(
|
440
|
+
f"Existing virtual environment directory {env_dir} cannot be accessed "
|
441
|
+
"due to permission error. Check the permissions of the directory and "
|
442
|
+
"try again. If the issue persists, consider cleaning up the directory manually."
|
443
|
+
)
|
444
|
+
raise
|
445
|
+
|
446
|
+
extra_env = _get_virtualenv_extra_env_vars(env_root_dir)
|
447
|
+
|
448
|
+
# Create an environment
|
449
|
+
return _create_virtualenv(
|
450
|
+
local_model_path=local_model_path,
|
451
|
+
python_env=python_env,
|
452
|
+
env_dir=env_dir,
|
453
|
+
pyenv_root_dir=pyenv_root_dir,
|
454
|
+
env_manager=env_manager,
|
455
|
+
extra_env=extra_env,
|
456
|
+
capture_output=capture_output,
|
457
|
+
pip_requirements_override=pip_requirements_override,
|
458
|
+
)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import warnings
|
2
|
+
|
3
|
+
# ANSI escape code
|
4
|
+
ANSI_BASE = "\033["
|
5
|
+
COLORS = {
|
6
|
+
"default_bold": f"{ANSI_BASE}1m",
|
7
|
+
"red": f"{ANSI_BASE}31m",
|
8
|
+
"red_bold": f"{ANSI_BASE}1;31m",
|
9
|
+
"yellow": f"{ANSI_BASE}33m",
|
10
|
+
"yellow_bold": f"{ANSI_BASE}1;33m",
|
11
|
+
"blue": f"{ANSI_BASE}34m",
|
12
|
+
"blue_bold": f"{ANSI_BASE}1;34m",
|
13
|
+
}
|
14
|
+
RESET = "\033[0m"
|
15
|
+
|
16
|
+
|
17
|
+
def color_warning(message: str, stacklevel: int, color: str, category: type[Warning] = UserWarning):
|
18
|
+
if color in COLORS:
|
19
|
+
message = f"{COLORS[color]}{message}{RESET}"
|
20
|
+
|
21
|
+
warnings.warn(
|
22
|
+
message=message,
|
23
|
+
category=category,
|
24
|
+
stacklevel=stacklevel + 1,
|
25
|
+
)
|
@@ -0,0 +1,179 @@
|
|
1
|
+
import codecs
|
2
|
+
import json
|
3
|
+
import os
|
4
|
+
import pathlib
|
5
|
+
import shutil
|
6
|
+
import tempfile
|
7
|
+
|
8
|
+
import yaml
|
9
|
+
|
10
|
+
from mlflow.utils.file_utils import ENCODING, exists, get_parent_dir
|
11
|
+
|
12
|
+
try:
|
13
|
+
from yaml import CSafeDumper as YamlSafeDumper
|
14
|
+
from yaml import CSafeLoader as YamlSafeLoader
|
15
|
+
|
16
|
+
except ImportError:
|
17
|
+
from yaml import SafeDumper as YamlSafeDumper
|
18
|
+
from yaml import SafeLoader as YamlSafeLoader
|
19
|
+
|
20
|
+
from mlflow.exceptions import MissingConfigException
|
21
|
+
from mlflow.utils import merge_dicts
|
22
|
+
|
23
|
+
|
24
|
+
def write_yaml(root, file_name, data, overwrite=False, sort_keys=True, ensure_yaml_extension=True):
|
25
|
+
"""Write dictionary data in yaml format.
|
26
|
+
|
27
|
+
Args:
|
28
|
+
root: Directory name.
|
29
|
+
file_name: Desired file name.
|
30
|
+
data: Data to be dumped as yaml format.
|
31
|
+
overwrite: If True, will overwrite existing files.
|
32
|
+
sort_keys: Whether to sort the keys when writing the yaml file.
|
33
|
+
ensure_yaml_extension: If True, will automatically add .yaml extension if not given.
|
34
|
+
"""
|
35
|
+
if not exists(root):
|
36
|
+
raise MissingConfigException(f"Parent directory '{root}' does not exist.")
|
37
|
+
|
38
|
+
file_path = os.path.join(root, file_name)
|
39
|
+
yaml_file_name = file_path
|
40
|
+
if ensure_yaml_extension and not file_path.endswith(".yaml"):
|
41
|
+
yaml_file_name = file_path + ".yaml"
|
42
|
+
|
43
|
+
if exists(yaml_file_name) and not overwrite:
|
44
|
+
raise Exception(f"Yaml file '{file_path}' exists as '{yaml_file_name}")
|
45
|
+
|
46
|
+
with codecs.open(yaml_file_name, mode="w", encoding=ENCODING) as yaml_file:
|
47
|
+
yaml.dump(
|
48
|
+
data,
|
49
|
+
yaml_file,
|
50
|
+
default_flow_style=False,
|
51
|
+
allow_unicode=True,
|
52
|
+
sort_keys=sort_keys,
|
53
|
+
Dumper=YamlSafeDumper,
|
54
|
+
)
|
55
|
+
|
56
|
+
|
57
|
+
def overwrite_yaml(root, file_name, data, ensure_yaml_extension=True):
|
58
|
+
"""Safely overwrites a preexisting yaml file, ensuring that file contents are not deleted or
|
59
|
+
corrupted if the write fails. This is achieved by writing contents to a temporary file
|
60
|
+
and moving the temporary file to replace the preexisting file, rather than opening the
|
61
|
+
preexisting file for a direct write.
|
62
|
+
|
63
|
+
Args:
|
64
|
+
root: Directory name.
|
65
|
+
file_name: File name.
|
66
|
+
data: The data to write, represented as a dictionary.
|
67
|
+
ensure_yaml_extension: If True, Will automatically add .yaml extension if not given.
|
68
|
+
"""
|
69
|
+
tmp_file_path = None
|
70
|
+
original_file_path = os.path.join(root, file_name)
|
71
|
+
original_file_mode = os.stat(original_file_path).st_mode
|
72
|
+
try:
|
73
|
+
tmp_file_fd, tmp_file_path = tempfile.mkstemp(suffix="file.yaml")
|
74
|
+
os.close(tmp_file_fd)
|
75
|
+
write_yaml(
|
76
|
+
root=get_parent_dir(tmp_file_path),
|
77
|
+
file_name=os.path.basename(tmp_file_path),
|
78
|
+
data=data,
|
79
|
+
overwrite=True,
|
80
|
+
sort_keys=True,
|
81
|
+
ensure_yaml_extension=ensure_yaml_extension,
|
82
|
+
)
|
83
|
+
shutil.move(tmp_file_path, original_file_path)
|
84
|
+
# restores original file permissions, see https://docs.python.org/3/library/tempfile.html#tempfile.mkstemp
|
85
|
+
os.chmod(original_file_path, original_file_mode)
|
86
|
+
finally:
|
87
|
+
if tmp_file_path is not None and os.path.exists(tmp_file_path):
|
88
|
+
os.remove(tmp_file_path)
|
89
|
+
|
90
|
+
|
91
|
+
def read_yaml(root, file_name):
|
92
|
+
"""Read data from yaml file and return as dictionary
|
93
|
+
Args:
|
94
|
+
root: Directory name.
|
95
|
+
file_name: File name. Expects to have '.yaml' extension.
|
96
|
+
|
97
|
+
Returns:
|
98
|
+
Data in yaml file as dictionary.
|
99
|
+
"""
|
100
|
+
if not exists(root):
|
101
|
+
raise MissingConfigException(
|
102
|
+
f"Cannot read '{file_name}'. Parent dir '{root}' does not exist."
|
103
|
+
)
|
104
|
+
|
105
|
+
file_path = os.path.join(root, file_name)
|
106
|
+
if not exists(file_path):
|
107
|
+
raise MissingConfigException(f"Yaml file '{file_path}' does not exist.")
|
108
|
+
with codecs.open(file_path, mode="r", encoding=ENCODING) as yaml_file:
|
109
|
+
return yaml.load(yaml_file, Loader=YamlSafeLoader)
|
110
|
+
|
111
|
+
|
112
|
+
class UniqueKeyLoader(YamlSafeLoader):
|
113
|
+
def construct_mapping(self, node, deep=False):
|
114
|
+
mapping = set()
|
115
|
+
for key_node, _ in node.value:
|
116
|
+
key = self.construct_object(key_node, deep=deep)
|
117
|
+
if key in mapping:
|
118
|
+
raise ValueError(f"Duplicate '{key}' key found in YAML.")
|
119
|
+
mapping.add(key)
|
120
|
+
return super().construct_mapping(node, deep)
|
121
|
+
|
122
|
+
|
123
|
+
def render_and_merge_yaml(root, template_name, context_name):
|
124
|
+
"""Renders a Jinja2-templated YAML file based on a YAML context file, merge them, and return
|
125
|
+
result as a dictionary.
|
126
|
+
|
127
|
+
Args:
|
128
|
+
root: Root directory of the YAML files.
|
129
|
+
template_name: Name of the template file.
|
130
|
+
context_name: Name of the context file.
|
131
|
+
|
132
|
+
Returns:
|
133
|
+
Data in yaml file as dictionary.
|
134
|
+
"""
|
135
|
+
from jinja2 import FileSystemLoader, StrictUndefined
|
136
|
+
from jinja2.sandbox import SandboxedEnvironment
|
137
|
+
|
138
|
+
template_path = os.path.join(root, template_name)
|
139
|
+
context_path = os.path.join(root, context_name)
|
140
|
+
|
141
|
+
for path in (template_path, context_path):
|
142
|
+
if not pathlib.Path(path).is_file():
|
143
|
+
raise MissingConfigException(f"Yaml file '{path}' does not exist.")
|
144
|
+
|
145
|
+
j2_env = SandboxedEnvironment(
|
146
|
+
loader=FileSystemLoader(root, encoding=ENCODING),
|
147
|
+
undefined=StrictUndefined,
|
148
|
+
line_comment_prefix="#",
|
149
|
+
)
|
150
|
+
|
151
|
+
def from_json(input_var):
|
152
|
+
with open(input_var, encoding="utf-8") as f:
|
153
|
+
return json.load(f)
|
154
|
+
|
155
|
+
j2_env.filters["from_json"] = from_json
|
156
|
+
# Compute final source of context file (e.g. my-profile.yml), applying Jinja filters
|
157
|
+
# like from_json as needed to load context information from files, then load into a dict
|
158
|
+
context_source = j2_env.get_template(context_name).render({})
|
159
|
+
context_dict = yaml.load(context_source, Loader=UniqueKeyLoader) or {}
|
160
|
+
|
161
|
+
# Substitute parameters from context dict into template
|
162
|
+
source = j2_env.get_template(template_name).render(context_dict)
|
163
|
+
rendered_template_dict = yaml.load(source, Loader=UniqueKeyLoader)
|
164
|
+
return merge_dicts(rendered_template_dict, context_dict)
|
165
|
+
|
166
|
+
|
167
|
+
class safe_edit_yaml:
|
168
|
+
def __init__(self, root, file_name, edit_func):
|
169
|
+
self._root = root
|
170
|
+
self._file_name = file_name
|
171
|
+
self._edit_func = edit_func
|
172
|
+
self._original = read_yaml(root, file_name)
|
173
|
+
|
174
|
+
def __enter__(self):
|
175
|
+
new_dict = self._edit_func(self._original.copy())
|
176
|
+
write_yaml(self._root, self._file_name, new_dict, overwrite=True)
|
177
|
+
|
178
|
+
def __exit__(self, *args):
|
179
|
+
write_yaml(self._root, self._file_name, self._original, overwrite=True)
|
mlflow/version.py
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright 2018 Databricks, Inc.
|
2
|
+
import importlib.metadata
|
3
|
+
import re
|
4
|
+
|
5
|
+
VERSION = "3.1.2.dev0"
|
6
|
+
|
7
|
+
|
8
|
+
def is_release_version():
|
9
|
+
return bool(re.match(r"^\d+\.\d+\.\d+$", VERSION))
|
10
|
+
|
11
|
+
|
12
|
+
def _is_package_installed(package_name: str) -> bool:
|
13
|
+
try:
|
14
|
+
importlib.metadata.version(package_name)
|
15
|
+
return True
|
16
|
+
except importlib.metadata.PackageNotFoundError:
|
17
|
+
return False
|
18
|
+
|
19
|
+
|
20
|
+
# A flag to indicate whether the environment only has the tracing SDK
|
21
|
+
# installed, or includes the full MLflow or mlflow-skinny package.
|
22
|
+
# This is used to determine whether to import modules that require
|
23
|
+
# dependencies that are not included in the tracing SDK.
|
24
|
+
IS_TRACING_SDK_ONLY = not any(_is_package_installed(pkg) for pkg in ["mlflow", "mlflow-skinny"])
|