-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[QI2-1081] Implemented job result fetching
- Loading branch information
1 parent
1059296
commit 1c6424f
Showing
5 changed files
with
218 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,15 @@ | ||
{ | ||
"python.analysis.extraPaths": [ | ||
"qiskit_quantuminspire" | ||
] | ||
} | ||
], | ||
"editor.codeActionsOnSave": {}, | ||
"editor.formatOnSave": true, | ||
"black-formatter.path": [ | ||
"${command:python.interpreterPath}" | ||
], | ||
"python.testing.unittestEnabled": false, | ||
"python.testing.pytestEnabled": true, | ||
"python.testing.pytestPath": "${command:python.interpreterPath}", | ||
"python.testing.autoTestDiscoverOnSaveEnabled": true, | ||
"python.testing.cwd": "${workspaceFolder}", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import asyncio | ||
from unittest.mock import AsyncMock, MagicMock | ||
|
||
import pytest | ||
from pytest_mock import MockerFixture | ||
from qiskit.providers.jobstatus import JobStatus | ||
|
||
from qiskit_quantuminspire.qi_jobs import QIJob | ||
|
||
|
||
def test_result(mocker: MockerFixture): | ||
job = QIJob(run_input="", backend=None, job_id="some-id") | ||
|
||
mocker.patch.object(job, "status", return_value=JobStatus.DONE) | ||
|
||
mock_fetch_job_results = AsyncMock(return_value=[MagicMock()]) | ||
mocker.patch.object(job, "_fetch_job_results", mock_fetch_job_results) | ||
|
||
mock_process = mocker.patch( | ||
"qiskit_quantuminspire.qi_jobs.QIResult.process", | ||
return_value=MagicMock(), | ||
) | ||
|
||
job.result() | ||
|
||
assert mock_fetch_job_results.called | ||
mock_process.assert_called_once() | ||
|
||
|
||
def test_result_raises_error_when_status_not_done(mocker: MockerFixture): | ||
job = QIJob(run_input="", backend=None, job_id="some-id") | ||
|
||
mocker.patch.object(job, "status", return_value=JobStatus.RUNNING) | ||
|
||
with pytest.raises(RuntimeError): | ||
job.result() | ||
|
||
|
||
def test_fetch_job_result(mocker: MockerFixture): | ||
|
||
mocker.patch( | ||
"qiskit_quantuminspire.qi_jobs.config", | ||
return_value=MagicMock(), | ||
) | ||
mocker.patch( | ||
"qiskit_quantuminspire.qi_jobs.ApiClient", | ||
autospec=True, | ||
) | ||
n_jobs = 3 | ||
|
||
mock_results_api = MagicMock() | ||
mock_get_result_by_id = AsyncMock() | ||
mock_get_result_by_id.side_effect = [MagicMock() for _ in range(n_jobs)] | ||
mock_results_api.read_results_by_job_id_results_job_job_id_get = mock_get_result_by_id | ||
|
||
mock_results_api = mocker.patch("qiskit_quantuminspire.qi_jobs.ResultsApi", return_value=mock_results_api) | ||
|
||
job = QIJob(run_input="", backend=None, job_id="some-id") | ||
|
||
job._job_ids = [str(i) for i in range(n_jobs)] | ||
|
||
results = asyncio.run(job._fetch_job_results()) | ||
|
||
assert len(results) == n_jobs | ||
assert mock_get_result_by_id.call_count == n_jobs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
from datetime import datetime, timezone | ||
|
||
import pytest | ||
from compute_api_client import BackendStatus, BackendType, Metadata, Result as JobResult | ||
from qiskit.result.models import ExperimentResult, ExperimentResultData | ||
from qiskit.result.result import Result | ||
|
||
from qiskit_quantuminspire.qi_backend import QIBackend | ||
from qiskit_quantuminspire.qi_jobs import QIJob | ||
from qiskit_quantuminspire.qi_results import QIResult | ||
|
||
|
||
@pytest.fixture | ||
def qi_backend() -> QIBackend: | ||
backend_type = BackendType( | ||
id=1, | ||
name="Spin 2", | ||
infrastructure="Hetzner", | ||
description="Silicon spin quantum computer", | ||
image_id="abcd1234", | ||
is_hardware=True, | ||
features=["multiple_measurements"], | ||
default_compiler_config={}, | ||
native_gateset={"single_qubit_gates": ["X"]}, | ||
status=BackendStatus.IDLE, | ||
default_number_of_shots=1024, | ||
max_number_of_shots=2048, | ||
) | ||
|
||
metadata = Metadata(id=1, backend_id=1, created_on=datetime.now(timezone.utc), data={"nqubits": 6}) | ||
return QIBackend(backend_type=backend_type, metadata=metadata) | ||
|
||
|
||
@pytest.fixture | ||
def qi_job(qi_backend: QIBackend) -> QIJob: | ||
return QIJob(run_input="", backend=qi_backend, job_id="some-id") | ||
|
||
|
||
def test_process(qi_job: QIJob): | ||
qi_job._job_ids = ["1"] # The jobs in the batch job | ||
qi_job.job_id = "100" # The batch job ID | ||
raw_results = [] | ||
for _id in qi_job._job_ids: | ||
raw_results.append( | ||
JobResult( | ||
id=int(_id), | ||
metadata_id=1, | ||
created_on=datetime(2022, 10, 25, 15, 37, 54, 269823, tzinfo=timezone.utc), | ||
execution_time_in_seconds=1.23, | ||
shots_requested=100, | ||
shots_done=100, | ||
results={ | ||
"0000000000": 256, | ||
"0000000001": 256, | ||
"0000000010": 256, | ||
"0000000011": 256, | ||
}, | ||
job_id=int(qi_job.job_id), | ||
) | ||
) | ||
processed_results = QIResult(raw_results).process(qi_job) | ||
expected_results = Result( | ||
backend_name="Spin 2", | ||
backend_version="1.0.0", | ||
qobj_id="1234", | ||
job_id="100", | ||
success=True, | ||
results=[ | ||
ExperimentResult( | ||
shots=100, | ||
success=True, | ||
meas_level=2, | ||
data=ExperimentResultData(counts={"0x0": 256, "0x1": 256, "0x2": 256, "0x3": 256}), | ||
) | ||
], | ||
date=None, | ||
status=None, | ||
header=None, | ||
) | ||
assert processed_results.to_dict() == expected_results.to_dict() | ||
|
||
|
||
def test_process_handles_failed_job(qi_job: QIJob): | ||
qi_job._job_ids = ["1"] # The jobs in the batch job | ||
qi_job.job_id = "100" # The batch job ID | ||
raw_results = [Exception("Bad Result")] | ||
|
||
processed_results = QIResult(raw_results).process(qi_job) | ||
expected_results = Result( | ||
backend_name="Spin 2", | ||
backend_version="1.0.0", | ||
qobj_id="1234", | ||
job_id="100", | ||
success=False, | ||
results=[ | ||
ExperimentResult( | ||
shots=0, | ||
success=False, | ||
meas_level=2, | ||
data=ExperimentResultData(counts={}), | ||
) | ||
], | ||
date=None, | ||
status=None, | ||
header=None, | ||
) | ||
assert processed_results.to_dict() == expected_results.to_dict() |