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,340 @@
|
|
1
|
+
"""Database connection factory with Azure authentication support."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
import logging
|
6
|
+
from typing import Optional, Dict, Any
|
7
|
+
from urllib.parse import urlparse, urlencode, parse_qs
|
8
|
+
|
9
|
+
from sqlalchemy import create_engine, event, Engine, text
|
10
|
+
from sqlalchemy.engine import make_url
|
11
|
+
from sqlalchemy.pool import QueuePool
|
12
|
+
|
13
|
+
from mlflow.azure.auth_handler import AzureAuthHandler
|
14
|
+
from mlflow.azure.config import AzureAuthConfig
|
15
|
+
from mlflow.azure.exceptions import ConnectionError, ConfigurationError
|
16
|
+
from mlflow.azure.utils import sanitize_connection_string_for_logging
|
17
|
+
|
18
|
+
logger = logging.getLogger(__name__)
|
19
|
+
|
20
|
+
|
21
|
+
class ConnectionFactory:
|
22
|
+
"""Factory for creating database connections with Azure authentication."""
|
23
|
+
|
24
|
+
def __init__(self, config: Optional[AzureAuthConfig] = None):
|
25
|
+
"""Initialize the connection factory.
|
26
|
+
|
27
|
+
Args:
|
28
|
+
config: Azure authentication configuration
|
29
|
+
"""
|
30
|
+
self.config = config or AzureAuthConfig()
|
31
|
+
self.auth_handler = (
|
32
|
+
AzureAuthHandler(self.config) if self.config.should_use_azure_auth else None
|
33
|
+
)
|
34
|
+
|
35
|
+
logger.info(
|
36
|
+
"Initialized connection factory: azure_auth_enabled=%s, auth_method=%s",
|
37
|
+
self.config.should_use_azure_auth,
|
38
|
+
self.config.auth_method.value if self.config.should_use_azure_auth else "sql_auth",
|
39
|
+
)
|
40
|
+
|
41
|
+
def create_engine(
|
42
|
+
self,
|
43
|
+
database_uri: str,
|
44
|
+
**engine_kwargs: Any,
|
45
|
+
) -> Engine:
|
46
|
+
"""Create a SQLAlchemy engine with Azure authentication support.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
database_uri: Database connection URI
|
50
|
+
**engine_kwargs: Additional engine configuration
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
Configured SQLAlchemy engine
|
54
|
+
|
55
|
+
Raises:
|
56
|
+
ConnectionError: If connection configuration fails
|
57
|
+
ConfigurationError: If the URI is invalid
|
58
|
+
"""
|
59
|
+
logger.info(
|
60
|
+
"Creating database engine: connection_info=%s, azure_auth=%s",
|
61
|
+
sanitize_connection_string_for_logging(database_uri),
|
62
|
+
self.config.should_use_azure_auth,
|
63
|
+
)
|
64
|
+
|
65
|
+
try:
|
66
|
+
# Parse and validate the URI
|
67
|
+
parsed_uri = self._parse_and_validate_uri(database_uri)
|
68
|
+
|
69
|
+
# Prepare engine configuration
|
70
|
+
engine_config = self._prepare_engine_config(parsed_uri, **engine_kwargs)
|
71
|
+
|
72
|
+
# Create the engine
|
73
|
+
engine = create_engine(**engine_config)
|
74
|
+
|
75
|
+
# Set up Azure authentication if enabled
|
76
|
+
if self.config.should_use_azure_auth and self.auth_handler:
|
77
|
+
self._setup_azure_auth_events(engine)
|
78
|
+
|
79
|
+
logger.info("Database engine created successfully")
|
80
|
+
return engine
|
81
|
+
|
82
|
+
except Exception as e:
|
83
|
+
logger.error("Failed to create database engine: %s", str(e))
|
84
|
+
raise ConnectionError(f"Failed to create database engine: {e}") from e
|
85
|
+
|
86
|
+
def _parse_and_validate_uri(self, database_uri: str) -> Dict[str, Any]:
|
87
|
+
"""Parse and validate database URI.
|
88
|
+
|
89
|
+
Args:
|
90
|
+
database_uri: Database connection URI
|
91
|
+
|
92
|
+
Returns:
|
93
|
+
Parsed URI components
|
94
|
+
|
95
|
+
Raises:
|
96
|
+
ConfigurationError: If URI is invalid
|
97
|
+
"""
|
98
|
+
try:
|
99
|
+
# Handle azure-postgres:// scheme by converting to postgresql://
|
100
|
+
if database_uri.startswith("azure-postgres://"):
|
101
|
+
database_uri = database_uri.replace("azure-postgres://", "postgresql://", 1)
|
102
|
+
|
103
|
+
url = make_url(database_uri)
|
104
|
+
|
105
|
+
if url.drivername not in ["postgresql", "postgresql+psycopg2"]:
|
106
|
+
raise ConfigurationError(f"Unsupported database driver: {url.drivername}")
|
107
|
+
|
108
|
+
return {
|
109
|
+
"drivername": url.drivername,
|
110
|
+
"username": url.username,
|
111
|
+
"password": url.password,
|
112
|
+
"host": url.host,
|
113
|
+
"port": url.port or 5432,
|
114
|
+
"database": url.database,
|
115
|
+
"query": dict(url.query),
|
116
|
+
}
|
117
|
+
|
118
|
+
except Exception as e:
|
119
|
+
raise ConfigurationError(f"Invalid database URI: {e}") from e
|
120
|
+
|
121
|
+
def _prepare_engine_config(
|
122
|
+
self,
|
123
|
+
parsed_uri: Dict[str, Any],
|
124
|
+
**engine_kwargs: Any,
|
125
|
+
) -> Dict[str, Any]:
|
126
|
+
"""Prepare SQLAlchemy engine configuration.
|
127
|
+
|
128
|
+
Args:
|
129
|
+
parsed_uri: Parsed database URI components
|
130
|
+
**engine_kwargs: Additional engine configuration
|
131
|
+
|
132
|
+
Returns:
|
133
|
+
Engine configuration dictionary
|
134
|
+
"""
|
135
|
+
# Build connection URL
|
136
|
+
url_parts = {
|
137
|
+
"drivername": parsed_uri["drivername"],
|
138
|
+
"username": parsed_uri["username"],
|
139
|
+
"host": parsed_uri["host"],
|
140
|
+
"port": parsed_uri["port"],
|
141
|
+
"database": parsed_uri["database"],
|
142
|
+
}
|
143
|
+
|
144
|
+
# Handle password for non-Azure auth
|
145
|
+
if not self.config.should_use_azure_auth:
|
146
|
+
url_parts["password"] = parsed_uri["password"]
|
147
|
+
|
148
|
+
# Prepare query parameters - remove custom auth parameters
|
149
|
+
query_params = parsed_uri["query"].copy()
|
150
|
+
|
151
|
+
# Remove custom parameters that psycopg2 doesn't understand
|
152
|
+
query_params.pop("auth_method", None)
|
153
|
+
|
154
|
+
# Ensure SSL for Azure connections
|
155
|
+
if self.config.should_use_azure_auth:
|
156
|
+
query_params.setdefault("sslmode", "require")
|
157
|
+
|
158
|
+
url_parts["query"] = query_params
|
159
|
+
|
160
|
+
# Create URL
|
161
|
+
from sqlalchemy.engine.url import URL
|
162
|
+
|
163
|
+
url = URL.create(**url_parts)
|
164
|
+
|
165
|
+
# Default engine configuration
|
166
|
+
config = {
|
167
|
+
"url": url,
|
168
|
+
"echo": engine_kwargs.pop("echo", False),
|
169
|
+
"echo_pool": engine_kwargs.pop("echo_pool", False),
|
170
|
+
"poolclass": engine_kwargs.pop("poolclass", QueuePool),
|
171
|
+
"pool_size": engine_kwargs.pop("pool_size", self.config.pool_size),
|
172
|
+
"max_overflow": engine_kwargs.pop("max_overflow", self.config.max_overflow),
|
173
|
+
"pool_recycle": engine_kwargs.pop("pool_recycle", self.config.pool_recycle),
|
174
|
+
"pool_pre_ping": engine_kwargs.pop("pool_pre_ping", self.config.pool_pre_ping),
|
175
|
+
"connect_args": engine_kwargs.pop("connect_args", {}),
|
176
|
+
}
|
177
|
+
|
178
|
+
# Add connection timeout
|
179
|
+
config["connect_args"].setdefault("connect_timeout", self.config.connection_timeout)
|
180
|
+
|
181
|
+
# Add any remaining engine kwargs
|
182
|
+
config.update(engine_kwargs)
|
183
|
+
|
184
|
+
return config
|
185
|
+
|
186
|
+
def _setup_azure_auth_events(self, engine: Engine) -> None:
|
187
|
+
"""Set up SQLAlchemy events for Azure authentication.
|
188
|
+
|
189
|
+
Args:
|
190
|
+
engine: SQLAlchemy engine to configure
|
191
|
+
"""
|
192
|
+
if not self.auth_handler:
|
193
|
+
return
|
194
|
+
|
195
|
+
@event.listens_for(engine, "do_connect")
|
196
|
+
def do_connect(dialect, conn_rec, cargs, cparams):
|
197
|
+
"""Inject Azure token before connecting."""
|
198
|
+
try:
|
199
|
+
# Get fresh token
|
200
|
+
token = self.auth_handler.get_access_token()
|
201
|
+
|
202
|
+
# Inject token as password
|
203
|
+
cparams["password"] = token
|
204
|
+
|
205
|
+
logger.debug("Injected Azure token for database connection")
|
206
|
+
|
207
|
+
except Exception as e:
|
208
|
+
logger.error("Failed to inject Azure token: %s", str(e))
|
209
|
+
raise ConnectionError(f"Failed to inject Azure token: {e}") from e
|
210
|
+
|
211
|
+
@event.listens_for(engine, "connect")
|
212
|
+
def connect(dbapi_connection, connection_record):
|
213
|
+
"""Handle post-connection setup."""
|
214
|
+
logger.debug("Database connection established")
|
215
|
+
|
216
|
+
@event.listens_for(engine, "checkout")
|
217
|
+
def checkout(dbapi_connection, connection_record, connection_proxy):
|
218
|
+
"""Handle connection checkout from pool."""
|
219
|
+
# Refresh token if needed before using connection
|
220
|
+
if self.auth_handler:
|
221
|
+
try:
|
222
|
+
self.auth_handler.refresh_token_if_needed()
|
223
|
+
except Exception as e:
|
224
|
+
logger.warning("Token refresh failed during checkout: %s", str(e))
|
225
|
+
|
226
|
+
def test_connection(self, database_uri: str) -> bool:
|
227
|
+
"""Test database connection.
|
228
|
+
|
229
|
+
Args:
|
230
|
+
database_uri: Database connection URI
|
231
|
+
|
232
|
+
Returns:
|
233
|
+
True if connection successful, False otherwise
|
234
|
+
"""
|
235
|
+
try:
|
236
|
+
engine = self.create_engine(database_uri)
|
237
|
+
|
238
|
+
with engine.connect() as conn:
|
239
|
+
# Simple test query
|
240
|
+
result = conn.execute(text("SELECT 1"))
|
241
|
+
result.fetchone()
|
242
|
+
|
243
|
+
logger.info("Database connection test successful")
|
244
|
+
return True
|
245
|
+
|
246
|
+
except Exception as e:
|
247
|
+
logger.error("Database connection test failed: %s", str(e))
|
248
|
+
return False
|
249
|
+
|
250
|
+
def create_connection_url(
|
251
|
+
self,
|
252
|
+
host: str,
|
253
|
+
database: str,
|
254
|
+
username: str,
|
255
|
+
port: int = 5432,
|
256
|
+
password: Optional[str] = None,
|
257
|
+
**params: Any,
|
258
|
+
) -> str:
|
259
|
+
"""Create a PostgreSQL connection URL.
|
260
|
+
|
261
|
+
Args:
|
262
|
+
host: Database host
|
263
|
+
database: Database name
|
264
|
+
username: Database username
|
265
|
+
port: Database port
|
266
|
+
password: Database password (optional for Azure auth)
|
267
|
+
**params: Additional connection parameters
|
268
|
+
|
269
|
+
Returns:
|
270
|
+
PostgreSQL connection URL
|
271
|
+
"""
|
272
|
+
# Ensure SSL for Azure connections
|
273
|
+
if self.config.should_use_azure_auth:
|
274
|
+
params.setdefault("sslmode", "require")
|
275
|
+
|
276
|
+
# Build URL components
|
277
|
+
url_parts = ["postgresql://"]
|
278
|
+
|
279
|
+
# Add credentials
|
280
|
+
if username:
|
281
|
+
url_parts.append(username)
|
282
|
+
if password and not self.config.should_use_azure_auth:
|
283
|
+
url_parts.append(f":{password}")
|
284
|
+
url_parts.append("@")
|
285
|
+
|
286
|
+
# Add host and port
|
287
|
+
url_parts.append(f"{host}:{port}")
|
288
|
+
|
289
|
+
# Add database
|
290
|
+
if database:
|
291
|
+
url_parts.append(f"/{database}")
|
292
|
+
|
293
|
+
# Add query parameters
|
294
|
+
if params:
|
295
|
+
query_string = urlencode(params)
|
296
|
+
url_parts.append(f"?{query_string}")
|
297
|
+
|
298
|
+
url = "".join(url_parts)
|
299
|
+
logger.debug("Created connection URL: %s", sanitize_connection_string_for_logging(url))
|
300
|
+
|
301
|
+
return url
|
302
|
+
|
303
|
+
|
304
|
+
class PoolManager:
|
305
|
+
"""Manages connection pools with token refresh capabilities."""
|
306
|
+
|
307
|
+
def __init__(self, connection_factory: ConnectionFactory):
|
308
|
+
self.connection_factory = connection_factory
|
309
|
+
self._engines: Dict[str, Engine] = {}
|
310
|
+
|
311
|
+
def get_engine(self, connection_string: str, **kwargs) -> Engine:
|
312
|
+
"""Get or create engine for connection string."""
|
313
|
+
# Use connection string as key (could be enhanced with hashing)
|
314
|
+
key = connection_string
|
315
|
+
|
316
|
+
if key not in self._engines:
|
317
|
+
self._engines[key] = self.connection_factory.create_engine(connection_string, **kwargs)
|
318
|
+
|
319
|
+
return self._engines[key]
|
320
|
+
|
321
|
+
def refresh_connections(self):
|
322
|
+
"""Refresh all connection pools to get new tokens."""
|
323
|
+
for engine in self._engines.values():
|
324
|
+
try:
|
325
|
+
# Dispose current connections to force new ones with fresh tokens
|
326
|
+
engine.dispose()
|
327
|
+
logger.info("Refreshed connection pool")
|
328
|
+
except Exception as e:
|
329
|
+
logger.error("Failed to refresh connection pool: %s", str(e))
|
330
|
+
|
331
|
+
def close_all(self):
|
332
|
+
"""Close all connection pools."""
|
333
|
+
for engine in self._engines.values():
|
334
|
+
try:
|
335
|
+
engine.dispose()
|
336
|
+
except Exception as e:
|
337
|
+
logger.error("Failed to dispose engine: %s", str(e))
|
338
|
+
|
339
|
+
self._engines.clear()
|
340
|
+
logger.info("Closed all connection pools")
|
@@ -0,0 +1,27 @@
|
|
1
|
+
"""Custom exceptions for Azure authentication."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
|
6
|
+
class AzureAuthError(Exception):
|
7
|
+
"""Base exception for Azure authentication errors."""
|
8
|
+
|
9
|
+
pass
|
10
|
+
|
11
|
+
|
12
|
+
class TokenAcquisitionError(AzureAuthError):
|
13
|
+
"""Raised when token acquisition fails."""
|
14
|
+
|
15
|
+
pass
|
16
|
+
|
17
|
+
|
18
|
+
class ConnectionError(AzureAuthError):
|
19
|
+
"""Raised when database connection fails."""
|
20
|
+
|
21
|
+
pass
|
22
|
+
|
23
|
+
|
24
|
+
class ConfigurationError(AzureAuthError):
|
25
|
+
"""Raised when configuration is invalid."""
|
26
|
+
|
27
|
+
pass
|
mlflow/azure/stores.py
ADDED
@@ -0,0 +1,327 @@
|
|
1
|
+
"""Azure-authenticated PostgreSQL stores for MLflow."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
import os
|
6
|
+
import logging
|
7
|
+
from typing import Optional, Any, Dict
|
8
|
+
|
9
|
+
from sqlalchemy import Engine
|
10
|
+
|
11
|
+
from mlflow.azure.config import AzureAuthConfig
|
12
|
+
from mlflow.azure.connection_factory import ConnectionFactory
|
13
|
+
from mlflow.azure.exceptions import ConnectionError, ConfigurationError
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
class AzurePostgreSQLStore:
|
19
|
+
"""MLflow tracking store with Azure Managed Identity authentication for PostgreSQL."""
|
20
|
+
|
21
|
+
def __init__(
|
22
|
+
self,
|
23
|
+
db_uri: str,
|
24
|
+
default_artifact_root: Optional[str] = None,
|
25
|
+
config: Optional[AzureAuthConfig] = None,
|
26
|
+
):
|
27
|
+
"""Initialize the Azure PostgreSQL tracking store.
|
28
|
+
|
29
|
+
Args:
|
30
|
+
db_uri: Database connection URI
|
31
|
+
default_artifact_root: Default artifact root path
|
32
|
+
config: Azure authentication configuration
|
33
|
+
"""
|
34
|
+
# Import MLflow classes only when needed to avoid circular imports
|
35
|
+
from mlflow.store.tracking.sqlalchemy_store import SqlAlchemyStore
|
36
|
+
|
37
|
+
self.config = config or AzureAuthConfig()
|
38
|
+
self.connection_factory = ConnectionFactory(self.config)
|
39
|
+
|
40
|
+
logger.info(
|
41
|
+
"Initializing Azure PostgreSQL tracking store: azure_auth_enabled=%s, auth_method=%s",
|
42
|
+
self.config.should_use_azure_auth,
|
43
|
+
self.config.auth_method.value,
|
44
|
+
)
|
45
|
+
|
46
|
+
# Create engine with Azure authentication
|
47
|
+
try:
|
48
|
+
engine = self._create_engine(db_uri)
|
49
|
+
except Exception as e:
|
50
|
+
logger.error("Failed to create database engine: %s", str(e))
|
51
|
+
raise ConnectionError(f"Failed to initialize tracking store: {e}") from e
|
52
|
+
|
53
|
+
# Initialize internal SQLAlchemy store
|
54
|
+
try:
|
55
|
+
# Convert azure-postgres:// scheme to postgresql:// for MLflow compatibility
|
56
|
+
# MLflow only recognizes standard database schemes
|
57
|
+
standard_uri = db_uri.replace("azure-postgres://", "postgresql://", 1)
|
58
|
+
|
59
|
+
# Remove auth_method parameter from URI for MLflow
|
60
|
+
from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
|
61
|
+
parsed = urlparse(standard_uri)
|
62
|
+
query_params = parse_qs(parsed.query)
|
63
|
+
clean_query_params = {k: v for k, v in query_params.items() if k != "auth_method"}
|
64
|
+
clean_query = urlencode(clean_query_params, doseq=True)
|
65
|
+
clean_parsed = parsed._replace(query=clean_query)
|
66
|
+
clean_uri = urlunparse(clean_parsed)
|
67
|
+
|
68
|
+
# Add our Azure-enabled engine to the engine map BEFORE initializing SqlAlchemyStore
|
69
|
+
# This prevents MLflow from creating its own engine and ensures migrations work correctly
|
70
|
+
SqlAlchemyStore._db_uri_sql_alchemy_engine_map[clean_uri] = engine
|
71
|
+
|
72
|
+
# Initialize with the clean PostgreSQL URI so MLflow's validation passes
|
73
|
+
self._store = SqlAlchemyStore(clean_uri, default_artifact_root)
|
74
|
+
|
75
|
+
logger.info("Azure PostgreSQL tracking store initialized successfully")
|
76
|
+
|
77
|
+
except Exception as e:
|
78
|
+
logger.error("Failed to initialize SQLAlchemy store: %s", str(e))
|
79
|
+
raise
|
80
|
+
|
81
|
+
def __getattr__(self, name):
|
82
|
+
"""Delegate all method calls to the internal SQLAlchemy store."""
|
83
|
+
return getattr(self._store, name)
|
84
|
+
|
85
|
+
def _create_engine(self, db_uri: str) -> Engine:
|
86
|
+
"""Create database engine with Azure authentication.
|
87
|
+
|
88
|
+
Args:
|
89
|
+
db_uri: Database connection URI
|
90
|
+
|
91
|
+
Returns:
|
92
|
+
Configured SQLAlchemy engine
|
93
|
+
"""
|
94
|
+
# Use our connection factory to create the engine
|
95
|
+
return self.connection_factory.create_engine(
|
96
|
+
db_uri,
|
97
|
+
echo=self.config.enable_debug_logging,
|
98
|
+
)
|
99
|
+
|
100
|
+
@classmethod
|
101
|
+
def from_config(
|
102
|
+
cls,
|
103
|
+
db_uri: Optional[str] = None,
|
104
|
+
default_artifact_root: Optional[str] = None,
|
105
|
+
config: Optional[AzureAuthConfig] = None,
|
106
|
+
) -> "AzurePostgreSQLStore":
|
107
|
+
"""Create store from configuration.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
db_uri: Database URI (defaults to MLFLOW_BACKEND_STORE_URI)
|
111
|
+
default_artifact_root: Artifact root (defaults to MLFLOW_DEFAULT_ARTIFACT_ROOT)
|
112
|
+
config: Azure authentication configuration
|
113
|
+
|
114
|
+
Returns:
|
115
|
+
Configured store instance
|
116
|
+
"""
|
117
|
+
# Get URI from environment if not provided
|
118
|
+
if not db_uri:
|
119
|
+
db_uri = os.getenv("MLFLOW_BACKEND_STORE_URI")
|
120
|
+
if not db_uri:
|
121
|
+
raise ConfigurationError(
|
122
|
+
"Database URI must be provided or set in MLFLOW_BACKEND_STORE_URI"
|
123
|
+
)
|
124
|
+
|
125
|
+
# Get artifact root from environment if not provided
|
126
|
+
if not default_artifact_root:
|
127
|
+
default_artifact_root = os.getenv("MLFLOW_DEFAULT_ARTIFACT_ROOT")
|
128
|
+
|
129
|
+
# Create config if not provided
|
130
|
+
if not config:
|
131
|
+
config = AzureAuthConfig()
|
132
|
+
|
133
|
+
return cls(db_uri, default_artifact_root, config)
|
134
|
+
|
135
|
+
def __enter__(self):
|
136
|
+
"""Context manager entry."""
|
137
|
+
return self
|
138
|
+
|
139
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
140
|
+
"""Context manager exit with cleanup."""
|
141
|
+
try:
|
142
|
+
if hasattr(self, "engine") and self.engine:
|
143
|
+
self.engine.dispose()
|
144
|
+
logger.debug("Database engine disposed")
|
145
|
+
except Exception as e:
|
146
|
+
logger.warning("Error during cleanup: %s", str(e))
|
147
|
+
|
148
|
+
|
149
|
+
def create_store(store_uri: str, artifact_uri: Optional[str] = None):
|
150
|
+
"""Factory function for creating tracking store with Azure authentication.
|
151
|
+
|
152
|
+
This function is called by MLflow's plugin system and automatically detects
|
153
|
+
if Azure authentication should be used based on environment variables.
|
154
|
+
|
155
|
+
Args:
|
156
|
+
store_uri: Database connection URI
|
157
|
+
artifact_uri: Artifact storage URI
|
158
|
+
|
159
|
+
Returns:
|
160
|
+
Azure-enabled tracking store if Azure auth is enabled, standard store otherwise
|
161
|
+
"""
|
162
|
+
# Check if Azure authentication should be used
|
163
|
+
config = AzureAuthConfig()
|
164
|
+
|
165
|
+
# Auto-detect Azure PostgreSQL and enable auth if credentials are available
|
166
|
+
is_azure_postgres = (
|
167
|
+
store_uri.startswith("azure-postgres://") or
|
168
|
+
".postgres.database.azure.com" in store_uri or
|
169
|
+
"auth_method=managed_identity" in store_uri
|
170
|
+
)
|
171
|
+
|
172
|
+
# For Azure PostgreSQL, enable auth if we have any Azure credentials
|
173
|
+
if is_azure_postgres and not config.auth_enabled:
|
174
|
+
# Enable auth automatically if we have Azure credentials
|
175
|
+
if config.client_id or config.client_secret or os.getenv("AZURE_CLIENT_ID"):
|
176
|
+
config.auth_enabled = True
|
177
|
+
if not config.auth_method or config.auth_method == config.auth_method.SQL_AUTH:
|
178
|
+
# Default to service principal if we have credentials, managed identity otherwise
|
179
|
+
config.auth_method = (
|
180
|
+
config.auth_method.SERVICE_PRINCIPAL
|
181
|
+
if config.client_secret or os.getenv("AZURE_CLIENT_SECRET")
|
182
|
+
else config.auth_method.MANAGED_IDENTITY
|
183
|
+
)
|
184
|
+
|
185
|
+
if config.should_use_azure_auth:
|
186
|
+
logger.info("Creating Azure-enabled tracking store via plugin: auth_method=%s", config.auth_method.value)
|
187
|
+
|
188
|
+
try:
|
189
|
+
# Import MLflow store
|
190
|
+
from mlflow.store.tracking.sqlalchemy_store import SqlAlchemyStore
|
191
|
+
|
192
|
+
# Ensure we have a postgresql:// scheme
|
193
|
+
standard_uri = store_uri.replace("azure-postgres://", "postgresql://", 1)
|
194
|
+
|
195
|
+
# Clean the URI
|
196
|
+
from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
|
197
|
+
parsed = urlparse(standard_uri)
|
198
|
+
query_params = parse_qs(parsed.query)
|
199
|
+
clean_query_params = {k: v for k, v in query_params.items() if k != "auth_method"}
|
200
|
+
clean_query = urlencode(clean_query_params, doseq=True)
|
201
|
+
clean_parsed = parsed._replace(query=clean_query)
|
202
|
+
clean_uri = urlunparse(clean_parsed)
|
203
|
+
|
204
|
+
# Check if we already have this engine cached
|
205
|
+
if clean_uri not in SqlAlchemyStore._db_uri_sql_alchemy_engine_map:
|
206
|
+
# Create our Azure-enabled engine and cache it
|
207
|
+
connection_factory = ConnectionFactory(config)
|
208
|
+
engine = connection_factory.create_engine(standard_uri)
|
209
|
+
SqlAlchemyStore._db_uri_sql_alchemy_engine_map[clean_uri] = engine
|
210
|
+
logger.debug("Cached new Azure-enabled engine")
|
211
|
+
else:
|
212
|
+
logger.debug("Reusing cached Azure-enabled engine")
|
213
|
+
|
214
|
+
# Create the standard MLflow store - it will use our cached engine
|
215
|
+
# Ensure artifact_uri is not None or empty to avoid FileNotFoundError
|
216
|
+
logger.debug(f"Raw artifact_uri: {repr(artifact_uri)}")
|
217
|
+
safe_artifact_uri = artifact_uri if (artifact_uri and artifact_uri.strip()) else "./mlflow-artifacts"
|
218
|
+
logger.debug(f"Safe artifact_uri: {repr(safe_artifact_uri)}")
|
219
|
+
return SqlAlchemyStore(clean_uri, safe_artifact_uri)
|
220
|
+
|
221
|
+
except Exception as e:
|
222
|
+
logger.error("Failed to create Azure-enabled store via plugin: %s", str(e))
|
223
|
+
raise
|
224
|
+
else:
|
225
|
+
# Azure auth not enabled, fall back to standard MLflow behavior
|
226
|
+
logger.info("Azure authentication not enabled, using standard tracking store")
|
227
|
+
from mlflow.store.tracking.sqlalchemy_store import SqlAlchemyStore
|
228
|
+
# Ensure artifact_uri is not None or empty to avoid FileNotFoundError
|
229
|
+
logger.debug(f"Fallback raw artifact_uri: {repr(artifact_uri)}")
|
230
|
+
safe_artifact_uri = artifact_uri if (artifact_uri and artifact_uri.strip()) else "./mlflow-artifacts"
|
231
|
+
logger.debug(f"Fallback safe artifact_uri: {repr(safe_artifact_uri)}")
|
232
|
+
return SqlAlchemyStore(store_uri, safe_artifact_uri)
|
233
|
+
|
234
|
+
|
235
|
+
# For backward compatibility and testing
|
236
|
+
def get_store(store_uri: str, artifact_uri: Optional[str] = None) -> AzurePostgreSQLStore:
|
237
|
+
"""Get a configured Azure PostgreSQL tracking store.
|
238
|
+
|
239
|
+
Args:
|
240
|
+
store_uri: Database connection URI
|
241
|
+
artifact_uri: Artifact storage URI
|
242
|
+
|
243
|
+
Returns:
|
244
|
+
Configured store instance
|
245
|
+
"""
|
246
|
+
return create_store(store_uri, artifact_uri)
|
247
|
+
|
248
|
+
|
249
|
+
# Utility functions for manual store creation
|
250
|
+
def get_azure_tracking_store(
|
251
|
+
db_uri: str, artifact_uri: Optional[str] = None, config: Optional[AzureAuthConfig] = None
|
252
|
+
) -> AzurePostgreSQLStore:
|
253
|
+
"""
|
254
|
+
Create a tracking store with specific configuration.
|
255
|
+
|
256
|
+
Args:
|
257
|
+
db_uri: Database connection URI
|
258
|
+
artifact_uri: Artifact storage URI
|
259
|
+
config: Authentication configuration
|
260
|
+
|
261
|
+
Returns:
|
262
|
+
Configured AzurePostgreSQLStore
|
263
|
+
"""
|
264
|
+
if config:
|
265
|
+
# Temporarily override global config
|
266
|
+
import os
|
267
|
+
|
268
|
+
original_env = {}
|
269
|
+
|
270
|
+
try:
|
271
|
+
# Save original environment
|
272
|
+
for key in [
|
273
|
+
"MLFLOW_AZURE_AUTH_ENABLED",
|
274
|
+
"MLFLOW_AZURE_AUTH_METHOD",
|
275
|
+
"AZURE_CLIENT_ID",
|
276
|
+
"AZURE_TENANT_ID",
|
277
|
+
]:
|
278
|
+
if key in os.environ:
|
279
|
+
original_env[key] = os.environ[key]
|
280
|
+
|
281
|
+
# Set new environment
|
282
|
+
os.environ["MLFLOW_AZURE_AUTH_ENABLED"] = str(config.auth_enabled).lower()
|
283
|
+
os.environ["MLFLOW_AZURE_AUTH_METHOD"] = config.auth_method.value
|
284
|
+
if config.client_id:
|
285
|
+
os.environ["AZURE_CLIENT_ID"] = config.client_id
|
286
|
+
if config.tenant_id:
|
287
|
+
os.environ["AZURE_TENANT_ID"] = config.tenant_id
|
288
|
+
|
289
|
+
# Create store with new config
|
290
|
+
store = AzurePostgreSQLStore(db_uri, artifact_uri)
|
291
|
+
|
292
|
+
finally:
|
293
|
+
# Restore original environment
|
294
|
+
for key, value in original_env.items():
|
295
|
+
os.environ[key] = value
|
296
|
+
|
297
|
+
# Remove keys that weren't originally set
|
298
|
+
for key in [
|
299
|
+
"MLFLOW_AZURE_AUTH_ENABLED",
|
300
|
+
"MLFLOW_AZURE_AUTH_METHOD",
|
301
|
+
"AZURE_CLIENT_ID",
|
302
|
+
"AZURE_TENANT_ID",
|
303
|
+
]:
|
304
|
+
if key not in original_env and key in os.environ:
|
305
|
+
del os.environ[key]
|
306
|
+
|
307
|
+
return store
|
308
|
+
|
309
|
+
else:
|
310
|
+
return AzurePostgreSQLStore(db_uri, artifact_uri)
|
311
|
+
|
312
|
+
|
313
|
+
def test_azure_connection(db_uri: str, config: Optional[AzureAuthConfig] = None) -> bool:
|
314
|
+
"""
|
315
|
+
Test Azure database connection.
|
316
|
+
|
317
|
+
Args:
|
318
|
+
db_uri: Database connection URI
|
319
|
+
config: Authentication configuration
|
320
|
+
|
321
|
+
Returns:
|
322
|
+
True if connection successful, False otherwise
|
323
|
+
"""
|
324
|
+
test_config = config or AzureAuthConfig()
|
325
|
+
connection_factory = ConnectionFactory(test_config)
|
326
|
+
|
327
|
+
return connection_factory.test_connection(db_uri)
|