Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 151 additions & 24 deletions test/registries.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,28 @@ def from_(
)


@dataclass
class Job:
"""Registry representation of a job."""

id: str
"""Job id."""

backend_name: str
"""Backend name."""

program: Literal["sampler", "estimator"] = "sampler"

status: Literal["queued", "running", "completed", "cancelled", "failed"] = "completed"
"""Job status."""

raw_details: str | None = None
"""Response for the job details."""

raw_results: str | None = None
"""Response for the job results."""


class BaseRegistry(FirstMatchRegistry):
"""Registry that dynamically serves IBM Quantum Compute responses.

Expand All @@ -141,13 +163,17 @@ class BaseRegistry(FirstMatchRegistry):
"""Instances in this registry, keyed by instance name."""

backends: dict[str, dict[str, Backend]]
"""Backends in this registry, keyed by instance name."""
"""Backends in this registry, keyed by instance name and backend name."""

jobs: dict[str, dict[str, Job]]
"""Jobs in this registry, keyed by instance name and job id."""

def __init__(self) -> None:
super().__init__()

self.instances = {}
self.backends = defaultdict(dict)
self.jobs = defaultdict(dict)

# Add callbacks for IBM Global Search and Global Catalog.
self.add(
Expand Down Expand Up @@ -201,7 +227,7 @@ def __init__(self) -> None:
)
)

# Add responses for the IBM Quantum Compute `/instances` endpoint.
# Add responses for the IBM Quantum Compute `/instances` endpoints.
self.add(
Response(
method=GET,
Expand All @@ -215,7 +241,28 @@ def __init__(self) -> None:
CallbackResponse(
method=POST,
url="https://my-region.quantum.cloud.ibm.com/api/v1/jobs",
callback=self.callback_jobs,
callback=self.callback_jobs_post,
),
)
self.add(
CallbackResponse(
method=GET,
url="https://my-region.quantum.cloud.ibm.com/api/v1/jobs",
callback=self.callback_jobs_get,
),
)
self.add(
CallbackResponse(
method=GET,
url=re.compile(r"https://my-region.quantum.cloud.ibm.com/api/v1/jobs/\w+"),
callback=self.callback_jobs_id,
),
)
self.add(
CallbackResponse(
method=GET,
url=re.compile(r"https://my-region.quantum.cloud.ibm.com/api/v1/jobs/\w+/results"),
callback=self.callback_jobs_results,
),
)

Expand All @@ -232,6 +279,10 @@ def add_backend(self, backend: Backend, instance: str | None = None) -> None:
for name in instances:
self.backends[name][backend.name] = backend

def add_job(self, job: Job, instance: str) -> None:
"""Add a new job to the registry."""
self.jobs[instance][job.id] = job

def callback_global_search(self, _: PreparedRequest) -> CallbackResult:
"""Callback for the IBM Cloud Global Search API.

Expand Down Expand Up @@ -281,10 +332,7 @@ def callback_backends(self, request: PreparedRequest) -> CallbackResult:
https://quantum.cloud.ibm.com/docs/en/api/qiskit-runtime-rest/tags/backends
"""
# Validate the instance CRN.
instance_crn = request.headers.get("Service-CRN")
instance = next(
instance for instance in self.instances.values() if instance.crn == instance_crn
)
instance = self.get_crn_from_request(request)
if instance.name not in self.backends:
return (404, {"Content-Type": "application/json"}, "{}")

Expand All @@ -309,10 +357,7 @@ def callback_backends_configuration(self, request: PreparedRequest) -> CallbackR
https://quantum.cloud.ibm.com/docs/en/api/qiskit-runtime-rest/tags/backends
"""
# Validate the instance CRN and backend name.
instance_crn = request.headers.get("Service-CRN")
instance = next(
instance for instance in self.instances.values() if instance.crn == instance_crn
)
instance = self.get_crn_from_request(request)
backend_name = request.path_url.split("/")[4]
if instance.name not in self.backends or backend_name not in self.backends[instance.name]:
return (404, {"Content-Type": "application/json"}, "{}")
Expand All @@ -329,10 +374,7 @@ def callback_backends_properties(self, request: PreparedRequest) -> CallbackResu
https://quantum.cloud.ibm.com/docs/en/api/qiskit-runtime-rest/tags/backends
"""
# Validate the instance CRN and backend name.
instance_crn = request.headers.get("Service-CRN")
instance = next(
instance for instance in self.instances.values() if instance.crn == instance_crn
)
instance = self.get_crn_from_request(request)
backend_name = request.path_url.split("/")[4]
if instance.name not in self.backends or backend_name not in self.backends[instance.name]:
return (404, {"Content-Type": "application/json"}, "{}")
Expand All @@ -349,10 +391,7 @@ def callback_backends_status(self, request: PreparedRequest) -> CallbackResult:
https://quantum.cloud.ibm.com/docs/en/api/qiskit-runtime-rest/tags/backends
"""
# Validate the instance CRN and backend name.
instance_crn = request.headers.get("Service-CRN")
instance = next(
instance for instance in self.instances.values() if instance.crn == instance_crn
)
instance = self.get_crn_from_request(request)
backend_name = request.path_url.split("/")[4]
if instance.name not in self.backends or backend_name not in self.backends[instance.name]:
return (404, {"Content-Type": "application/json"}, "{}")
Expand All @@ -366,7 +405,7 @@ def callback_backends_status(self, request: PreparedRequest) -> CallbackResult:
}
return (200, {"Content-Type": "application/json"}, json.dumps(response_body))

