Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support downloading result from external url #709

Merged
merged 9 commits into from
Feb 28, 2023
25 changes: 24 additions & 1 deletion qiskit_ibm_runtime/runtime_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import traceback
import queue
from datetime import datetime
import requests

from qiskit.providers.backend import Backend
from qiskit.providers.jobstatus import JobStatus, JOB_FINAL_STATES
Expand Down Expand Up @@ -158,6 +159,21 @@ def __init__(
self.job_id = CallableStr(job_id)
self.backend = self._backend

def _download_external_result(self, response: Any) -> Any:
"""Download result from external URL.

Args:
response: Response to check for url keyword, if available, download result from given URL
"""
if "url" in response:
result_url_json = json.loads(response)
if "url" in result_url_json:
url = result_url_json["url"]
result_response = requests.get(url)
response = result_response.content

return response

def interim_results(self, decoder: Optional[Type[ResultDecoder]] = None) -> Any:
"""Return the interim results of the job.

Expand Down Expand Up @@ -208,7 +224,11 @@ def result( # pylint: disable=arguments-differ
raise RuntimeJobFailureError(
f"Unable to retrieve job result. " f"{error_message}"
)
result_raw = self._api_client.job_results(job_id=self.job_id())

result_raw = self._download_external_result(
self._api_client.job_results(job_id=self.job_id())
)

self._results = _decoder.decode(result_raw) if result_raw else None
return self._results

Expand Down Expand Up @@ -494,6 +514,9 @@ def _stream_results(
if response == self._POISON_PILL:
self._empty_result_queue(result_queue)
return

response = self._download_external_result(response)

user_callback(self.job_id(), _decoder.decode(response))
except Exception: # pylint: disable=broad-except
logger.warning(
Expand Down
20 changes: 19 additions & 1 deletion test/unit/test_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import random
import time
from unittest.mock import MagicMock
from unittest.mock import MagicMock, patch

from qiskit.providers.exceptions import QiskitBackendNotFoundError
from qiskit.providers.jobstatus import JobStatus
Expand Down Expand Up @@ -295,6 +295,24 @@ def test_job_id_attribute(self):
self.assertIsInstance(job.job_id, str)
self.assertEqual(job.job_id, "12345")

@run_quantum_and_cloud_fake
def test_download_external_job_result(self, service):
"""Test downloading the job result from an external URL."""
with patch("qiskit_ibm_runtime.runtime_job.requests") as request_mock:
job = run_program(service=service)
with mock_wait_for_final_state(service, job):
mock_response = MagicMock()
mock_response.content = "content-from-external-url"
request_mock.get.return_value = mock_response
with mock_wait_for_final_state(service, job):
job.wait_for_final_state()
job._api_client.job_results = MagicMock(
return_value='{"url": "https://external-url.com/"}'
)
result = job.result()

self.assertEqual(result, "content-from-external-url")

def test_job_backend_attribute(self):
"""Test using backend as an attribute still works."""
backend = MagicMock(spec=IBMBackend)
Expand Down