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 c68bcc823..17c3d0649 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -22,12 +22,13 @@ from qiskit.providers.backend import BackendV1, BackendV2 from qiskit_ibm_runtime import QiskitRuntimeService +from .exceptions import IBMInputValueError from .runtime_job import RuntimeJob from .runtime_job_v2 import RuntimeJobV2 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 @@ -286,6 +287,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. usage_time: The usage time, in seconds, of this Session or Batch. Usage is defined as the time a quantum system is committed to complete a job. """ @@ -305,6 +307,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"), "usage_time": response.get("elapsed_time"), } return None @@ -332,7 +335,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,15 +342,34 @@ 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. + If ``None``, ``QiskitRuntimeService()`` is used to initialize your default saved account. + + Raises: + IBMInputValueError: If given `session_id` does not exist. Returns: A new Session with the given ``session_id`` """ - if backend: - deprecate_arguments("backend", "0.15.0", "Sessions do not support multiple backends.") + 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.23.0 ." + ), + DeprecationWarning, + stacklevel=2, + ) + service = QiskitRuntimeService() + + response = service._api_client.session_details(session_id) + backend = response.get("backend_name") + mode = response.get("mode") + class_name = "dedicated" if cls.__name__.lower() == "session" else cls.__name__.lower() + if mode != class_name: + raise IBMInputValueError( + f"Input ID {session_id} has execution mode {mode} instead of {class_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..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(backend=backend, session_id=session_id) - 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..9dcd2a089 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": "dedicated", "backend_name": "common_backend"} + 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..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 = MagicMock() + 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={})