Skip to content

Commit 4640862

Browse files
authored
Add Job.list_attachments() to enumerate a job's output container blobs (#768)
1 parent 82cced9 commit 4640862

2 files changed

Lines changed: 74 additions & 1 deletion

File tree

azure-quantum/azure/quantum/job/base_job.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from datetime import datetime, timezone, timedelta
1111
from urllib.parse import urlparse, parse_qs
1212
from typing import Any, Dict, Optional, TYPE_CHECKING
13-
from azure.storage.blob import BlobClient
13+
from azure.storage.blob import BlobClient, BlobProperties
1414

1515
from azure.quantum.storage import upload_blob, download_blob, download_blob_properties, ContainerClient
1616
from azure.quantum._client.models import JobDetails
@@ -390,6 +390,25 @@ def download_attachment(
390390
return response
391391

392392

393+
def list_attachments(self) -> list[BlobProperties]:
394+
""" Lists the attachments in the job's linked storage container. Attachments are blobs of
395+
data created as part of the Job's execution, or they can be uploaded directly from Python
396+
using the upload_attachment method.
397+
398+
:return: List of blobs in the job's linked storage container.
399+
:rtype: list[~azure.storage.blob.BlobProperties]
400+
"""
401+
402+
# Use the job's linked storage container.
403+
if self._details.container_uri is None:
404+
container_uri = self.workspace.get_container_uri(job_id=self.id)
405+
else:
406+
container_uri = self._details.container_uri
407+
408+
container_client = ContainerClient.from_container_url(container_uri)
409+
return list(container_client.list_blobs())
410+
411+
393412
def _get_blob_uri_with_sas_token(self, blob_uri: str) -> str:
394413
"""Get Blob URI with SAS-token if one was not specified in blob_uri parameter
395414
:param blob_uri: Blob URI
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
##
2+
# Copyright (c) Microsoft Corporation.
3+
# Licensed under the MIT License.
4+
##
5+
6+
from unittest.mock import Mock, patch
7+
from azure.quantum import Job, JobDetails
8+
9+
10+
CONTAINER_URI = "https://acct.blob.core.windows.net/job-id?sas"
11+
12+
13+
def _job_with_container(container_uri=CONTAINER_URI, workspace=None) -> Job:
14+
job_details = JobDetails(
15+
id="job-id",
16+
name="",
17+
provider_id="",
18+
target="",
19+
container_uri=container_uri,
20+
input_data_format="",
21+
output_data_format="",
22+
)
23+
return Job(workspace=workspace, job_details=job_details)
24+
25+
26+
@patch("azure.quantum.job.base_job.ContainerClient")
27+
def test_list_attachments_returns_container_blobs(mock_container_client):
28+
job = _job_with_container()
29+
30+
blob_a = Mock()
31+
blob_b = Mock()
32+
container = mock_container_client.from_container_url.return_value
33+
container.list_blobs.return_value = [blob_a, blob_b]
34+
35+
result = job.list_attachments()
36+
37+
mock_container_client.from_container_url.assert_called_once_with(CONTAINER_URI)
38+
assert result == [blob_a, blob_b]
39+
40+
41+
@patch("azure.quantum.job.base_job.ContainerClient")
42+
def test_list_attachments_uses_workspace_container_when_unset(mock_container_client):
43+
workspace = Mock()
44+
workspace.get_container_uri.return_value = CONTAINER_URI
45+
job = _job_with_container(container_uri=None, workspace=workspace)
46+
47+
container = mock_container_client.from_container_url.return_value
48+
container.list_blobs.return_value = []
49+
50+
result = job.list_attachments()
51+
52+
workspace.get_container_uri.assert_called_once_with(job_id="job-id")
53+
mock_container_client.from_container_url.assert_called_once_with(CONTAINER_URI)
54+
assert result == []

0 commit comments

Comments
 (0)