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.
Files changed (645) hide show
  1. genesis_flow-1.0.0.dist-info/METADATA +822 -0
  2. genesis_flow-1.0.0.dist-info/RECORD +645 -0
  3. genesis_flow-1.0.0.dist-info/WHEEL +5 -0
  4. genesis_flow-1.0.0.dist-info/entry_points.txt +19 -0
  5. genesis_flow-1.0.0.dist-info/licenses/LICENSE.txt +202 -0
  6. genesis_flow-1.0.0.dist-info/top_level.txt +1 -0
  7. mlflow/__init__.py +367 -0
  8. mlflow/__main__.py +3 -0
  9. mlflow/ag2/__init__.py +56 -0
  10. mlflow/ag2/ag2_logger.py +294 -0
  11. mlflow/anthropic/__init__.py +40 -0
  12. mlflow/anthropic/autolog.py +129 -0
  13. mlflow/anthropic/chat.py +144 -0
  14. mlflow/artifacts/__init__.py +268 -0
  15. mlflow/autogen/__init__.py +144 -0
  16. mlflow/autogen/chat.py +142 -0
  17. mlflow/azure/__init__.py +26 -0
  18. mlflow/azure/auth_handler.py +257 -0
  19. mlflow/azure/client.py +319 -0
  20. mlflow/azure/config.py +120 -0
  21. mlflow/azure/connection_factory.py +340 -0
  22. mlflow/azure/exceptions.py +27 -0
  23. mlflow/azure/stores.py +327 -0
  24. mlflow/azure/utils.py +183 -0
  25. mlflow/bedrock/__init__.py +45 -0
  26. mlflow/bedrock/_autolog.py +202 -0
  27. mlflow/bedrock/chat.py +122 -0
  28. mlflow/bedrock/stream.py +160 -0
  29. mlflow/bedrock/utils.py +43 -0
  30. mlflow/cli.py +707 -0
  31. mlflow/client.py +12 -0
  32. mlflow/config/__init__.py +56 -0
  33. mlflow/crewai/__init__.py +79 -0
  34. mlflow/crewai/autolog.py +253 -0
  35. mlflow/crewai/chat.py +29 -0
  36. mlflow/data/__init__.py +75 -0
  37. mlflow/data/artifact_dataset_sources.py +170 -0
  38. mlflow/data/code_dataset_source.py +40 -0
  39. mlflow/data/dataset.py +123 -0
  40. mlflow/data/dataset_registry.py +168 -0
  41. mlflow/data/dataset_source.py +110 -0
  42. mlflow/data/dataset_source_registry.py +219 -0
  43. mlflow/data/delta_dataset_source.py +167 -0
  44. mlflow/data/digest_utils.py +108 -0
  45. mlflow/data/evaluation_dataset.py +562 -0
  46. mlflow/data/filesystem_dataset_source.py +81 -0
  47. mlflow/data/http_dataset_source.py +145 -0
  48. mlflow/data/huggingface_dataset.py +258 -0
  49. mlflow/data/huggingface_dataset_source.py +118 -0
  50. mlflow/data/meta_dataset.py +104 -0
  51. mlflow/data/numpy_dataset.py +223 -0
  52. mlflow/data/pandas_dataset.py +231 -0
  53. mlflow/data/polars_dataset.py +352 -0
  54. mlflow/data/pyfunc_dataset_mixin.py +31 -0
  55. mlflow/data/schema.py +76 -0
  56. mlflow/data/sources.py +1 -0
  57. mlflow/data/spark_dataset.py +406 -0
  58. mlflow/data/spark_dataset_source.py +74 -0
  59. mlflow/data/spark_delta_utils.py +118 -0
  60. mlflow/data/tensorflow_dataset.py +350 -0
  61. mlflow/data/uc_volume_dataset_source.py +81 -0
  62. mlflow/db.py +27 -0
  63. mlflow/dspy/__init__.py +17 -0
  64. mlflow/dspy/autolog.py +197 -0
  65. mlflow/dspy/callback.py +398 -0
  66. mlflow/dspy/constant.py +1 -0
  67. mlflow/dspy/load.py +93 -0
  68. mlflow/dspy/save.py +393 -0
  69. mlflow/dspy/util.py +109 -0
  70. mlflow/dspy/wrapper.py +226 -0
  71. mlflow/entities/__init__.py +104 -0
  72. mlflow/entities/_mlflow_object.py +52 -0
  73. mlflow/entities/assessment.py +545 -0
  74. mlflow/entities/assessment_error.py +80 -0
  75. mlflow/entities/assessment_source.py +141 -0
  76. mlflow/entities/dataset.py +92 -0
  77. mlflow/entities/dataset_input.py +51 -0
  78. mlflow/entities/dataset_summary.py +62 -0
  79. mlflow/entities/document.py +48 -0
  80. mlflow/entities/experiment.py +109 -0
  81. mlflow/entities/experiment_tag.py +35 -0
  82. mlflow/entities/file_info.py +45 -0
  83. mlflow/entities/input_tag.py +35 -0
  84. mlflow/entities/lifecycle_stage.py +35 -0
  85. mlflow/entities/logged_model.py +228 -0
  86. mlflow/entities/logged_model_input.py +26 -0
  87. mlflow/entities/logged_model_output.py +32 -0
  88. mlflow/entities/logged_model_parameter.py +46 -0
  89. mlflow/entities/logged_model_status.py +74 -0
  90. mlflow/entities/logged_model_tag.py +33 -0
  91. mlflow/entities/metric.py +200 -0
  92. mlflow/entities/model_registry/__init__.py +29 -0
  93. mlflow/entities/model_registry/_model_registry_entity.py +13 -0
  94. mlflow/entities/model_registry/model_version.py +243 -0
  95. mlflow/entities/model_registry/model_version_deployment_job_run_state.py +44 -0
  96. mlflow/entities/model_registry/model_version_deployment_job_state.py +70 -0
  97. mlflow/entities/model_registry/model_version_search.py +25 -0
  98. mlflow/entities/model_registry/model_version_stages.py +25 -0
  99. mlflow/entities/model_registry/model_version_status.py +35 -0
  100. mlflow/entities/model_registry/model_version_tag.py +35 -0
  101. mlflow/entities/model_registry/prompt.py +73 -0
  102. mlflow/entities/model_registry/prompt_version.py +244 -0
  103. mlflow/entities/model_registry/registered_model.py +175 -0
  104. mlflow/entities/model_registry/registered_model_alias.py +35 -0
  105. mlflow/entities/model_registry/registered_model_deployment_job_state.py +39 -0
  106. mlflow/entities/model_registry/registered_model_search.py +25 -0
  107. mlflow/entities/model_registry/registered_model_tag.py +35 -0
  108. mlflow/entities/multipart_upload.py +74 -0
  109. mlflow/entities/param.py +49 -0
  110. mlflow/entities/run.py +97 -0
  111. mlflow/entities/run_data.py +84 -0
  112. mlflow/entities/run_info.py +188 -0
  113. mlflow/entities/run_inputs.py +59 -0
  114. mlflow/entities/run_outputs.py +43 -0
  115. mlflow/entities/run_status.py +41 -0
  116. mlflow/entities/run_tag.py +36 -0
  117. mlflow/entities/source_type.py +31 -0
  118. mlflow/entities/span.py +774 -0
  119. mlflow/entities/span_event.py +96 -0
  120. mlflow/entities/span_status.py +102 -0
  121. mlflow/entities/trace.py +317 -0
  122. mlflow/entities/trace_data.py +71 -0
  123. mlflow/entities/trace_info.py +220 -0
  124. mlflow/entities/trace_info_v2.py +162 -0
  125. mlflow/entities/trace_location.py +173 -0
  126. mlflow/entities/trace_state.py +39 -0
  127. mlflow/entities/trace_status.py +68 -0
  128. mlflow/entities/view_type.py +51 -0
  129. mlflow/environment_variables.py +866 -0
  130. mlflow/evaluation/__init__.py +16 -0
  131. mlflow/evaluation/assessment.py +369 -0
  132. mlflow/evaluation/evaluation.py +411 -0
  133. mlflow/evaluation/evaluation_tag.py +61 -0
  134. mlflow/evaluation/fluent.py +48 -0
  135. mlflow/evaluation/utils.py +201 -0
  136. mlflow/exceptions.py +213 -0
  137. mlflow/experiments.py +140 -0
  138. mlflow/gemini/__init__.py +81 -0
  139. mlflow/gemini/autolog.py +186 -0
  140. mlflow/gemini/chat.py +261 -0
  141. mlflow/genai/__init__.py +71 -0
  142. mlflow/genai/datasets/__init__.py +67 -0
  143. mlflow/genai/datasets/evaluation_dataset.py +131 -0
  144. mlflow/genai/evaluation/__init__.py +3 -0
  145. mlflow/genai/evaluation/base.py +411 -0
  146. mlflow/genai/evaluation/constant.py +23 -0
  147. mlflow/genai/evaluation/utils.py +244 -0
  148. mlflow/genai/judges/__init__.py +21 -0
  149. mlflow/genai/judges/databricks.py +404 -0
  150. mlflow/genai/label_schemas/__init__.py +153 -0
  151. mlflow/genai/label_schemas/label_schemas.py +209 -0
  152. mlflow/genai/labeling/__init__.py +159 -0
  153. mlflow/genai/labeling/labeling.py +250 -0
  154. mlflow/genai/optimize/__init__.py +13 -0
  155. mlflow/genai/optimize/base.py +198 -0
  156. mlflow/genai/optimize/optimizers/__init__.py +4 -0
  157. mlflow/genai/optimize/optimizers/base_optimizer.py +38 -0
  158. mlflow/genai/optimize/optimizers/dspy_mipro_optimizer.py +221 -0
  159. mlflow/genai/optimize/optimizers/dspy_optimizer.py +91 -0
  160. mlflow/genai/optimize/optimizers/utils/dspy_mipro_callback.py +76 -0
  161. mlflow/genai/optimize/optimizers/utils/dspy_mipro_utils.py +18 -0
  162. mlflow/genai/optimize/types.py +75 -0
  163. mlflow/genai/optimize/util.py +30 -0
  164. mlflow/genai/prompts/__init__.py +206 -0
  165. mlflow/genai/scheduled_scorers.py +431 -0
  166. mlflow/genai/scorers/__init__.py +26 -0
  167. mlflow/genai/scorers/base.py +492 -0
  168. mlflow/genai/scorers/builtin_scorers.py +765 -0
  169. mlflow/genai/scorers/scorer_utils.py +138 -0
  170. mlflow/genai/scorers/validation.py +165 -0
  171. mlflow/genai/utils/data_validation.py +146 -0
  172. mlflow/genai/utils/enum_utils.py +23 -0
  173. mlflow/genai/utils/trace_utils.py +211 -0
  174. mlflow/groq/__init__.py +42 -0
  175. mlflow/groq/_groq_autolog.py +74 -0
  176. mlflow/johnsnowlabs/__init__.py +888 -0
  177. mlflow/langchain/__init__.py +24 -0
  178. mlflow/langchain/api_request_parallel_processor.py +330 -0
  179. mlflow/langchain/autolog.py +147 -0
  180. mlflow/langchain/chat_agent_langgraph.py +340 -0
  181. mlflow/langchain/constant.py +1 -0
  182. mlflow/langchain/constants.py +1 -0
  183. mlflow/langchain/databricks_dependencies.py +444 -0
  184. mlflow/langchain/langchain_tracer.py +597 -0
  185. mlflow/langchain/model.py +919 -0
  186. mlflow/langchain/output_parsers.py +142 -0
  187. mlflow/langchain/retriever_chain.py +153 -0
  188. mlflow/langchain/runnables.py +527 -0
  189. mlflow/langchain/utils/chat.py +402 -0
  190. mlflow/langchain/utils/logging.py +671 -0
  191. mlflow/langchain/utils/serialization.py +36 -0
  192. mlflow/legacy_databricks_cli/__init__.py +0 -0
  193. mlflow/legacy_databricks_cli/configure/__init__.py +0 -0
  194. mlflow/legacy_databricks_cli/configure/provider.py +482 -0
  195. mlflow/litellm/__init__.py +175 -0
  196. mlflow/llama_index/__init__.py +22 -0
  197. mlflow/llama_index/autolog.py +55 -0
  198. mlflow/llama_index/chat.py +43 -0
  199. mlflow/llama_index/constant.py +1 -0
  200. mlflow/llama_index/model.py +577 -0
  201. mlflow/llama_index/pyfunc_wrapper.py +332 -0
  202. mlflow/llama_index/serialize_objects.py +188 -0
  203. mlflow/llama_index/tracer.py +561 -0
  204. mlflow/metrics/__init__.py +479 -0
  205. mlflow/metrics/base.py +39 -0
  206. mlflow/metrics/genai/__init__.py +25 -0
  207. mlflow/metrics/genai/base.py +101 -0
  208. mlflow/metrics/genai/genai_metric.py +771 -0
  209. mlflow/metrics/genai/metric_definitions.py +450 -0
  210. mlflow/metrics/genai/model_utils.py +371 -0
  211. mlflow/metrics/genai/prompt_template.py +68 -0
  212. mlflow/metrics/genai/prompts/__init__.py +0 -0
  213. mlflow/metrics/genai/prompts/v1.py +422 -0
  214. mlflow/metrics/genai/utils.py +6 -0
  215. mlflow/metrics/metric_definitions.py +619 -0
  216. mlflow/mismatch.py +34 -0
  217. mlflow/mistral/__init__.py +34 -0
  218. mlflow/mistral/autolog.py +71 -0
  219. mlflow/mistral/chat.py +135 -0
  220. mlflow/ml_package_versions.py +452 -0
  221. mlflow/models/__init__.py +97 -0
  222. mlflow/models/auth_policy.py +83 -0
  223. mlflow/models/cli.py +354 -0
  224. mlflow/models/container/__init__.py +294 -0
  225. mlflow/models/container/scoring_server/__init__.py +0 -0
  226. mlflow/models/container/scoring_server/nginx.conf +39 -0
  227. mlflow/models/dependencies_schemas.py +287 -0
  228. mlflow/models/display_utils.py +158 -0
  229. mlflow/models/docker_utils.py +211 -0
  230. mlflow/models/evaluation/__init__.py +23 -0
  231. mlflow/models/evaluation/_shap_patch.py +64 -0
  232. mlflow/models/evaluation/artifacts.py +194 -0
  233. mlflow/models/evaluation/base.py +1811 -0
  234. mlflow/models/evaluation/calibration_curve.py +109 -0
  235. mlflow/models/evaluation/default_evaluator.py +996 -0
  236. mlflow/models/evaluation/deprecated.py +23 -0
  237. mlflow/models/evaluation/evaluator_registry.py +80 -0
  238. mlflow/models/evaluation/evaluators/classifier.py +704 -0
  239. mlflow/models/evaluation/evaluators/default.py +233 -0
  240. mlflow/models/evaluation/evaluators/regressor.py +96 -0
  241. mlflow/models/evaluation/evaluators/shap.py +296 -0
  242. mlflow/models/evaluation/lift_curve.py +178 -0
  243. mlflow/models/evaluation/utils/metric.py +123 -0
  244. mlflow/models/evaluation/utils/trace.py +179 -0
  245. mlflow/models/evaluation/validation.py +434 -0
  246. mlflow/models/flavor_backend.py +93 -0
  247. mlflow/models/flavor_backend_registry.py +53 -0
  248. mlflow/models/model.py +1639 -0
  249. mlflow/models/model_config.py +150 -0
  250. mlflow/models/notebook_resources/agent_evaluation_template.html +235 -0
  251. mlflow/models/notebook_resources/eval_with_dataset_example.py +22 -0
  252. mlflow/models/notebook_resources/eval_with_synthetic_example.py +22 -0
  253. mlflow/models/python_api.py +369 -0
  254. mlflow/models/rag_signatures.py +128 -0
  255. mlflow/models/resources.py +321 -0
  256. mlflow/models/signature.py +662 -0
  257. mlflow/models/utils.py +2054 -0
  258. mlflow/models/wheeled_model.py +280 -0
  259. mlflow/openai/__init__.py +57 -0
  260. mlflow/openai/_agent_tracer.py +364 -0
  261. mlflow/openai/api_request_parallel_processor.py +131 -0
  262. mlflow/openai/autolog.py +509 -0
  263. mlflow/openai/constant.py +1 -0
  264. mlflow/openai/model.py +824 -0
  265. mlflow/openai/utils/chat_schema.py +367 -0
  266. mlflow/optuna/__init__.py +3 -0
  267. mlflow/optuna/storage.py +646 -0
  268. mlflow/plugins/__init__.py +72 -0
  269. mlflow/plugins/base.py +358 -0
  270. mlflow/plugins/builtin/__init__.py +24 -0
  271. mlflow/plugins/builtin/pytorch_plugin.py +150 -0
  272. mlflow/plugins/builtin/sklearn_plugin.py +158 -0
  273. mlflow/plugins/builtin/transformers_plugin.py +187 -0
  274. mlflow/plugins/cli.py +321 -0
  275. mlflow/plugins/discovery.py +340 -0
  276. mlflow/plugins/manager.py +465 -0
  277. mlflow/plugins/registry.py +316 -0
  278. mlflow/plugins/templates/framework_plugin_template.py +329 -0
  279. mlflow/prompt/constants.py +20 -0
  280. mlflow/prompt/promptlab_model.py +197 -0
  281. mlflow/prompt/registry_utils.py +248 -0
  282. mlflow/promptflow/__init__.py +495 -0
  283. mlflow/protos/__init__.py +0 -0
  284. mlflow/protos/assessments_pb2.py +174 -0
  285. mlflow/protos/databricks_artifacts_pb2.py +489 -0
  286. mlflow/protos/databricks_filesystem_service_pb2.py +196 -0
  287. mlflow/protos/databricks_managed_catalog_messages_pb2.py +95 -0
  288. mlflow/protos/databricks_managed_catalog_service_pb2.py +86 -0
  289. mlflow/protos/databricks_pb2.py +267 -0
  290. mlflow/protos/databricks_trace_server_pb2.py +374 -0
  291. mlflow/protos/databricks_uc_registry_messages_pb2.py +1249 -0
  292. mlflow/protos/databricks_uc_registry_service_pb2.py +170 -0
  293. mlflow/protos/facet_feature_statistics_pb2.py +296 -0
  294. mlflow/protos/internal_pb2.py +77 -0
  295. mlflow/protos/mlflow_artifacts_pb2.py +336 -0
  296. mlflow/protos/model_registry_pb2.py +1073 -0
  297. mlflow/protos/scalapb/__init__.py +0 -0
  298. mlflow/protos/scalapb/scalapb_pb2.py +104 -0
  299. mlflow/protos/service_pb2.py +2600 -0
  300. mlflow/protos/unity_catalog_oss_messages_pb2.py +457 -0
  301. mlflow/protos/unity_catalog_oss_service_pb2.py +130 -0
  302. mlflow/protos/unity_catalog_prompt_messages_pb2.py +447 -0
  303. mlflow/protos/unity_catalog_prompt_messages_pb2_grpc.py +24 -0
  304. mlflow/protos/unity_catalog_prompt_service_pb2.py +164 -0
  305. mlflow/protos/unity_catalog_prompt_service_pb2_grpc.py +785 -0
  306. mlflow/py.typed +0 -0
  307. mlflow/pydantic_ai/__init__.py +57 -0
  308. mlflow/pydantic_ai/autolog.py +173 -0
  309. mlflow/pyfunc/__init__.py +3844 -0
  310. mlflow/pyfunc/_mlflow_pyfunc_backend_predict.py +61 -0
  311. mlflow/pyfunc/backend.py +523 -0
  312. mlflow/pyfunc/context.py +78 -0
  313. mlflow/pyfunc/dbconnect_artifact_cache.py +144 -0
  314. mlflow/pyfunc/loaders/__init__.py +7 -0
  315. mlflow/pyfunc/loaders/chat_agent.py +117 -0
  316. mlflow/pyfunc/loaders/chat_model.py +125 -0
  317. mlflow/pyfunc/loaders/code_model.py +31 -0
  318. mlflow/pyfunc/loaders/responses_agent.py +112 -0
  319. mlflow/pyfunc/mlserver.py +46 -0
  320. mlflow/pyfunc/model.py +1473 -0
  321. mlflow/pyfunc/scoring_server/__init__.py +604 -0
  322. mlflow/pyfunc/scoring_server/app.py +7 -0
  323. mlflow/pyfunc/scoring_server/client.py +146 -0
  324. mlflow/pyfunc/spark_model_cache.py +48 -0
  325. mlflow/pyfunc/stdin_server.py +44 -0
  326. mlflow/pyfunc/utils/__init__.py +3 -0
  327. mlflow/pyfunc/utils/data_validation.py +224 -0
  328. mlflow/pyfunc/utils/environment.py +22 -0
  329. mlflow/pyfunc/utils/input_converter.py +47 -0
  330. mlflow/pyfunc/utils/serving_data_parser.py +11 -0
  331. mlflow/pytorch/__init__.py +1171 -0
  332. mlflow/pytorch/_lightning_autolog.py +580 -0
  333. mlflow/pytorch/_pytorch_autolog.py +50 -0
  334. mlflow/pytorch/pickle_module.py +35 -0
  335. mlflow/rfunc/__init__.py +42 -0
  336. mlflow/rfunc/backend.py +134 -0
  337. mlflow/runs.py +89 -0
  338. mlflow/server/__init__.py +302 -0
  339. mlflow/server/auth/__init__.py +1224 -0
  340. mlflow/server/auth/__main__.py +4 -0
  341. mlflow/server/auth/basic_auth.ini +6 -0
  342. mlflow/server/auth/cli.py +11 -0
  343. mlflow/server/auth/client.py +537 -0
  344. mlflow/server/auth/config.py +34 -0
  345. mlflow/server/auth/db/__init__.py +0 -0
  346. mlflow/server/auth/db/cli.py +18 -0
  347. mlflow/server/auth/db/migrations/__init__.py +0 -0
  348. mlflow/server/auth/db/migrations/alembic.ini +110 -0
  349. mlflow/server/auth/db/migrations/env.py +76 -0
  350. mlflow/server/auth/db/migrations/versions/8606fa83a998_initial_migration.py +51 -0
  351. mlflow/server/auth/db/migrations/versions/__init__.py +0 -0
  352. mlflow/server/auth/db/models.py +67 -0
  353. mlflow/server/auth/db/utils.py +37 -0
  354. mlflow/server/auth/entities.py +165 -0
  355. mlflow/server/auth/logo.py +14 -0
  356. mlflow/server/auth/permissions.py +65 -0
  357. mlflow/server/auth/routes.py +18 -0
  358. mlflow/server/auth/sqlalchemy_store.py +263 -0
  359. mlflow/server/graphql/__init__.py +0 -0
  360. mlflow/server/graphql/autogenerated_graphql_schema.py +353 -0
  361. mlflow/server/graphql/graphql_custom_scalars.py +24 -0
  362. mlflow/server/graphql/graphql_errors.py +15 -0
  363. mlflow/server/graphql/graphql_no_batching.py +89 -0
  364. mlflow/server/graphql/graphql_schema_extensions.py +74 -0
  365. mlflow/server/handlers.py +3217 -0
  366. mlflow/server/prometheus_exporter.py +17 -0
  367. mlflow/server/validation.py +30 -0
  368. mlflow/shap/__init__.py +691 -0
  369. mlflow/sklearn/__init__.py +1994 -0
  370. mlflow/sklearn/utils.py +1041 -0
  371. mlflow/smolagents/__init__.py +66 -0
  372. mlflow/smolagents/autolog.py +139 -0
  373. mlflow/smolagents/chat.py +29 -0
  374. mlflow/store/__init__.py +10 -0
  375. mlflow/store/_unity_catalog/__init__.py +1 -0
  376. mlflow/store/_unity_catalog/lineage/__init__.py +1 -0
  377. mlflow/store/_unity_catalog/lineage/constants.py +2 -0
  378. mlflow/store/_unity_catalog/registry/__init__.py +6 -0
  379. mlflow/store/_unity_catalog/registry/prompt_info.py +75 -0
  380. mlflow/store/_unity_catalog/registry/rest_store.py +1740 -0
  381. mlflow/store/_unity_catalog/registry/uc_oss_rest_store.py +507 -0
  382. mlflow/store/_unity_catalog/registry/utils.py +121 -0
  383. mlflow/store/artifact/__init__.py +0 -0
  384. mlflow/store/artifact/artifact_repo.py +472 -0
  385. mlflow/store/artifact/artifact_repository_registry.py +154 -0
  386. mlflow/store/artifact/azure_blob_artifact_repo.py +275 -0
  387. mlflow/store/artifact/azure_data_lake_artifact_repo.py +295 -0
  388. mlflow/store/artifact/cli.py +141 -0
  389. mlflow/store/artifact/cloud_artifact_repo.py +332 -0
  390. mlflow/store/artifact/databricks_artifact_repo.py +729 -0
  391. mlflow/store/artifact/databricks_artifact_repo_resources.py +301 -0
  392. mlflow/store/artifact/databricks_logged_model_artifact_repo.py +93 -0
  393. mlflow/store/artifact/databricks_models_artifact_repo.py +216 -0
  394. mlflow/store/artifact/databricks_sdk_artifact_repo.py +134 -0
  395. mlflow/store/artifact/databricks_sdk_models_artifact_repo.py +97 -0
  396. mlflow/store/artifact/dbfs_artifact_repo.py +240 -0
  397. mlflow/store/artifact/ftp_artifact_repo.py +132 -0
  398. mlflow/store/artifact/gcs_artifact_repo.py +296 -0
  399. mlflow/store/artifact/hdfs_artifact_repo.py +209 -0
  400. mlflow/store/artifact/http_artifact_repo.py +218 -0
  401. mlflow/store/artifact/local_artifact_repo.py +142 -0
  402. mlflow/store/artifact/mlflow_artifacts_repo.py +94 -0
  403. mlflow/store/artifact/models_artifact_repo.py +259 -0
  404. mlflow/store/artifact/optimized_s3_artifact_repo.py +356 -0
  405. mlflow/store/artifact/presigned_url_artifact_repo.py +173 -0
  406. mlflow/store/artifact/r2_artifact_repo.py +70 -0
  407. mlflow/store/artifact/runs_artifact_repo.py +265 -0
  408. mlflow/store/artifact/s3_artifact_repo.py +330 -0
  409. mlflow/store/artifact/sftp_artifact_repo.py +141 -0
  410. mlflow/store/artifact/uc_volume_artifact_repo.py +76 -0
  411. mlflow/store/artifact/unity_catalog_models_artifact_repo.py +168 -0
  412. mlflow/store/artifact/unity_catalog_oss_models_artifact_repo.py +168 -0
  413. mlflow/store/artifact/utils/__init__.py +0 -0
  414. mlflow/store/artifact/utils/models.py +148 -0
  415. mlflow/store/db/__init__.py +0 -0
  416. mlflow/store/db/base_sql_model.py +3 -0
  417. mlflow/store/db/db_types.py +10 -0
  418. mlflow/store/db/utils.py +314 -0
  419. mlflow/store/db_migrations/__init__.py +0 -0
  420. mlflow/store/db_migrations/alembic.ini +74 -0
  421. mlflow/store/db_migrations/env.py +84 -0
  422. mlflow/store/db_migrations/versions/0584bdc529eb_add_cascading_deletion_to_datasets_from_experiments.py +88 -0
  423. mlflow/store/db_migrations/versions/0a8213491aaa_drop_duplicate_killed_constraint.py +49 -0
  424. mlflow/store/db_migrations/versions/0c779009ac13_add_deleted_time_field_to_runs_table.py +24 -0
  425. mlflow/store/db_migrations/versions/181f10493468_allow_nulls_for_metric_values.py +35 -0
  426. mlflow/store/db_migrations/versions/27a6a02d2cf1_add_model_version_tags_table.py +38 -0
  427. mlflow/store/db_migrations/versions/2b4d017a5e9b_add_model_registry_tables_to_db.py +77 -0
  428. mlflow/store/db_migrations/versions/2d6e25af4d3e_increase_max_param_val_length.py +33 -0
  429. mlflow/store/db_migrations/versions/3500859a5d39_add_model_aliases_table.py +50 -0
  430. mlflow/store/db_migrations/versions/39d1c3be5f05_add_is_nan_constraint_for_metrics_tables_if_necessary.py +41 -0
  431. mlflow/store/db_migrations/versions/400f98739977_add_logged_model_tables.py +123 -0
  432. mlflow/store/db_migrations/versions/4465047574b1_increase_max_dataset_schema_size.py +38 -0
  433. mlflow/store/db_migrations/versions/451aebb31d03_add_metric_step.py +35 -0
  434. mlflow/store/db_migrations/versions/5b0e9adcef9c_add_cascade_deletion_to_trace_tables_fk.py +40 -0
  435. mlflow/store/db_migrations/versions/6953534de441_add_step_to_inputs_table.py +25 -0
  436. mlflow/store/db_migrations/versions/728d730b5ebd_add_registered_model_tags_table.py +38 -0
  437. mlflow/store/db_migrations/versions/7ac759974ad8_update_run_tags_with_larger_limit.py +36 -0
  438. mlflow/store/db_migrations/versions/7f2a7d5fae7d_add_datasets_inputs_input_tags_tables.py +82 -0
  439. mlflow/store/db_migrations/versions/84291f40a231_add_run_link_to_model_version.py +26 -0
  440. mlflow/store/db_migrations/versions/867495a8f9d4_add_trace_tables.py +90 -0
  441. mlflow/store/db_migrations/versions/89d4b8295536_create_latest_metrics_table.py +169 -0
  442. mlflow/store/db_migrations/versions/90e64c465722_migrate_user_column_to_tags.py +64 -0
  443. mlflow/store/db_migrations/versions/97727af70f4d_creation_time_last_update_time_experiments.py +25 -0
  444. mlflow/store/db_migrations/versions/__init__.py +0 -0
  445. mlflow/store/db_migrations/versions/a8c4a736bde6_allow_nulls_for_run_id.py +27 -0
  446. mlflow/store/db_migrations/versions/acf3f17fdcc7_add_storage_location_field_to_model_.py +29 -0
  447. mlflow/store/db_migrations/versions/bd07f7e963c5_create_index_on_run_uuid.py +26 -0
  448. mlflow/store/db_migrations/versions/bda7b8c39065_increase_model_version_tag_value_limit.py +38 -0
  449. mlflow/store/db_migrations/versions/c48cb773bb87_reset_default_value_for_is_nan_in_metrics_table_for_mysql.py +41 -0
  450. mlflow/store/db_migrations/versions/cbc13b556ace_add_v3_trace_schema_columns.py +31 -0
  451. mlflow/store/db_migrations/versions/cc1f77228345_change_param_value_length_to_500.py +34 -0
  452. mlflow/store/db_migrations/versions/cfd24bdc0731_update_run_status_constraint_with_killed.py +78 -0
  453. mlflow/store/db_migrations/versions/df50e92ffc5e_add_experiment_tags_table.py +38 -0
  454. mlflow/store/db_migrations/versions/f5a4f2784254_increase_run_tag_value_limit.py +36 -0
  455. mlflow/store/entities/__init__.py +3 -0
  456. mlflow/store/entities/paged_list.py +18 -0
  457. mlflow/store/model_registry/__init__.py +10 -0
  458. mlflow/store/model_registry/abstract_store.py +1081 -0
  459. mlflow/store/model_registry/base_rest_store.py +44 -0
  460. mlflow/store/model_registry/databricks_workspace_model_registry_rest_store.py +37 -0
  461. mlflow/store/model_registry/dbmodels/__init__.py +0 -0
  462. mlflow/store/model_registry/dbmodels/models.py +206 -0
  463. mlflow/store/model_registry/file_store.py +1091 -0
  464. mlflow/store/model_registry/rest_store.py +481 -0
  465. mlflow/store/model_registry/sqlalchemy_store.py +1286 -0
  466. mlflow/store/tracking/__init__.py +23 -0
  467. mlflow/store/tracking/abstract_store.py +816 -0
  468. mlflow/store/tracking/dbmodels/__init__.py +0 -0
  469. mlflow/store/tracking/dbmodels/initial_models.py +243 -0
  470. mlflow/store/tracking/dbmodels/models.py +1073 -0
  471. mlflow/store/tracking/file_store.py +2438 -0
  472. mlflow/store/tracking/postgres_managed_identity.py +146 -0
  473. mlflow/store/tracking/rest_store.py +1131 -0
  474. mlflow/store/tracking/sqlalchemy_store.py +2785 -0
  475. mlflow/system_metrics/__init__.py +61 -0
  476. mlflow/system_metrics/metrics/__init__.py +0 -0
  477. mlflow/system_metrics/metrics/base_metrics_monitor.py +32 -0
  478. mlflow/system_metrics/metrics/cpu_monitor.py +23 -0
  479. mlflow/system_metrics/metrics/disk_monitor.py +21 -0
  480. mlflow/system_metrics/metrics/gpu_monitor.py +71 -0
  481. mlflow/system_metrics/metrics/network_monitor.py +34 -0
  482. mlflow/system_metrics/metrics/rocm_monitor.py +123 -0
  483. mlflow/system_metrics/system_metrics_monitor.py +198 -0
  484. mlflow/tracing/__init__.py +16 -0
  485. mlflow/tracing/assessment.py +356 -0
  486. mlflow/tracing/client.py +531 -0
  487. mlflow/tracing/config.py +125 -0
  488. mlflow/tracing/constant.py +105 -0
  489. mlflow/tracing/destination.py +81 -0
  490. mlflow/tracing/display/__init__.py +40 -0
  491. mlflow/tracing/display/display_handler.py +196 -0
  492. mlflow/tracing/export/async_export_queue.py +186 -0
  493. mlflow/tracing/export/inference_table.py +138 -0
  494. mlflow/tracing/export/mlflow_v3.py +137 -0
  495. mlflow/tracing/export/utils.py +70 -0
  496. mlflow/tracing/fluent.py +1417 -0
  497. mlflow/tracing/processor/base_mlflow.py +199 -0
  498. mlflow/tracing/processor/inference_table.py +175 -0
  499. mlflow/tracing/processor/mlflow_v3.py +47 -0
  500. mlflow/tracing/processor/otel.py +73 -0
  501. mlflow/tracing/provider.py +487 -0
  502. mlflow/tracing/trace_manager.py +200 -0
  503. mlflow/tracing/utils/__init__.py +616 -0
  504. mlflow/tracing/utils/artifact_utils.py +28 -0
  505. mlflow/tracing/utils/copy.py +55 -0
  506. mlflow/tracing/utils/environment.py +55 -0
  507. mlflow/tracing/utils/exception.py +21 -0
  508. mlflow/tracing/utils/once.py +35 -0
  509. mlflow/tracing/utils/otlp.py +63 -0
  510. mlflow/tracing/utils/processor.py +54 -0
  511. mlflow/tracing/utils/search.py +292 -0
  512. mlflow/tracing/utils/timeout.py +250 -0
  513. mlflow/tracing/utils/token.py +19 -0
  514. mlflow/tracing/utils/truncation.py +124 -0
  515. mlflow/tracing/utils/warning.py +76 -0
  516. mlflow/tracking/__init__.py +39 -0
  517. mlflow/tracking/_model_registry/__init__.py +1 -0
  518. mlflow/tracking/_model_registry/client.py +764 -0
  519. mlflow/tracking/_model_registry/fluent.py +853 -0
  520. mlflow/tracking/_model_registry/registry.py +67 -0
  521. mlflow/tracking/_model_registry/utils.py +251 -0
  522. mlflow/tracking/_tracking_service/__init__.py +0 -0
  523. mlflow/tracking/_tracking_service/client.py +883 -0
  524. mlflow/tracking/_tracking_service/registry.py +56 -0
  525. mlflow/tracking/_tracking_service/utils.py +275 -0
  526. mlflow/tracking/artifact_utils.py +179 -0
  527. mlflow/tracking/client.py +5900 -0
  528. mlflow/tracking/context/__init__.py +0 -0
  529. mlflow/tracking/context/abstract_context.py +35 -0
  530. mlflow/tracking/context/databricks_cluster_context.py +15 -0
  531. mlflow/tracking/context/databricks_command_context.py +15 -0
  532. mlflow/tracking/context/databricks_job_context.py +49 -0
  533. mlflow/tracking/context/databricks_notebook_context.py +41 -0
  534. mlflow/tracking/context/databricks_repo_context.py +43 -0
  535. mlflow/tracking/context/default_context.py +51 -0
  536. mlflow/tracking/context/git_context.py +32 -0
  537. mlflow/tracking/context/registry.py +98 -0
  538. mlflow/tracking/context/system_environment_context.py +15 -0
  539. mlflow/tracking/default_experiment/__init__.py +1 -0
  540. mlflow/tracking/default_experiment/abstract_context.py +43 -0
  541. mlflow/tracking/default_experiment/databricks_notebook_experiment_provider.py +44 -0
  542. mlflow/tracking/default_experiment/registry.py +75 -0
  543. mlflow/tracking/fluent.py +3595 -0
  544. mlflow/tracking/metric_value_conversion_utils.py +93 -0
  545. mlflow/tracking/multimedia.py +206 -0
  546. mlflow/tracking/registry.py +86 -0
  547. mlflow/tracking/request_auth/__init__.py +0 -0
  548. mlflow/tracking/request_auth/abstract_request_auth_provider.py +34 -0
  549. mlflow/tracking/request_auth/registry.py +60 -0
  550. mlflow/tracking/request_header/__init__.py +0 -0
  551. mlflow/tracking/request_header/abstract_request_header_provider.py +36 -0
  552. mlflow/tracking/request_header/databricks_request_header_provider.py +38 -0
  553. mlflow/tracking/request_header/default_request_header_provider.py +17 -0
  554. mlflow/tracking/request_header/registry.py +79 -0
  555. mlflow/transformers/__init__.py +2982 -0
  556. mlflow/transformers/flavor_config.py +258 -0
  557. mlflow/transformers/hub_utils.py +83 -0
  558. mlflow/transformers/llm_inference_utils.py +468 -0
  559. mlflow/transformers/model_io.py +301 -0
  560. mlflow/transformers/peft.py +51 -0
  561. mlflow/transformers/signature.py +183 -0
  562. mlflow/transformers/torch_utils.py +55 -0
  563. mlflow/types/__init__.py +21 -0
  564. mlflow/types/agent.py +270 -0
  565. mlflow/types/chat.py +240 -0
  566. mlflow/types/llm.py +935 -0
  567. mlflow/types/responses.py +139 -0
  568. mlflow/types/responses_helpers.py +416 -0
  569. mlflow/types/schema.py +1505 -0
  570. mlflow/types/type_hints.py +647 -0
  571. mlflow/types/utils.py +753 -0
  572. mlflow/utils/__init__.py +283 -0
  573. mlflow/utils/_capture_modules.py +256 -0
  574. mlflow/utils/_capture_transformers_modules.py +75 -0
  575. mlflow/utils/_spark_utils.py +201 -0
  576. mlflow/utils/_unity_catalog_oss_utils.py +97 -0
  577. mlflow/utils/_unity_catalog_utils.py +479 -0
  578. mlflow/utils/annotations.py +218 -0
  579. mlflow/utils/arguments_utils.py +16 -0
  580. mlflow/utils/async_logging/__init__.py +1 -0
  581. mlflow/utils/async_logging/async_artifacts_logging_queue.py +258 -0
  582. mlflow/utils/async_logging/async_logging_queue.py +366 -0
  583. mlflow/utils/async_logging/run_artifact.py +38 -0
  584. mlflow/utils/async_logging/run_batch.py +58 -0
  585. mlflow/utils/async_logging/run_operations.py +49 -0
  586. mlflow/utils/autologging_utils/__init__.py +737 -0
  587. mlflow/utils/autologging_utils/client.py +432 -0
  588. mlflow/utils/autologging_utils/config.py +33 -0
  589. mlflow/utils/autologging_utils/events.py +294 -0
  590. mlflow/utils/autologging_utils/logging_and_warnings.py +328 -0
  591. mlflow/utils/autologging_utils/metrics_queue.py +71 -0
  592. mlflow/utils/autologging_utils/safety.py +1104 -0
  593. mlflow/utils/autologging_utils/versioning.py +95 -0
  594. mlflow/utils/checkpoint_utils.py +206 -0
  595. mlflow/utils/class_utils.py +6 -0
  596. mlflow/utils/cli_args.py +257 -0
  597. mlflow/utils/conda.py +354 -0
  598. mlflow/utils/credentials.py +231 -0
  599. mlflow/utils/data_utils.py +17 -0
  600. mlflow/utils/databricks_utils.py +1436 -0
  601. mlflow/utils/docstring_utils.py +477 -0
  602. mlflow/utils/doctor.py +133 -0
  603. mlflow/utils/download_cloud_file_chunk.py +43 -0
  604. mlflow/utils/env_manager.py +16 -0
  605. mlflow/utils/env_pack.py +131 -0
  606. mlflow/utils/environment.py +1009 -0
  607. mlflow/utils/exception_utils.py +14 -0
  608. mlflow/utils/file_utils.py +978 -0
  609. mlflow/utils/git_utils.py +77 -0
  610. mlflow/utils/gorilla.py +797 -0
  611. mlflow/utils/import_hooks/__init__.py +363 -0
  612. mlflow/utils/lazy_load.py +51 -0
  613. mlflow/utils/logging_utils.py +168 -0
  614. mlflow/utils/mime_type_utils.py +58 -0
  615. mlflow/utils/mlflow_tags.py +103 -0
  616. mlflow/utils/model_utils.py +486 -0
  617. mlflow/utils/name_utils.py +346 -0
  618. mlflow/utils/nfs_on_spark.py +62 -0
  619. mlflow/utils/openai_utils.py +164 -0
  620. mlflow/utils/os.py +12 -0
  621. mlflow/utils/oss_registry_utils.py +29 -0
  622. mlflow/utils/plugins.py +17 -0
  623. mlflow/utils/process.py +182 -0
  624. mlflow/utils/promptlab_utils.py +146 -0
  625. mlflow/utils/proto_json_utils.py +743 -0
  626. mlflow/utils/pydantic_utils.py +54 -0
  627. mlflow/utils/request_utils.py +279 -0
  628. mlflow/utils/requirements_utils.py +704 -0
  629. mlflow/utils/rest_utils.py +673 -0
  630. mlflow/utils/search_logged_model_utils.py +127 -0
  631. mlflow/utils/search_utils.py +2111 -0
  632. mlflow/utils/secure_loading.py +221 -0
  633. mlflow/utils/security_validation.py +384 -0
  634. mlflow/utils/server_cli_utils.py +61 -0
  635. mlflow/utils/spark_utils.py +15 -0
  636. mlflow/utils/string_utils.py +138 -0
  637. mlflow/utils/thread_utils.py +63 -0
  638. mlflow/utils/time.py +54 -0
  639. mlflow/utils/timeout.py +42 -0
  640. mlflow/utils/uri.py +572 -0
  641. mlflow/utils/validation.py +662 -0
  642. mlflow/utils/virtualenv.py +458 -0
  643. mlflow/utils/warnings_utils.py +25 -0
  644. mlflow/utils/yaml_utils.py +179 -0
  645. mlflow/version.py +24 -0
