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
@@ -0,0 +1,1417 @@
1
+ from __future__ import annotations
2
+
3
+ import contextlib
4
+ import functools
5
+ import importlib
6
+ import inspect
7
+ import json
8
+ import logging
9
+ from contextvars import ContextVar
10
+ from typing import TYPE_CHECKING, Any, Callable, Generator, Literal, Optional, Union
11
+
12
+ from cachetools import TTLCache
13
+ from opentelemetry import trace as trace_api
14
+
15
+ from mlflow.entities import NoOpSpan, SpanType, Trace
16
+ from mlflow.entities.span import NO_OP_SPAN_TRACE_ID, LiveSpan, create_mlflow_span
17
+ from mlflow.entities.span_event import SpanEvent
18
+ from mlflow.entities.span_status import SpanStatusCode
19
+ from mlflow.entities.trace_state import TraceState
20
+ from mlflow.entities.trace_status import TraceStatus
21
+ from mlflow.exceptions import MlflowException
22
+ from mlflow.store.tracking import SEARCH_TRACES_DEFAULT_MAX_RESULTS
23
+ from mlflow.tracing import provider
24
+ from mlflow.tracing.client import TracingClient
25
+ from mlflow.tracing.constant import (
26
+ STREAM_CHUNK_EVENT_NAME_FORMAT,
27
+ STREAM_CHUNK_EVENT_VALUE_KEY,
28
+ SpanAttributeKey,
29
+ )
30
+ from mlflow.tracing.provider import is_tracing_enabled, safe_set_span_in_context
31
+ from mlflow.tracing.trace_manager import InMemoryTraceManager
32
+ from mlflow.tracing.utils import (
33
+ SPANS_COLUMN_NAME,
34
+ TraceJSONEncoder,
35
+ capture_function_input_args,
36
+ encode_span_id,
37
+ exclude_immutable_tags,
38
+ get_otel_attribute,
39
+ set_chat_attributes_special_case,
40
+ )
41
+ from mlflow.tracing.utils.search import extract_span_inputs_outputs, traces_to_df
42
+ from mlflow.tracing.utils.warning import request_id_backward_compatible
43
+ from mlflow.utils import get_results_from_paginated_fn
44
+ from mlflow.utils.annotations import experimental
45
+
46
+ _logger = logging.getLogger(__name__)
47
+
48
+ if TYPE_CHECKING:
49
+ import pandas
50
+
51
+
52
+ _LAST_ACTIVE_TRACE_ID_GLOBAL = None
53
+ _LAST_ACTIVE_TRACE_ID_THREAD_LOCAL = ContextVar("last_active_trace_id", default=None)
54
+
55
+ # Cache mapping between evaluation request ID to MLflow backend request ID.
56
+ # This is necessary for evaluation harness to access generated traces during
57
+ # evaluation using the dataset row ID (evaluation request ID).
58
+ _EVAL_REQUEST_ID_TO_TRACE_ID = TTLCache(maxsize=10000, ttl=3600)
59
+
60
+
61
+ def trace(
62
+ func: Optional[Callable[..., Any]] = None,
63
+ name: Optional[str] = None,
64
+ span_type: str = SpanType.UNKNOWN,
65
+ attributes: Optional[dict[str, Any]] = None,
66
+ output_reducer: Optional[Callable[[list[Any]], Any]] = None,
67
+ ) -> Callable[..., Any]:
68
+ """
69
+ A decorator that creates a new span for the decorated function.
70
+
71
+ When you decorate a function with this :py:func:`@mlflow.trace() <trace>` decorator,
72
+ a span will be created for the scope of the decorated function. The span will automatically
73
+ capture the input and output of the function. When it is applied to a method, it doesn't
74
+ capture the `self` argument. Any exception raised within the function will set the span
75
+ status to ``ERROR`` and detailed information such as exception message and stacktrace
76
+ will be recorded to the ``attributes`` field of the span.
77
+
78
+ For example, the following code will yield a span with the name ``"my_function"``,
79
+ capturing the input arguments ``x`` and ``y``, and the output of the function.
80
+
81
+ .. code-block:: python
82
+ :test:
83
+
84
+ import mlflow
85
+
86
+
87
+ @mlflow.trace
88
+ def my_function(x, y):
89
+ return x + y
90
+
91
+ This is equivalent to doing the following using the :py:func:`mlflow.start_span` context
92
+ manager, but requires less boilerplate code.
93
+
94
+ .. code-block:: python
95
+ :test:
96
+
97
+ import mlflow
98
+
99
+
100
+ def my_function(x, y):
101
+ return x + y
102
+
103
+
104
+ with mlflow.start_span("my_function") as span:
105
+ x = 1
106
+ y = 2
107
+ span.set_inputs({"x": x, "y": y})
108
+ result = my_function(x, y)
109
+ span.set_outputs({"output": result})
110
+
111
+
112
+ The @mlflow.trace decorator currently support the following types of functions:
113
+
114
+ .. list-table:: Supported Function Types
115
+ :widths: 20 30
116
+ :header-rows: 1
117
+
118
+ * - Function Type
119
+ - Supported
120
+ * - Sync
121
+ - ✅
122
+ * - Async
123
+ - ✅ (>= 2.16.0)
124
+ * - Generator
125
+ - ✅ (>= 2.20.2)
126
+ * - Async Generator
127
+ - ✅ (>= 2.20.2)
128
+ * - ClassMethod
129
+ - ✅ (>= 3.0.0)
130
+ * - StaticMethod
131
+ - ✅ (>= 3.0.0)
132
+
133
+ For more examples of using the @mlflow.trace decorator, including streaming/async
134
+ handling, see the `MLflow Tracing documentation <https://www.mlflow.org/docs/latest/tracing/api/manual-instrumentation#decorator>`_.
135
+
136
+ .. tip::
137
+
138
+ The @mlflow.trace decorator is useful when you want to trace a function defined by
139
+ yourself. However, you may also want to trace a function in external libraries. In
140
+ such case, you can use this ``mlflow.trace()`` function to directly wrap the function,
141
+ instead of using as the decorator. This will create the exact same span as the
142
+ one created by the decorator i.e. captures information from the function call.
143
+
144
+ .. code-block:: python
145
+ :test:
146
+
147
+ import math
148
+
149
+ import mlflow
150
+
151
+ mlflow.trace(math.factorial)(5)
152
+
153
+ Args:
154
+ func: The function to be decorated. Must **not** be provided when using as a decorator.
155
+ name: The name of the span. If not provided, the name of the function will be used.
156
+ span_type: The type of the span. Can be either a string or a
157
+ :py:class:`SpanType <mlflow.entities.SpanType>` enum value.
158
+ attributes: A dictionary of attributes to set on the span.
159
+ output_reducer: A function that reduces the outputs of the generator function into a
160
+ single value to be set as the span output.
161
+ """
162
+
163
+ def decorator(fn):
164
+ # Check if the function is a classmethod or staticmethod
165
+ is_classmethod = isinstance(fn, classmethod)
166
+ is_staticmethod = isinstance(fn, staticmethod)
167
+
168
+ # Extract the original function if it's a descriptor
169
+ original_fn = fn.__func__ if is_classmethod or is_staticmethod else fn
170
+
171
+ # Apply the appropriate wrapper to the original function
172
+ if inspect.isgeneratorfunction(original_fn) or inspect.isasyncgenfunction(original_fn):
173
+ wrapped = _wrap_generator(
174
+ original_fn,
175
+ name,
176
+ span_type,
177
+ attributes,
178
+ output_reducer,
179
+ )
180
+ else:
181
+ if output_reducer is not None:
182
+ raise MlflowException.invalid_parameter_value(
183
+ "The output_reducer argument is only supported for generator functions."
184
+ )
185
+ wrapped = _wrap_function(original_fn, name, span_type, attributes)
186
+
187
+ # If the original was a descriptor, wrap the result back as the same type of descriptor
188
+ if is_classmethod:
189
+ return classmethod(wrapped)
190
+ elif is_staticmethod:
191
+ return staticmethod(wrapped)
192
+ else:
193
+ return wrapped
194
+
195
+ return decorator(func) if func else decorator
196
+
197
+
198
+ def _wrap_function(
199
+ fn: Callable[..., Any],
200
+ name: Optional[str] = None,
201
+ span_type: str = SpanType.UNKNOWN,
202
+ attributes: Optional[dict[str, Any]] = None,
203
+ ) -> Callable[..., Any]:
204
+ class _WrappingContext:
205
+ # define the wrapping logic as a coroutine to avoid code duplication
206
+ # between sync and async cases
207
+ @staticmethod
208
+ def _wrapping_logic(fn, args, kwargs):
209
+ span_name = name or fn.__name__
210
+
211
+ with start_span(name=span_name, span_type=span_type, attributes=attributes) as span:
212
+ span.set_attribute(SpanAttributeKey.FUNCTION_NAME, fn.__name__)
213
+ inputs = capture_function_input_args(fn, args, kwargs)
214
+ span.set_inputs(inputs)
215
+ result = yield # sync/async function output to be sent here
216
+ span.set_outputs(result)
217
+
218
+ set_chat_attributes_special_case(span, inputs=inputs, outputs=result)
219
+
220
+ try:
221
+ yield result
222
+ except GeneratorExit:
223
+ # Swallow `GeneratorExit` raised when the generator is closed
224
+ pass
225
+
226
+ def __init__(self, fn, args, kwargs):
227
+ self.coro = self._wrapping_logic(fn, args, kwargs)
228
+
229
+ def __enter__(self):
230
+ next(self.coro)
231
+ return self.coro
232
+
233
+ def __exit__(self, exc_type, exc_value, traceback):
234
+ # Since the function call occurs outside the coroutine,
235
+ # if an exception occurs, we need to throw it back in, so that
236
+ # we return control to the coro (in particular, so that the __exit__'s
237
+ # of start_span and OTel's use_span can execute).
238
+ if exc_type is not None:
239
+ self.coro.throw(exc_type, exc_value, traceback)
240
+ self.coro.close()
241
+
242
+ if inspect.iscoroutinefunction(fn):
243
+
244
+ async def wrapper(*args, **kwargs):
245
+ with _WrappingContext(fn, args, kwargs) as wrapping_coro:
246
+ return wrapping_coro.send(await fn(*args, **kwargs))
247
+ else:
248
+
249
+ def wrapper(*args, **kwargs):
250
+ with _WrappingContext(fn, args, kwargs) as wrapping_coro:
251
+ return wrapping_coro.send(fn(*args, **kwargs))
252
+
253
+ return _wrap_function_safe(fn, wrapper)
254
+
255
+
256
+ def _wrap_generator(
257
+ fn: Callable[..., Any],
258
+ name: Optional[str] = None,
259
+ span_type: str = SpanType.UNKNOWN,
260
+ attributes: Optional[dict[str, Any]] = None,
261
+ output_reducer: Optional[Callable[[list[Any]], Any]] = None,
262
+ ) -> Callable[..., Any]:
263
+ """
264
+ Wrap a generator function to create a span.
265
+ Generator functions need special handling because of its lazy evaluation nature.
266
+ Let's say we have a generator function like this:
267
+ ```
268
+ @mlflow.trace
269
+ def generate_stream():
270
+ # B
271
+ for i in range(10):
272
+ # C
273
+ yield i * 2
274
+ # E
275
+
276
+
277
+ stream = generate_stream()
278
+ # A
279
+ for chunk in stream:
280
+ # D
281
+ pass
282
+ # F
283
+ ```
284
+ The execution order is A -> B -> C -> D -> C -> D -> ... -> E -> F.
285
+ The span should only be "active" at B, C, and E, namely, when the code execution
286
+ is inside the generator function. Otherwise it will create wrong span tree, or
287
+ even worse, leak span context and pollute subsequent traces.
288
+ """
289
+
290
+ def _start_stream_span(fn, inputs):
291
+ try:
292
+ return start_span_no_context(
293
+ name=name or fn.__name__,
294
+ parent_span=get_current_active_span(),
295
+ span_type=span_type,
296
+ attributes=attributes,
297
+ inputs=inputs,
298
+ )
299
+ except Exception as e:
300
+ _logger.debug(f"Failed to start stream span: {e}")
301
+ return NoOpSpan()
302
+
303
+ def _end_stream_span(
304
+ span: LiveSpan,
305
+ inputs: Optional[dict[str, Any]] = None,
306
+ outputs: Optional[list[Any]] = None,
307
+ output_reducer: Optional[Callable[[list[Any]], Any]] = None,
308
+ error: Optional[Exception] = None,
309
+ ):
310
+ if error:
311
+ span.add_event(SpanEvent.from_exception(error))
312
+ span.end(status=SpanStatusCode.ERROR)
313
+ return
314
+
315
+ if output_reducer:
316
+ try:
317
+ outputs = output_reducer(outputs)
318
+ except Exception as e:
319
+ _logger.debug(f"Failed to reduce outputs from stream: {e}")
320
+
321
+ set_chat_attributes_special_case(span, inputs=inputs, outputs=outputs)
322
+ span.end(outputs=outputs)
323
+
324
+ def _record_chunk_event(span: LiveSpan, chunk: Any, chunk_index: int):
325
+ try:
326
+ event = SpanEvent(
327
+ name=STREAM_CHUNK_EVENT_NAME_FORMAT.format(index=chunk_index),
328
+ # OpenTelemetry SpanEvent only support str-str key-value pairs for attributes
329
+ attributes={STREAM_CHUNK_EVENT_VALUE_KEY: json.dumps(chunk, cls=TraceJSONEncoder)},
330
+ )
331
+ span.add_event(event)
332
+ except Exception as e:
333
+ _logger.debug(f"Failing to record chunk event for span {span.name}: {e}")
334
+
335
+ if inspect.isgeneratorfunction(fn):
336
+
337
+ def wrapper(*args, **kwargs):
338
+ inputs = capture_function_input_args(fn, args, kwargs)
339
+ span = _start_stream_span(fn, inputs)
340
+ generator = fn(*args, **kwargs)
341
+
342
+ i = 0
343
+ outputs = []
344
+ while True:
345
+ try:
346
+ # NB: Set the span to active only when the generator is running
347
+ with safe_set_span_in_context(span):
348
+ value = next(generator)
349
+ except StopIteration:
350
+ break
351
+ except Exception as e:
352
+ _end_stream_span(span, error=e)
353
+ raise e
354
+ else:
355
+ outputs.append(value)
356
+ _record_chunk_event(span, value, i)
357
+ yield value
358
+ i += 1
359
+ _end_stream_span(span, inputs, outputs, output_reducer)
360
+ else:
361
+
362
+ async def wrapper(*args, **kwargs):
363
+ inputs = capture_function_input_args(fn, args, kwargs)
364
+ span = _start_stream_span(fn, inputs)
365
+ generator = fn(*args, **kwargs)
366
+
367
+ i = 0
368
+ outputs = []
369
+ while True:
370
+ try:
371
+ with safe_set_span_in_context(span):
372
+ value = await generator.__anext__()
373
+ except StopAsyncIteration:
374
+ break
375
+ except Exception as e:
376
+ _end_stream_span(span, error=e)
377
+ raise e
378
+ else:
379
+ outputs.append(value)
380
+ _record_chunk_event(span, value, i)
381
+ yield value
382
+ i += 1
383
+ _end_stream_span(span, inputs, outputs, output_reducer)
384
+
385
+ return _wrap_function_safe(fn, wrapper)
386
+
387
+
388
+ def _wrap_function_safe(fn: Callable[..., Any], wrapper: Callable[..., Any]) -> Callable[..., Any]:
389
+ wrapped = functools.wraps(fn)(wrapper)
390
+ # Update the signature of the wrapper to match the signature of the original (safely)
391
+ try:
392
+ wrapped.__signature__ = inspect.signature(fn)
393
+ except Exception:
394
+ pass
395
+ return wrapped
396
+
397
+
398
+ @contextlib.contextmanager
399
+ def start_span(
400
+ name: str = "span",
401
+ span_type: Optional[str] = SpanType.UNKNOWN,
402
+ attributes: Optional[dict[str, Any]] = None,
403
+ ) -> Generator[LiveSpan, None, None]:
404
+ """
405
+ Context manager to create a new span and start it as the current span in the context.
406
+
407
+ This context manager automatically manages the span lifecycle and parent-child relationships.
408
+ The span will be ended when the context manager exits. Any exception raised within the
409
+ context manager will set the span status to ``ERROR``, and detailed information such as
410
+ exception message and stacktrace will be recorded to the ``attributes`` field of the span.
411
+ New spans can be created within the context manager, then they will be assigned as child
412
+ spans.
413
+
414
+ .. code-block:: python
415
+ :test:
416
+
417
+ import mlflow
418
+
419
+ with mlflow.start_span("my_span") as span:
420
+ x = 1
421
+ y = 2
422
+ span.set_inputs({"x": x, "y": y})
423
+
424
+ z = x + y
425
+
426
+ span.set_outputs(z)
427
+ span.set_attribute("key", "value")
428
+ # do something
429
+
430
+ When this context manager is used in the top-level scope, i.e. not within another span context,
431
+ the span will be treated as a root span. The root span doesn't have a parent reference and
432
+ **the entire trace will be logged when the root span is ended**.
433
+
434
+
435
+ .. tip::
436
+
437
+ If you want more explicit control over the trace lifecycle, you can use
438
+ the `mlflow.start_span_no_context()` API. It provides lower
439
+ level to start spans and control the parent-child relationships explicitly.
440
+ However, it is generally recommended to use this context manager as long as it satisfies
441
+ your requirements, because it requires less boilerplate code and is less error-prone.
442
+
443
+ .. note::
444
+
445
+ The context manager doesn't propagate the span context across threads by default. see
446
+ `Multi Threading <https://mlflow.org/docs/latest/tracing/api/manual-instrumentation#multi-threading>`_
447
+ for how to propagate the span context across threads.
448
+
449
+ Args:
450
+ name: The name of the span.
451
+ span_type: The type of the span. Can be either a string or
452
+ a :py:class:`SpanType <mlflow.entities.SpanType>` enum value
453
+ attributes: A dictionary of attributes to set on the span.
454
+
455
+ Returns:
456
+ Yields an :py:class:`mlflow.entities.Span` that represents the created span.
457
+ """
458
+ try:
459
+ otel_span = provider.start_span_in_context(name)
460
+
461
+ # Create a new MLflow span and register it to the in-memory trace manager
462
+ request_id = get_otel_attribute(otel_span, SpanAttributeKey.REQUEST_ID)
463
+ mlflow_span = create_mlflow_span(otel_span, request_id, span_type)
464
+ attributes = dict(attributes) if attributes is not None else {}
465
+ mlflow_span.set_attributes(attributes)
466
+ InMemoryTraceManager.get_instance().register_span(mlflow_span)
467
+
468
+ except Exception:
469
+ _logger.debug(f"Failed to start span {name}.", exc_info=True)
470
+ mlflow_span = NoOpSpan()
471
+ yield mlflow_span
472
+ return
473
+
474
+ try:
475
+ # Setting end_on_exit = False to suppress the default span
476
+ # export and instead invoke MLflow span's end() method.
477
+ with trace_api.use_span(mlflow_span._span, end_on_exit=False):
478
+ yield mlflow_span
479
+ finally:
480
+ try:
481
+ mlflow_span.end()
482
+ except Exception:
483
+ _logger.debug(f"Failed to end span {mlflow_span.span_id}.", exc_info=True)
484
+
485
+
486
+ def start_span_no_context(
487
+ name: str,
488
+ span_type: str = SpanType.UNKNOWN,
489
+ parent_span: Optional[LiveSpan] = None,
490
+ inputs: Optional[Any] = None,
491
+ attributes: Optional[dict[str, str]] = None,
492
+ tags: Optional[dict[str, str]] = None,
493
+ experiment_id: Optional[str] = None,
494
+ start_time_ns: Optional[int] = None,
495
+ ) -> LiveSpan:
496
+ """
497
+ Start a span without attaching it to the global tracing context.
498
+
499
+ This is useful when you want to create a span without automatically linking
500
+ with a parent span and instead manually manage the parent-child relationships.
501
+
502
+ The span started with this function must be ended manually using the
503
+ `end()` method of the span object.
504
+
505
+ Args:
506
+ name: The name of the span.
507
+ span_type: The type of the span. Can be either a string or
508
+ a :py:class:`SpanType <mlflow.entities.SpanType>` enum value
509
+ parent_span: The parent span to link with. If None, the span will be treated as a root span.
510
+ inputs: The input data for the span.
511
+ attributes: A dictionary of attributes to set on the span.
512
+ tags: A dictionary of tags to set on the trace.
513
+ experiment_id: The experiment ID to associate with the trace. If not provided,
514
+ the current active experiment will be used.
515
+ start_time_ns: The start time of the span in nanoseconds. If not provided,
516
+ the current time will be used.
517
+
518
+ Returns:
519
+ A :py:class:`mlflow.entities.Span` that represents the created span.
520
+
521
+ Example:
522
+ .. code-block:: python
523
+ :test:
524
+
525
+ import mlflow
526
+
527
+ root_span = mlflow.start_span_no_context("my_trace")
528
+
529
+ # Create a child span
530
+ child_span = mlflow.start_span_no_context(
531
+ "child_span",
532
+ # Manually specify the parent span
533
+ parent_span=root_span,
534
+ )
535
+ # Do something...
536
+ child_span.end()
537
+
538
+ root_span.end()
539
+
540
+ """
541
+ # If parent span is no-op span, the child should also be no-op too
542
+ if parent_span and parent_span.trace_id == NO_OP_SPAN_TRACE_ID:
543
+ return NoOpSpan()
544
+
545
+ try:
546
+ # Create new trace and a root span
547
+ # Once OTel span is created, SpanProcessor.on_start is invoked
548
+ # TraceInfo is created and logged into backend store inside on_start method
549
+ otel_span = provider.start_detached_span(
550
+ name,
551
+ parent=parent_span._span if parent_span else None,
552
+ start_time_ns=start_time_ns,
553
+ experiment_id=experiment_id,
554
+ )
555
+
556
+ if parent_span:
557
+ trace_id = parent_span.trace_id
558
+ else:
559
+ trace_id = get_otel_attribute(otel_span, SpanAttributeKey.REQUEST_ID)
560
+
561
+ mlflow_span = create_mlflow_span(otel_span, trace_id, span_type)
562
+
563
+ # # If the span is a no-op span i.e. tracing is disabled, do nothing
564
+ if isinstance(mlflow_span, NoOpSpan):
565
+ return mlflow_span
566
+
567
+ if inputs is not None:
568
+ mlflow_span.set_inputs(inputs)
569
+ mlflow_span.set_attributes(attributes or {})
570
+
571
+ trace_manager = InMemoryTraceManager.get_instance()
572
+ if tags := exclude_immutable_tags(tags or {}):
573
+ # Update trace tags for trace in in-memory trace manager
574
+ with trace_manager.get_trace(trace_id) as trace:
575
+ trace.info.tags.update(tags)
576
+
577
+ # Register new span in the in-memory trace manager
578
+ trace_manager.register_span(mlflow_span)
579
+
580
+ return mlflow_span
581
+ except Exception as e:
582
+ _logger.warning(
583
+ f"Failed to start span {name}: {e}. For full traceback, set logging level to debug.",
584
+ exc_info=_logger.isEnabledFor(logging.DEBUG),
585
+ )
586
+ return NoOpSpan()
587
+
588
+
589
+ @request_id_backward_compatible
590
+ def get_trace(trace_id: str) -> Optional[Trace]:
591
+ """
592
+ Get a trace by the given request ID if it exists.
593
+
594
+ This function retrieves the trace from the in-memory buffer first, and if it doesn't exist,
595
+ it fetches the trace from the tracking store. If the trace is not found in the tracking store,
596
+ it returns None.
597
+
598
+ Args:
599
+ trace_id: The ID of the trace.
600
+
601
+
602
+ .. code-block:: python
603
+ :test:
604
+
605
+ import mlflow
606
+
607
+
608
+ with mlflow.start_span(name="span") as span:
609
+ span.set_attribute("key", "value")
610
+
611
+ trace = mlflow.get_trace(span.trace_id)
612
+ print(trace)
613
+
614
+
615
+ Returns:
616
+ A :py:class:`mlflow.entities.Trace` objects with the given request ID.
617
+ """
618
+ # Special handling for evaluation request ID.
619
+ trace_id = _EVAL_REQUEST_ID_TO_TRACE_ID.get(trace_id) or trace_id
620
+
621
+ try:
622
+ return TracingClient().get_trace(trace_id)
623
+ except MlflowException as e:
624
+ _logger.warning(
625
+ f"Failed to get trace from the tracking store: {e}"
626
+ "For full traceback, set logging level to debug.",
627
+ exc_info=_logger.isEnabledFor(logging.DEBUG),
628
+ )
629
+ return None
630
+
631
+
632
+ def search_traces(
633
+ experiment_ids: Optional[list[str]] = None,
634
+ filter_string: Optional[str] = None,
635
+ max_results: Optional[int] = None,
636
+ order_by: Optional[list[str]] = None,
637
+ extract_fields: Optional[list[str]] = None,
638
+ run_id: Optional[str] = None,
639
+ return_type: Optional[Literal["pandas", "list"]] = None,
640
+ model_id: Optional[str] = None,
641
+ sql_warehouse_id: Optional[str] = None,
642
+ include_spans: bool = True,
643
+ ) -> Union["pandas.DataFrame", list[Trace]]:
644
+ """
645
+ Return traces that match the given list of search expressions within the experiments.
646
+
647
+ .. note::
648
+
649
+ If expected number of search results is large, consider using the
650
+ `MlflowClient.search_traces` API directly to paginate through the results. This
651
+ function returns all results in memory and may not be suitable for large result sets.
652
+
653
+ Args:
654
+ experiment_ids: List of experiment ids to scope the search. If not provided, the search
655
+ will be performed across the current active experiment.
656
+ filter_string: A search filter string.
657
+ max_results: Maximum number of traces desired. If None, all traces matching the search
658
+ expressions will be returned.
659
+ order_by: List of order_by clauses.
660
+ extract_fields: Specify fields to extract from traces using the format
661
+ ``"span_name.[inputs|outputs].field_name"`` or ``"span_name.[inputs|outputs]"``.
662
+
663
+ .. note::
664
+
665
+ This parameter is only supported when the return type is set to "pandas".
666
+
667
+ For instance, ``"predict.outputs.result"`` retrieves the output ``"result"`` field from
668
+ a span named ``"predict"``, while ``"predict.outputs"`` fetches the entire outputs
669
+ dictionary, including keys ``"result"`` and ``"explanation"``.
670
+
671
+ By default, no fields are extracted into the DataFrame columns. When multiple
672
+ fields are specified, each is extracted as its own column. If an invalid field
673
+ string is provided, the function silently returns without adding that field's column.
674
+ The supported fields are limited to ``"inputs"`` and ``"outputs"`` of spans. If the
675
+ span name or field name contains a dot it must be enclosed in backticks. For example:
676
+
677
+ .. code-block:: python
678
+
679
+ # span name contains a dot
680
+ extract_fields = ["`span.name`.inputs.field"]
681
+
682
+ # field name contains a dot
683
+ extract_fields = ["span.inputs.`field.name`"]
684
+
685
+ # span name and field name contain a dot
686
+ extract_fields = ["`span.name`.inputs.`field.name`"]
687
+
688
+ run_id: A run id to scope the search. When a trace is created under an active run,
689
+ it will be associated with the run and you can filter on the run id to retrieve the
690
+ trace. See the example below for how to filter traces by run id.
691
+
692
+ return_type: The type of the return value. The following return types are supported. If
693
+ the pandas library is installed, the default return type is "pandas". Otherwise, the
694
+ default return type is "list".
695
+
696
+ - `"pandas"`: Returns a Pandas DataFrame containing information about traces
697
+ where each row represents a single trace and each column represents a field of the
698
+ trace e.g. trace_id, spans, etc.
699
+ - `"list"`: Returns a list of :py:class:`Trace <mlflow.entities.Trace>` objects.
700
+
701
+ model_id: If specified, search traces associated with the given model ID.
702
+ sql_warehouse_id: Only used in Databricks. The ID of the SQL warehouse to use for
703
+ searching traces in inference tables.
704
+
705
+ include_spans: If ``True``, include spans in the returned traces. Otherwise, only
706
+ the trace metadata is returned, e.g., trace ID, start time, end time, etc,
707
+ without any spans. Default to ``True``.
708
+
709
+ Returns:
710
+ Traces that satisfy the search expressions. Either as a list of
711
+ :py:class:`Trace <mlflow.entities.Trace>` objects or as a Pandas DataFrame,
712
+ depending on the value of the `return_type` parameter.
713
+
714
+ .. code-block:: python
715
+ :test:
716
+ :caption: Search traces with extract_fields
717
+
718
+ import mlflow
719
+
720
+ with mlflow.start_span(name="span1") as span:
721
+ span.set_inputs({"a": 1, "b": 2})
722
+ span.set_outputs({"c": 3, "d": 4})
723
+
724
+ mlflow.search_traces(
725
+ extract_fields=["span1.inputs", "span1.outputs", "span1.outputs.c"],
726
+ return_type="pandas",
727
+ )
728
+
729
+
730
+ .. code-block:: python
731
+ :test:
732
+ :caption: Search traces with extract_fields and non-dictionary span inputs and outputs
733
+
734
+ import mlflow
735
+
736
+ with mlflow.start_span(name="non_dict_span") as span:
737
+ span.set_inputs(["a", "b"])
738
+ span.set_outputs([1, 2, 3])
739
+
740
+ mlflow.search_traces(
741
+ extract_fields=["non_dict_span.inputs", "non_dict_span.outputs"],
742
+ )
743
+
744
+ .. code-block:: python
745
+ :test:
746
+ :caption: Search traces by run ID and return as a list of Trace objects
747
+
748
+ import mlflow
749
+
750
+
751
+ @mlflow.trace
752
+ def traced_func(x):
753
+ return x + 1
754
+
755
+
756
+ with mlflow.start_run() as run:
757
+ traced_func(1)
758
+
759
+ mlflow.search_traces(run_id=run.info.run_id, return_type="list")
760
+
761
+ """
762
+ from mlflow.tracking.fluent import _get_experiment_id
763
+
764
+ # Default to "pandas" only if the pandas library is installed
765
+ if return_type is None:
766
+ try:
767
+ import pandas # noqa: F401
768
+
769
+ return_type = "pandas"
770
+ except ImportError:
771
+ return_type = "list"
772
+
773
+ if return_type not in ["pandas", "list"]:
774
+ raise MlflowException.invalid_parameter_value(
775
+ f"Invalid return type: {return_type}. Return type must be either 'pandas' or 'list'."
776
+ )
777
+ elif return_type == "list" and extract_fields:
778
+ raise MlflowException.invalid_parameter_value(
779
+ "The `extract_fields` parameter is only supported when return type is set to 'pandas'."
780
+ )
781
+ elif return_type == "pandas":
782
+ # Check if pandas is installed early to avoid unnecessary computation
783
+ if importlib.util.find_spec("pandas") is None:
784
+ raise MlflowException(
785
+ message=(
786
+ "The `pandas` library is not installed. Please install `pandas` to use"
787
+ " the `return_type='pandas'` option, or set `return_type='list'`."
788
+ ),
789
+ )
790
+
791
+ if not experiment_ids:
792
+ if experiment_id := _get_experiment_id():
793
+ experiment_ids = [experiment_id]
794
+ else:
795
+ raise MlflowException(
796
+ "No active experiment found. Set an experiment using `mlflow.set_experiment`, "
797
+ "or specify the list of experiment IDs in the `experiment_ids` parameter."
798
+ )
799
+
800
+ def pagination_wrapper_func(number_to_get, next_page_token):
801
+ return TracingClient().search_traces(
802
+ experiment_ids=experiment_ids,
803
+ run_id=run_id,
804
+ max_results=number_to_get,
805
+ filter_string=filter_string,
806
+ order_by=order_by,
807
+ page_token=next_page_token,
808
+ model_id=model_id,
809
+ sql_warehouse_id=sql_warehouse_id,
810
+ include_spans=include_spans,
811
+ )
812
+
813
+ results = get_results_from_paginated_fn(
814
+ pagination_wrapper_func,
815
+ max_results_per_page=SEARCH_TRACES_DEFAULT_MAX_RESULTS,
816
+ max_results=max_results,
817
+ )
818
+
819
+ if return_type == "pandas":
820
+ results = traces_to_df(results)
821
+ if extract_fields:
822
+ results = extract_span_inputs_outputs(
823
+ traces=results,
824
+ fields=extract_fields,
825
+ col_name=SPANS_COLUMN_NAME,
826
+ )
827
+
828
+ return results
829
+
830
+
831
+ def get_current_active_span() -> Optional[LiveSpan]:
832
+ """
833
+ Get the current active span in the global context.
834
+
835
+ .. attention::
836
+
837
+ This only works when the span is created with fluent APIs like `@mlflow.trace` or
838
+ `with mlflow.start_span`. If a span is created with the
839
+ `mlflow.start_span_no_context` APIs, it won't be
840
+ attached to the global context so this function will not return it.
841
+
842
+
843
+ .. code-block:: python
844
+ :test:
845
+
846
+ import mlflow
847
+
848
+
849
+ @mlflow.trace
850
+ def f():
851
+ span = mlflow.get_current_active_span()
852
+ span.set_attribute("key", "value")
853
+ return 0
854
+
855
+
856
+ f()
857
+
858
+ Returns:
859
+ The current active span if exists, otherwise None.
860
+ """
861
+ otel_span = trace_api.get_current_span()
862
+ # NonRecordingSpan is returned if a tracer is not instantiated.
863
+ if otel_span is None or isinstance(otel_span, trace_api.NonRecordingSpan):
864
+ return None
865
+
866
+ trace_manager = InMemoryTraceManager.get_instance()
867
+ request_id = json.loads(otel_span.attributes.get(SpanAttributeKey.REQUEST_ID))
868
+ return trace_manager.get_span_from_id(request_id, encode_span_id(otel_span.context.span_id))
869
+
870
+
871
+ def get_active_trace_id() -> Optional[str]:
872
+ """
873
+ Get the active trace ID in the current process.
874
+
875
+ This function is thread-safe.
876
+
877
+ Example:
878
+
879
+ .. code-block:: python
880
+ :test:
881
+
882
+ import mlflow
883
+
884
+
885
+ @mlflow.trace
886
+ def f():
887
+ trace_id = mlflow.get_active_trace_id()
888
+ print(trace_id)
889
+
890
+
891
+ f()
892
+
893
+ Returns:
894
+ The ID of the current active trace if exists, otherwise None.
895
+ """
896
+ active_span = get_current_active_span()
897
+ if active_span:
898
+ return active_span.trace_id
899
+ return None
900
+
901
+
902
+ def get_last_active_trace_id(thread_local: bool = False) -> Optional[str]:
903
+ """
904
+ Get the **LAST** active trace in the same process if exists.
905
+
906
+ .. warning::
907
+
908
+ This function is not thread-safe by default, returns the last active trace in
909
+ the same process. If you want to get the last active trace in the current thread,
910
+ set the `thread_local` parameter to True.
911
+
912
+ Args:
913
+
914
+ thread_local: If True, returns the last active trace in the current thread. Otherwise,
915
+ returns the last active trace in the same process. Default is False.
916
+
917
+ Returns:
918
+ The ID of the last active trace if exists, otherwise None.
919
+
920
+ .. code-block:: python
921
+ :test:
922
+
923
+ import mlflow
924
+
925
+
926
+ @mlflow.trace
927
+ def f():
928
+ pass
929
+
930
+
931
+ f()
932
+
933
+ trace_id = mlflow.get_last_active_trace_id()
934
+
935
+ # Set a tag on the trace
936
+ mlflow.set_trace_tag(trace_id, "key", "value")
937
+
938
+ # Get the full trace object
939
+ trace = mlflow.get_trace(trace_id)
940
+ """
941
+ return (
942
+ _LAST_ACTIVE_TRACE_ID_THREAD_LOCAL.get() if thread_local else _LAST_ACTIVE_TRACE_ID_GLOBAL
943
+ )
944
+
945
+
946
+ def _set_last_active_trace_id(trace_id: str):
947
+ """Internal function to set the last active trace ID."""
948
+ global _LAST_ACTIVE_TRACE_ID_GLOBAL
949
+ _LAST_ACTIVE_TRACE_ID_GLOBAL = trace_id
950
+ _LAST_ACTIVE_TRACE_ID_THREAD_LOCAL.set(trace_id)
951
+
952
+
953
+ def update_current_trace(
954
+ tags: Optional[dict[str, str]] = None,
955
+ metadata: Optional[dict[str, str]] = None,
956
+ client_request_id: Optional[str] = None,
957
+ request_preview: Optional[str] = None,
958
+ response_preview: Optional[str] = None,
959
+ state: Optional[Union[TraceState, str]] = None,
960
+ ):
961
+ """
962
+ Update the current active trace with the given options.
963
+
964
+ Args:
965
+ tags: A dictionary of tags to update the trace with Tags are designed for mutable values,
966
+ that can be updated after the trace is created via MLflow UI or API.
967
+ metadata: A dictionary of metadata to update the trace with. Metadata cannot be updated
968
+ once the trace is logged. It is suitable for recording immutable values like the
969
+ git hash of the application version that produced the trace.
970
+ client_request_id: Client supplied request ID to associate with the trace. This is
971
+ useful for linking the trace back to a specific request in your application or
972
+ external system. If None, the client request ID is not updated.
973
+ request_preview: A preview of the request to be shown in the Trace list view in the UI.
974
+ By default, MLflow will truncate the trace request naively by limiting the length.
975
+ This parameter allows you to specify a custom preview string.
976
+ response_preview: A preview of the response to be shown in the Trace list view in the UI.
977
+ By default, MLflow will truncate the trace response naively by limiting the length.
978
+ This parameter allows you to specify a custom preview string.
979
+ state: The state to set on the trace. Can be a TraceState enum value or string.
980
+ Only "OK" and "ERROR" are allowed. This overrides the overall trace state without
981
+ affecting the status of the current span.
982
+
983
+ Example:
984
+
985
+ You can use this function either within a function decorated with ``@mlflow.trace`` or
986
+ within the scope of the `with mlflow.start_span` context manager. If there is no active
987
+ trace found, this function will raise an exception.
988
+
989
+ Using within a function decorated with `@mlflow.trace`:
990
+
991
+ .. code-block:: python
992
+
993
+ @mlflow.trace
994
+ def my_func(x):
995
+ mlflow.update_current_trace(tags={"fruit": "apple"}, client_request_id="req-12345")
996
+ return x + 1
997
+
998
+ Using within the ``with mlflow.start_span`` context manager:
999
+
1000
+ .. code-block:: python
1001
+
1002
+ with mlflow.start_span("span"):
1003
+ mlflow.update_current_trace(tags={"fruit": "apple"}, client_request_id="req-12345")
1004
+
1005
+ Updating source information of the trace. These keys are reserved ones and MLflow populate
1006
+ them from environment information by default. You can override them if needed. Please refer
1007
+ to the MLflow Tracing documentation for the full list of reserved metadata keys.
1008
+
1009
+ .. code-block:: python
1010
+
1011
+ mlflow.update_current_trace(
1012
+ metadata={
1013
+ "mlflow.trace.session": "session-4f855da00427",
1014
+ "mlflow.trace.user": "user-id-cc156f29bcfb",
1015
+ "mlflow.source.name": "inference.py",
1016
+ "mlflow.source.git.commit": "1234567890",
1017
+ "mlflow.source.git.repoURL": "https://github.com/mlflow/mlflow",
1018
+ },
1019
+ )
1020
+
1021
+ Updating request preview:
1022
+
1023
+ .. code-block:: python
1024
+
1025
+ import mlflow
1026
+ import openai
1027
+
1028
+
1029
+ @mlflow.trace
1030
+ def predict(messages: list[dict]) -> str:
1031
+ # Customize the request preview to show the first and last messages
1032
+ custom_preview = f"{messages[0]['content'][:10]} ... {messages[-1]['content'][:10]}"
1033
+ mlflow.update_current_trace(request_preview=custom_preview)
1034
+
1035
+ # Call the model
1036
+ response = openai.chat.completions.create(
1037
+ model="o4-mini",
1038
+ messages=messages,
1039
+ )
1040
+
1041
+ return response.choices[0].message.content
1042
+
1043
+
1044
+ messages = [
1045
+ {"role": "user", "content": "Hi, how are you?"},
1046
+ {"role": "assistant", "content": "I'm good, thank you!"},
1047
+ {"role": "user", "content": "What's your name?"},
1048
+ # ... (long message history)
1049
+ {"role": "assistant", "content": "Bye!"},
1050
+ ]
1051
+ predict(messages)
1052
+
1053
+ # The request preview rendered in the UI will be:
1054
+ # "Hi, how are you? ... Bye!"
1055
+
1056
+ """
1057
+ active_span = get_current_active_span()
1058
+
1059
+ if not active_span:
1060
+ _logger.warning(
1061
+ "No active trace found. Please create a span using `mlflow.start_span` or "
1062
+ "`@mlflow.trace` before calling `mlflow.update_current_trace`.",
1063
+ )
1064
+ return
1065
+
1066
+ def _warn_non_string_values(d: dict[str, Any], field_name: str):
1067
+ non_string_items = {k: v for k, v in d.items() if not isinstance(v, str)}
1068
+ if non_string_items:
1069
+ _logger.warning(
1070
+ f"Found non-string values in {field_name}. Non-string values in {field_name} will "
1071
+ f"automatically be stringified when the trace is logged. Non-string items: "
1072
+ f"{non_string_items}"
1073
+ )
1074
+
1075
+ _warn_non_string_values(tags or {}, "tags")
1076
+ _warn_non_string_values(metadata or {}, "metadata")
1077
+
1078
+ # Update tags and client request ID for the trace stored in-memory rather than directly
1079
+ # updating the backend store. The in-memory trace will be exported when it is ended.
1080
+ # By doing this, we can avoid unnecessary server requests for each tag update.
1081
+ if request_preview is not None and not isinstance(request_preview, str):
1082
+ raise MlflowException.invalid_parameter_value(
1083
+ "The `request_preview` parameter must be a string."
1084
+ )
1085
+ if response_preview is not None and not isinstance(response_preview, str):
1086
+ raise MlflowException.invalid_parameter_value(
1087
+ "The `response_preview` parameter must be a string."
1088
+ )
1089
+
1090
+ # Update trace info for the trace stored in-memory rather than directly updating the
1091
+ # backend store. The in-memory trace will be exported when it is ended. By doing
1092
+ # this, we can avoid unnecessary server requests for each tag update.
1093
+ request_id = active_span.request_id
1094
+ with InMemoryTraceManager.get_instance().get_trace(request_id) as trace:
1095
+ if request_preview:
1096
+ trace.info.request_preview = request_preview
1097
+ if response_preview:
1098
+ trace.info.response_preview = response_preview
1099
+ if state is not None:
1100
+
1101
+ def _invalid_state_error(value):
1102
+ return MlflowException.invalid_parameter_value(
1103
+ f"State must be either 'OK' or 'ERROR', but got '{value}'."
1104
+ )
1105
+
1106
+ if state not in (TraceState.OK, TraceState.ERROR):
1107
+ raise _invalid_state_error(state)
1108
+
1109
+ trace.info.state = TraceState(state) if isinstance(state, str) else state
1110
+
1111
+ trace.info.tags.update(tags or {})
1112
+ trace.info.trace_metadata.update(metadata or {})
1113
+ if client_request_id is not None:
1114
+ trace.info.client_request_id = str(client_request_id)
1115
+
1116
+
1117
+ @request_id_backward_compatible
1118
+ def set_trace_tag(trace_id: str, key: str, value: str):
1119
+ """
1120
+ Set a tag on the trace with the given trace ID.
1121
+
1122
+ The trace can be an active one or the one that has already ended and recorded in the
1123
+ backend. Below is an example of setting a tag on an active trace. You can replace the
1124
+ ``trace_id`` parameter to set a tag on an already ended trace.
1125
+
1126
+ .. code-block:: python
1127
+ :test:
1128
+
1129
+ import mlflow
1130
+
1131
+ with mlflow.start_span(name="span") as span:
1132
+ mlflow.set_trace_tag(span.trace_id, "key", "value")
1133
+
1134
+ Args:
1135
+ trace_id: The ID of the trace to set the tag on.
1136
+ key: The string key of the tag. Must be at most 250 characters long, otherwise
1137
+ it will be truncated when stored.
1138
+ value: The string value of the tag. Must be at most 250 characters long, otherwise
1139
+ it will be truncated when stored.
1140
+ """
1141
+ TracingClient().set_trace_tag(trace_id, key, value)
1142
+
1143
+
1144
+ @request_id_backward_compatible
1145
+ def delete_trace_tag(trace_id: str, key: str) -> None:
1146
+ """
1147
+ Delete a tag on the trace with the given trace ID.
1148
+
1149
+ The trace can be an active one or the one that has already ended and recorded in the
1150
+ backend. Below is an example of deleting a tag on an active trace. You can replace the
1151
+ ``trace_id`` parameter to delete a tag on an already ended trace.
1152
+
1153
+ .. code-block:: python
1154
+ :test:
1155
+
1156
+ import mlflow
1157
+
1158
+ with mlflow.start_span("my_span") as span:
1159
+ mlflow.set_trace_tag(span.trace_id, "key", "value")
1160
+ mlflow.delete_trace_tag(span.trace_id, "key")
1161
+
1162
+ Args:
1163
+ trace_id: The ID of the trace to delete the tag from.
1164
+ key: The string key of the tag. Must be at most 250 characters long, otherwise
1165
+ it will be truncated when stored.
1166
+ """
1167
+ TracingClient().delete_trace_tag(trace_id, key)
1168
+
1169
+
1170
+ @experimental(version="2.17.0")
1171
+ def add_trace(trace: Union[Trace, dict[str, Any]], target: Optional[LiveSpan] = None):
1172
+ """
1173
+ Add a completed trace object into another trace.
1174
+
1175
+ This is particularly useful when you call a remote service instrumented by
1176
+ MLflow Tracing. By using this function, you can merge the trace from the remote
1177
+ service into the current active local trace, so that you can see the full
1178
+ trace including what happens inside the remote service call.
1179
+
1180
+ The following example demonstrates how to use this function to merge a trace from a remote
1181
+ service to the current active trace in the function.
1182
+
1183
+ .. code-block:: python
1184
+
1185
+ @mlflow.trace(name="predict")
1186
+ def predict(input):
1187
+ # Call a remote service that returns a trace in the response
1188
+ resp = requests.get("https://your-service-endpoint", ...)
1189
+
1190
+ # Extract the trace from the response
1191
+ trace_json = resp.json().get("trace")
1192
+
1193
+ # Use the remote trace as a part of the current active trace.
1194
+ # It will be merged under the span "predict" and exported together when it is ended.
1195
+ mlflow.add_trace(trace_json)
1196
+
1197
+ If you have a specific target span to merge the trace under, you can pass the target span
1198
+
1199
+ .. code-block:: python
1200
+
1201
+ def predict(input):
1202
+ # Create a local span
1203
+ with mlflow.start_span(name="predict") as span:
1204
+ resp = requests.get("https://your-service-endpoint", ...)
1205
+ trace_json = resp.json().get("trace")
1206
+
1207
+ # Merge the remote trace under the span created above
1208
+ mlflow.add_trace(trace_json, target=span)
1209
+
1210
+ Args:
1211
+ trace: A :py:class:`Trace <mlflow.entities.Trace>` object or a dictionary representation
1212
+ of the trace. The trace **must** be already completed i.e. no further updates should
1213
+ be made to it. Otherwise, this function will raise an exception.
1214
+
1215
+ .. attention:
1216
+
1217
+ The spans in the trace must be ordered in a way that the parent span comes
1218
+ before its children. If the spans are not ordered correctly, this function
1219
+ will raise an exception.
1220
+
1221
+ target: The target span to merge the given trace.
1222
+
1223
+ - If provided, the trace will be merged under the target span.
1224
+ - If not provided, the trace will be merged under the current active span.
1225
+ - If not provided and there is no active span, a new span named "Remote Trace <...>"
1226
+ will be created and the trace will be merged under it.
1227
+ """
1228
+ if not is_tracing_enabled():
1229
+ _logger.debug("Tracing is disabled. Skipping add_trace.")
1230
+ return
1231
+
1232
+ if isinstance(trace, dict):
1233
+ try:
1234
+ trace = Trace.from_dict(trace)
1235
+ except Exception as e:
1236
+ raise MlflowException.invalid_parameter_value(
1237
+ "Failed to load a trace object from the given dictionary. Please ensure the "
1238
+ f"dictionary is in the correct MLflow Trace format. Error: {e}",
1239
+ )
1240
+ elif not isinstance(trace, Trace):
1241
+ raise MlflowException.invalid_parameter_value(
1242
+ f"Invalid trace object: {type(trace)}. Please provide a valid MLflow Trace object "
1243
+ "to use it as a remote trace. You can create a Trace object from its json format by "
1244
+ "using the Trace.from_dict() method."
1245
+ )
1246
+
1247
+ if trace.info.status not in TraceStatus.end_statuses():
1248
+ raise MlflowException.invalid_parameter_value(
1249
+ "The trace must be ended before adding it to another trace. "
1250
+ f"Current status: {trace.info.status}.",
1251
+ )
1252
+
1253
+ if target_span := target or get_current_active_span():
1254
+ _merge_trace(
1255
+ trace=trace,
1256
+ target_trace_id=target_span.trace_id,
1257
+ target_parent_span_id=target_span.span_id,
1258
+ )
1259
+ else:
1260
+ # If there is no target span, create a new root span named "Remote Trace <...>"
1261
+ # and put the remote trace under it. This design aims to keep the trace export
1262
+ # logic simpler and consistent, rather than directly exporting the remote trace.
1263
+ remote_root_span = trace.data.spans[0]
1264
+ span = start_span_no_context(
1265
+ name=f"Remote Trace <{remote_root_span.name}>",
1266
+ inputs=remote_root_span.inputs,
1267
+ attributes={
1268
+ # Exclude request ID attribute not to reuse same request ID
1269
+ k: v
1270
+ for k, v in remote_root_span.attributes.items()
1271
+ if k != SpanAttributeKey.REQUEST_ID
1272
+ },
1273
+ start_time_ns=remote_root_span.start_time_ns,
1274
+ )
1275
+ _merge_trace(
1276
+ trace=trace,
1277
+ target_trace_id=span.trace_id,
1278
+ target_parent_span_id=span.span_id,
1279
+ )
1280
+ span.end(
1281
+ status=trace.info.status,
1282
+ outputs=remote_root_span.outputs,
1283
+ end_time_ns=remote_root_span.end_time_ns,
1284
+ )
1285
+
1286
+
1287
+ @experimental(version="2.21.0")
1288
+ def log_trace(
1289
+ name: str = "Task",
1290
+ request: Optional[Any] = None,
1291
+ response: Optional[Any] = None,
1292
+ intermediate_outputs: Optional[dict[str, Any]] = None,
1293
+ attributes: Optional[dict[str, Any]] = None,
1294
+ tags: Optional[dict[str, str]] = None,
1295
+ start_time_ms: Optional[int] = None,
1296
+ execution_time_ms: Optional[int] = None,
1297
+ ) -> str:
1298
+ """
1299
+ Create a trace with a single root span.
1300
+ This API is useful when you want to log an arbitrary (request, response) pair
1301
+ without structured OpenTelemetry spans. The trace is linked to the active experiment.
1302
+
1303
+ Args:
1304
+ name: The name of the trace (and the root span). Default to "Task".
1305
+ request: Input data for the entire trace. This is also set on the root span of the trace.
1306
+ response: Output data for the entire trace. This is also set on the root span of the trace.
1307
+ intermediate_outputs: A dictionary of intermediate outputs produced by the model or agent
1308
+ while handling the request. Keys are the names of the outputs,
1309
+ and values are the outputs themselves. Values must be JSON-serializable.
1310
+ attributes: A dictionary of attributes to set on the root span of the trace.
1311
+ tags: A dictionary of tags to set on the trace.
1312
+ start_time_ms: The start time of the trace in milliseconds since the UNIX epoch.
1313
+ When not specified, current time is used for start and end time of the trace.
1314
+ execution_time_ms: The execution time of the trace in milliseconds since the UNIX epoch.
1315
+
1316
+ Returns:
1317
+ The ID of the logged trace.
1318
+
1319
+ Example:
1320
+
1321
+ .. code-block:: python
1322
+ :test:
1323
+
1324
+ import time
1325
+ import mlflow
1326
+
1327
+ trace_id = mlflow.log_trace(
1328
+ request="Does mlflow support tracing?",
1329
+ response="Yes",
1330
+ intermediate_outputs={
1331
+ "retrieved_documents": ["mlflow documentation"],
1332
+ "system_prompt": ["answer the question with yes or no"],
1333
+ },
1334
+ start_time_ms=int(time.time() * 1000),
1335
+ execution_time_ms=5129,
1336
+ )
1337
+ trace = mlflow.get_trace(trace_id)
1338
+
1339
+ print(trace.data.intermediate_outputs)
1340
+ """
1341
+ if intermediate_outputs:
1342
+ if attributes:
1343
+ attributes.update(SpanAttributeKey.INTERMEDIATE_OUTPUTS, intermediate_outputs)
1344
+ else:
1345
+ attributes = {SpanAttributeKey.INTERMEDIATE_OUTPUTS: intermediate_outputs}
1346
+
1347
+ span = start_span_no_context(
1348
+ name=name,
1349
+ inputs=request,
1350
+ attributes=attributes,
1351
+ tags=tags,
1352
+ start_time_ns=start_time_ms * 1000000 if start_time_ms else None,
1353
+ )
1354
+ span.end(
1355
+ outputs=response,
1356
+ end_time_ns=(start_time_ms + execution_time_ms) * 1000000
1357
+ if start_time_ms and execution_time_ms
1358
+ else None,
1359
+ )
1360
+
1361
+ return span.trace_id
1362
+
1363
+
1364
+ def _merge_trace(
1365
+ trace: Trace,
1366
+ target_trace_id: str,
1367
+ target_parent_span_id: str,
1368
+ ):
1369
+ """
1370
+ Merge the given trace object under an existing trace in the in-memory trace registry.
1371
+
1372
+ Args:
1373
+ trace: The trace object to be merged.
1374
+ target_trace_id: The ID of the parent trace.
1375
+ target_parent_span_id: The parent span ID, under which the child trace should be merged.
1376
+ """
1377
+ trace_manager = InMemoryTraceManager.get_instance()
1378
+
1379
+ # The merged trace should have the same trace ID as the parent trace.
1380
+ with trace_manager.get_trace(target_trace_id) as parent_trace:
1381
+ if not parent_trace:
1382
+ _logger.warning(f"Parent trace with ID {target_trace_id} not found. Skipping merge.")
1383
+ return
1384
+
1385
+ new_trace_id = parent_trace.span_dict[target_parent_span_id]._trace_id
1386
+
1387
+ for span in trace.data.spans:
1388
+ parent_span_id = span.parent_id or target_parent_span_id
1389
+
1390
+ # NB: We clone span one by one in the order it was saved in the original trace. This
1391
+ # works upon the assumption that the parent span always comes before its children.
1392
+ # This is guaranteed in current implementation, but if it changes in the future,
1393
+ # we have to traverse the tree to determine the order.
1394
+ if not trace_manager.get_span_from_id(target_trace_id, parent_span_id):
1395
+ raise MlflowException.invalid_parameter_value(
1396
+ f"Span with ID {parent_span_id} not found. Please make sure the "
1397
+ "spans in the trace are ordered correctly i.e. the parent span comes before "
1398
+ "its children."
1399
+ )
1400
+
1401
+ cloned_span = LiveSpan.from_immutable_span(
1402
+ span=span,
1403
+ parent_span_id=parent_span_id,
1404
+ trace_id=target_trace_id,
1405
+ otel_trace_id=new_trace_id,
1406
+ )
1407
+ trace_manager.register_span(cloned_span)
1408
+
1409
+ # Merge the tags and metadata from the child trace to the parent trace.
1410
+ with trace_manager.get_trace(target_trace_id) as parent_trace:
1411
+ # Order of merging is important to ensure the parent trace's metadata is
1412
+ # not overwritten by the child trace's metadata if they have the same key.
1413
+ parent_trace.info.tags = {**trace.info.tags, **parent_trace.info.tags}
1414
+ parent_trace.info.trace_metadata = {
1415
+ **trace.info.request_metadata,
1416
+ **parent_trace.info.trace_metadata,
1417
+ }