Skip to content

Commit 472bdfb

Browse files
fix: case-insensitive UserError blame check in _get_single_run_results + unit tests
Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-python/sessions/85522f11-e665-4eb7-b1bc-05e48272e704 Co-authored-by: posaninagendra <2713981+posaninagendra@users.noreply.github.com>
1 parent 2240bf9 commit 472bdfb

2 files changed

Lines changed: 88 additions & 2 deletions

File tree

sdk/evaluation/azure-ai-evaluation/azure/ai/evaluation/_evaluate/_evaluate_aoai.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,12 @@ def _get_single_run_results(
307307

308308
LOGGER.info(f"AOAI: Eval run {run_info['eval_run_id']} completed with status: {run_results.status}")
309309
if run_results.status != "completed":
310+
error_code = getattr(getattr(run_results, "error", None), "code", None)
311+
blame = ErrorBlame.USER_ERROR if isinstance(error_code, str) and error_code.lower() == "usererror" else ErrorBlame.UNKNOWN
310312
raise EvaluationException(
311313
message=f"AOAI evaluation run {run_info['eval_group_id']}/{run_info['eval_run_id']}"
312314
+ f" failed with status {run_results.status}.",
313-
blame=ErrorBlame.UNKNOWN,
315+
blame=blame,
314316
category=ErrorCategory.FAILED_EXECUTION,
315317
target=ErrorTarget.AOAI_GRADER,
316318
)

sdk/evaluation/azure-ai-evaluation/tests/unittests/test_evaluate_aoai.py

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import pytest
22
import copy
3-
from azure.ai.evaluation._evaluate._evaluate_aoai import _combine_item_schemas
3+
from unittest.mock import MagicMock, patch
4+
from azure.ai.evaluation._evaluate._evaluate_aoai import _combine_item_schemas, _get_single_run_results
5+
from azure.ai.evaluation._exceptions import ErrorBlame, EvaluationException
46

57

68
@pytest.fixture
@@ -119,3 +121,85 @@ def test_combine_item_schemas_with_external_properties_without_required(self, de
119121

120122
assert data_source_config["item_schema"]["properties"] == expected_properties
121123
assert data_source_config["item_schema"]["required"] == expected_required
124+
125+
126+
class TestGetSingleRunResultsBlame:
127+
"""Unit tests for blame attribution in _get_single_run_results."""
128+
129+
def _make_run_info(self, client):
130+
return {
131+
"client": client,
132+
"eval_group_id": "group-1",
133+
"eval_run_id": "run-1",
134+
"grader_name_map": {},
135+
}
136+
137+
@patch("azure.ai.evaluation._evaluate._evaluate_aoai._wait_for_run_conclusion")
138+
@pytest.mark.parametrize("code", ["UserError", "usererror", "USERERROR", "uSeReRrOr"])
139+
def test_user_error_code_sets_user_blame(self, mock_wait, code):
140+
"""When run fails with error.code matching 'usererror' (case-insensitive), blame should be USER_ERROR."""
141+
run_result = MagicMock()
142+
run_result.status = "failed"
143+
run_result.error.code = code
144+
mock_wait.return_value = run_result
145+
client = MagicMock()
146+
147+
with pytest.raises(EvaluationException) as exc_info:
148+
_get_single_run_results(self._make_run_info(client))
149+
150+
assert exc_info.value.blame == ErrorBlame.USER_ERROR
151+
152+
@patch("azure.ai.evaluation._evaluate._evaluate_aoai._wait_for_run_conclusion")
153+
def test_non_user_error_code_sets_unknown_blame(self, mock_wait):
154+
"""When run fails with a non-UserError code, blame should be UNKNOWN."""
155+
run_result = MagicMock()
156+
run_result.status = "failed"
157+
run_result.error.code = "SystemError"
158+
mock_wait.return_value = run_result
159+
client = MagicMock()
160+
161+
with pytest.raises(EvaluationException) as exc_info:
162+
_get_single_run_results(self._make_run_info(client))
163+
164+
assert exc_info.value.blame == ErrorBlame.UNKNOWN
165+
166+
@patch("azure.ai.evaluation._evaluate._evaluate_aoai._wait_for_run_conclusion")
167+
def test_missing_error_attribute_sets_unknown_blame(self, mock_wait):
168+
"""When run fails and error attribute is absent, blame should be UNKNOWN."""
169+
run_result = MagicMock(spec=["status"])
170+
run_result.status = "failed"
171+
mock_wait.return_value = run_result
172+
client = MagicMock()
173+
174+
with pytest.raises(EvaluationException) as exc_info:
175+
_get_single_run_results(self._make_run_info(client))
176+
177+
assert exc_info.value.blame == ErrorBlame.UNKNOWN
178+
179+
@patch("azure.ai.evaluation._evaluate._evaluate_aoai._wait_for_run_conclusion")
180+
def test_error_present_but_code_missing_sets_unknown_blame(self, mock_wait):
181+
"""When error object exists but has no code attribute, blame should be UNKNOWN."""
182+
run_result = MagicMock()
183+
run_result.status = "failed"
184+
run_result.error = MagicMock(spec=[]) # error object without 'code'
185+
mock_wait.return_value = run_result
186+
client = MagicMock()
187+
188+
with pytest.raises(EvaluationException) as exc_info:
189+
_get_single_run_results(self._make_run_info(client))
190+
191+
assert exc_info.value.blame == ErrorBlame.UNKNOWN
192+
193+
@patch("azure.ai.evaluation._evaluate._evaluate_aoai._wait_for_run_conclusion")
194+
def test_error_is_none_sets_unknown_blame(self, mock_wait):
195+
"""When error attribute is None, blame should be UNKNOWN."""
196+
run_result = MagicMock()
197+
run_result.status = "failed"
198+
run_result.error = None
199+
mock_wait.return_value = run_result
200+
client = MagicMock()
201+
202+
with pytest.raises(EvaluationException) as exc_info:
203+
_get_single_run_results(self._make_run_info(client))
204+
205+
assert exc_info.value.blame == ErrorBlame.UNKNOWN

0 commit comments

Comments
 (0)