mlflow/models/model.py ADDED
@@ -0,0 +1,1639 @@
1
+ import json
2
+ import logging
3
+ import os
4
+ import shutil
5
+ import uuid
6
+ from datetime import datetime
7
+ from pathlib import Path
8
+ from pprint import pformat
9
+ from typing import Any, Callable, Literal, NamedTuple, Optional, Union
10
+ from urllib.parse import urlparse
11
+
12
+ import yaml
13
+ from packaging.requirements import InvalidRequirement, Requirement
14
+
15
+ import mlflow
16
+ from mlflow.entities import LoggedModel, LoggedModelOutput, Metric
17
+ from mlflow.entities.model_registry.prompt_version import PromptVersion
18
+ from mlflow.environment_variables import (
19
+ MLFLOW_PRINT_MODEL_URLS_ON_CREATION,
20
+ MLFLOW_RECORD_ENV_VARS_IN_MODEL_LOGGING,
21
+ )
22
+ from mlflow.exceptions import MlflowException
23
+ from mlflow.models.auth_policy import AuthPolicy
24
+ from mlflow.models.resources import Resource, ResourceType, _ResourceBuilder
25
+ from mlflow.protos.databricks_pb2 import (
26
+ INVALID_PARAMETER_VALUE,
27
+ RESOURCE_DOES_NOT_EXIST,
28
+ )
29
+ from mlflow.store.artifact.models_artifact_repo import ModelsArtifactRepository
30
+ from mlflow.store.artifact.runs_artifact_repo import RunsArtifactRepository
31
+ from mlflow.tracking._model_registry import DEFAULT_AWAIT_MAX_SLEEP_SECONDS
32
+ from mlflow.tracking._tracking_service.utils import _resolve_tracking_uri
33
+ from mlflow.tracking.artifact_utils import _download_artifact_from_uri, _upload_artifact_to_uri
34
+ from mlflow.tracking.fluent import (
35
+ _get_active_model_context,
36
+ _set_active_model_id,
37
+ _use_logged_model,
38
+ )
39
+ from mlflow.utils.annotations import experimental
40
+ from mlflow.utils.databricks_utils import (
41
+ _construct_databricks_logged_model_url,
42
+ get_databricks_runtime_version,
43
+ get_workspace_id,
44
+ get_workspace_url,
45
+ is_in_databricks_runtime,
46
+ )
47
+ from mlflow.utils.docstring_utils import LOG_MODEL_PARAM_DOCS, format_docstring
48
+ from mlflow.utils.environment import (
49
+ _CONDA_ENV_FILE_NAME,
50
+ _PYTHON_ENV_FILE_NAME,
51
+ _REQUIREMENTS_FILE_NAME,
52
+ _add_or_overwrite_requirements,
53
+ _get_requirements_from_file,
54
+ _remove_requirements,
55
+ _write_requirements_to_file,
56
+ )
57
+ from mlflow.utils.file_utils import TempDir
58
+ from mlflow.utils.logging_utils import eprint
59
+ from mlflow.utils.mlflow_tags import MLFLOW_MODEL_IS_EXTERNAL
60
+ from mlflow.utils.uri import (
61
+ append_to_uri_path,
62
+ get_uri_scheme,
63
+ is_databricks_uri,
64
+ )
65
+
66
+ _logger = logging.getLogger(__name__)
67
+
68
+ # NOTE: The MLMODEL_FILE_NAME constant is considered @developer_stable
69
+ MLMODEL_FILE_NAME = "MLmodel"
70
+ _DATABRICKS_FS_LOADER_MODULE = "databricks.feature_store.mlflow_model"
71
+ _LOG_MODEL_METADATA_WARNING_TEMPLATE = (
72
+ "Logging model metadata to the tracking server has failed. The model artifacts "
73
+ "have been logged successfully under %s. Set logging level to DEBUG via "
74
+ '`logging.getLogger("mlflow").setLevel(logging.DEBUG)` to see the full traceback.'
75
+ )
76
+ _LOG_MODEL_MISSING_SIGNATURE_WARNING = (
77
+ "Model logged without a signature. Signatures are required for Databricks UC model registry "
78
+ "as they validate model inputs and denote the expected schema of model outputs. "
79
+ f"Please visit https://www.mlflow.org/docs/{mlflow.__version__.replace('.dev0', '')}/"
80
+ "model/signatures.html#how-to-set-signatures-on-models for instructions on setting "
81
+ "signature on models."
82
+ )
83
+ _LOG_MODEL_MISSING_INPUT_EXAMPLE_WARNING = (
84
+ "Model logged without a signature and input example. Please set `input_example` parameter "
85
+ "when logging the model to auto infer the model signature."
86
+ )
87
+ # NOTE: The _MLFLOW_VERSION_KEY constant is considered @developer_stable
88
+ _MLFLOW_VERSION_KEY = "mlflow_version"
89
+ METADATA_FILES = [
90
+ MLMODEL_FILE_NAME,
91
+ _CONDA_ENV_FILE_NAME,
92
+ _REQUIREMENTS_FILE_NAME,
93
+ _PYTHON_ENV_FILE_NAME,
94
+ ]
95
+ MODEL_CONFIG = "config"
96
+ MODEL_CODE_PATH = "model_code_path"
97
+ SET_MODEL_ERROR = (
98
+ "Model should either be an instance of PyFuncModel, Langchain type, or LlamaIndex index."
99
+ )
100
+ ENV_VAR_FILE_NAME = "environment_variables.txt"
101
+ ENV_VAR_FILE_HEADER = (
102
+ "# This file records environment variable names that are used during model inference.\n"
103
+ "# They might need to be set when creating a serving endpoint from this model.\n"
104
+ "# Note: it is not guaranteed that all environment variables listed here are required\n"
105
+ )
106
+
107
+
108
+ class ModelInfo:
109
+ """
110
+ The metadata of a logged MLflow Model.
111
+ """
112
+
113
+ def __init__(
114
+ self,
115
+ artifact_path: str,
116
+ flavors: dict[str, Any],
117
+ model_uri: str,
118
+ model_uuid: str,
119
+ run_id: str,
120
+ saved_input_example_info: Optional[dict[str, Any]],
121
+ signature, # Optional[ModelSignature]
122
+ utc_time_created: str,
123
+ mlflow_version: str,
124
+ metadata: Optional[dict[str, Any]] = None,
125
+ registered_model_version: Optional[int] = None,
126
+ env_vars: Optional[list[str]] = None,
127
+ prompts: Optional[list[str]] = None,
128
+ logged_model: Optional[LoggedModel] = None,
129
+ ):
130
+ self._artifact_path = artifact_path
131
+ self._flavors = flavors
132
+ self._model_uri = model_uri
133
+ self._model_uuid = model_uuid
134
+ self._run_id = run_id
135
+ self._saved_input_example_info = saved_input_example_info
136
+ self._signature = signature
137
+ self._utc_time_created = utc_time_created
138
+ self._mlflow_version = mlflow_version
139
+ self._metadata = metadata
140
+ self._prompts = prompts
141
+ self._registered_model_version = registered_model_version
142
+ self._env_vars = env_vars
143
+ self._logged_model = logged_model
144
+
145
+ @property
146
+ def artifact_path(self) -> str:
147
+ """
148
+ Run relative path identifying the logged model.
149
+
150
+ :getter: Retrieves the relative path of the logged model.
151
+ :type: str
152
+ """
153
+ return self._artifact_path
154
+
155
+ @property
156
+ def flavors(self) -> dict[str, Any]:
157
+ """
158
+ A dictionary mapping the flavor name to how to serve
159
+ the model as that flavor.
160
+
161
+ :getter: Gets the mapping for the logged model's flavor that defines parameters used in
162
+ serving of the model
163
+ :type: Dict[str, str]
164
+
165
+ .. code-block:: python
166
+ :caption: Example flavor mapping for a scikit-learn logged model
167
+
168
+ {
169
+ "python_function": {
170
+ "model_path": "model.pkl",
171
+ "loader_module": "mlflow.sklearn",
172
+ "python_version": "3.8.10",
173
+ "env": "conda.yaml",
174
+ },
175
+ "sklearn": {
176
+ "pickled_model": "model.pkl",
177
+ "sklearn_version": "0.24.1",
178
+ "serialization_format": "cloudpickle",
179
+ },
180
+ }
181
+
182
+ """
183
+ return self._flavors
184
+
185
+ @property
186
+ def model_uri(self) -> str:
187
+ """
188
+ The ``model_uri`` of the logged model in the format ``'runs:/<run_id>/<artifact_path>'``.
189
+
190
+ :getter: Gets the uri path of the logged model from the uri `runs:/<run_id>` path
191
+ encapsulation
192
+ :type: str
193
+ """
194
+ return self._model_uri
195
+
196
+ @property
197
+ def model_uuid(self) -> str:
198
+ """
199
+ The ``model_uuid`` of the logged model,
200
+ e.g., ``'39ca11813cfc46b09ab83972740b80ca'``.
201
+
202
+ :getter: [Legacy] Gets the model_uuid (run_id) of a logged model
203
+ :type: str
204
+ """
205
+ return self._model_uuid
206
+
207
+ @property
208
+ def run_id(self) -> str:
209
+ """
210
+ The ``run_id`` associated with the logged model,
211
+ e.g., ``'8ede7df408dd42ed9fc39019ef7df309'``
212
+
213
+ :getter: Gets the run_id identifier for the logged model
214
+ :type: str
215
+ """
216
+ return self._run_id
217
+
218
+ @property
219
+ def saved_input_example_info(self) -> Optional[dict[str, Any]]:
220
+ """
221
+ A dictionary that contains the metadata of the saved input example, e.g.,
222
+ ``{"artifact_path": "input_example.json", "type": "dataframe", "pandas_orient": "split"}``.
223
+
224
+ :getter: Gets the input example if specified during model logging
225
+ :type: Optional[Dict[str, str]]
226
+ """
227
+ return self._saved_input_example_info
228
+
229
+ @property
230
+ def signature(self): # -> Optional[ModelSignature]
231
+ """
232
+ A :py:class:`ModelSignature <mlflow.models.ModelSignature>` that describes the
233
+ model input and output.
234
+
235
+ :getter: Gets the model signature if it is defined
236
+ :type: Optional[ModelSignature]
237
+ """
238
+ return self._signature
239
+
240
+ @property
241
+ def utc_time_created(self) -> str:
242
+ """
243
+ The UTC time that the logged model is created, e.g., ``'2022-01-12 05:17:31.634689'``.
244
+
245
+ :getter: Gets the UTC formatted timestamp for when the model was logged
246
+ :type: str
247
+ """
248
+ return self._utc_time_created
249
+
250
+ @property
251
+ def mlflow_version(self) -> str:
252
+ """
253
+ Version of MLflow used to log the model
254
+
255
+ :getter: Gets the version of MLflow that was installed when a model was logged
256
+ :type: str
257
+ """
258
+ return self._mlflow_version
259
+
260
+ @property
261
+ def env_vars(self) -> Optional[list[str]]:
262
+ """
263
+ Environment variables used during the model logging process.
264
+
265
+ :getter: Gets the environment variables used during the model logging process.
266
+ :type: Optional[List[str]]
267
+ """
268
+ return self._env_vars
269
+
270
+ @env_vars.setter
271
+ def env_vars(self, value: Optional[list[str]]) -> None:
272
+ if value and not (isinstance(value, list) and all(isinstance(x, str) for x in value)):
273
+ raise TypeError(f"env_vars must be a list of strings. Got: {value}")
274
+ self._env_vars = value
275
+
276
+ @property
277
+ def metadata(self) -> Optional[dict[str, Any]]:
278
+ """
279
+ User defined metadata added to the model.
280
+
281
+ :getter: Gets the user-defined metadata about a model
282
+ :type: Optional[Dict[str, Any]]
283
+
284
+ .. code-block:: python
285
+ :caption: Example usage of Model Metadata
286
+
287
+ # Create and log a model with metadata to the Model Registry
288
+
289
+ from sklearn import datasets
290
+ from sklearn.ensemble import RandomForestClassifier
291
+ import mlflow
292
+ from mlflow.models import infer_signature
293
+
294
+ with mlflow.start_run():
295
+ iris = datasets.load_iris()
296
+ clf = RandomForestClassifier()
297
+ clf.fit(iris.data, iris.target)
298
+ signature = infer_signature(iris.data, iris.target)
299
+ mlflow.sklearn.log_model(
300
+ clf,
301
+ name="iris_rf",
302
+ signature=signature,
303
+ registered_model_name="model-with-metadata",
304
+ metadata={"metadata_key": "metadata_value"},
305
+ )
306
+
307
+ # model uri for the above model
308
+ model_uri = "models:/model-with-metadata/1"
309
+
310
+ # Load the model and access the custom metadata from its ModelInfo object
311
+ model = mlflow.pyfunc.load_model(model_uri=model_uri)
312
+ assert model.metadata.get_model_info().metadata["metadata_key"] == "metadata_value"
313
+
314
+ # Load the ModelInfo and access the custom metadata
315
+ model_info = mlflow.models.get_model_info(model_uri=model_uri)
316
+ assert model_info.metadata["metadata_key"] == "metadata_value"
317
+ """
318
+ return self._metadata
319
+
320
+ @property
321
+ def prompts(self) -> Optional[list[str]]:
322
+ """A list of prompt URIs associated with the model."""
323
+ return self._prompts
324
+
325
+ @property
326
+ def registered_model_version(self) -> Optional[int]:
327
+ """
328
+ The registered model version, if the model is registered.
329
+
330
+ :getter: Gets the registered model version, if the model is registered in Model Registry.
331
+ :setter: Sets the registered model version.
332
+ :type: Optional[int]
333
+ """
334
+ return self._registered_model_version
335
+
336
+ @registered_model_version.setter
337
+ def registered_model_version(self, value) -> None:
338
+ self._registered_model_version = value
339
+
340
+ @property
341
+ def model_id(self) -> str:
342
+ """
343
+ The model ID of the logged model.
344
+
345
+ :getter: Gets the model ID of the logged model
346
+ """
347
+ return self._logged_model.model_id
348
+
349
+ @property
350
+ def metrics(self) -> Optional[list[Metric]]:
351
+ """
352
+ Returns the metrics of the logged model.
353
+
354
+ :getter: Retrieves the metrics of the logged model
355
+ """
356
+ return self._logged_model.metrics
357
+
358
+ @property
359
+ def params(self) -> dict[str, str]:
360
+ """
361
+ Returns the parameters of the logged model.
362
+
363
+ :getter: Retrieves the parameters of the logged model
364
+ """
365
+ return self._logged_model.params
366
+
367
+ @property
368
+ def tags(self) -> dict[str, str]:
369
+ """
370
+ Returns the tags of the logged model.
371
+
372
+ :getter: Retrieves the tags of the logged model
373
+ """
374
+ return self._logged_model.tags
375
+
376
+ @property
377
+ def creation_timestamp(self) -> int:
378
+ """
379
+ Returns the creation timestamp of the logged model.
380
+
381
+ :getter: the creation timestamp of the logged model
382
+ """
383
+ return self._logged_model.creation_timestamp
384
+
385
+ @property
386
+ def name(self) -> str:
387
+ """
388
+ Returns the name of the logged model.
389
+ """
390
+ return self._logged_model.name
391
+
392
+
393
+ class Model:
394
+ """
395
+ An MLflow Model that can support multiple model flavors. Provides APIs for implementing
396
+ new Model flavors.
397
+ """
398
+
399
+ def __init__(
400
+ self,
401
+ artifact_path=None,
402
+ run_id=None,
403
+ utc_time_created=None,
404
+ flavors=None,
405
+ signature=None, # ModelSignature
406
+ saved_input_example_info: Optional[dict[str, Any]] = None,
407
+ model_uuid: Union[str, Callable[[], str], None] = lambda: uuid.uuid4().hex,
408
+ mlflow_version: Union[str, None] = mlflow.version.VERSION,
409
+ metadata: Optional[dict[str, Any]] = None,
410
+ model_size_bytes: Optional[int] = None,
411
+ resources: Optional[Union[str, list[Resource]]] = None,
412
+ env_vars: Optional[list[str]] = None,
413
+ auth_policy: Optional[AuthPolicy] = None,
414
+ model_id: Optional[str] = None,
415
+ prompts: Optional[list[str]] = None,
416
+ **kwargs,
417
+ ):
418
+ # store model id instead of run_id and path to avoid confusion when model gets exported
419
+ self.run_id = run_id
420
+ self.artifact_path = artifact_path
421
+ self.utc_time_created = str(utc_time_created or datetime.now())
422
+ self.flavors = flavors if flavors is not None else {}
423
+ self.signature = signature
424
+ self.saved_input_example_info = saved_input_example_info
425
+ self.model_uuid = model_uuid() if callable(model_uuid) else model_uuid
426
+ self.mlflow_version = mlflow_version
427
+ self.metadata = metadata
428
+ self.prompts = prompts
429
+ self.model_size_bytes = model_size_bytes
430
+ self.resources = resources
431
+ self.env_vars = env_vars
432
+ self.auth_policy = auth_policy
433
+ self.model_id = model_id
434
+ self.__dict__.update(kwargs)
435
+
436
+ def __eq__(self, other):
437
+ if not isinstance(other, Model):
438
+ return False
439
+ return self.__dict__ == other.__dict__
440
+
441
+ def get_input_schema(self):
442
+ """
443
+ Retrieves the input schema of the Model iff the model was saved with a schema definition.
444
+ """
445
+ return self.signature.inputs if self.signature is not None else None
446
+
447
+ def get_output_schema(self):
448
+ """
449
+ Retrieves the output schema of the Model iff the model was saved with a schema definition.
450
+ """
451
+ return self.signature.outputs if self.signature is not None else None
452
+
453
+ def get_params_schema(self):
454
+ """
455
+ Retrieves the parameters schema of the Model iff the model was saved with a schema
456
+ definition.
457
+ """
458
+ return getattr(self.signature, "params", None)
459
+
460
+ def get_serving_input(self, path: str) -> Optional[str]:
461
+ """
462
+ Load serving input example from a model directory. Returns None if there is no serving input
463
+ example.
464
+
465
+ Args:
466
+ path: Path to the model directory.
467
+
468
+ Returns:
469
+ Serving input example or None if the model has no serving input example.
470
+ """
471
+ from mlflow.models.utils import _load_serving_input_example
472
+
473
+ return _load_serving_input_example(self, path)
474
+
475
+ def load_input_example(self, path: Optional[str] = None) -> Optional[str]:
476
+ """
477
+ Load the input example saved along a model. Returns None if there is no example metadata
478
+ (i.e. the model was saved without example). Raises FileNotFoundError if there is model
479
+ metadata but the example file is missing.
480
+
481
+ Args:
482
+ path: Model or run URI, or path to the `model` directory.
483
+ e.g. models://<model_name>/<model_version>, runs:/<run_id>/<artifact_path>
484
+ or /path/to/model
485
+
486
+ Returns:
487
+ Input example (NumPy ndarray, SciPy csc_matrix, SciPy csr_matrix,
488
+ pandas DataFrame, dict) or None if the model has no example.
489
+ """
490
+
491
+ # Just-in-time import to only load example-parsing libraries (e.g. numpy, pandas, etc.) if
492
+ # example is requested.
493
+ from mlflow.models.utils import _read_example
494
+
495
+ if path is None:
496
+ path = (
497
+ f"runs:/{self.run_id}/{self.artifact_path}"
498
+ if self.model_id is None
499
+ else self.artifact_path
500
+ )
501
+
502
+ return _read_example(self, str(path))
503
+
504
+ def load_input_example_params(self, path: str):
505
+ """
506
+ Load the params of input example saved along a model. Returns None if there are no params in
507
+ the input_example.
508
+
509
+ Args:
510
+ path: Path to the model directory.
511
+
512
+ Returns:
513
+ params (dict) or None if the model has no params.
514
+ """
515
+ from mlflow.models.utils import _read_example_params
516
+
517
+ return _read_example_params(self, path)
518
+
519
+ def add_flavor(self, name, **params) -> "Model":
520
+ """Add an entry for how to serve the model in a given format."""
521
+ self.flavors[name] = params
522
+ return self
523
+
524
+ @property
525
+ def metadata(self) -> Optional[dict[str, Any]]:
526
+ """
527
+ Custom metadata dictionary passed to the model and stored in the MLmodel file.
528
+
529
+ :getter: Retrieves custom metadata that have been applied to a model instance.
530
+ :setter: Sets a dictionary of custom keys and values to be included with the model instance
531
+ :type: Optional[Dict[str, Any]]
532
+
533
+ Returns:
534
+ A Dictionary of user-defined metadata iff defined.
535
+
536
+ .. code-block:: python
537
+ :caption: Example
538
+
539
+ # Create and log a model with metadata to the Model Registry
540
+ from sklearn import datasets
541
+ from sklearn.ensemble import RandomForestClassifier
542
+ import mlflow
543
+ from mlflow.models import infer_signature
544
+
545
+ with mlflow.start_run():
546
+ iris = datasets.load_iris()
547
+ clf = RandomForestClassifier()
548
+ clf.fit(iris.data, iris.target)
549
+ signature = infer_signature(iris.data, iris.target)
550
+ mlflow.sklearn.log_model(
551
+ clf,
552
+ name="iris_rf",
553
+ signature=signature,
554
+ registered_model_name="model-with-metadata",
555
+ metadata={"metadata_key": "metadata_value"},
556
+ )
557
+
558
+ # model uri for the above model
559
+ model_uri = "models:/model-with-metadata/1"
560
+
561
+ # Load the model and access the custom metadata
562
+ model = mlflow.pyfunc.load_model(model_uri=model_uri)
563
+ assert model.metadata.metadata["metadata_key"] == "metadata_value"
564
+ """
565
+
566
+ return self._metadata
567
+
568
+ @metadata.setter
569
+ def metadata(self, value: Optional[dict[str, Any]]) -> None:
570
+ self._metadata = value
571
+
572
+ @property
573
+ def signature(self): # -> Optional[ModelSignature]
574
+ """
575
+ An optional definition of the expected inputs to and outputs from a model object, defined
576
+ with both field names and data types. Signatures support both column-based and tensor-based
577
+ inputs and outputs.
578
+
579
+ :getter: Retrieves the signature of a model instance iff the model was saved with a
580
+ signature definition.
581
+ :setter: Sets a signature to a model instance.
582
+ :type: Optional[ModelSignature]
583
+ """
584
+ return self._signature
585
+
586
+ @signature.setter
587
+ def signature(self, value) -> None:
588
+ # signature cannot be set to `False`, which is used in `log_model` and `save_model` calls
589
+ # to disable automatic signature inference
590
+ if value is not False:
591
+ self._signature = value
592
+
593
+ @property
594
+ def saved_input_example_info(self) -> Optional[dict[str, Any]]:
595
+ """
596
+ A dictionary that contains the metadata of the saved input example, e.g.,
597
+ ``{"artifact_path": "input_example.json", "type": "dataframe", "pandas_orient": "split"}``.
598
+ """
599
+ return self._saved_input_example_info
600
+
601
+ @saved_input_example_info.setter
602
+ def saved_input_example_info(self, value: dict[str, Any]) -> None:
603
+ self._saved_input_example_info = value
604
+
605
+ @property
606
+ def model_size_bytes(self) -> Optional[int]:
607
+ """
608
+ An optional integer that represents the model size in bytes
609
+
610
+ :getter: Retrieves the model size if it's calculated when the model is saved
611
+ :setter: Sets the model size to a model instance
612
+ :type: Optional[int]
613
+ """
614
+ return self._model_size_bytes
615
+
616
+ @model_size_bytes.setter
617
+ def model_size_bytes(self, value: Optional[int]) -> None:
618
+ self._model_size_bytes = value
619
+
620
+ @experimental(version="2.13.0")
621
+ @property
622
+ def resources(self) -> dict[str, dict[ResourceType, list[dict[str, Any]]]]:
623
+ """
624
+ An optional dictionary that contains the resources required to serve the model.
625
+
626
+ :getter: Retrieves the resources required to serve the model
627
+ :setter: Sets the resources required to serve the model
628
+ :type: Dict[str, Dict[ResourceType, List[Dict]]]
629
+ """
630
+ return self._resources
631
+
632
+ @experimental(version="2.13.0")
633
+ @resources.setter
634
+ def resources(self, value: Optional[Union[str, list[Resource]]]) -> None:
635
+ if isinstance(value, (Path, str)):
636
+ serialized_resource = _ResourceBuilder.from_yaml_file(value)
637
+ elif isinstance(value, list) and all(isinstance(resource, Resource) for resource in value):
638
+ serialized_resource = _ResourceBuilder.from_resources(value)
639
+ else:
640
+ serialized_resource = value
641
+ self._resources = serialized_resource
642
+
643
+ @experimental(version="2.21.0")
644
+ @property
645
+ def auth_policy(self) -> dict[str, dict[str, Any]]:
646
+ """
647
+ An optional dictionary that contains the auth policy required to serve the model.
648
+
649
+ :getter: Retrieves the auth_policy required to serve the model
650
+ :setter: Sets the auth_policy required to serve the model
651
+ :type: Dict[str, dict]
652
+ """
653
+ return self._auth_policy
654
+
655
+ @experimental(version="2.21.0")
656
+ @auth_policy.setter
657
+ def auth_policy(self, value: Optional[Union[dict[str, Any], AuthPolicy]]) -> None:
658
+ self._auth_policy = value.to_dict() if isinstance(value, AuthPolicy) else value
659
+
660
+ @property
661
+ def env_vars(self) -> Optional[list[str]]:
662
+ return self._env_vars
663
+
664
+ @env_vars.setter
665
+ def env_vars(self, value: Optional[list[str]]) -> None:
666
+ if value and not (isinstance(value, list) and all(isinstance(x, str) for x in value)):
667
+ raise TypeError(f"env_vars must be a list of strings. Got: {value}")
668
+ self._env_vars = value
669
+
670
+ def _is_signature_from_type_hint(self):
671
+ return self.signature._is_signature_from_type_hint if self.signature is not None else False
672
+
673
+ def _is_type_hint_from_example(self):
674
+ return self.signature._is_type_hint_from_example if self.signature is not None else False
675
+
676
+ def get_model_info(self, logged_model: Optional[LoggedModel] = None) -> ModelInfo:
677
+ """
678
+ Create a :py:class:`ModelInfo <mlflow.models.model.ModelInfo>` instance that contains the
679
+ model metadata.
680
+ """
681
+ return ModelInfo(
682
+ artifact_path=self.artifact_path,
683
+ flavors=self.flavors,
684
+ model_uri=(
685
+ f"models:/{self.model_id}"
686
+ if self.model_id
687
+ else f"runs:/{self.run_id}/{self.artifact_path}"
688
+ ),
689
+ model_uuid=self.model_uuid,
690
+ run_id=self.run_id,
691
+ saved_input_example_info=self.saved_input_example_info,
692
+ signature=self.signature,
693
+ utc_time_created=self.utc_time_created,
694
+ mlflow_version=self.mlflow_version,
695
+ metadata=self.metadata,
696
+ prompts=self.prompts,
697
+ env_vars=self.env_vars,
698
+ logged_model=logged_model,
699
+ )
700
+
701
+ def get_tags_dict(self) -> dict[str, Any]:
702
+ result = self.to_dict()
703
+
704
+ tags = {
705
+ key: value
706
+ for key, value in result.items()
707
+ if key in ["run_id", "utc_time_created", "artifact_path", "model_uuid"]
708
+ }
709
+
710
+ tags["flavors"] = {
711
+ flavor: (
712
+ {k: v for k, v in config.items() if k != "config"}
713
+ if isinstance(config, dict)
714
+ else config
715
+ )
716
+ for flavor, config in result.get("flavors", {}).items()
717
+ }
718
+
719
+ return tags
720
+
721
+ def to_dict(self) -> dict[str, Any]:
722
+ """Serialize the model to a dictionary."""
723
+ res = {k: v for k, v in self.__dict__.items() if not k.startswith("_")}
724
+ databricks_runtime = get_databricks_runtime_version()
725
+ if databricks_runtime:
726
+ res["databricks_runtime"] = databricks_runtime
727
+ if self.signature is not None:
728
+ res["signature"] = self.signature.to_dict()
729
+ res["is_signature_from_type_hint"] = self.signature._is_signature_from_type_hint
730
+ res["type_hint_from_example"] = self.signature._is_type_hint_from_example
731
+ if self.saved_input_example_info is not None:
732
+ res["saved_input_example_info"] = self.saved_input_example_info
733
+ if self.mlflow_version is None and _MLFLOW_VERSION_KEY in res:
734
+ res.pop(_MLFLOW_VERSION_KEY)
735
+ if self.metadata is not None:
736
+ res["metadata"] = self.metadata
737
+ if self.prompts is not None:
738
+ res["prompts"] = self.prompts
739
+ if self.resources is not None:
740
+ res["resources"] = self.resources
741
+ if self.model_size_bytes is not None:
742
+ res["model_size_bytes"] = self.model_size_bytes
743
+ if self.auth_policy is not None:
744
+ res["auth_policy"] = self.auth_policy
745
+ # Exclude null fields in case MLmodel file consumers such as Model Serving may not
746
+ # handle them correctly.
747
+ if self.artifact_path is None:
748
+ res.pop("artifact_path", None)
749
+ if self.run_id is None:
750
+ res.pop("run_id", None)
751
+ if self.env_vars is not None:
752
+ res["env_vars"] = self.env_vars
753
+ return res
754
+
755
+ def to_yaml(self, stream=None) -> str:
756
+ """Write the model as yaml string."""
757
+ return yaml.safe_dump(self.to_dict(), stream=stream, default_flow_style=False)
758
+
759
+ def __str__(self):
760
+ return self.to_yaml()
761
+
762
+ def to_json(self) -> str:
763
+ """Write the model as json."""
764
+ return json.dumps(self.to_dict())
765
+
766
+ def save(self, path) -> None:
767
+ """Write the model as a local YAML file."""
768
+ with open(path, "w") as out:
769
+ self.to_yaml(out)
770
+
771
+ @classmethod
772
+ def load(cls, path) -> "Model":
773
+ """
774
+ Load a model from its YAML representation.
775
+
776
+ Args:
777
+ path: A local filesystem path or URI referring to the MLmodel YAML file
778
+ representation of the Model object or to the directory containing
779
+ the MLmodel YAML file representation.
780
+
781
+ Returns:
782
+ An instance of Model.
783
+
784
+ .. code-block:: python
785
+ :caption: example
786
+
787
+ from mlflow.models import Model
788
+
789
+ # Load the Model object from a local MLmodel file
790
+ model1 = Model.load("~/path/to/my/MLmodel")
791
+
792
+ # Load the Model object from a remote model directory
793
+ model2 = Model.load("s3://mybucket/path/to/my/model")
794
+ """
795
+
796
+ # Check if the path is a local directory and not remote
797
+ sep = os.path.sep
798
+ path = str(path).rstrip(sep)
799
+ path_scheme = urlparse(path).scheme
800
+ if (not path_scheme or path_scheme == "file") and not os.path.exists(path):
801
+ raise MlflowException(
802
+ f'Could not find an "{MLMODEL_FILE_NAME}" configuration file at "{path}"',
803
+ RESOURCE_DOES_NOT_EXIST,
804
+ )
805
+
806
+ if ModelsArtifactRepository._is_logged_model_uri(path):
807
+ path = ModelsArtifactRepository.get_underlying_uri(path)
808
+
809
+ is_model_dir = path.rsplit(sep, maxsplit=1)[-1] != MLMODEL_FILE_NAME
810
+ mlmodel_file_path = f"{path}/{MLMODEL_FILE_NAME}" if is_model_dir else path
811
+ mlmodel_local_path = _download_artifact_from_uri(artifact_uri=mlmodel_file_path)
812
+ with open(mlmodel_local_path) as f:
813
+ model_dict = yaml.safe_load(f)
814
+ return cls.from_dict(model_dict)
815
+
816
+ @classmethod
817
+ def from_dict(cls, model_dict) -> "Model":
818
+ """Load a model from its YAML representation."""
819
+
820
+ from mlflow.models.signature import ModelSignature
821
+
822
+ model_dict = model_dict.copy()
823
+ if "signature" in model_dict and isinstance(model_dict["signature"], dict):
824
+ signature = ModelSignature.from_dict(model_dict["signature"])
825
+ if "is_signature_from_type_hint" in model_dict:
826
+ signature._is_signature_from_type_hint = model_dict.pop(
827
+ "is_signature_from_type_hint"
828
+ )
829
+ if "type_hint_from_example" in model_dict:
830
+ signature._is_type_hint_from_example = model_dict.pop("type_hint_from_example")
831
+ model_dict["signature"] = signature
832
+
833
+ if "model_uuid" not in model_dict:
834
+ model_dict["model_uuid"] = None
835
+
836
+ if _MLFLOW_VERSION_KEY not in model_dict:
837
+ model_dict[_MLFLOW_VERSION_KEY] = None
838
+ return cls(**model_dict)
839
+
840
+ # MLflow 2.x log_model API. Only spark flavors uses this API.
841
+ # https://github.com/mlflow/mlflow/blob/fd2d9861fa52eeca178825c871d5d29fbb3b95c4/mlflow/models/model.py#L773-L982
842
+ @format_docstring(LOG_MODEL_PARAM_DOCS)
843
+ @classmethod
844
+ def _log_v2(
845
+ cls,
846
+ artifact_path,
847
+ flavor,
848
+ registered_model_name=None,
849
+ await_registration_for=DEFAULT_AWAIT_MAX_SLEEP_SECONDS,
850
+ metadata=None,
851
+ run_id=None,
852
+ resources=None,
853
+ auth_policy=None,
854
+ prompts=None,
855
+ **kwargs,
856
+ ) -> ModelInfo:
857
+ """
858
+ Log model using supplied flavor module. If no run is active, this method will create a new
859
+ active run.
860
+
861
+ Args:
862
+ artifact_path: Run relative path identifying the model.
863
+ flavor: Flavor module to save the model with. The module must have
864
+ the ``save_model`` function that will persist the model as a valid
865
+ MLflow model.
866
+ registered_model_name: If given, create a model version under
867
+ ``registered_model_name``, also creating a registered model if
868
+ one with the given name does not exist.
869
+ await_registration_for: Number of seconds to wait for the model version to finish
870
+ being created and is in ``READY`` status. By default, the
871
+ function waits for five minutes. Specify 0 or None to skip
872
+ waiting.
873
+ metadata: {{ metadata }}
874
+ run_id: The run ID to associate with this model. If not provided,
875
+ a new run will be started.
876
+ resources: {{ resources }}
877
+ auth_policy: {{ auth_policy }}
878
+ prompts: {{ prompts }}
879
+ kwargs: Extra args passed to the model flavor.
880
+
881
+ Returns:
882
+ A :py:class:`ModelInfo <mlflow.models.model.ModelInfo>` instance that contains the
883
+ metadata of the logged model.
884
+ """
885
+
886
+ # Only one of Auth policy and resources should be defined
887
+
888
+ if resources is not None and auth_policy is not None:
889
+ raise ValueError("Only one of `resources`, and `auth_policy` can be specified.")
890
+
891
+ from mlflow.utils.model_utils import _validate_and_get_model_config_from_file
892
+
893
+ registered_model = None
894
+ with TempDir() as tmp:
895
+ local_path = tmp.path("model")
896
+ if run_id is None:
897
+ run_id = mlflow.tracking.fluent._get_or_start_run().info.run_id
898
+ if prompts is not None:
899
+ # Convert to URIs for serialization
900
+ prompts = [pr.uri if isinstance(pr, PromptVersion) else pr for pr in prompts]
901
+ mlflow_model = cls(
902
+ artifact_path=artifact_path,
903
+ run_id=run_id,
904
+ metadata=metadata,
905
+ resources=resources,
906
+ auth_policy=auth_policy,
907
+ prompts=prompts,
908
+ )
909
+ flavor.save_model(path=local_path, mlflow_model=mlflow_model, **kwargs)
910
+ # `save_model` calls `load_model` to infer the model requirements, which may result in
911
+ # __pycache__ directories being created in the model directory.
912
+ for pycache in Path(local_path).rglob("__pycache__"):
913
+ shutil.rmtree(pycache, ignore_errors=True)
914
+
915
+ if is_in_databricks_runtime():
916
+ _copy_model_metadata_for_uc_sharing(local_path, flavor)
917
+
918
+ tracking_uri = _resolve_tracking_uri()
919
+ serving_input = mlflow_model.get_serving_input(local_path)
920
+ # We check signature presence here as some flavors have a default signature as a
921
+ # fallback when not provided by user, which is set during flavor's save_model() call.
922
+ if mlflow_model.signature is None:
923
+ if serving_input is None:
924
+ _logger.warning(
925
+ _LOG_MODEL_MISSING_INPUT_EXAMPLE_WARNING, extra={"color": "red"}
926
+ )
927
+ elif tracking_uri == "databricks" or get_uri_scheme(tracking_uri) == "databricks":
928
+ _logger.warning(_LOG_MODEL_MISSING_SIGNATURE_WARNING, extra={"color": "red"})
929
+
930
+ env_vars = None
931
+ # validate input example works for serving when logging the model
932
+ if serving_input and kwargs.get("validate_serving_input", True):
933
+ from mlflow.models import validate_serving_input
934
+ from mlflow.utils.model_utils import RECORD_ENV_VAR_ALLOWLIST, env_var_tracker
935
+
936
+ with env_var_tracker() as tracked_env_names:
937
+ try:
938
+ validate_serving_input(
939
+ model_uri=local_path,
940
+ serving_input=serving_input,
941
+ )
942
+ except Exception as e:
943
+ serving_input_msg = (
944
+ serving_input[:50] + "..." if len(serving_input) > 50 else serving_input
945
+ )
946
+ _logger.warning(
947
+ f"Failed to validate serving input example {serving_input_msg}. "
948
+ "Alternatively, you can avoid passing input example and pass model "
949
+ "signature instead when logging the model. To ensure the input example "
950
+ "is valid prior to serving, please try calling "
951
+ "`mlflow.models.validate_serving_input` on the model uri and serving "
952
+ "input example. A serving input example can be generated from model "
953
+ "input example using "
954
+ "`mlflow.models.convert_input_example_to_serving_input` function.\n"
955
+ f"Got error: {e}",
956
+ exc_info=_logger.isEnabledFor(logging.DEBUG),
957
+ )
958
+ env_vars = (
959
+ sorted(
960
+ x
961
+ for x in tracked_env_names
962
+ if any(env_var in x for env_var in RECORD_ENV_VAR_ALLOWLIST)
963
+ )
964
+ or None
965
+ )
966
+ if env_vars:
967
+ # Keep the environment variable file as it serves as a check
968
+ # for displaying tips in Databricks serving endpoint
969
+ env_var_path = Path(local_path, ENV_VAR_FILE_NAME)
970
+ env_var_path.write_text(ENV_VAR_FILE_HEADER + "\n".join(env_vars) + "\n")
971
+ if len(env_vars) <= 3:
972
+ env_var_info = "[" + ", ".join(env_vars) + "]"
973
+ else:
974
+ env_var_info = "[" + ", ".join(env_vars[:3]) + ", ... " + "]"
975
+ f"(check file {ENV_VAR_FILE_NAME} in the model's artifact folder for full list"
976
+ " of environment variable names)"
977
+ _logger.info(
978
+ "Found the following environment variables used during model inference: "
979
+ f"{env_var_info}. Please check if you need to set them when deploying the "
980
+ "model. To disable this message, set environment variable "
981
+ f"`{MLFLOW_RECORD_ENV_VARS_IN_MODEL_LOGGING.name}` to `false`."
982
+ )
983
+ mlflow_model.env_vars = env_vars
984
+ # mlflow_model is updated, rewrite the MLmodel file
985
+ mlflow_model.save(os.path.join(local_path, MLMODEL_FILE_NAME))
986
+
987
+ # Associate prompts to the model Run
988
+ if prompts:
989
+ client = mlflow.MlflowClient()
990
+ for prompt in prompts:
991
+ client.link_prompt_version_to_run(run_id, prompt)
992
+
993
+ mlflow.tracking.fluent.log_artifacts(local_path, mlflow_model.artifact_path, run_id)
994
+
995
+ # if the model_config kwarg is passed in, then log the model config as an params
996
+ if model_config := kwargs.get("model_config"):
997
+ if isinstance(model_config, str):
998
+ try:
999
+ file_extension = os.path.splitext(model_config)[1].lower()
1000
+ if file_extension == ".json":
1001
+ with open(model_config) as f:
1002
+ model_config = json.load(f)
1003
+ elif file_extension in [".yaml", ".yml"]:
1004
+ model_config = _validate_and_get_model_config_from_file(model_config)
1005
+ else:
1006
+ _logger.warning(
1007
+ "Unsupported file format for model config: %s. "
1008
+ "Failed to load model config.",
1009
+ model_config,
1010
+ )
1011
+ except Exception as e:
1012
+ _logger.warning("Failed to load model config from %s: %s", model_config, e)
1013
+
1014
+ try:
1015
+ from mlflow.models.utils import _flatten_nested_params
1016
+
1017
+ # We are using the `/` separator to flatten the nested params
1018
+ # since we are using the same separator to log nested metrics.
1019
+ params_to_log = _flatten_nested_params(model_config, sep="/")
1020
+ except Exception as e:
1021
+ _logger.warning("Failed to flatten nested params: %s", str(e))
1022
+ params_to_log = model_config
1023
+
1024
+ try:
1025
+ mlflow.tracking.fluent.log_params(params_to_log or {}, run_id=run_id)
1026
+ except Exception as e:
1027
+ _logger.warning("Failed to log model config as params: %s", str(e))
1028
+
1029
+ try:
1030
+ mlflow.tracking.fluent._record_logged_model(mlflow_model, run_id)
1031
+ except MlflowException:
1032
+ # We need to swallow all mlflow exceptions to maintain backwards compatibility with
1033
+ # older tracking servers. Only print out a warning for now.
1034
+ _logger.warning(_LOG_MODEL_METADATA_WARNING_TEMPLATE, mlflow.get_artifact_uri())
1035
+ _logger.debug("", exc_info=True)
1036
+
1037
+ if registered_model_name is not None:
1038
+ registered_model = mlflow.tracking._model_registry.fluent._register_model(
1039
+ f"runs:/{run_id}/{mlflow_model.artifact_path}",
1040
+ registered_model_name,
1041
+ await_registration_for=await_registration_for,
1042
+ local_model_path=local_path,
1043
+ )
1044
+
1045
+ model_info = mlflow_model.get_model_info()
1046
+ if registered_model is not None:
1047
+ model_info.registered_model_version = registered_model.version
1048
+
1049
+ # If the model signature is Mosaic AI Agent compatible, render a recipe for evaluation.
1050
+ from mlflow.models.display_utils import maybe_render_agent_eval_recipe
1051
+
1052
+ maybe_render_agent_eval_recipe(model_info)
1053
+
1054
+ return model_info
1055
+
1056
+ @format_docstring(LOG_MODEL_PARAM_DOCS)
1057
+ @classmethod
1058
+ def log(
1059
+ cls,
1060
+ artifact_path,
1061
+ flavor,
1062
+ registered_model_name=None,
1063
+ await_registration_for=DEFAULT_AWAIT_MAX_SLEEP_SECONDS,
1064
+ metadata=None,
1065
+ run_id=None,
1066
+ resources=None,
1067
+ auth_policy=None,
1068
+ prompts=None,
1069
+ name: Optional[str] = None,
1070
+ model_type: Optional[str] = None,
1071
+ params: Optional[dict[str, Any]] = None,
1072
+ tags: Optional[dict[str, Any]] = None,
1073
+ step: int = 0,
1074
+ model_id: Optional[str] = None,
1075
+ **kwargs,
1076
+ ) -> ModelInfo:
1077
+ """
1078
+ Log model using supplied flavor module. If no run is active, this method will create a new
1079
+ active run.
1080
+
1081
+ Args:
1082
+ artifact_path: Deprecated. Use `name` instead.
1083
+ flavor: Flavor module to save the model with. The module must have
1084
+ the ``save_model`` function that will persist the model as a valid
1085
+ MLflow model.
1086
+ registered_model_name: If given, create a model version under
1087
+ ``registered_model_name``, also creating a registered model if
1088
+ one with the given name does not exist.
1089
+ await_registration_for: Number of seconds to wait for the model version to finish
1090
+ being created and is in ``READY`` status. By default, the
1091
+ function waits for five minutes. Specify 0 or None to skip
1092
+ waiting.
1093
+ metadata: {{ metadata }}
1094
+ run_id: The run ID to associate with this model.
1095
+ resources: {{ resources }}
1096
+ auth_policy: {{ auth_policy }}
1097
+ prompts: {{ prompts }}
1098
+ name: The name of the model.
1099
+ model_type: {{ model_type }}
1100
+ params: {{ params }}
1101
+ tags: {{ tags }}
1102
+ step: {{ step }}
1103
+ model_id: {{ model_id }}
1104
+ kwargs: Extra args passed to the model flavor.
1105
+
1106
+ Returns:
1107
+ A :py:class:`ModelInfo <mlflow.models.model.ModelInfo>` instance that contains the
1108
+ metadata of the logged model.
1109
+ """
1110
+ if name is not None and artifact_path is not None:
1111
+ raise MlflowException.invalid_parameter_value(
1112
+ "Both `artifact_path` (deprecated) and `name` parameters were specified. "
1113
+ "Please only specify `name`."
1114
+ )
1115
+ elif artifact_path is not None:
1116
+ _logger.warning("`artifact_path` is deprecated. Please use `name` instead.")
1117
+
1118
+ name = name or artifact_path
1119
+
1120
+ def log_model_metrics_for_step(client, model_id, run_id, step):
1121
+ metric_names = client.get_run(run_id).data.metrics.keys()
1122
+ metrics_for_step = []
1123
+ for metric_name in metric_names:
1124
+ history = client.get_metric_history(run_id, metric_name)
1125
+ metrics_for_step.extend(
1126
+ [
1127
+ Metric(
1128
+ key=metric.key,
1129
+ value=metric.value,
1130
+ timestamp=metric.timestamp,
1131
+ step=metric.step,
1132
+ dataset_name=metric.dataset_name,
1133
+ dataset_digest=metric.dataset_digest,
1134
+ run_id=metric.run_id,
1135
+ model_id=model_id,
1136
+ )
1137
+ for metric in history
1138
+ if metric.step == step and metric.model_id is None
1139
+ ]
1140
+ )
1141
+ client.log_batch(run_id=run_id, metrics=metrics_for_step)
1142
+
1143
+ # Only one of Auth policy and resources should be defined
1144
+
1145
+ if resources is not None and auth_policy is not None:
1146
+ raise ValueError("Only one of `resources`, and `auth_policy` can be specified.")
1147
+
1148
+ registered_model = None
1149
+ with TempDir() as tmp:
1150
+ local_path = tmp.path("model")
1151
+
1152
+ tracking_uri = _resolve_tracking_uri()
1153
+ client = mlflow.MlflowClient(tracking_uri)
1154
+ if not run_id:
1155
+ run_id = active_run.info.run_id if (active_run := mlflow.active_run()) else None
1156
+
1157
+ if model_id is not None:
1158
+ model = client.get_logged_model(model_id)
1159
+ else:
1160
+ params = {
1161
+ **(params or {}),
1162
+ **(client.get_run(run_id).data.params if run_id else {}),
1163
+ }
1164
+ model = mlflow.initialize_logged_model(
1165
+ # TODO: Update model name
1166
+ name=name,
1167
+ source_run_id=run_id,
1168
+ model_type=model_type,
1169
+ params={key: str(value) for key, value in params.items()},
1170
+ tags={key: str(value) for key, value in tags.items()}
1171
+ if tags is not None
1172
+ else None,
1173
+ )
1174
+ if (
1175
+ MLFLOW_PRINT_MODEL_URLS_ON_CREATION.get()
1176
+ and is_databricks_uri(tracking_uri)
1177
+ and (workspace_url := get_workspace_url())
1178
+ ):
1179
+ logged_model_url = _construct_databricks_logged_model_url(
1180
+ workspace_url,
1181
+ model.experiment_id,
1182
+ model.model_id,
1183
+ get_workspace_id(),
1184
+ )
1185
+ eprint(f"🔗 View Logged Model at: {logged_model_url}")
1186
+
1187
+ with _use_logged_model(model=model):
1188
+ if run_id is not None:
1189
+ client.log_outputs(
1190
+ run_id=run_id, models=[LoggedModelOutput(model.model_id, step=step)]
1191
+ )
1192
+ log_model_metrics_for_step(
1193
+ client=client, model_id=model.model_id, run_id=run_id, step=step
1194
+ )
1195
+
1196
+ if prompts is not None:
1197
+ # Convert to URIs for serialization
1198
+ prompts = [pr.uri if isinstance(pr, PromptVersion) else pr for pr in prompts]
1199
+
1200
+ mlflow_model = cls(
1201
+ artifact_path=model.artifact_location,
1202
+ model_uuid=model.model_id,
1203
+ run_id=run_id,
1204
+ metadata=metadata,
1205
+ resources=resources,
1206
+ auth_policy=auth_policy,
1207
+ prompts=prompts,
1208
+ model_id=model.model_id,
1209
+ )
1210
+ flavor.save_model(path=local_path, mlflow_model=mlflow_model, **kwargs)
1211
+ # `save_model` calls `load_model` to infer the model requirements, which may result
1212
+ # in __pycache__ directories being created in the model directory.
1213
+ for pycache in Path(local_path).rglob("__pycache__"):
1214
+ shutil.rmtree(pycache, ignore_errors=True)
1215
+
1216
+ if is_in_databricks_runtime():
1217
+ _copy_model_metadata_for_uc_sharing(local_path, flavor)
1218
+
1219
+ serving_input = mlflow_model.get_serving_input(local_path)
1220
+ # We check signature presence here as some flavors have a default signature as a
1221
+ # fallback when not provided by user, which is set during flavor's save_model()
1222
+ # call.
1223
+ if mlflow_model.signature is None:
1224
+ if serving_input is None:
1225
+ _logger.warning(
1226
+ _LOG_MODEL_MISSING_INPUT_EXAMPLE_WARNING, extra={"color": "red"}
1227
+ )
1228
+ elif (
1229
+ tracking_uri == "databricks" or get_uri_scheme(tracking_uri) == "databricks"
1230
+ ):
1231
+ _logger.warning(
1232
+ _LOG_MODEL_MISSING_SIGNATURE_WARNING, extra={"color": "red"}
1233
+ )
1234
+
1235
+ env_vars = None
1236
+ # validate input example works for serving when logging the model
1237
+ if serving_input and kwargs.get("validate_serving_input", True):
1238
+ from mlflow.models import validate_serving_input
1239
+ from mlflow.utils.model_utils import RECORD_ENV_VAR_ALLOWLIST, env_var_tracker
1240
+
1241
+ with env_var_tracker() as tracked_env_names:
1242
+ try:
1243
+ validate_serving_input(
1244
+ model_uri=local_path,
1245
+ serving_input=serving_input,
1246
+ )
1247
+ except Exception as e:
1248
+ serving_input_msg = (
1249
+ serving_input[:50] + "..."
1250
+ if len(serving_input) > 50
1251
+ else serving_input
1252
+ )
1253
+ _logger.warning(
1254
+ f"Failed to validate serving input example {serving_input_msg}. "
1255
+ "Alternatively, you can avoid passing input example and pass model "
1256
+ "signature instead when logging the model. To ensure the input "
1257
+ "example is valid prior to serving, please try calling "
1258
+ "`mlflow.models.validate_serving_input` on the model uri and "
1259
+ "serving input example. A serving input example can be generated "
1260
+ "from model input example using "
1261
+ "`mlflow.models.convert_input_example_to_serving_input` function.\n"
1262
+ f"Got error: {e}",
1263
+ exc_info=_logger.isEnabledFor(logging.DEBUG),
1264
+ )
1265
+ env_vars = (
1266
+ sorted(
1267
+ x
1268
+ for x in tracked_env_names
1269
+ if any(env_var in x for env_var in RECORD_ENV_VAR_ALLOWLIST)
1270
+ )
1271
+ or None
1272
+ )
1273
+ if env_vars:
1274
+ # Keep the environment variable file as it serves as a check
1275
+ # for displaying tips in Databricks serving endpoint
1276
+ env_var_path = Path(local_path, ENV_VAR_FILE_NAME)
1277
+ env_var_path.write_text(ENV_VAR_FILE_HEADER + "\n".join(env_vars) + "\n")
1278
+ if len(env_vars) <= 3:
1279
+ env_var_info = "[" + ", ".join(env_vars) + "]"
1280
+ else:
1281
+ env_var_info = "[" + ", ".join(env_vars[:3]) + ", ... " + "]"
1282
+ f"(check file {ENV_VAR_FILE_NAME} in the model's artifact folder for full "
1283
+ "list of environment variable names)"
1284
+ _logger.info(
1285
+ "Found the following environment variables used during model inference: "
1286
+ f"{env_var_info}. Please check if you need to set them when deploying the "
1287
+ "model. To disable this message, set environment variable "
1288
+ f"`{MLFLOW_RECORD_ENV_VARS_IN_MODEL_LOGGING.name}` to `false`."
1289
+ )
1290
+ mlflow_model.env_vars = env_vars
1291
+ # mlflow_model is updated, rewrite the MLmodel file
1292
+ mlflow_model.save(os.path.join(local_path, MLMODEL_FILE_NAME))
1293
+
1294
+ client.log_model_artifacts(model.model_id, local_path)
1295
+ # If the model was previously identified as external, delete the tag because
1296
+ # the model now has artifacts in MLflow Model format
1297
+ if model.tags.get(MLFLOW_MODEL_IS_EXTERNAL, "false").lower() == "true":
1298
+ client.delete_logged_model_tag(model.model_id, MLFLOW_MODEL_IS_EXTERNAL)
1299
+ # client.finalize_logged_model(model.model_id, status=LoggedModelStatus.READY)
1300
+
1301
+ # Associate prompts to the model Run
1302
+ if prompts and run_id:
1303
+ client = mlflow.MlflowClient()
1304
+ for prompt in prompts:
1305
+ client.link_prompt_version_to_run(run_id, prompt)
1306
+
1307
+ # if the model_config kwarg is passed in, then log the model config as an params
1308
+ if model_config := kwargs.get("model_config"):
1309
+ if isinstance(model_config, str):
1310
+ try:
1311
+ file_extension = os.path.splitext(model_config)[1].lower()
1312
+ if file_extension == ".json":
1313
+ with open(model_config) as f:
1314
+ model_config = json.load(f)
1315
+ elif file_extension in [".yaml", ".yml"]:
1316
+ from mlflow.utils.model_utils import (
1317
+ _validate_and_get_model_config_from_file,
1318
+ )
1319
+
1320
+ model_config = _validate_and_get_model_config_from_file(
1321
+ model_config
1322
+ )
1323
+ else:
1324
+ _logger.warning(
1325
+ "Unsupported file format for model config: %s. "
1326
+ "Failed to load model config.",
1327
+ model_config,
1328
+ )
1329
+ except Exception as e:
1330
+ _logger.warning(
1331
+ "Failed to load model config from %s: %s", model_config, e
1332
+ )
1333
+
1334
+ try:
1335
+ from mlflow.models.utils import _flatten_nested_params
1336
+
1337
+ # We are using the `/` separator to flatten the nested params
1338
+ # since we are using the same separator to log nested metrics.
1339
+ params_to_log = _flatten_nested_params(model_config, sep="/")
1340
+ except Exception as e:
1341
+ _logger.warning("Failed to flatten nested params: %s", str(e))
1342
+ params_to_log = model_config
1343
+
1344
+ try:
1345
+ # do not log params to run if run_id is None, since that could trigger
1346
+ # a new run to be created
1347
+ if run_id:
1348
+ mlflow.tracking.fluent.log_params(params_to_log or {}, run_id=run_id)
1349
+ except Exception as e:
1350
+ _logger.warning("Failed to log model config as params: %s", str(e))
1351
+
1352
+ if registered_model_name is not None:
1353
+ registered_model = mlflow.tracking._model_registry.fluent._register_model(
1354
+ f"models:/{model.model_id}",
1355
+ registered_model_name,
1356
+ await_registration_for=await_registration_for,
1357
+ local_model_path=local_path,
1358
+ )
1359
+ model_info = mlflow_model.get_model_info(model)
1360
+ if registered_model is not None:
1361
+ model_info.registered_model_version = registered_model.version
1362
+
1363
+ # If the model signature is Mosaic AI Agent compatible, render a recipe for evaluation.
1364
+ from mlflow.models.display_utils import maybe_render_agent_eval_recipe
1365
+
1366
+ maybe_render_agent_eval_recipe(model_info)
1367
+
1368
+ return model_info
1369
+
1370
+
1371
+ def _copy_model_metadata_for_uc_sharing(local_path: str, flavor) -> None:
1372
+ """
1373
+ Copy model metadata files to a sub-directory 'metadata',
1374
+ For Databricks Unity Catalog sharing use-cases.
1375
+
1376
+ Args:
1377
+ local_path: Local path to the model directory.
1378
+ flavor: Flavor module to save the model with.
1379
+ """
1380
+ from mlflow.models.wheeled_model import _ORIGINAL_REQ_FILE_NAME, WheeledModel
1381
+
1382
+ metadata_path = os.path.join(local_path, "metadata")
1383
+ if isinstance(flavor, WheeledModel):
1384
+ # wheeled model updates several metadata files in original model directory
1385
+ # copy these updated metadata files to the 'metadata' subdirectory
1386
+ os.makedirs(metadata_path, exist_ok=True)
1387
+ for file_name in METADATA_FILES + [
1388
+ _ORIGINAL_REQ_FILE_NAME,
1389
+ ]:
1390
+ src_file_path = os.path.join(local_path, file_name)
1391
+ if os.path.exists(src_file_path):
1392
+ dest_file_path = os.path.join(metadata_path, file_name)
1393
+ shutil.copyfile(src_file_path, dest_file_path)
1394
+ else:
1395
+ os.makedirs(metadata_path, exist_ok=True)
1396
+ for file_name in METADATA_FILES:
1397
+ src_file_path = os.path.join(local_path, file_name)
1398
+ if os.path.exists(src_file_path):
1399
+ dest_file_path = os.path.join(metadata_path, file_name)
1400
+ shutil.copyfile(src_file_path, dest_file_path)
1401
+
1402
+
1403
+ def get_model_info(model_uri: str) -> ModelInfo:
1404
+ """
1405
+ Get metadata for the specified model, such as its input/output signature.
1406
+
1407
+ Args:
1408
+ model_uri: The location, in URI format, of the MLflow model. For example:
1409
+
1410
+ - ``/Users/me/path/to/local/model``
1411
+ - ``relative/path/to/local/model``
1412
+ - ``s3://my_bucket/path/to/model``
1413
+ - ``runs:/<mlflow_run_id>/run-relative/path/to/model``
1414
+ - ``models:/<model_name>/<model_version>``
1415
+ - ``models:/<model_name>/<stage>``
1416
+ - ``mlflow-artifacts:/path/to/model``
1417
+
1418
+ For more information about supported URI schemes, see
1419
+ `Referencing Artifacts <https://www.mlflow.org/docs/latest/concepts.html#
1420
+ artifact-locations>`_.
1421
+
1422
+ Returns:
1423
+ A :py:class:`ModelInfo <mlflow.models.model.ModelInfo>` instance that contains the
1424
+ metadata of the logged model.
1425
+
1426
+ .. code-block:: python
1427
+ :caption: Example usage of get_model_info
1428
+
1429
+ import mlflow.models
1430
+ import mlflow.sklearn
1431
+ from sklearn.ensemble import RandomForestRegressor
1432
+
1433
+ with mlflow.start_run() as run:
1434
+ params = {"n_estimators": 3, "random_state": 42}
1435
+ X = [[0, 1]]
1436
+ y = [1]
1437
+ signature = mlflow.models.infer_signature(X, y)
1438
+ rfr = RandomForestRegressor(**params).fit(X, y)
1439
+ mlflow.log_params(params)
1440
+ mlflow.sklearn.log_model(rfr, name="sklearn-model", signature=signature)
1441
+
1442
+ model_uri = f"runs:/{run.info.run_id}/sklearn-model"
1443
+ # Get model info with model_uri
1444
+ model_info = mlflow.models.get_model_info(model_uri)
1445
+ # Get model signature directly
1446
+ model_signature = model_info.signature
1447
+ assert model_signature == signature
1448
+ """
1449
+ return Model.load(model_uri).get_model_info()
1450
+
1451
+
1452
+ class Files(NamedTuple):
1453
+ requirements: Path
1454
+ conda: Path
1455
+
1456
+
1457
+ def get_model_requirements_files(resolved_uri: str) -> Files:
1458
+ requirements_txt_file = _download_artifact_from_uri(
1459
+ artifact_uri=append_to_uri_path(resolved_uri, _REQUIREMENTS_FILE_NAME)
1460
+ )
1461
+ conda_yaml_file = _download_artifact_from_uri(
1462
+ artifact_uri=append_to_uri_path(resolved_uri, _CONDA_ENV_FILE_NAME)
1463
+ )
1464
+
1465
+ return Files(
1466
+ Path(requirements_txt_file),
1467
+ Path(conda_yaml_file),
1468
+ )
1469
+
1470
+
1471
+ def update_model_requirements(
1472
+ model_uri: str,
1473
+ operation: Literal["add", "remove"],
1474
+ requirement_list: list[str],
1475
+ ) -> None:
1476
+ """
1477
+ Add or remove requirements from a model's conda.yaml and requirements.txt files.
1478
+
1479
+ The process involves downloading these two files from the model artifacts
1480
+ (if they're non-local), updating them with the specified requirements,
1481
+ and then overwriting the existing files. Should the artifact repository
1482
+ associated with the model artifacts disallow overwriting, this function will
1483
+ fail.
1484
+
1485
+ Note that model registry URIs (i.e. URIs in the form ``models:/``) are not
1486
+ supported, as artifacts in the model registry are intended to be read-only.
1487
+
1488
+ If adding requirements, the function will overwrite any existing requirements
1489
+ that overlap, or else append the new requirements to the existing list.
1490
+
1491
+ If removing requirements, the function will ignore any version specifiers,
1492
+ and remove all the specified package names. Any requirements that are not
1493
+ found in the existing files will be ignored.
1494
+
1495
+ Args:
1496
+ model_uri: The location, in URI format, of the MLflow model. For example:
1497
+
1498
+ - ``/Users/me/path/to/local/model``
1499
+ - ``relative/path/to/local/model``
1500
+ - ``s3://my_bucket/path/to/model``
1501
+ - ``runs:/<mlflow_run_id>/run-relative/path/to/model``
1502
+ - ``mlflow-artifacts:/path/to/model``
1503
+
1504
+ For more information about supported URI schemes, see
1505
+ `Referencing Artifacts <https://www.mlflow.org/docs/latest/concepts.html#
1506
+ artifact-locations>`_.
1507
+
1508
+ operation: The operation to perform. Must be one of "add" or "remove".
1509
+
1510
+ requirement_list: A list of requirements to add or remove from the model.
1511
+ For example: ["numpy==1.20.3", "pandas>=1.3.3"]
1512
+ """
1513
+ resolved_uri = model_uri
1514
+ if ModelsArtifactRepository.is_models_uri(model_uri):
1515
+ if not ModelsArtifactRepository._is_logged_model_uri(model_uri):
1516
+ raise MlflowException(
1517
+ f'Failed to set requirements on "{model_uri}". '
1518
+ + "Model URIs with the `models:/` scheme are not supported.",
1519
+ INVALID_PARAMETER_VALUE,
1520
+ )
1521
+ resolved_uri = ModelsArtifactRepository.get_underlying_uri(model_uri)
1522
+ elif RunsArtifactRepository.is_runs_uri(model_uri):
1523
+ resolved_uri = RunsArtifactRepository.get_underlying_uri(model_uri)
1524
+
1525
+ _logger.info(f"Retrieving model requirements files from {resolved_uri}...")
1526
+ local_paths = get_model_requirements_files(resolved_uri)
1527
+ conda_yaml_path = local_paths.conda
1528
+ requirements_txt_path = local_paths.requirements
1529
+
1530
+ old_conda_reqs = _get_requirements_from_file(conda_yaml_path)
1531
+ old_requirements_reqs = _get_requirements_from_file(requirements_txt_path)
1532
+
1533
+ requirements = []
1534
+ invalid_requirements = {}
1535
+ for s in requirement_list:
1536
+ try:
1537
+ requirements.append(Requirement(s.strip().lower()))
1538
+ except InvalidRequirement as e:
1539
+ invalid_requirements[s] = e
1540
+ if invalid_requirements:
1541
+ raise MlflowException.invalid_parameter_value(
1542
+ f"Found invalid requirements: {invalid_requirements}"
1543
+ )
1544
+ if operation == "add":
1545
+ updated_conda_reqs = _add_or_overwrite_requirements(requirements, old_conda_reqs)
1546
+ updated_requirements_reqs = _add_or_overwrite_requirements(
1547
+ requirements, old_requirements_reqs
1548
+ )
1549
+ else:
1550
+ updated_conda_reqs = _remove_requirements(requirements, old_conda_reqs)
1551
+ updated_requirements_reqs = _remove_requirements(requirements, old_requirements_reqs)
1552
+
1553
+ _write_requirements_to_file(conda_yaml_path, updated_conda_reqs)
1554
+ _write_requirements_to_file(requirements_txt_path, updated_requirements_reqs)
1555
+
1556
+ # just print conda reqs here to avoid log spam
1557
+ # it should be the same as requirements.txt anyway
1558
+ _logger.info(
1559
+ "Done updating requirements!\n\n"
1560
+ f"Old requirements:\n{pformat([str(req) for req in old_conda_reqs])}\n\n"
1561
+ f"Updated requirements:\n{pformat(updated_conda_reqs)}\n"
1562
+ )
1563
+
1564
+ _logger.info(f"Uploading updated requirements files to {resolved_uri}...")
1565
+ _upload_artifact_to_uri(conda_yaml_path, resolved_uri)
1566
+ _upload_artifact_to_uri(requirements_txt_path, resolved_uri)
1567
+
1568
+
1569
+ __mlflow_model__ = None
1570
+
1571
+
1572
+ def _validate_langchain_model(model):
1573
+ from langchain_core.runnables.base import Runnable
1574
+
1575
+ from mlflow.models.utils import _validate_and_get_model_code_path
1576
+
1577
+ if isinstance(model, str):
1578
+ return _validate_and_get_model_code_path(model, None)
1579
+
1580
+ if not isinstance(model, Runnable):
1581
+ raise MlflowException.invalid_parameter_value(
1582
+ "Model must be a Langchain Runnable type or path to a Langchain model, "
1583
+ f"got {type(model)}"
1584
+ )
1585
+
1586
+ return model
1587
+
1588
+
1589
+ def _validate_llama_index_model(model):
1590
+ from mlflow.llama_index.model import _validate_and_prepare_llama_index_model_or_path
1591
+
1592
+ return _validate_and_prepare_llama_index_model_or_path(model, None)
1593
+
1594
+
1595
+ @experimental(version="2.13.0")
1596
+ def set_model(model) -> None:
1597
+ """
1598
+ When logging model as code, this function can be used to set the model object
1599
+ to be logged.
1600
+
1601
+ Args:
1602
+ model: The model object to be logged. Supported model types are:
1603
+
1604
+ - A Python function or callable object.
1605
+ - A Langchain model or path to a Langchain model.
1606
+ - A Llama Index model or path to a Llama Index model.
1607
+ """
1608
+ from mlflow.pyfunc import PythonModel
1609
+
1610
+ if isinstance(model, str):
1611
+ raise mlflow.MlflowException(SET_MODEL_ERROR)
1612
+
1613
+ if isinstance(model, PythonModel) or callable(model):
1614
+ globals()["__mlflow_model__"] = model
1615
+ return
1616
+
1617
+ for validate_function in [_validate_langchain_model, _validate_llama_index_model]:
1618
+ try:
1619
+ globals()["__mlflow_model__"] = validate_function(model)
1620
+ return
1621
+ except Exception:
1622
+ pass
1623
+
1624
+ raise mlflow.MlflowException(SET_MODEL_ERROR)
1625
+
1626
+
1627
+ def _update_active_model_id_based_on_mlflow_model(mlflow_model: Model):
1628
+ """
1629
+ Update the current active model ID based on the provided MLflow model.
1630
+ Only set the active model ID if it is not already set by the user.
1631
+ This is useful for setting the active model ID when loading a model
1632
+ to ensure traces generated are associated with the loaded model.
1633
+ """
1634
+ if mlflow_model.model_id is None:
1635
+ return
1636
+ amc = _get_active_model_context()
1637
+ # only set the active model if the model is not set by the user
1638
+ if amc.model_id != mlflow_model.model_id and not amc.set_by_user:
1639
+ _set_active_model_id(model_id=mlflow_model.model_id)