def callback_jobs(self, request: PreparedRequest) -> CallbackResult:
def callback_jobs_post(self, request: PreparedRequest) -> CallbackResult:
"""Callback for the IBM Quantum Compute API ``/jobs`` endpoint.

Dynamically return a job, based on the contents of `self.backends`.
Expand All @@ -375,10 +414,7 @@ def callback_jobs(self, request: PreparedRequest) -> CallbackResult:
https://quantum.cloud.ibm.com/docs/en/api/qiskit-runtime-rest/tags/jobs
"""
# Validate the instance CRN and backend name.
instance_crn = request.headers.get("Service-CRN")
instance = next(
instance for instance in self.instances.values() if instance.crn == instance_crn
)
instance = self.get_crn_from_request(request)
backend_name = json.loads(str(request.body))["backend"]

if instance.name not in self.backends or backend_name not in self.backends[instance.name]:
Expand All @@ -390,6 +426,97 @@ def callback_jobs(self, request: PreparedRequest) -> CallbackResult:
}
return (200, {"Content-Type": "application/json"}, json.dumps(response_body))

def callback_jobs_get(self, request: PreparedRequest) -> CallbackResult:
"""Callback for the IBM Quantum Compute API ``/jobs`` endpoint.

Dynamically return a list of job, based on the contents of `self.jobs`.

References:
https://quantum.cloud.ibm.com/docs/en/api/qiskit-runtime-rest/tags/jobs
"""
# Validate the instance CRN.
instance = self.get_crn_from_request(request)
if instance.name not in self.backends:
return (404, {"Content-Type": "application/json"}, "{}")

jobs = [
{
"id": job.id,
"backend": job.backend_name,
"status": job.status.capitalize(),
"program": {"id": job.program},
}
for job in self.jobs[instance.name].values()
]

response_body = {
"jobs": jobs,
"count": len(jobs),
"limit": 20,
"offset": 0,
}
return (200, {"Content-Type": "application/json"}, json.dumps(response_body))

def callback_jobs_id(self, request: PreparedRequest) -> CallbackResult:
"""Callback for the IBM Quantum Compute API ``/jobs/{}`` endpoint.

Dynamically return a job, based on the contents of `self.jobs`.

References:
https://quantum.cloud.ibm.com/docs/en/api/qiskit-runtime-rest/tags/jobs
"""
# Validate the instance CRN and backend name.
instance = self.get_crn_from_request(request)
job_id = request.path_url.split("/")[-1].split("?")[0]

if instance.name not in self.backends or job_id not in self.jobs[instance.name]:
return (404, {"Content-Type": "application/json"}, "{}")

job = self.jobs[instance.name][job_id]

if job.raw_details:
response_body = job.raw_details
else:
response_body = json.dumps(
{
"id": job.id,
"backend": job.backend_name,
"status": job.status.capitalize(),
"program": {"id": job.program},
}
)
return (200, {"Content-Type": "application/json"}, response_body)

def callback_jobs_results(self, request: PreparedRequest) -> CallbackResult:
"""Callback for the IBM Quantum Compute API ``/jobs/{}/results`` endpoint.

Dynamically return a job results, based on the contents of `self.jobs`.

References:
https://quantum.cloud.ibm.com/docs/en/api/qiskit-runtime-rest/tags/jobs
"""
# Validate the instance CRN and backend name.
instance = self.get_crn_from_request(request)
job_id = request.path_url.split("/")[-2].split("?")[0]

if instance.name not in self.backends or job_id not in self.jobs[instance.name]:
return (404, {"Content-Type": "application/json"}, "{}")

job = self.jobs[instance.name][job_id]

if job.raw_results:
response_body = job.raw_results
else:
response_body = json.dumps({})
return (200, {"Content-Type": "application/json"}, response_body)

def get_crn_from_request(self, request: PreparedRequest) -> Instance:
"""Retrieve the `Instance` from the request headers."""
instance_crn = request.headers.get("Service-CRN")
return next(
instance for instance in self.instances.values() if instance.crn == instance_crn
)


