From aadceb033dde7bb66d4ac74ad3cc1f29c4f8d962 Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Wed, 10 Jan 2024 13:36:20 -0500 Subject: [PATCH 1/8] Update from_id() --- qiskit_ibm_runtime/session.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index 5647f5a44..96ac4047b 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -20,6 +20,7 @@ from qiskit_ibm_provider.utils.converters import hms_to_seconds from qiskit_ibm_runtime import QiskitRuntimeService +from .exceptions import IBMInputValueError from .runtime_job import RuntimeJob from .utils.result_decoder import ResultDecoder from .ibm_backend import IBMBackend @@ -304,12 +305,33 @@ def from_id( backend: instance of :class:`qiskit_ibm_runtime.IBMBackend` class or string name of backend. + Raises: + IBMInputValueError: If given `session_id` does not exist. or the backend passed in does + not match the original session backend. + Returns: A new Session with the given ``session_id`` """ if backend: deprecate_arguments("backend", "0.15.0", "Sessions do not support multiple backends.") + if isinstance(backend, IBMBackend): + backend = backend.name + + if service: + response = service._api_client.session_details(session_id) + if response: + session_backend = response.get("backend_name") + if backend and backend != session_backend: + raise IBMInputValueError( + f"The session_id {session_id} was created with backend {session_backend}, " + f"but backend {backend} was given." + ) + backend = session_backend + else: + raise IBMInputValueError(f"The session_id {session_id} does not exist.") + if not service and not backend: + raise IBMInputValueError("Either service or backend must be given.") session = cls(service, backend) session._session_id = session_id From 82aebd5fa9cdf269af607e9f147190cdc92b9bf4 Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Mon, 22 Jan 2024 00:41:03 -0500 Subject: [PATCH 2/8] update docstring --- qiskit_ibm_runtime/session.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index 96ac4047b..cd64dc88c 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -302,8 +302,8 @@ def from_id( session_id: the id of the session to be created. This must be an already existing session id. service: instance of the ``QiskitRuntimeService`` class. - backend: instance of :class:`qiskit_ibm_runtime.IBMBackend` class or - string name of backend. + backend (DEPRECATED): instance of :class:`qiskit_ibm_runtime.IBMBackend` class or + string name of backend. Either ``service`` or ``backend`` must be given. Raises: IBMInputValueError: If given `session_id` does not exist. or the backend passed in does From 101363dd52e8b3711a3e400a8be45ef39c9bfd06 Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Tue, 27 Feb 2024 14:01:02 -0500 Subject: [PATCH 3/8] add service warning deprecation --- qiskit_ibm_runtime/session.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index dc5cb91ba..3a7cada68 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -12,6 +12,7 @@ """Qiskit Runtime flexible session.""" +import warnings from typing import Dict, Optional, Type, Union, Callable, Any from types import TracebackType from functools import wraps @@ -321,7 +322,9 @@ def from_id( """ if backend: - deprecate_arguments("backend", "0.15.0", "Sessions do not support multiple backends.") + deprecate_arguments( + "backend", "0.15.0", "The backend used to open the session will be used." + ) if isinstance(backend, IBMBackend): backend = backend.name @@ -337,6 +340,15 @@ def from_id( backend = session_backend else: raise IBMInputValueError(f"The session_id {session_id} does not exist.") + else: + warnings.warn( + ( + "The `service` parameter will be required in a future release no sooner than " + "3 months after the release of qiskit-ibm-runtime 0.21.0 ." + ), + DeprecationWarning, + stacklevel=2, + ) if not service and not backend: raise IBMInputValueError("Either service or backend must be given.") From 14d240ea3b148f41bd00d8dee987758025519aa4 Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Fri, 1 Mar 2024 21:23:06 -0500 Subject: [PATCH 4/8] add mode to session details --- qiskit_ibm_runtime/session.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index d0cbf386a..1a02787d1 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -265,6 +265,7 @@ def details(self) -> Optional[Dict[str, Any]]: started_at: Timestamp of when the session was started. closed_at: Timestamp of when the session was closed. activated_at: Timestamp of when the session state was changed to active. + mode: Execution mode of the session """ if self._session_id: response = self._service._api_client.session_details(self._session_id) @@ -282,6 +283,7 @@ def details(self) -> Optional[Dict[str, Any]]: "started_at": response.get("started_at"), "closed_at": response.get("closed_at"), "activated_at": response.get("activated_at"), + "mode": response.get("mode"), } return None From 97553ed4817a30afbb65d97efbe1b3cd0ca5ba29 Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Fri, 5 Apr 2024 16:13:41 -0400 Subject: [PATCH 5/8] address comments --- .../api/rest/runtime_session.py | 6 +-- qiskit_ibm_runtime/session.py | 39 ++++++------------- test/integration/test_session.py | 2 +- 3 files changed, 14 insertions(+), 33 deletions(-) diff --git a/qiskit_ibm_runtime/api/rest/runtime_session.py b/qiskit_ibm_runtime/api/rest/runtime_session.py index 87f66c076..7a585b54e 100644 --- a/qiskit_ibm_runtime/api/rest/runtime_session.py +++ b/qiskit_ibm_runtime/api/rest/runtime_session.py @@ -83,8 +83,4 @@ def close(self) -> None: def details(self) -> Dict[str, Any]: """Return the details of this session.""" - try: - return self.session.get(self.get_url("self")).json() - # return None if API is not supported - except: # pylint: disable=bare-except - return None + return self.session.get(self.get_url("self")).json() diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index 6fbe4f9d1..14f45b8f8 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -28,7 +28,7 @@ from .utils.result_decoder import ResultDecoder from .ibm_backend import IBMBackend from .utils.default_session import set_cm_session -from .utils.deprecation import deprecate_arguments, issue_deprecation_msg +from .utils.deprecation import issue_deprecation_msg from .utils.converters import hms_to_seconds from .fake_provider.local_service import QiskitRuntimeLocalService @@ -332,7 +332,6 @@ def from_id( cls, session_id: str, service: Optional[QiskitRuntimeService] = None, - backend: Optional[Union[str, IBMBackend]] = None, ) -> "Session": """Construct a Session object with a given session_id @@ -340,8 +339,6 @@ def from_id( session_id: the id of the session to be created. This must be an already existing session id. service: instance of the ``QiskitRuntimeService`` class. - backend (DEPRECATED): instance of :class:`qiskit_ibm_runtime.IBMBackend` class or - string name of backend. Either ``service`` or ``backend`` must be given. Raises: IBMInputValueError: If given `session_id` does not exist. or the backend passed in does @@ -351,36 +348,24 @@ def from_id( A new Session with the given ``session_id`` """ - if backend: - deprecate_arguments( - "backend", "0.15.0", "The backend used to open the session will be used." - ) - if isinstance(backend, IBMBackend): - backend = backend.name - - if service: - response = service._api_client.session_details(session_id) - if response: - session_backend = response.get("backend_name") - if backend and backend != session_backend: - raise IBMInputValueError( - f"The session_id {session_id} was created with backend {session_backend}, " - f"but backend {backend} was given." - ) - backend = session_backend - else: - raise IBMInputValueError(f"The session_id {session_id} does not exist.") - else: + if not service: warnings.warn( ( "The `service` parameter will be required in a future release no sooner than " - "3 months after the release of qiskit-ibm-runtime 0.21.0 ." + "3 months after the release of qiskit-ibm-runtime 0.23.0 ." ), DeprecationWarning, stacklevel=2, ) - if not service and not backend: - raise IBMInputValueError("Either service or backend must be given.") + service = QiskitRuntimeService() + + response = service._api_client.session_details(session_id) + backend = response.get("backend_name") + mode = response.get("mode") + if mode != cls.__name__.lower(): + raise IBMInputValueError( + f"Session ID {session_id} has session mode {mode} instead of {cls.__name__}." + ) session = cls(service, backend) session._session_id = session_id diff --git a/test/integration/test_session.py b/test/integration/test_session.py index 03cd309f0..44f0e8326 100644 --- a/test/integration/test_session.py +++ b/test/integration/test_session.py @@ -100,7 +100,7 @@ def test_session_from_id(self, service): sampler = Sampler(session=session) job = sampler.run(bell(), shots=400) session_id = job.session_id - new_session = Session.from_id(backend=backend, session_id=session_id) + new_session = Session.from_id(session_id=session_id, service=service) sampler = Sampler(session=new_session) job = sampler.run(bell(), shots=400) self.assertEqual(session_id, job.session_id) From d607ac5d213e554d059f70e31dafd4f17704154e Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Mon, 8 Apr 2024 13:54:46 -0400 Subject: [PATCH 6/8] Update tests --- qiskit_ibm_runtime/session.py | 3 ++- test/integration/test_session.py | 24 ++++++++++++++++-------- test/unit/mock/fake_runtime_client.py | 4 ++++ test/unit/test_session.py | 2 +- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index b9c05b90a..650b9a778 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -365,7 +365,8 @@ def from_id( response = service._api_client.session_details(session_id) backend = response.get("backend_name") mode = response.get("mode") - if mode != cls.__name__.lower(): + class_name = "dedicated" if cls.__name__.lower() == "session" else cls.__name__.lower() + if mode != class_name: raise IBMInputValueError( f"Session ID {session_id} has session mode {mode} instead of {cls.__name__}." ) diff --git a/test/integration/test_session.py b/test/integration/test_session.py index 44f0e8326..b911eca03 100644 --- a/test/integration/test_session.py +++ b/test/integration/test_session.py @@ -13,6 +13,7 @@ """Integration tests for Session.""" import warnings +from unittest import SkipTest from qiskit.circuit.library import RealAmplitudes from qiskit.quantum_info import SparsePauliOp @@ -21,7 +22,8 @@ from qiskit.result import Result from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager -from qiskit_ibm_runtime import Estimator, Session, Sampler, Options +from qiskit_ibm_runtime import Estimator, Session, Sampler, Options, Batch +from qiskit_ibm_runtime.exceptions import IBMInputValueError from ..utils import bell from ..decorators import run_integration_test, quantum_only @@ -95,15 +97,21 @@ def test_using_correct_instance(self, service): @run_integration_test def test_session_from_id(self, service): """Test creating a session from a given id""" - backend = service.backend("ibmq_qasm_simulator") + try: + backend = service.backend("fake_backend1") + except: + raise SkipTest("No proper backends available") + pm = generate_preset_pass_manager(backend=backend, optimization_level=1) + isa_circuit = pm.run(bell()) with Session(service, backend=backend) as session: sampler = Sampler(session=session) - job = sampler.run(bell(), shots=400) - session_id = job.session_id - new_session = Session.from_id(session_id=session_id, service=service) - sampler = Sampler(session=new_session) - job = sampler.run(bell(), shots=400) - self.assertEqual(session_id, job.session_id) + sampler.run(isa_circuit) + + new_session = Session.from_id(session_id=session._session_id, service=service) + self.assertEqual(session._session_id, new_session._session_id) + + with self.assertRaises(IBMInputValueError): + Batch.from_id(session_id=session._session_id, service=service) class TestBackendRunInSession(IBMIntegrationTestCase): diff --git a/test/unit/mock/fake_runtime_client.py b/test/unit/mock/fake_runtime_client.py index a977597a7..362b096d7 100644 --- a/test/unit/mock/fake_runtime_client.py +++ b/test/unit/mock/fake_runtime_client.py @@ -478,6 +478,10 @@ def close_session(self, session_id: str) -> None: raise ValueError(f"Session {session_id} not found.") self._sessions.remove(session_id) + def session_details(self, session_id: str) -> dict[str, Any]: + """Return the details of the session.""" + return {"id": session_id, "mode": "session"} + def _find_backend(self, backend_name): for back in self._backends: if back.name == backend_name: diff --git a/test/unit/test_session.py b/test/unit/test_session.py index b0ae0211d..63d461d87 100644 --- a/test/unit/test_session.py +++ b/test/unit/test_session.py @@ -161,7 +161,7 @@ def test_global_service(self): def test_session_from_id(self): """Create session with given session_id""" - service = MagicMock() + service = FakeRuntimeService() session_id = "123" session = Session.from_id(session_id=session_id, service=service) session.run(program_id="foo", inputs={}) From 992f26c31a3e79ef24f53516f56bf3207e35517f Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Mon, 8 Apr 2024 14:06:48 -0400 Subject: [PATCH 7/8] Address docstring comments --- qiskit_ibm_runtime/session.py | 6 +++--- test/unit/mock/fake_runtime_client.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index 650b9a778..17c3d0649 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -342,10 +342,10 @@ def from_id( session_id: the id of the session to be created. This must be an already existing session id. service: instance of the ``QiskitRuntimeService`` class. + If ``None``, ``QiskitRuntimeService()`` is used to initialize your default saved account. Raises: - IBMInputValueError: If given `session_id` does not exist. or the backend passed in does - not match the original session backend. + IBMInputValueError: If given `session_id` does not exist. Returns: A new Session with the given ``session_id`` @@ -368,7 +368,7 @@ def from_id( class_name = "dedicated" if cls.__name__.lower() == "session" else cls.__name__.lower() if mode != class_name: raise IBMInputValueError( - f"Session ID {session_id} has session mode {mode} instead of {cls.__name__}." + f"Input ID {session_id} has execution mode {mode} instead of {class_name}." ) session = cls(service, backend) diff --git a/test/unit/mock/fake_runtime_client.py b/test/unit/mock/fake_runtime_client.py index 362b096d7..e0704fb9c 100644 --- a/test/unit/mock/fake_runtime_client.py +++ b/test/unit/mock/fake_runtime_client.py @@ -478,7 +478,7 @@ def close_session(self, session_id: str) -> None: raise ValueError(f"Session {session_id} not found.") self._sessions.remove(session_id) - def session_details(self, session_id: str) -> dict[str, Any]: + def session_details(self, session_id: str) -> Dict[str, Any]: """Return the details of the session.""" return {"id": session_id, "mode": "session"} From b4eafa220ab2f558c5a8ffd891ae11b82bc7aa99 Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Mon, 8 Apr 2024 18:18:43 -0400 Subject: [PATCH 8/8] update unit test --- test/unit/mock/fake_runtime_client.py | 2 +- test/unit/test_session.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/mock/fake_runtime_client.py b/test/unit/mock/fake_runtime_client.py index e0704fb9c..9dcd2a089 100644 --- a/test/unit/mock/fake_runtime_client.py +++ b/test/unit/mock/fake_runtime_client.py @@ -480,7 +480,7 @@ def close_session(self, session_id: str) -> None: def session_details(self, session_id: str) -> Dict[str, Any]: """Return the details of the session.""" - return {"id": session_id, "mode": "session"} + return {"id": session_id, "mode": "dedicated", "backend_name": "common_backend"} def _find_backend(self, backend_name): for back in self._backends: diff --git a/test/unit/test_session.py b/test/unit/test_session.py index 63d461d87..930ec89a6 100644 --- a/test/unit/test_session.py +++ b/test/unit/test_session.py @@ -161,7 +161,7 @@ def test_global_service(self): def test_session_from_id(self): """Create session with given session_id""" - service = FakeRuntimeService() + service = FakeRuntimeService(channel="ibm_quantum", token="abc") session_id = "123" session = Session.from_id(session_id=session_id, service=service) session.run(program_id="foo", inputs={})