diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index cf221371b..a3a20b495 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -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( @@ -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() @@ -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." diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index f7a9ec91b..683ef2a6c 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -118,6 +118,8 @@ class QiskitRuntimeService(Provider): canceling job. """ + global_service = None + def __init__( self, channel: Optional[ChannelType] = None, @@ -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) @@ -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. diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index a540602d9..913247999 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -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 diff --git a/releasenotes/notes/global_service-ad56a0209e7b9891.yaml b/releasenotes/notes/global_service-ad56a0209e7b9891.yaml new file mode 100644 index 000000000..c0f657edc --- /dev/null +++ b/releasenotes/notes/global_service-ad56a0209e7b9891.yaml @@ -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") diff --git a/test/unit/test_ibm_primitives.py b/test/unit/test_ibm_primitives.py index 1564e2a1d..634491460 100644 --- a/test/unit/test_ibm_primitives.py +++ b/test/unit/test_ibm_primitives.py @@ -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) @@ -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) @@ -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) diff --git a/test/unit/test_session.py b/test/unit/test_session.py index c4ba5c1b5..446caacc4 100644 --- a/test/unit/test_session.py +++ b/test/unit/test_session.py @@ -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() @@ -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() @@ -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")