azure-ai-evaluation 1.0.0b2__py3-none-any.whl → 1.13.3__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.

Potentially problematic release.


This version of azure-ai-evaluation might be problematic. Click here for more details.

Files changed (299) hide show
  1. azure/ai/evaluation/__init__.py +100 -5
  2. azure/ai/evaluation/{_evaluators/_chat → _aoai}/__init__.py +3 -2
  3. azure/ai/evaluation/_aoai/aoai_grader.py +140 -0
  4. azure/ai/evaluation/_aoai/label_grader.py +68 -0
  5. azure/ai/evaluation/_aoai/python_grader.py +86 -0
  6. azure/ai/evaluation/_aoai/score_model_grader.py +94 -0
  7. azure/ai/evaluation/_aoai/string_check_grader.py +66 -0
  8. azure/ai/evaluation/_aoai/text_similarity_grader.py +80 -0
  9. azure/ai/evaluation/_azure/__init__.py +3 -0
  10. azure/ai/evaluation/_azure/_clients.py +204 -0
  11. azure/ai/evaluation/_azure/_envs.py +207 -0
  12. azure/ai/evaluation/_azure/_models.py +227 -0
  13. azure/ai/evaluation/_azure/_token_manager.py +129 -0
  14. azure/ai/evaluation/_common/__init__.py +9 -1
  15. azure/ai/evaluation/{simulator/_helpers → _common}/_experimental.py +24 -9
  16. azure/ai/evaluation/_common/constants.py +131 -2
  17. azure/ai/evaluation/_common/evaluation_onedp_client.py +169 -0
  18. azure/ai/evaluation/_common/math.py +89 -0
  19. azure/ai/evaluation/_common/onedp/__init__.py +32 -0
  20. azure/ai/evaluation/_common/onedp/_client.py +166 -0
  21. azure/ai/evaluation/_common/onedp/_configuration.py +72 -0
  22. azure/ai/evaluation/_common/onedp/_model_base.py +1232 -0
  23. azure/ai/evaluation/_common/onedp/_patch.py +21 -0
  24. azure/ai/evaluation/_common/onedp/_serialization.py +2032 -0
  25. azure/ai/evaluation/_common/onedp/_types.py +21 -0
  26. azure/ai/evaluation/_common/onedp/_utils/__init__.py +6 -0
  27. azure/ai/evaluation/_common/onedp/_utils/model_base.py +1232 -0
  28. azure/ai/evaluation/_common/onedp/_utils/serialization.py +2032 -0
  29. azure/ai/evaluation/_common/onedp/_validation.py +66 -0
  30. azure/ai/evaluation/_common/onedp/_vendor.py +50 -0
  31. azure/ai/evaluation/_common/onedp/_version.py +9 -0
  32. azure/ai/evaluation/_common/onedp/aio/__init__.py +29 -0
  33. azure/ai/evaluation/_common/onedp/aio/_client.py +168 -0
  34. azure/ai/evaluation/_common/onedp/aio/_configuration.py +72 -0
  35. azure/ai/evaluation/_common/onedp/aio/_patch.py +21 -0
  36. azure/ai/evaluation/_common/onedp/aio/operations/__init__.py +49 -0
  37. azure/ai/evaluation/_common/onedp/aio/operations/_operations.py +7143 -0
  38. azure/ai/evaluation/_common/onedp/aio/operations/_patch.py +21 -0
  39. azure/ai/evaluation/_common/onedp/models/__init__.py +358 -0
  40. azure/ai/evaluation/_common/onedp/models/_enums.py +447 -0
  41. azure/ai/evaluation/_common/onedp/models/_models.py +5963 -0
  42. azure/ai/evaluation/_common/onedp/models/_patch.py +21 -0
  43. azure/ai/evaluation/_common/onedp/operations/__init__.py +49 -0
  44. azure/ai/evaluation/_common/onedp/operations/_operations.py +8951 -0
  45. azure/ai/evaluation/_common/onedp/operations/_patch.py +21 -0
  46. azure/ai/evaluation/_common/onedp/py.typed +1 -0
  47. azure/ai/evaluation/_common/onedp/servicepatterns/__init__.py +1 -0
  48. azure/ai/evaluation/_common/onedp/servicepatterns/aio/__init__.py +1 -0
  49. azure/ai/evaluation/_common/onedp/servicepatterns/aio/operations/__init__.py +25 -0
  50. azure/ai/evaluation/_common/onedp/servicepatterns/aio/operations/_operations.py +34 -0
  51. azure/ai/evaluation/_common/onedp/servicepatterns/aio/operations/_patch.py +20 -0
  52. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/__init__.py +1 -0
  53. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/aio/__init__.py +1 -0
  54. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/aio/operations/__init__.py +22 -0
  55. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/aio/operations/_operations.py +29 -0
  56. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/aio/operations/_patch.py +20 -0
  57. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/operations/__init__.py +22 -0
  58. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/operations/_operations.py +29 -0
  59. azure/ai/evaluation/_common/onedp/servicepatterns/buildingblocks/operations/_patch.py +20 -0
  60. azure/ai/evaluation/_common/onedp/servicepatterns/operations/__init__.py +25 -0
  61. azure/ai/evaluation/_common/onedp/servicepatterns/operations/_operations.py +34 -0
  62. azure/ai/evaluation/_common/onedp/servicepatterns/operations/_patch.py +20 -0
  63. azure/ai/evaluation/_common/rai_service.py +831 -142
  64. azure/ai/evaluation/_common/raiclient/__init__.py +34 -0
  65. azure/ai/evaluation/_common/raiclient/_client.py +128 -0
  66. azure/ai/evaluation/_common/raiclient/_configuration.py +87 -0
  67. azure/ai/evaluation/_common/raiclient/_model_base.py +1235 -0
  68. azure/ai/evaluation/_common/raiclient/_patch.py +20 -0
  69. azure/ai/evaluation/_common/raiclient/_serialization.py +2050 -0
  70. azure/ai/evaluation/_common/raiclient/_version.py +9 -0
  71. azure/ai/evaluation/_common/raiclient/aio/__init__.py +29 -0
  72. azure/ai/evaluation/_common/raiclient/aio/_client.py +130 -0
  73. azure/ai/evaluation/_common/raiclient/aio/_configuration.py +87 -0
  74. azure/ai/evaluation/_common/raiclient/aio/_patch.py +20 -0
  75. azure/ai/evaluation/_common/raiclient/aio/operations/__init__.py +25 -0
  76. azure/ai/evaluation/_common/raiclient/aio/operations/_operations.py +981 -0
  77. azure/ai/evaluation/_common/raiclient/aio/operations/_patch.py +20 -0
  78. azure/ai/evaluation/_common/raiclient/models/__init__.py +60 -0
  79. azure/ai/evaluation/_common/raiclient/models/_enums.py +18 -0
  80. azure/ai/evaluation/_common/raiclient/models/_models.py +651 -0
  81. azure/ai/evaluation/_common/raiclient/models/_patch.py +20 -0
  82. azure/ai/evaluation/_common/raiclient/operations/__init__.py +25 -0
  83. azure/ai/evaluation/_common/raiclient/operations/_operations.py +1238 -0
  84. azure/ai/evaluation/_common/raiclient/operations/_patch.py +20 -0
  85. azure/ai/evaluation/_common/raiclient/py.typed +1 -0
  86. azure/ai/evaluation/_common/utils.py +870 -34
  87. azure/ai/evaluation/_constants.py +167 -6
  88. azure/ai/evaluation/_converters/__init__.py +3 -0
  89. azure/ai/evaluation/_converters/_ai_services.py +899 -0
  90. azure/ai/evaluation/_converters/_models.py +467 -0
  91. azure/ai/evaluation/_converters/_sk_services.py +495 -0
  92. azure/ai/evaluation/_eval_mapping.py +83 -0
  93. azure/ai/evaluation/_evaluate/_batch_run/__init__.py +17 -0
  94. azure/ai/evaluation/_evaluate/_batch_run/_run_submitter_client.py +176 -0
  95. azure/ai/evaluation/_evaluate/_batch_run/batch_clients.py +82 -0
  96. azure/ai/evaluation/_evaluate/{_batch_run_client → _batch_run}/code_client.py +47 -25
  97. azure/ai/evaluation/_evaluate/{_batch_run_client/batch_run_context.py → _batch_run/eval_run_context.py} +42 -13
  98. azure/ai/evaluation/_evaluate/_batch_run/proxy_client.py +124 -0
  99. azure/ai/evaluation/_evaluate/_batch_run/target_run_context.py +62 -0
  100. azure/ai/evaluation/_evaluate/_eval_run.py +102 -59
  101. azure/ai/evaluation/_evaluate/_evaluate.py +2134 -311
  102. azure/ai/evaluation/_evaluate/_evaluate_aoai.py +992 -0
  103. azure/ai/evaluation/_evaluate/_telemetry/__init__.py +14 -99
  104. azure/ai/evaluation/_evaluate/_utils.py +289 -40
  105. azure/ai/evaluation/_evaluator_definition.py +76 -0
  106. azure/ai/evaluation/_evaluators/_bleu/_bleu.py +93 -42
  107. azure/ai/evaluation/_evaluators/_code_vulnerability/__init__.py +5 -0
  108. azure/ai/evaluation/_evaluators/_code_vulnerability/_code_vulnerability.py +119 -0
  109. azure/ai/evaluation/_evaluators/_coherence/_coherence.py +117 -91
  110. azure/ai/evaluation/_evaluators/_coherence/coherence.prompty +76 -39
  111. azure/ai/evaluation/_evaluators/_common/__init__.py +15 -0
  112. azure/ai/evaluation/_evaluators/_common/_base_eval.py +742 -0
  113. azure/ai/evaluation/_evaluators/_common/_base_multi_eval.py +63 -0
  114. azure/ai/evaluation/_evaluators/_common/_base_prompty_eval.py +345 -0
  115. azure/ai/evaluation/_evaluators/_common/_base_rai_svc_eval.py +198 -0
  116. azure/ai/evaluation/_evaluators/_common/_conversation_aggregators.py +49 -0
  117. azure/ai/evaluation/_evaluators/_content_safety/__init__.py +0 -4
  118. azure/ai/evaluation/_evaluators/_content_safety/_content_safety.py +144 -86
  119. azure/ai/evaluation/_evaluators/_content_safety/_hate_unfairness.py +138 -57
  120. azure/ai/evaluation/_evaluators/_content_safety/_self_harm.py +123 -55
  121. azure/ai/evaluation/_evaluators/_content_safety/_sexual.py +133 -54
  122. azure/ai/evaluation/_evaluators/_content_safety/_violence.py +134 -54
  123. azure/ai/evaluation/_evaluators/_document_retrieval/__init__.py +7 -0
  124. azure/ai/evaluation/_evaluators/_document_retrieval/_document_retrieval.py +442 -0
  125. azure/ai/evaluation/_evaluators/_eci/_eci.py +49 -56
  126. azure/ai/evaluation/_evaluators/_f1_score/_f1_score.py +102 -60
  127. azure/ai/evaluation/_evaluators/_fluency/_fluency.py +115 -92
  128. azure/ai/evaluation/_evaluators/_fluency/fluency.prompty +66 -41
  129. azure/ai/evaluation/_evaluators/_gleu/_gleu.py +90 -37
  130. azure/ai/evaluation/_evaluators/_groundedness/_groundedness.py +318 -82
  131. azure/ai/evaluation/_evaluators/_groundedness/groundedness_with_query.prompty +114 -0
  132. azure/ai/evaluation/_evaluators/_groundedness/groundedness_without_query.prompty +104 -0
  133. azure/ai/evaluation/{_evaluate/_batch_run_client → _evaluators/_intent_resolution}/__init__.py +3 -4
  134. azure/ai/evaluation/_evaluators/_intent_resolution/_intent_resolution.py +196 -0
  135. azure/ai/evaluation/_evaluators/_intent_resolution/intent_resolution.prompty +275 -0
  136. azure/ai/evaluation/_evaluators/_meteor/_meteor.py +107 -61
  137. azure/ai/evaluation/_evaluators/_protected_material/_protected_material.py +104 -77
  138. azure/ai/evaluation/_evaluators/_qa/_qa.py +115 -63
  139. azure/ai/evaluation/_evaluators/_relevance/_relevance.py +182 -98
  140. azure/ai/evaluation/_evaluators/_relevance/relevance.prompty +178 -49
  141. azure/ai/evaluation/_evaluators/_response_completeness/__init__.py +7 -0
  142. azure/ai/evaluation/_evaluators/_response_completeness/_response_completeness.py +202 -0
  143. azure/ai/evaluation/_evaluators/_response_completeness/response_completeness.prompty +84 -0
  144. azure/ai/evaluation/_evaluators/{_chat/retrieval → _retrieval}/__init__.py +2 -2
  145. azure/ai/evaluation/_evaluators/_retrieval/_retrieval.py +148 -0
  146. azure/ai/evaluation/_evaluators/_retrieval/retrieval.prompty +93 -0
  147. azure/ai/evaluation/_evaluators/_rouge/_rouge.py +189 -50
  148. azure/ai/evaluation/_evaluators/_service_groundedness/__init__.py +9 -0
  149. azure/ai/evaluation/_evaluators/_service_groundedness/_service_groundedness.py +179 -0
  150. azure/ai/evaluation/_evaluators/_similarity/_similarity.py +102 -91
  151. azure/ai/evaluation/_evaluators/_similarity/similarity.prompty +0 -5
  152. azure/ai/evaluation/_evaluators/_task_adherence/__init__.py +7 -0
  153. azure/ai/evaluation/_evaluators/_task_adherence/_task_adherence.py +226 -0
  154. azure/ai/evaluation/_evaluators/_task_adherence/task_adherence.prompty +101 -0
  155. azure/ai/evaluation/_evaluators/_task_completion/__init__.py +7 -0
  156. azure/ai/evaluation/_evaluators/_task_completion/_task_completion.py +177 -0
  157. azure/ai/evaluation/_evaluators/_task_completion/task_completion.prompty +220 -0
  158. azure/ai/evaluation/_evaluators/_task_navigation_efficiency/__init__.py +7 -0
  159. azure/ai/evaluation/_evaluators/_task_navigation_efficiency/_task_navigation_efficiency.py +384 -0
  160. azure/ai/evaluation/_evaluators/_tool_call_accuracy/__init__.py +9 -0
  161. azure/ai/evaluation/_evaluators/_tool_call_accuracy/_tool_call_accuracy.py +298 -0
  162. azure/ai/evaluation/_evaluators/_tool_call_accuracy/tool_call_accuracy.prompty +166 -0
  163. azure/ai/evaluation/_evaluators/_tool_input_accuracy/__init__.py +9 -0
  164. azure/ai/evaluation/_evaluators/_tool_input_accuracy/_tool_input_accuracy.py +263 -0
  165. azure/ai/evaluation/_evaluators/_tool_input_accuracy/tool_input_accuracy.prompty +76 -0
  166. azure/ai/evaluation/_evaluators/_tool_output_utilization/__init__.py +7 -0
  167. azure/ai/evaluation/_evaluators/_tool_output_utilization/_tool_output_utilization.py +225 -0
  168. azure/ai/evaluation/_evaluators/_tool_output_utilization/tool_output_utilization.prompty +221 -0
  169. azure/ai/evaluation/_evaluators/_tool_selection/__init__.py +9 -0
  170. azure/ai/evaluation/_evaluators/_tool_selection/_tool_selection.py +266 -0
  171. azure/ai/evaluation/_evaluators/_tool_selection/tool_selection.prompty +104 -0
  172. azure/ai/evaluation/_evaluators/_tool_success/__init__.py +7 -0
  173. azure/ai/evaluation/_evaluators/_tool_success/_tool_success.py +301 -0
  174. azure/ai/evaluation/_evaluators/_tool_success/tool_success.prompty +321 -0
  175. azure/ai/evaluation/_evaluators/_ungrounded_attributes/__init__.py +5 -0
  176. azure/ai/evaluation/_evaluators/_ungrounded_attributes/_ungrounded_attributes.py +102 -0
  177. azure/ai/evaluation/_evaluators/_xpia/xpia.py +109 -107
  178. azure/ai/evaluation/_exceptions.py +51 -7
  179. azure/ai/evaluation/_http_utils.py +210 -137
  180. azure/ai/evaluation/_legacy/__init__.py +3 -0
  181. azure/ai/evaluation/_legacy/_adapters/__init__.py +7 -0
  182. azure/ai/evaluation/_legacy/_adapters/_check.py +17 -0
  183. azure/ai/evaluation/_legacy/_adapters/_configuration.py +45 -0
  184. azure/ai/evaluation/_legacy/_adapters/_constants.py +10 -0
  185. azure/ai/evaluation/_legacy/_adapters/_errors.py +29 -0
  186. azure/ai/evaluation/_legacy/_adapters/_flows.py +28 -0
  187. azure/ai/evaluation/_legacy/_adapters/_service.py +16 -0
  188. azure/ai/evaluation/_legacy/_adapters/client.py +51 -0
  189. azure/ai/evaluation/_legacy/_adapters/entities.py +26 -0
  190. azure/ai/evaluation/_legacy/_adapters/tracing.py +28 -0
  191. azure/ai/evaluation/_legacy/_adapters/types.py +15 -0
  192. azure/ai/evaluation/_legacy/_adapters/utils.py +31 -0
  193. azure/ai/evaluation/_legacy/_batch_engine/__init__.py +9 -0
  194. azure/ai/evaluation/_legacy/_batch_engine/_config.py +48 -0
  195. azure/ai/evaluation/_legacy/_batch_engine/_engine.py +477 -0
  196. azure/ai/evaluation/_legacy/_batch_engine/_exceptions.py +88 -0
  197. azure/ai/evaluation/_legacy/_batch_engine/_openai_injector.py +132 -0
  198. azure/ai/evaluation/_legacy/_batch_engine/_result.py +107 -0
  199. azure/ai/evaluation/_legacy/_batch_engine/_run.py +127 -0
  200. azure/ai/evaluation/_legacy/_batch_engine/_run_storage.py +128 -0
  201. azure/ai/evaluation/_legacy/_batch_engine/_run_submitter.py +262 -0
  202. azure/ai/evaluation/_legacy/_batch_engine/_status.py +25 -0
  203. azure/ai/evaluation/_legacy/_batch_engine/_trace.py +97 -0
  204. azure/ai/evaluation/_legacy/_batch_engine/_utils.py +97 -0
  205. azure/ai/evaluation/_legacy/_batch_engine/_utils_deprecated.py +131 -0
  206. azure/ai/evaluation/_legacy/_common/__init__.py +3 -0
  207. azure/ai/evaluation/_legacy/_common/_async_token_provider.py +117 -0
  208. azure/ai/evaluation/_legacy/_common/_logging.py +292 -0
  209. azure/ai/evaluation/_legacy/_common/_thread_pool_executor_with_context.py +17 -0
  210. azure/ai/evaluation/_legacy/prompty/__init__.py +36 -0
  211. azure/ai/evaluation/_legacy/prompty/_connection.py +119 -0
  212. azure/ai/evaluation/_legacy/prompty/_exceptions.py +139 -0
  213. azure/ai/evaluation/_legacy/prompty/_prompty.py +430 -0
  214. azure/ai/evaluation/_legacy/prompty/_utils.py +663 -0
  215. azure/ai/evaluation/_legacy/prompty/_yaml_utils.py +99 -0
  216. azure/ai/evaluation/_model_configurations.py +130 -8
  217. azure/ai/evaluation/_safety_evaluation/__init__.py +3 -0
  218. azure/ai/evaluation/_safety_evaluation/_generated_rai_client.py +0 -0
  219. azure/ai/evaluation/_safety_evaluation/_safety_evaluation.py +917 -0
  220. azure/ai/evaluation/_user_agent.py +32 -1
  221. azure/ai/evaluation/_vendor/__init__.py +3 -0
  222. azure/ai/evaluation/_vendor/rouge_score/__init__.py +14 -0
  223. azure/ai/evaluation/_vendor/rouge_score/rouge_scorer.py +324 -0
  224. azure/ai/evaluation/_vendor/rouge_score/scoring.py +59 -0
  225. azure/ai/evaluation/_vendor/rouge_score/tokenize.py +59 -0
  226. azure/ai/evaluation/_vendor/rouge_score/tokenizers.py +53 -0
  227. azure/ai/evaluation/_version.py +2 -1
  228. azure/ai/evaluation/red_team/__init__.py +22 -0
  229. azure/ai/evaluation/red_team/_agent/__init__.py +3 -0
  230. azure/ai/evaluation/red_team/_agent/_agent_functions.py +261 -0
  231. azure/ai/evaluation/red_team/_agent/_agent_tools.py +461 -0
  232. azure/ai/evaluation/red_team/_agent/_agent_utils.py +89 -0
  233. azure/ai/evaluation/red_team/_agent/_semantic_kernel_plugin.py +228 -0
  234. azure/ai/evaluation/red_team/_attack_objective_generator.py +268 -0
  235. azure/ai/evaluation/red_team/_attack_strategy.py +49 -0
  236. azure/ai/evaluation/red_team/_callback_chat_target.py +115 -0
  237. azure/ai/evaluation/red_team/_default_converter.py +21 -0
  238. azure/ai/evaluation/red_team/_evaluation_processor.py +505 -0
  239. azure/ai/evaluation/red_team/_mlflow_integration.py +430 -0
  240. azure/ai/evaluation/red_team/_orchestrator_manager.py +803 -0
  241. azure/ai/evaluation/red_team/_red_team.py +1717 -0
  242. azure/ai/evaluation/red_team/_red_team_result.py +661 -0
  243. azure/ai/evaluation/red_team/_result_processor.py +1708 -0
  244. azure/ai/evaluation/red_team/_utils/__init__.py +37 -0
  245. azure/ai/evaluation/red_team/_utils/_rai_service_eval_chat_target.py +128 -0
  246. azure/ai/evaluation/red_team/_utils/_rai_service_target.py +601 -0
  247. azure/ai/evaluation/red_team/_utils/_rai_service_true_false_scorer.py +114 -0
  248. azure/ai/evaluation/red_team/_utils/constants.py +72 -0
  249. azure/ai/evaluation/red_team/_utils/exception_utils.py +345 -0
  250. azure/ai/evaluation/red_team/_utils/file_utils.py +266 -0
  251. azure/ai/evaluation/red_team/_utils/formatting_utils.py +365 -0
  252. azure/ai/evaluation/red_team/_utils/logging_utils.py +139 -0
  253. azure/ai/evaluation/red_team/_utils/metric_mapping.py +73 -0
  254. azure/ai/evaluation/red_team/_utils/objective_utils.py +46 -0
  255. azure/ai/evaluation/red_team/_utils/progress_utils.py +252 -0
  256. azure/ai/evaluation/red_team/_utils/retry_utils.py +218 -0
  257. azure/ai/evaluation/red_team/_utils/strategy_utils.py +218 -0
  258. azure/ai/evaluation/simulator/__init__.py +2 -1
  259. azure/ai/evaluation/simulator/_adversarial_scenario.py +26 -1
  260. azure/ai/evaluation/simulator/_adversarial_simulator.py +270 -144
  261. azure/ai/evaluation/simulator/_constants.py +12 -1
  262. azure/ai/evaluation/simulator/_conversation/__init__.py +151 -23
  263. azure/ai/evaluation/simulator/_conversation/_conversation.py +10 -6
  264. azure/ai/evaluation/simulator/_conversation/constants.py +1 -1
  265. azure/ai/evaluation/simulator/_data_sources/__init__.py +3 -0
  266. azure/ai/evaluation/simulator/_data_sources/grounding.json +1150 -0
  267. azure/ai/evaluation/simulator/_direct_attack_simulator.py +54 -75
  268. azure/ai/evaluation/simulator/_helpers/__init__.py +1 -2
  269. azure/ai/evaluation/simulator/_helpers/_language_suffix_mapping.py +1 -0
  270. azure/ai/evaluation/simulator/_helpers/_simulator_data_classes.py +26 -5
  271. azure/ai/evaluation/simulator/_indirect_attack_simulator.py +145 -104
  272. azure/ai/evaluation/simulator/_model_tools/__init__.py +2 -1
  273. azure/ai/evaluation/simulator/_model_tools/_generated_rai_client.py +225 -0
  274. azure/ai/evaluation/simulator/_model_tools/_identity_manager.py +80 -30
  275. azure/ai/evaluation/simulator/_model_tools/_proxy_completion_model.py +117 -45
  276. azure/ai/evaluation/simulator/_model_tools/_rai_client.py +109 -7
  277. azure/ai/evaluation/simulator/_model_tools/_template_handler.py +97 -33
  278. azure/ai/evaluation/simulator/_model_tools/models.py +30 -27
  279. azure/ai/evaluation/simulator/_prompty/task_query_response.prompty +6 -10
  280. azure/ai/evaluation/simulator/_prompty/task_simulate.prompty +6 -5
  281. azure/ai/evaluation/simulator/_simulator.py +302 -208
  282. azure/ai/evaluation/simulator/_utils.py +31 -13
  283. azure_ai_evaluation-1.13.3.dist-info/METADATA +939 -0
  284. azure_ai_evaluation-1.13.3.dist-info/RECORD +305 -0
  285. {azure_ai_evaluation-1.0.0b2.dist-info → azure_ai_evaluation-1.13.3.dist-info}/WHEEL +1 -1
  286. azure_ai_evaluation-1.13.3.dist-info/licenses/NOTICE.txt +70 -0
  287. azure/ai/evaluation/_evaluate/_batch_run_client/proxy_client.py +0 -71
  288. azure/ai/evaluation/_evaluators/_chat/_chat.py +0 -357
  289. azure/ai/evaluation/_evaluators/_chat/retrieval/_retrieval.py +0 -157
  290. azure/ai/evaluation/_evaluators/_chat/retrieval/retrieval.prompty +0 -48
  291. azure/ai/evaluation/_evaluators/_content_safety/_content_safety_base.py +0 -65
  292. azure/ai/evaluation/_evaluators/_content_safety/_content_safety_chat.py +0 -301
  293. azure/ai/evaluation/_evaluators/_groundedness/groundedness.prompty +0 -54
  294. azure/ai/evaluation/_evaluators/_protected_materials/__init__.py +0 -5
  295. azure/ai/evaluation/_evaluators/_protected_materials/_protected_materials.py +0 -104
  296. azure/ai/evaluation/simulator/_tracing.py +0 -89
  297. azure_ai_evaluation-1.0.0b2.dist-info/METADATA +0 -449
  298. azure_ai_evaluation-1.0.0b2.dist-info/RECORD +0 -99
  299. {azure_ai_evaluation-1.0.0b2.dist-info → azure_ai_evaluation-1.13.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,80 @@
1
+ # ---------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # ---------------------------------------------------------
4
+ from typing import Any, Dict, Optional, Union
5
+
6
+ from openai.types.graders import TextSimilarityGrader
7
+ from typing_extensions import Literal
8
+
9
+ from azure.ai.evaluation._common._experimental import experimental
10
+ from azure.ai.evaluation._model_configurations import AzureOpenAIModelConfiguration, OpenAIModelConfiguration
11
+ from azure.core.credentials import TokenCredential
12
+
13
+ from .aoai_grader import AzureOpenAIGrader
14
+
15
+
16
+ @experimental
17
+ class AzureOpenAITextSimilarityGrader(AzureOpenAIGrader):
18
+ """Wrapper class for OpenAI's string check graders.
19
+
20
+ Supplying a StringCheckGrader to the `evaluate` method will cause an asynchronous request to evaluate
21
+ the grader via the OpenAI API. The results of the evaluation will then be merged into the standard
22
+ evaluation results.
23
+
24
+ :param model_config: The model configuration to use for the grader.
25
+ :type model_config: Union[
26
+ ~azure.ai.evaluation.AzureOpenAIModelConfiguration,
27
+ ~azure.ai.evaluation.OpenAIModelConfiguration]
28
+ :param evaluation_metric: The evaluation metric to use.
29
+ :type evaluation_metric: Literal["fuzzy_match", "bleu", "gleu", "meteor", "rouge_1", "rouge_2", "rouge_3",
30
+ "rouge_4", "rouge_5", "rouge_l", "cosine"]
31
+ :param input: The text being graded.
32
+ :type input: str
33
+ :param pass_threshold: A float score where a value greater than or equal indicates a passing grade.
34
+ :type pass_threshold: float
35
+ :param reference: The text being graded against.
36
+ :type reference: str
37
+ :param name: The name of the grader.
38
+ :type name: str
39
+ :param credential: The credential to use to authenticate to the model. Only applicable to AzureOpenAI models.
40
+ :type credential: ~azure.core.credentials.TokenCredential
41
+ :param kwargs: Additional keyword arguments to pass to the grader.
42
+ :type kwargs: Any
43
+ """
44
+
45
+ id = "azureai://built-in/evaluators/azure-openai/text_similarity_grader"
46
+ _type = "text_similarity"
47
+
48
+ def __init__(
49
+ self,
50
+ *,
51
+ model_config: Union[AzureOpenAIModelConfiguration, OpenAIModelConfiguration],
52
+ evaluation_metric: Literal[
53
+ "fuzzy_match",
54
+ "bleu",
55
+ "gleu",
56
+ "meteor",
57
+ "rouge_1",
58
+ "rouge_2",
59
+ "rouge_3",
60
+ "rouge_4",
61
+ "rouge_5",
62
+ "rouge_l",
63
+ "cosine",
64
+ ],
65
+ input: str,
66
+ pass_threshold: float,
67
+ reference: str,
68
+ name: str,
69
+ credential: Optional[TokenCredential] = None,
70
+ **kwargs: Any
71
+ ):
72
+ grader = TextSimilarityGrader(
73
+ evaluation_metric=evaluation_metric,
74
+ input=input,
75
+ pass_threshold=pass_threshold,
76
+ name=name,
77
+ reference=reference,
78
+ type=AzureOpenAITextSimilarityGrader._type,
79
+ )
80
+ super().__init__(model_config=model_config, grader_config=grader, credential=credential, **kwargs)
@@ -0,0 +1,3 @@
1
+ # ---------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # ---------------------------------------------------------
@@ -0,0 +1,204 @@
1
+ # ---------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # ---------------------------------------------------------
4
+
5
+ from logging import Logger
6
+ from typing import Any, Dict, Final, Optional, Set, Union, cast
7
+ from threading import Lock
8
+ from urllib.parse import quote
9
+ from json.decoder import JSONDecodeError
10
+
11
+ from azure.core.credentials import TokenCredential, AzureSasCredential, AccessToken
12
+ from azure.core.rest import HttpResponse
13
+ from azure.ai.evaluation._exceptions import ErrorBlame, ErrorCategory, ErrorTarget, EvaluationException
14
+ from azure.ai.evaluation._http_utils import HttpPipeline, get_http_client
15
+ from azure.ai.evaluation._azure._token_manager import AzureMLTokenManager
16
+ from azure.ai.evaluation._constants import TokenScope
17
+ from ._models import BlobStoreInfo, Workspace
18
+
19
+
20
+ API_VERSION: Final[str] = "2024-07-01-preview"
21
+ QUERY_KEY_API_VERSION: Final[str] = "api-version"
22
+ PATH_ML_WORKSPACES = ("providers", "Microsoft.MachineLearningServices", "workspaces")
23
+
24
+
25
+ class LiteMLClient:
26
+ """A lightweight Azure ML API client.
27
+
28
+ :param subscription_id: Azure subscription ID
29
+ :type subscription_id: str
30
+ :param resource_group: Azure resource group name
31
+ :type resource_group: str
32
+ :param logger: Logger object
33
+ :type logger: logging.Logger
34
+ :keyword credential: Azure credentials
35
+ :paramtype credential: TokenCredential
36
+ :keyword kwargs: Additional keyword arguments
37
+ :paramtype kwargs: Dict
38
+ :keyword str api_version: The API version. Default is 2024-10-01
39
+ """
40
+
41
+ def __init__(
42
+ self,
43
+ subscription_id: str,
44
+ resource_group: str,
45
+ logger: Logger,
46
+ credential: Optional[TokenCredential] = None,
47
+ **kwargs: Any,
48
+ ) -> None:
49
+ subscription_id = quote(subscription_id, safe="")
50
+ resource_group = quote(resource_group, safe="")
51
+
52
+ self._base_url: Final[str] = (
53
+ f"https://management.azure.com/subscriptions/{subscription_id}/resourceGroups/{resource_group}"
54
+ )
55
+ self._logger: Final[Logger] = logger
56
+ self._api_version: Final[str] = kwargs.get("api_version", API_VERSION)
57
+ self._http_client: Final[HttpPipeline] = get_http_client(**kwargs)
58
+ self._lock: Final[Lock] = Lock()
59
+
60
+ # things that can change under lock
61
+ self._token_manager: Optional[AzureMLTokenManager] = None
62
+ self._credential: Optional[TokenCredential] = credential
63
+
64
+ def get_token(self) -> AccessToken:
65
+ return self._get_token_manager().get_token()
66
+
67
+ def get_credential(self) -> TokenCredential:
68
+ # load the token manager to get the credential if needed
69
+ self._get_token_manager()
70
+ return cast(TokenCredential, self._credential)
71
+
72
+ def workspace_get_default_datastore(
73
+ self, workspace_name: str, *, include_credentials: bool = False, **kwargs: Any
74
+ ) -> BlobStoreInfo:
75
+ # 1. Get the default blob store
76
+ # REST API documentation:
77
+ # https://learn.microsoft.com/rest/api/azureml/datastores/list?view=rest-azureml-2024-10-01
78
+ url = self._generate_path( # pylint: disable=specify-parameter-names-in-call
79
+ *PATH_ML_WORKSPACES, workspace_name, "datastores"
80
+ )
81
+ headers = self._get_headers()
82
+
83
+ stores_response = self._http_client.request(
84
+ method="GET",
85
+ url=url,
86
+ params={QUERY_KEY_API_VERSION: self._api_version, "isDefault": True, "count": 1, "orderByAsc": "false"},
87
+ headers=headers,
88
+ )
89
+ self._throw_on_http_error(stores_response, "list default workspace datastore")
90
+
91
+ json = stores_response.json()["value"][0]
92
+ props_json = json["properties"]
93
+ name = json["name"]
94
+ account_name = props_json["accountName"]
95
+ endpoint = props_json["endpoint"]
96
+ container_name = props_json["containerName"]
97
+ credential_type = props_json.get("credentials", {}).get("credentialsType")
98
+
99
+ # 2. Get the SAS token to use for accessing the blob store
100
+ # REST API documentation:
101
+ # https://learn.microsoft.com/rest/api/azureml/datastores/list-secrets?view=rest-azureml-2024-10-01
102
+ blob_store_credential: Optional[Union[AzureSasCredential, TokenCredential, str]]
103
+ if not include_credentials:
104
+ blob_store_credential = None
105
+ elif credential_type and credential_type.lower() == "none":
106
+ # If storage account key access is disabled, and only Microsoft Entra ID authentication is available,
107
+ # the credentialsType will be "None" and we should not attempt to get the secrets.
108
+ blob_store_credential = self.get_credential()
109
+ else:
110
+ url = self._generate_path(
111
+ *PATH_ML_WORKSPACES, workspace_name, "datastores", "workspaceblobstore", "listSecrets"
112
+ )
113
+ secrets_response = self._http_client.request(
114
+ method="POST",
115
+ url=url,
116
+ json={
117
+ "expirableSecret": True,
118
+ "expireAfterHours": int(kwargs.get("key_expiration_hours", 1)),
119
+ },
120
+ params={
121
+ QUERY_KEY_API_VERSION: self._api_version,
122
+ },
123
+ headers=headers,
124
+ )
125
+ self._throw_on_http_error(secrets_response, "workspace datastore secrets")
126
+
127
+ secrets_json = secrets_response.json()
128
+ secrets_type = secrets_json["secretsType"].lower()
129
+
130
+ # As per this website, only SAS tokens, access tokens, or Entra IDs are valid for accessing blob data
131
+ # stores:
132
+ # https://learn.microsoft.com/rest/api/storageservices/authorize-requests-to-azure-storage.
133
+ if secrets_type == "sas":
134
+ blob_store_credential = AzureSasCredential(secrets_json["sasToken"])
135
+ elif secrets_type == "accountkey":
136
+ # To support older versions of azure-storage-blob better, we return a string here instead of
137
+ # an AzureNamedKeyCredential
138
+ blob_store_credential = secrets_json["key"]
139
+ else:
140
+ raise EvaluationException(
141
+ message=f"The '{account_name}' blob store does not use a recognized credential type.",
142
+ internal_message=f"The credential type is '{secrets_type}'",
143
+ target=ErrorTarget.EVALUATE,
144
+ category=ErrorCategory.INVALID_VALUE,
145
+ blame=ErrorBlame.SYSTEM_ERROR,
146
+ )
147
+
148
+ return BlobStoreInfo(name, account_name, endpoint, container_name, blob_store_credential)
149
+
150
+ def workspace_get_info(self, workspace_name: str) -> Workspace:
151
+ # https://learn.microsoft.com/rest/api/azureml/workspaces/get?view=rest-azureml-2024-10-01
152
+ workspace_response = self._http_client.request(
153
+ "GET",
154
+ self._generate_path(*PATH_ML_WORKSPACES, workspace_name),
155
+ params={QUERY_KEY_API_VERSION: self._api_version},
156
+ headers=self._get_headers(),
157
+ )
158
+
159
+ self._throw_on_http_error(workspace_response, f"get '{workspace_name}' workspace")
160
+ workspace = Workspace.deserialize(workspace_response)
161
+ return workspace
162
+
163
+ def _get_token_manager(self) -> AzureMLTokenManager:
164
+ # Lazy init since getting credentials in the constructor can take a long time in some situations
165
+ if self._token_manager is None:
166
+ with self._lock:
167
+ if self._token_manager is None:
168
+ self._token_manager = AzureMLTokenManager(
169
+ TokenScope.DEFAULT_AZURE_MANAGEMENT.value, self._logger, credential=self._credential
170
+ )
171
+ self._credential = self._token_manager.credential
172
+
173
+ return self._token_manager
174
+
175
+ @staticmethod
176
+ def _throw_on_http_error(response: HttpResponse, description: str, valid_status: Optional[Set[int]] = None) -> None:
177
+ if valid_status and (response.status_code in valid_status):
178
+ return
179
+ if response.status_code >= 200 and response.status_code < 300:
180
+ # nothing to see here, move along
181
+ return
182
+
183
+ message = f"The {description} request failed with HTTP {response.status_code}"
184
+ try:
185
+ error_json = response.json()["error"]
186
+ additional_info = f"({error_json['code']}) {error_json['message']}"
187
+ message += f" - {additional_info}"
188
+ except (JSONDecodeError, ValueError, KeyError):
189
+ pass
190
+
191
+ raise EvaluationException(
192
+ message=message,
193
+ target=ErrorTarget.EVALUATE,
194
+ category=ErrorCategory.FAILED_EXECUTION,
195
+ blame=ErrorBlame.SYSTEM_ERROR,
196
+ )
197
+
198
+ def _generate_path(self, *paths: str) -> str:
199
+ sanitized_paths = [quote(path, safe="") for path in paths]
200
+ url = self._base_url + "/" + str.join("/", sanitized_paths)
201
+ return url
202
+
203
+ def _get_headers(self) -> Dict[str, str]:
204
+ return {"Authorization": f"Bearer {self.get_token().token}", "Content-Type": "application/json"}
@@ -0,0 +1,207 @@
1
+ # ---------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # ---------------------------------------------------------
4
+
5
+ # NOTE:
6
+ # This is a simplified version of the original code from azure-ai-ml:
7
+ # sdk\ml\azure-ai-ml\azure\ai\ml\_azure_environments.py
8
+
9
+ import asyncio
10
+ import os
11
+
12
+ from typing import Any, Dict, Final, Mapping, Optional, Sequence, TypedDict
13
+
14
+ from azure.core import AsyncPipelineClient
15
+ from azure.core.configuration import Configuration
16
+ from azure.core.rest import HttpRequest
17
+ from azure.core.pipeline.policies import ProxyPolicy, AsyncRetryPolicy
18
+
19
+
20
+ class AzureEnvironmentMetadata(TypedDict):
21
+ """Configuration for various Azure environments. All endpoints include a trailing slash."""
22
+
23
+ portal_endpoint: str
24
+ """The management portal for the Azure environment (e.g. https://portal.azure.com/)"""
25
+ resource_manager_endpoint: str
26
+ """The API endpoint for Azure control plan (e.g. https://management.azure.com/)"""
27
+ active_directory_endpoint: str
28
+ """The active directory endpoint used for authentication (e.g. https://login.microsoftonline.com/)"""
29
+ aml_resource_endpoint: str
30
+ """The endpoint for Azure Machine Learning resources (e.g. https://ml.azure.com/)"""
31
+ storage_suffix: str
32
+ """The suffix to use for storage endpoint URLs (e.g. core.windows.net)"""
33
+ registry_discovery_endpoint: str
34
+
35
+
36
+ _ENV_ARM_CLOUD_METADATA_URL: Final[str] = "ARM_CLOUD_METADATA_URL"
37
+ _ENV_DEFAULT_CLOUD_NAME: Final[str] = "AZUREML_CURRENT_CLOUD"
38
+ _ENV_REGISTRY_DISCOVERY_URL: Final[str] = "REGISTRY_DISCOVERY_ENDPOINT_URL"
39
+ _ENV_REGISTRY_DISCOVERY_REGION: Final[str] = "REGISTRY_DISCOVERY_ENDPOINT_REGION"
40
+ _DEFAULT_REGISTRY_DISCOVERY_REGION: Final[str] = "west"
41
+ _DEFAULT_AZURE_ENV_NAME: Final[str] = "AzureCloud"
42
+
43
+
44
+ _ASYNC_LOCK = asyncio.Lock()
45
+ _KNOWN_AZURE_ENVIRONMENTS: Dict[str, AzureEnvironmentMetadata] = {
46
+ _DEFAULT_AZURE_ENV_NAME: {
47
+ "portal_endpoint": "https://portal.azure.com/",
48
+ "resource_manager_endpoint": "https://management.azure.com/",
49
+ "active_directory_endpoint": "https://login.microsoftonline.com/",
50
+ "aml_resource_endpoint": "https://ml.azure.com/",
51
+ "storage_suffix": "core.windows.net",
52
+ "registry_discovery_endpoint": "https://eastus.api.azureml.ms/",
53
+ },
54
+ "AzureChinaCloud": {
55
+ "portal_endpoint": "https://portal.azure.cn/",
56
+ "resource_manager_endpoint": "https://management.chinacloudapi.cn/",
57
+ "active_directory_endpoint": "https://login.chinacloudapi.cn/",
58
+ "aml_resource_endpoint": "https://ml.azure.cn/",
59
+ "storage_suffix": "core.chinacloudapi.cn",
60
+ "registry_discovery_endpoint": "https://chinaeast2.api.ml.azure.cn/",
61
+ },
62
+ "AzureUSGovernment": {
63
+ "portal_endpoint": "https://portal.azure.us/",
64
+ "resource_manager_endpoint": "https://management.usgovcloudapi.net/",
65
+ "active_directory_endpoint": "https://login.microsoftonline.us/",
66
+ "aml_resource_endpoint": "https://ml.azure.us/",
67
+ "storage_suffix": "core.usgovcloudapi.net",
68
+ "registry_discovery_endpoint": "https://usgovarizona.api.ml.azure.us/",
69
+ },
70
+ }
71
+
72
+
73
+ class AzureEnvironmentClient:
74
+ DEFAULT_API_VERSION: Final[str] = "2019-05-01"
75
+ DEFAULT_AZURE_CLOUD_NAME: Final[str] = _DEFAULT_AZURE_ENV_NAME
76
+
77
+ def __init__(self, *, base_url: Optional[str] = None, **kwargs: Any) -> None:
78
+ base_url = base_url if base_url is not None else AzureEnvironmentClient.get_default_metadata_url()
79
+
80
+ config: Configuration = kwargs.pop("config", Configuration(**kwargs))
81
+ if config.retry_policy is None:
82
+ config.retry_policy = AsyncRetryPolicy(**kwargs)
83
+ if config.proxy_policy is None and "proxy" in kwargs:
84
+ config.proxy_policy = ProxyPolicy(proxies={"http": kwargs["proxy"], "https": kwargs["proxy"]})
85
+
86
+ self._async_client = AsyncPipelineClient(base_url, config=config, **kwargs)
87
+
88
+ async def get_default_cloud_name_async(self, *, update_cached: bool = True) -> str:
89
+ current_cloud_env = os.getenv(_ENV_DEFAULT_CLOUD_NAME)
90
+ if current_cloud_env is not None:
91
+ return current_cloud_env
92
+
93
+ arm_metadata_url = os.getenv(_ENV_ARM_CLOUD_METADATA_URL)
94
+ if arm_metadata_url is None:
95
+ return _DEFAULT_AZURE_ENV_NAME
96
+
97
+ # load clouds from metadata url
98
+ clouds = await self.get_clouds_async(metadata_url=arm_metadata_url, update_cached=update_cached)
99
+ matched = next(filter(lambda t: t[1]["resource_manager_endpoint"] in arm_metadata_url, clouds.items()), None)
100
+ if matched is None:
101
+ return _DEFAULT_AZURE_ENV_NAME
102
+
103
+ os.environ[_ENV_DEFAULT_CLOUD_NAME] = matched[0]
104
+ return matched[0]
105
+
106
+ async def get_cloud_async(self, name: str, *, update_cached: bool = True) -> Optional[AzureEnvironmentMetadata]:
107
+ default_endpoint: Optional[str]
108
+
109
+ def case_insensitive_match(d: Mapping[str, Any], key: str) -> Optional[Any]:
110
+ key = key.strip().lower()
111
+ return next((v for k, v in d.items() if k.strip().lower() == key), None)
112
+
113
+ async with _ASYNC_LOCK:
114
+ cloud = _KNOWN_AZURE_ENVIRONMENTS.get(name) or case_insensitive_match(_KNOWN_AZURE_ENVIRONMENTS, name)
115
+ if cloud:
116
+ return cloud
117
+ default_endpoint = _KNOWN_AZURE_ENVIRONMENTS.get(_DEFAULT_AZURE_ENV_NAME, {}).get(
118
+ "resource_manager_endpoint"
119
+ )
120
+
121
+ metadata_url = self.get_default_metadata_url(default_endpoint)
122
+ clouds = await self.get_clouds_async(metadata_url=metadata_url, update_cached=update_cached)
123
+ cloud_metadata = clouds.get(name) or case_insensitive_match(clouds, name)
124
+
125
+ return cloud_metadata
126
+
127
+ async def get_clouds_async(
128
+ self, *, metadata_url: Optional[str] = None, update_cached: bool = True
129
+ ) -> Mapping[str, AzureEnvironmentMetadata]:
130
+ metadata_url = metadata_url or self.get_default_metadata_url()
131
+
132
+ clouds: Mapping[str, AzureEnvironmentMetadata]
133
+ async with self._async_client.send_request(HttpRequest("GET", metadata_url)) as response: # type: ignore
134
+ response.raise_for_status()
135
+ clouds = await self._parse_cloud_endpoints_async(response.json())
136
+
137
+ if update_cached:
138
+ async with _ASYNC_LOCK:
139
+ recursive_update(_KNOWN_AZURE_ENVIRONMENTS, clouds)
140
+ return clouds
141
+
142
+ async def close(self) -> None:
143
+ await self._async_client.close()
144
+
145
+ @staticmethod
146
+ def get_default_metadata_url(default_endpoint: Optional[str] = None) -> str:
147
+ default_endpoint = default_endpoint or "https://management.azure.com/"
148
+ metadata_url = os.getenv(
149
+ _ENV_ARM_CLOUD_METADATA_URL,
150
+ f"{default_endpoint}metadata/endpoints?api-version={AzureEnvironmentClient.DEFAULT_API_VERSION}",
151
+ )
152
+ return metadata_url
153
+
154
+ @staticmethod
155
+ async def _get_registry_discovery_url_async(cloud_name: str, cloud_suffix: str) -> str:
156
+ async with _ASYNC_LOCK:
157
+ discovery_url = _KNOWN_AZURE_ENVIRONMENTS.get(cloud_name, {}).get("registry_discovery_endpoint")
158
+ if discovery_url:
159
+ return discovery_url
160
+
161
+ discovery_url = os.getenv(_ENV_REGISTRY_DISCOVERY_URL)
162
+ if discovery_url is not None:
163
+ return discovery_url
164
+
165
+ region = os.getenv(_ENV_REGISTRY_DISCOVERY_REGION, _DEFAULT_REGISTRY_DISCOVERY_REGION)
166
+ return f"https://{cloud_name.lower()}{region}.api.ml.azure.{cloud_suffix}/"
167
+
168
+ @staticmethod
169
+ async def _parse_cloud_endpoints_async(data: Any) -> Mapping[str, AzureEnvironmentMetadata]:
170
+ # If there is only one cloud, you will get a dict, otherwise a list of dicts
171
+ cloud_data: Sequence[Mapping[str, Any]] = data if not isinstance(data, dict) else [data]
172
+ clouds: Dict[str, AzureEnvironmentMetadata] = {}
173
+
174
+ def append_trailing_slash(url: str) -> str:
175
+ return url if url.endswith("/") else f"{url}/"
176
+
177
+ for cloud in cloud_data:
178
+ try:
179
+ name: str = cloud["name"]
180
+ portal_endpoint: str = cloud["portal"]
181
+ cloud_suffix = ".".join(portal_endpoint.split(".")[2:]).replace("/", "")
182
+ discovery_url = await AzureEnvironmentClient._get_registry_discovery_url_async(name, cloud_suffix)
183
+ clouds[name] = {
184
+ "portal_endpoint": append_trailing_slash(portal_endpoint),
185
+ "resource_manager_endpoint": append_trailing_slash(cloud["resourceManager"]),
186
+ "active_directory_endpoint": append_trailing_slash(cloud["authentication"]["loginEndpoint"]),
187
+ "aml_resource_endpoint": append_trailing_slash(f"https://ml.azure.{cloud_suffix}/"),
188
+ "storage_suffix": cloud["suffixes"]["storage"],
189
+ "registry_discovery_endpoint": append_trailing_slash(discovery_url),
190
+ }
191
+ except KeyError:
192
+ continue
193
+
194
+ return clouds
195
+
196
+
197
+ def recursive_update(d: Dict, u: Mapping) -> None:
198
+ """Recursively update a dictionary.
199
+
200
+ :param Dict d: The dictionary to update.
201
+ :param Mapping u: The mapping to update from.
202
+ """
203
+ for k, v in u.items():
204
+ if isinstance(v, Dict) and k in d:
205
+ recursive_update(d[k], v)
206
+ else:
207
+ d[k] = v