Skip to content

Commit 5337072

Browse files
authored
[evaluation] ci: Re-enable Windows tests (Azure#37411)
* ci: Revert back to repo's platform matrix * fix: Wrap async clients in async with blocks * tests,fix: Ensure that promptflow service is stopped
1 parent 5c17720 commit 5337072

File tree

8 files changed

+59
-93
lines changed

8 files changed

+59
-93
lines changed

sdk/evaluation/azure-ai-evaluation/azure/ai/evaluation/_common/rai_service.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,10 @@ async def ensure_service_availability(rai_svc_url: str, token: str, capability:
6565
headers = get_common_headers(token)
6666
svc_liveness_url = rai_svc_url + "/checkannotation"
6767

68-
client = get_async_http_client()
69-
70-
response = await client.get( # pylint: disable=too-many-function-args,unexpected-keyword-arg
71-
svc_liveness_url, headers=headers, timeout=CommonConstants.DEFAULT_HTTP_TIMEOUT
72-
)
68+
async with get_async_http_client() as client:
69+
response = await client.get( # pylint: disable=too-many-function-args,unexpected-keyword-arg
70+
svc_liveness_url, headers=headers, timeout=CommonConstants.DEFAULT_HTTP_TIMEOUT
71+
)
7372

7473
if response.status_code != 200:
7574
raise Exception( # pylint: disable=broad-exception-raised
@@ -143,11 +142,10 @@ async def submit_request(question: str, answer: str, metric: str, rai_svc_url: s
143142
url = rai_svc_url + "/submitannotation"
144143
headers = get_common_headers(token)
145144

146-
client = get_async_http_client()
147-
148-
response = await client.post( # pylint: disable=too-many-function-args,unexpected-keyword-arg
149-
url, json=payload, headers=headers, timeout=CommonConstants.DEFAULT_HTTP_TIMEOUT
150-
)
145+
async with get_async_http_client() as client:
146+
response = await client.post( # pylint: disable=too-many-function-args,unexpected-keyword-arg
147+
url, json=payload, headers=headers, timeout=CommonConstants.DEFAULT_HTTP_TIMEOUT
148+
)
151149

152150
if response.status_code != 202:
153151
print("Fail evaluating '%s' with error message: %s" % (payload["UserTextList"], response.text))
@@ -180,11 +178,10 @@ async def fetch_result(operation_id: str, rai_svc_url: str, credential: TokenCre
180178
token = await fetch_or_reuse_token(credential, token)
181179
headers = get_common_headers(token)
182180

183-
client = get_async_http_client()
184-
185-
response = await client.get( # pylint: disable=too-many-function-args,unexpected-keyword-arg
186-
url, headers=headers, timeout=CommonConstants.DEFAULT_HTTP_TIMEOUT
187-
)
181+
async with get_async_http_client() as client:
182+
response = await client.get( # pylint: disable=too-many-function-args,unexpected-keyword-arg
183+
url, headers=headers, timeout=CommonConstants.DEFAULT_HTTP_TIMEOUT
184+
)
188185

189186
if response.status_code == 200:
190187
return response.json()
@@ -342,16 +339,15 @@ async def _get_service_discovery_url(azure_ai_project: dict, token: str) -> str:
342339
"""
343340
headers = get_common_headers(token)
344341

345-
client = get_async_http_client()
346-
347-
response = await client.get( # pylint: disable=too-many-function-args,unexpected-keyword-arg
348-
f"https://management.azure.com/subscriptions/{azure_ai_project['subscription_id']}/"
349-
f"resourceGroups/{azure_ai_project['resource_group_name']}/"
350-
f"providers/Microsoft.MachineLearningServices/workspaces/{azure_ai_project['project_name']}?"
351-
f"api-version=2023-08-01-preview",
352-
headers=headers,
353-
timeout=CommonConstants.DEFAULT_HTTP_TIMEOUT,
354-
)
342+
async with get_async_http_client() as client:
343+
response = await client.get( # pylint: disable=too-many-function-args,unexpected-keyword-arg
344+
f"https://management.azure.com/subscriptions/{azure_ai_project['subscription_id']}/"
345+
f"resourceGroups/{azure_ai_project['resource_group_name']}/"
346+
f"providers/Microsoft.MachineLearningServices/workspaces/{azure_ai_project['project_name']}?"
347+
f"api-version=2023-08-01-preview",
348+
headers=headers,
349+
timeout=CommonConstants.DEFAULT_HTTP_TIMEOUT,
350+
)
355351

356352
if response.status_code != 200:
357353
raise Exception("Failed to retrieve the discovery service URL") # pylint: disable=broad-exception-raised

sdk/evaluation/azure-ai-evaluation/azure/ai/evaluation/simulator/_adversarial_simulator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ async def _simulate_async(
321321
)
322322
)
323323

324-
async with semaphore:
324+
async with semaphore, session:
325325
_, conversation_history = await simulate_conversation(
326326
bots=bots,
327327
session=session,

sdk/evaluation/azure-ai-evaluation/azure/ai/evaluation/simulator/_model_tools/_proxy_completion_model.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,17 +196,16 @@ async def request_api(
196196
retry_mode=RetryMode.Exponential,
197197
)
198198

199-
exp_retry_client = get_async_http_client().with_policies(retry_policy=retry_policy)
200-
201199
# initial 15 seconds wait before attempting to fetch result
202200
# Need to wait both in this thread and in the async thread for some reason?
203201
# Someone not under a crunch and with better async understandings should dig into this more.
204202
await asyncio.sleep(15)
205203
time.sleep(15)
206204

207-
response = await exp_retry_client.get( # pylint: disable=too-many-function-args,unexpected-keyword-arg
208-
self.result_url, headers=proxy_headers
209-
)
205+
async with get_async_http_client().with_policies(retry_policy=retry_policy) as exp_retry_client:
206+
response = await exp_retry_client.get( # pylint: disable=too-many-function-args,unexpected-keyword-arg
207+
self.result_url, headers=proxy_headers
208+
)
210209

211210
response.raise_for_status()
212211

sdk/evaluation/azure-ai-evaluation/azure/ai/evaluation/simulator/_model_tools/_rai_client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ async def get(self, url: str) -> Any:
122122
}
123123

124124
session = self._create_async_client()
125-
response = await session.get(url=url, headers=headers) # pylint: disable=unexpected-keyword-arg
125+
126+
async with session:
127+
response = await session.get(url=url, headers=headers) # pylint: disable=unexpected-keyword-arg
126128

127129
if response.status_code == 200:
128130
return response.json()

sdk/evaluation/azure-ai-evaluation/tests/conftest.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,3 +471,28 @@ def pytest_collection_modifyitems(items):
471471
# If item's parent was marked as 'localtest', mark the child as such, but not if
472472
# it was marked as 'azuretest'.
473473
item.add_marker(pytest.mark.localtest)
474+
475+
476+
def pytest_sessionfinish() -> None:
477+
478+
def stop_promptflow_service() -> None:
479+
"""Ensure that the promptflow service is stopped when pytest exits.
480+
481+
.. note::
482+
483+
The azure-sdk-for-python CI performs a cleanup step that deletes
484+
the python environment that the tests run in.
485+
486+
At time of writing, at least one test starts the promptflow service
487+
(served from `waitress-serve`). The promptflow service is a separate
488+
process that gets orphaned by pytest.
489+
490+
Crucially, that process has a handles on files in the python environment.
491+
On Windows, this causes the cleanup step to fail with a permission issue
492+
since the OS disallows deletion of files in use by a process.
493+
"""
494+
from promptflow._cli._pf._service import stop_service
495+
496+
stop_service()
497+
498+
stop_promptflow_service()

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,11 @@ async def test_conversation_bot_initialization_user_invalid_jinja(self, bot_inva
8484
)
8585
)
8686

87-
parsed_response, req, time_taken, full_response = await bot.generate_response(
88-
session=client, conversation_history=[], max_history=0, turn_number=0
89-
)
87+
async with client:
88+
parsed_response, req, time_taken, full_response = await bot.generate_response(
89+
session=client, conversation_history=[], max_history=0, turn_number=0
90+
)
91+
9092
assert (
9193
parsed_response["samples"][0]
9294
== bot_invalid_jinja_params["instantiation_parameters"]["conversation_starter"]

sdk/evaluation/ci.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,6 @@ extends:
2828
ServiceDirectory: evaluation
2929
ValidateFormatting: true
3030
TestProxy: true
31-
# This custom matrix config should be dropped once:
32-
# * Resolve the issue of windows runners crashing because a file isn't deletable
33-
MatrixConfigs:
34-
- Name: ai_ci_matrix
35-
Path: sdk/evaluation/platform-matrix.json
36-
Selection: sparse
37-
GenerateVMJobs: true
3831
Artifacts:
3932
- name: azure-ai-evaluation
4033
safeName: azureaievaluation

sdk/evaluation/platform-matrix.json

Lines changed: 0 additions & 51 deletions
This file was deleted.

0 commit comments

Comments
 (0)