class DefaultRegistry(BaseRegistry):
"""Registry with two instances, with one common backend and two unique backends.
Expand Down
19 changes: 19 additions & 0 deletions test/unit/backwards_compatibility/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2026.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Tests for backwards compatibility.

Stored jobs:
* `d9qp8cvpemts73crjmsg` - circuit from
`test/integration/test_executor_sampler/TestSampler::test_sampler_with_parametric_circuits`
with no twirling, against `ibm_fez`, with version `0.49`.
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"backend":"ibm_fez","created":"2026-08-07T08:15:47.460045Z","id":"d9qp8cvpemts73crjmsg","cost":600,"program":{"id":"executor"},"state":{"status":"Completed"},"status":"Completed","user_id":"unknown"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"schema_version": "v2.0", "data": [{"results": {"meas": {"data": "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", "shape": [5, 4, 1000, 2], "dtype": "bool"}}, "metadata": {"scheduler_timing": null, "stretch_values": null}}, {"results": {"meas": {"data": "eJw9UkuOE0EMfeWuZNxRg4poNNLsPIFFC80iR6hBg5RlJC6A4AIcwcmwCBFCOUIzaw7RS47CkiPw3IkoRYrbn+fnZ+MR6BqIfgKgmhZAi4T3KLVPmIWvFnEUWHVhjivewIVlqEzke7DiEUgVkgSJsQ/JykeHZni+Yb01mnBLsOTYdiMIx0zCORK/aCUUo5HaDPMK2IgdkKcukTjLcranN7Z4YNBQU2B2yZgpukZOPme881Jr2mJCsPgZGuRTlWv4+lpj1oK+rpCtft/cKyyRSF41wBcOU22Ow4BxJy7z3BHbeoxwhxR51ZiwC2F16ccFzl1E9edAV/jf0cNxKvR2J98G7JWYz9VovSWZUOsPSAi/Y6C1LynIUXTAC6MyHdpfMm//YlkGPBGusKLYgmLNuxRiGNU76o9gwPqbupyRUU65D/AtDqqfc96Wl9zdo9md1nUs8ApuSlL32JMBTeIIyjyWeJhkik3I9KfR5hkpFrBmY+xjmc1Z/SZDZRSNxbSQ1xe/MI+ZfY2SkMWOZsHQz9h2RZsS1akFO36FTlpwwvNyLwP9f7ySBYR3wBvZbIDVxZ+I69oN0EXwDs2nCwwAJ+WnqXiPu4mQDc2IE4YT+n/chlGQ", "shape": [3, 1000, 2], "dtype": "bool"}}, "metadata": {"scheduler_timing": null, "stretch_values": null}}], "metadata": {"chunk_timing": [{"start": "2026-08-07T08:43:35.622741", "stop": "2026-08-07T08:43:42.687708", "parts": [{"idx_item": 0, "size": 20, "permutation": [0, 1], "element_range": [0, 20, 1]}, {"idx_item": 1, "size": 3, "permutation": [0], "element_range": [0, 3, 1]}]}]}, "passthrough_data": {"post_processor": {"circuits_metadata": [{"list": [1, 2, 3]}, {"tuple": [1, 2, 3]}], "meas_type": "classified", "shots": 1000, "twirling": false, "version": "v0.1"}}, "semantic_role": "sampler_v2"}
53 changes: 53 additions & 0 deletions test/unit/backwards_compatibility/test_load_jobs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2026.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Tests for backwards compatibility when loading jobs from earlier versions."""

from pathlib import Path

from qiskit.primitives import PrimitiveResult

from qiskit_ibm_runtime.fake_provider import FakeFez
from qiskit_ibm_runtime.qiskit_runtime_service import QiskitRuntimeService

from ...decorators import mock_responses
from ...ibm_test_case import IBMTestCase
from ...registries import Backend, Job, OneInstanceNoBackendsRegistry


class SamplerTestCase(IBMTestCase):
"""Test for loading Sampler jobs from earlier versions."""

@mock_responses(OneInstanceNoBackendsRegistry)
def test_wrapper_sampler_jobs(self, registry: OneInstanceNoBackendsRegistry) -> None:
"""Test stored WrapperSampler jobs."""
job_id = "d9qp8cvpemts73crjmsg"

resources_path = Path(__file__).resolve().parent / "resources"
job_details = (resources_path / f"{job_id}_details.json").read_text(encoding="utf-8")
job_results = (resources_path / f"{job_id}_results.json").read_text(encoding="utf-8")

# Prepare the contents of the registry.
registry.add_backend(Backend.from_(FakeFez))
registry.add_job(
Job(job_id, "ibm_fez", raw_details=job_details, raw_results=job_results), "a"
)

service = QiskitRuntimeService(token="my_token")
job = service.job(job_id)
result = job.result()

# Job should be an executor (wrapped sampler) job.
self.assertEqual(job.primitive_id, "executor")
# Result should be loaded correctly
self.assertIsInstance(result, PrimitiveResult)
self.assertIsInstance(result.metadata, dict)
Loading
Loading