Skip to content

Commit

Permalink
Use service defined by user as default (#955)
Browse files Browse the repository at this point in the history
* Adding global service

* Added tests for global service

* Fixed failing tests

* black

* Syntax changes

* Restored test

* Fixed tests that were failing. mock_service.global_service must be initialized for it to work correctly

* Fixed test and added another case to a test

* Fix in test

* Release note

---------

Co-authored-by: Kevin Tian <[email protected]>
  • Loading branch information
merav-aharoni and kt474 authored Aug 16, 2023
1 parent 3d8b9c9 commit ab01504
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 7 deletions.
18 changes: 15 additions & 3 deletions qiskit_ibm_runtime/base_primitive.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,11 @@ def __init__(
version="0.10.0",
remedy="Please pass it as the ``backend`` parameter instead.",
)
self._service = QiskitRuntimeService()
self._service = (
QiskitRuntimeService()
if QiskitRuntimeService.global_service is None
else QiskitRuntimeService.global_service
)
self._backend = self._service.backend(session)
elif isinstance(backend, Session):
issue_deprecation_msg(
Expand All @@ -123,7 +127,11 @@ def __init__(
self._service = backend.service
self._backend = backend
elif isinstance(backend, str):
self._service = QiskitRuntimeService()
self._service = (
QiskitRuntimeService()
if QiskitRuntimeService.global_service is None
else QiskitRuntimeService.global_service
)
self._backend = self._service.backend(backend)
elif get_cm_session():
self._session = get_cm_session()
Expand All @@ -132,7 +140,11 @@ def __init__(
name=self._session.backend(), instance=self._session._instance
)
else:
self._service = QiskitRuntimeService()
self._service = (
QiskitRuntimeService()
if QiskitRuntimeService.global_service is None
else QiskitRuntimeService.global_service
)
if self._service.channel != "ibm_cloud":
raise ValueError(
"A backend or session must be specified when not using ibm_cloud channel."
Expand Down
4 changes: 4 additions & 0 deletions qiskit_ibm_runtime/qiskit_runtime_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ class QiskitRuntimeService(Provider):
canceling job.
"""

global_service = None

def __init__(
self,
channel: Optional[ChannelType] = None,
Expand Down Expand Up @@ -199,6 +201,7 @@ def __init__(
self._api_client = RuntimeClient(self._client_params)
# TODO: We can make the backend discovery lazy
self._backends = self._discover_cloud_backends()
QiskitRuntimeService.global_service = self
return
else:
auth_client = self._authenticate_ibm_quantum_account(self._client_params)
Expand All @@ -211,6 +214,7 @@ def __init__(
for backend_name in hgp.backends:
if backend_name not in self._backends:
self._backends[backend_name] = None
QiskitRuntimeService.global_service = self

# TODO - it'd be nice to allow some kind of autocomplete, but `service.ibmq_foo`
# just seems wrong since backends are not runtime service instances.
Expand Down
12 changes: 9 additions & 3 deletions qiskit_ibm_runtime/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,15 @@ def __init__(
"""

if service is None:
self._service = (
backend.service if isinstance(backend, IBMBackend) else QiskitRuntimeService()
)
if isinstance(backend, IBMBackend):
self._service = backend.service
else:
self._service = (
QiskitRuntimeService()
if QiskitRuntimeService.global_service is None
else QiskitRuntimeService.global_service
)

else:
self._service = service

Expand Down
11 changes: 11 additions & 0 deletions releasenotes/notes/global_service-ad56a0209e7b9891.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
features:
- |
Added a ``global_service``, so that if the user defines a `QiskitRuntimeService`, it will
be used by the primitives, even if the service is not passed to them explicitly.
For example::
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler
service = QiskitRuntimeService(channel="ibm_quantum")
# Sampler._service field will be initialized to ``service``
sampler = Sampler(backend="ibmq_qasm_simulator")
3 changes: 3 additions & 0 deletions test/unit/test_ibm_primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ def test_init_with_backend_str(self):
mock_service.return_value = mock_service_inst
mock_backend = MagicMock()
mock_backend.name = backend_name
mock_service.global_service = None
mock_service_inst.backend.return_value = mock_backend

inst = cls(backend=backend_name)
Expand All @@ -176,6 +177,7 @@ def test_init_with_session_backend_str(self):
) as mock_service:
with self.assertWarns(DeprecationWarning):
mock_service.reset_mock()
mock_service.global_service = None
inst = cls(session=backend_name)
mock_service.assert_called_once()
self.assertIsNone(inst.session)
Expand Down Expand Up @@ -230,6 +232,7 @@ def test_init_with_no_backend_session_cloud(self):
mock_service_inst.channel = "ibm_cloud"
mock_service.return_value = mock_service_inst
mock_service.reset_mock()
mock_service.global_service = None
inst = cls()
mock_service.assert_called_once()
self.assertIsNone(inst.session)
Expand Down
18 changes: 17 additions & 1 deletion test/unit/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
from qiskit_ibm_runtime.ibm_backend import IBMBackend
from qiskit_ibm_runtime.exceptions import IBMInputValueError
import qiskit_ibm_runtime.session as session_pkg
from .mock.fake_runtime_service import FakeRuntimeService
from ..ibm_test_case import IBMTestCase


class TestSession(IBMTestCase):
"""Class for testing the Session classession."""
"""Class for testing the Session class."""

def tearDown(self) -> None:
super().tearDown()
Expand All @@ -31,6 +32,7 @@ def tearDown(self) -> None:
@patch("qiskit_ibm_runtime.session.QiskitRuntimeService", autospec=True)
def test_default_service(self, mock_service):
"""Test using default service."""
mock_service.global_service = None
session = Session(backend="ibm_gotham")
self.assertIsNotNone(session.service)
mock_service.assert_called_once()
Expand Down Expand Up @@ -147,3 +149,17 @@ def test_default_backend(self):
session = Session(service=service)
session.run(program_id="foo", inputs={})
self.assertEqual(session.backend(), "ibm_gotham")

def test_global_service(self):
"""Test that global service is used in Session"""
_ = FakeRuntimeService(channel="ibm_quantum", token="abc")
session = Session(backend="ibmq_qasm_simulator")
self.assertTrue(isinstance(session._service, FakeRuntimeService))
self.assertEqual(session._service._account.token, "abc")
_ = FakeRuntimeService(channel="ibm_quantum", token="xyz")
session = Session(backend="ibmq_qasm_simulator")
self.assertEqual(session._service._account.token, "xyz")
with Session(
service=FakeRuntimeService(channel="ibm_quantum", token="uvw"), backend="ibm_gotham"
) as session:
self.assertEqual(session._service._account.token, "uvw")

0 comments on commit ab01504

Please sign in to comment.