From d1c30abb08bb2574705efb44539a3186260f82d3 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Wed, 8 Nov 2023 15:56:39 +0000 Subject: [PATCH 1/7] Added test for backend.run and Sampler.run in a single session --- test/integration/test_session.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/integration/test_session.py b/test/integration/test_session.py index 6b7d77c5d..3a7285ec7 100644 --- a/test/integration/test_session.py +++ b/test/integration/test_session.py @@ -127,6 +127,23 @@ def test_backend_run_with_session(self): result.get_counts()["00"], result.get_counts()["11"], delta=shots / 10 ) + def test_backend_and_primitive_in_session(self): + """Test Sampler.run and backend.run in the same session.""" + backend = self.service.get_backend("ibmq_qasm_simulator") + with Session(backend=backend) as session: + sampler = Sampler(session=session) + job1 = sampler.run(circuits=ReferenceCircuits.bell()) + job2 = backend.run(circuits=ReferenceCircuits.bell()) + self.assertEqual(job1.session_id, job1.job_id()) + self.assertIsNone(job2.session_id) + with backend.open_session() as session: + sampler = Sampler(backend=backend) + job1 = backend.run(ReferenceCircuits.bell()) + job2 = sampler.run(circuits=ReferenceCircuits.bell()) + session_id = session.session_id + self.assertEqual(session_id, job1.job_id()) + self.assertIsNone(job2.session_id) + def test_session_cancel(self): """Test closing a session""" backend = self.service.backend("ibmq_qasm_simulator") From ac39d190e15835a449ac3c5d5e2b8ceaed4ee00c Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Mon, 13 Nov 2023 12:05:19 +0000 Subject: [PATCH 2/7] Issue warning when Primitive is run within a backend session --- qiskit_ibm_runtime/base_primitive.py | 8 ++++++++ test/integration/test_session.py | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 4dd596e2a..2666afc4a 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -18,9 +18,12 @@ import copy import logging from dataclasses import asdict +import warnings from qiskit.providers.options import Options as TerraOptions +from qiskit_ibm_provider.session import get_cm_session as get_cm_provider_session + from .options import Options from .options.utils import set_default_error_levels from .runtime_job import RuntimeJob @@ -118,6 +121,11 @@ def __init__( raise ValueError( "A backend or session must be specified when not using ibm_cloud channel." ) + # Check if initialized within a IBMProvider session. If so, issue a warning. + if get_cm_provider_session(): + warnings.warn( + "IBMBackend session is open, but Primitives will not be run within an IBMBackend session" + ) def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJob: """Run the primitive. diff --git a/test/integration/test_session.py b/test/integration/test_session.py index 3a7285ec7..4837595ed 100644 --- a/test/integration/test_session.py +++ b/test/integration/test_session.py @@ -12,6 +12,8 @@ """Integration tests for Session.""" +import warnings + from qiskit.circuit.library import RealAmplitudes from qiskit.quantum_info import SparsePauliOp from qiskit.test.reference_circuits import ReferenceCircuits @@ -137,7 +139,12 @@ def test_backend_and_primitive_in_session(self): self.assertEqual(job1.session_id, job1.job_id()) self.assertIsNone(job2.session_id) with backend.open_session() as session: - sampler = Sampler(backend=backend) + with warnings.catch_warnings(record=True) as warn: + sampler = Sampler(backend=backend) + self.assertIn( + "Primitives will not be run within an IBMBackend session", + str(warn[0].message) + ) job1 = backend.run(ReferenceCircuits.bell()) job2 = sampler.run(circuits=ReferenceCircuits.bell()) session_id = session.session_id From f50cd85c19fe15003c6092e378295b253cbbf46c Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Mon, 13 Nov 2023 12:05:54 +0000 Subject: [PATCH 3/7] Fixed comment --- qiskit_ibm_runtime/base_primitive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 2666afc4a..6c952aa7b 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -121,7 +121,7 @@ def __init__( raise ValueError( "A backend or session must be specified when not using ibm_cloud channel." ) - # Check if initialized within a IBMProvider session. If so, issue a warning. + # Check if initialized within a IBMBackend session. If so, issue a warning. if get_cm_provider_session(): warnings.warn( "IBMBackend session is open, but Primitives will not be run within an IBMBackend session" From 18fdc51d2d36dcbb70c04eaf78c680a720919819 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Mon, 13 Nov 2023 12:16:27 +0000 Subject: [PATCH 4/7] black --- test/integration/test_session.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/integration/test_session.py b/test/integration/test_session.py index 4837595ed..320cdd4df 100644 --- a/test/integration/test_session.py +++ b/test/integration/test_session.py @@ -142,8 +142,7 @@ def test_backend_and_primitive_in_session(self): with warnings.catch_warnings(record=True) as warn: sampler = Sampler(backend=backend) self.assertIn( - "Primitives will not be run within an IBMBackend session", - str(warn[0].message) + "Primitives will not be run within an IBMBackend session", str(warn[0].message) ) job1 = backend.run(ReferenceCircuits.bell()) job2 = sampler.run(circuits=ReferenceCircuits.bell()) From fb0566001bb449baa956d212075466528c26b818 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Mon, 13 Nov 2023 17:10:16 +0000 Subject: [PATCH 5/7] Added warning for when a backend is run in a primitive session and vice versa. --- qiskit_ibm_runtime/base_primitive.py | 2 +- qiskit_ibm_runtime/ibm_backend.py | 6 ++++ qiskit_ibm_runtime/session.py | 18 +---------- qiskit_ibm_runtime/utils/default_session.py | 34 +++++++++++++++++++++ test/integration/test_session.py | 6 +++- 5 files changed, 47 insertions(+), 19 deletions(-) create mode 100644 qiskit_ibm_runtime/utils/default_session.py diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 6c952aa7b..7c51ac7d0 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -28,7 +28,7 @@ from .options.utils import set_default_error_levels from .runtime_job import RuntimeJob from .ibm_backend import IBMBackend -from .session import get_cm_session +from .utils.default_session import get_cm_session from .constants import DEFAULT_DECODERS from .qiskit_runtime_service import QiskitRuntimeService diff --git a/qiskit_ibm_runtime/ibm_backend.py b/qiskit_ibm_runtime/ibm_backend.py index 3c472c0bf..ddf5851c6 100644 --- a/qiskit_ibm_runtime/ibm_backend.py +++ b/qiskit_ibm_runtime/ibm_backend.py @@ -65,6 +65,7 @@ from .utils.backend_converter import ( convert_to_target, ) +from .utils.default_session import get_cm_session as get_cm_primitive_session logger = logging.getLogger(__name__) @@ -751,6 +752,11 @@ def _runtime_run( if self._service._channel == "ibm_quantum": hgp_name = self._instance or self._service._get_hgp().name + # Check if initialized within a Primitive session. If so, issue a warning. + if get_cm_primitive_session(): + warnings.warn( + "Primitive session is open, but IBMBackend will not be run within a Primitive session" + ) if self._session: if not self._session.active: raise RuntimeError(f"The session {self._session.session_id} is closed.") diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index 36f7a0f62..b5f322639 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -15,7 +15,6 @@ from typing import Dict, Optional, Type, Union, Callable, Any from types import TracebackType from functools import wraps -from contextvars import ContextVar from qiskit_ibm_provider.utils.converters import hms_to_seconds @@ -24,6 +23,7 @@ from .runtime_program import ParameterNamespace from .program.result_decoder import ResultDecoder from .ibm_backend import IBMBackend +from .utils.default_session import set_cm_session def _active_session(func): # type: ignore @@ -314,19 +314,3 @@ def __exit__( ) -> None: set_cm_session(None) self.close() - - -# Default session -_DEFAULT_SESSION: ContextVar[Optional[Session]] = ContextVar("_DEFAULT_SESSION", default=None) -_IN_SESSION_CM: ContextVar[bool] = ContextVar("_IN_SESSION_CM", default=False) - - -def set_cm_session(session: Optional[Session]) -> None: - """Set the context manager session.""" - _DEFAULT_SESSION.set(session) - _IN_SESSION_CM.set(session is not None) - - -def get_cm_session() -> Session: - """Return the context managed session.""" - return _DEFAULT_SESSION.get() diff --git a/qiskit_ibm_runtime/utils/default_session.py b/qiskit_ibm_runtime/utils/default_session.py new file mode 100644 index 000000000..5049a65fb --- /dev/null +++ b/qiskit_ibm_runtime/utils/default_session.py @@ -0,0 +1,34 @@ +# This code is part of Qiskit. +# +# (C) Copyright IBM 2023. +# +# 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. + +"""Methods for checking if we are inside a Session context manager""" + +from contextvars import ContextVar +from typing import Optional, TYPE_CHECKING + +if TYPE_CHECKING: + from .session import Session + +# Default session +_DEFAULT_SESSION: ContextVar[Optional["Session"]] = ContextVar("_DEFAULT_SESSION", default=None) +_IN_SESSION_CM: ContextVar[bool] = ContextVar("_IN_SESSION_CM", default=False) + + +def set_cm_session(session: Optional["Session"]) -> None: + """Set the context manager session.""" + _DEFAULT_SESSION.set(session) + _IN_SESSION_CM.set(session is not None) + + +def get_cm_session() -> "Session": + """Return the context managed session.""" + return _DEFAULT_SESSION.get() diff --git a/test/integration/test_session.py b/test/integration/test_session.py index 320cdd4df..033726e75 100644 --- a/test/integration/test_session.py +++ b/test/integration/test_session.py @@ -135,7 +135,11 @@ def test_backend_and_primitive_in_session(self): with Session(backend=backend) as session: sampler = Sampler(session=session) job1 = sampler.run(circuits=ReferenceCircuits.bell()) - job2 = backend.run(circuits=ReferenceCircuits.bell()) + with warnings.catch_warnings(record=True) as warn: + job2 = backend.run(circuits=ReferenceCircuits.bell()) + self.assertIn( + "IBMBackend will not be run within a Primitive session", str(warn[0].message) + ) self.assertEqual(job1.session_id, job1.job_id()) self.assertIsNone(job2.session_id) with backend.open_session() as session: From 598eb266ab84f5ced6ddc2e81e0e7da1427ab755 Mon Sep 17 00:00:00 2001 From: merav-aharoni Date: Mon, 13 Nov 2023 17:21:21 +0000 Subject: [PATCH 6/7] Fixed imports from default_session --- test/unit/test_batch.py | 5 +++-- test/unit/test_ibm_primitives.py | 4 ++-- test/unit/test_session.py | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/unit/test_batch.py b/test/unit/test_batch.py index a27eca479..3b54b1094 100644 --- a/test/unit/test_batch.py +++ b/test/unit/test_batch.py @@ -15,7 +15,8 @@ from unittest.mock import patch from qiskit_ibm_runtime import Batch -import qiskit_ibm_runtime.session as session_pkg +from qiskit_ibm_runtime.utils.default_session import _DEFAULT_SESSION + from ..ibm_test_case import IBMTestCase @@ -24,7 +25,7 @@ class TestBatch(IBMTestCase): def tearDown(self) -> None: super().tearDown() - session_pkg._DEFAULT_SESSION.set(None) + _DEFAULT_SESSION.set(None) @patch("qiskit_ibm_runtime.session.QiskitRuntimeService", autospec=True) def test_default_batch(self, mock_service): diff --git a/test/unit/test_ibm_primitives.py b/test/unit/test_ibm_primitives.py index 9314e2a15..5e1e643c3 100644 --- a/test/unit/test_ibm_primitives.py +++ b/test/unit/test_ibm_primitives.py @@ -32,7 +32,7 @@ Session, ) from qiskit_ibm_runtime.ibm_backend import IBMBackend -import qiskit_ibm_runtime.session as session_pkg +from qiskit_ibm_runtime.utils.default_session import _DEFAULT_SESSION from ..ibm_test_case import IBMTestCase from ..utils import ( @@ -61,7 +61,7 @@ def setUpClass(cls): def tearDown(self) -> None: super().tearDown() - session_pkg._DEFAULT_SESSION.set(None) + _DEFAULT_SESSION.set(None) def test_dict_options(self): """Test passing a dictionary as options.""" diff --git a/test/unit/test_session.py b/test/unit/test_session.py index 9ac349c3f..f796f4b40 100644 --- a/test/unit/test_session.py +++ b/test/unit/test_session.py @@ -16,7 +16,7 @@ from qiskit_ibm_runtime import Session from qiskit_ibm_runtime.ibm_backend import IBMBackend -import qiskit_ibm_runtime.session as session_pkg +from qiskit_ibm_runtime.utils.default_session import _DEFAULT_SESSION from .mock.fake_runtime_service import FakeRuntimeService from ..ibm_test_case import IBMTestCase @@ -26,7 +26,7 @@ class TestSession(IBMTestCase): def tearDown(self) -> None: super().tearDown() - session_pkg._DEFAULT_SESSION.set(None) + _DEFAULT_SESSION.set(None) @patch("qiskit_ibm_runtime.session.QiskitRuntimeService", autospec=True) def test_default_service(self, mock_service): From 7fcbdf5412b0db7a308594ec9fabfde59204434b Mon Sep 17 00:00:00 2001 From: kevin-tian Date: Tue, 14 Nov 2023 14:19:07 -0500 Subject: [PATCH 7/7] minor wording change --- qiskit_ibm_runtime/base_primitive.py | 2 +- qiskit_ibm_runtime/ibm_backend.py | 2 +- test/integration/test_session.py | 10 ++-------- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/qiskit_ibm_runtime/base_primitive.py b/qiskit_ibm_runtime/base_primitive.py index 7c51ac7d0..13c759584 100644 --- a/qiskit_ibm_runtime/base_primitive.py +++ b/qiskit_ibm_runtime/base_primitive.py @@ -124,7 +124,7 @@ def __init__( # Check if initialized within a IBMBackend session. If so, issue a warning. if get_cm_provider_session(): warnings.warn( - "IBMBackend session is open, but Primitives will not be run within an IBMBackend session" + "A Backend.run() session is open but Primitives will not be run within this session" ) def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJob: diff --git a/qiskit_ibm_runtime/ibm_backend.py b/qiskit_ibm_runtime/ibm_backend.py index 5556a6879..1fb60dbd6 100644 --- a/qiskit_ibm_runtime/ibm_backend.py +++ b/qiskit_ibm_runtime/ibm_backend.py @@ -755,7 +755,7 @@ def _runtime_run( # Check if initialized within a Primitive session. If so, issue a warning. if get_cm_primitive_session(): warnings.warn( - "Primitive session is open, but IBMBackend will not be run within a Primitive session" + "A Primitive session is open but Backend.run() jobs will not be run within this session" ) if self._session: if not self._session.active: diff --git a/test/integration/test_session.py b/test/integration/test_session.py index be0387b35..b8c086a59 100644 --- a/test/integration/test_session.py +++ b/test/integration/test_session.py @@ -135,19 +135,13 @@ def test_backend_and_primitive_in_session(self): with Session(backend=backend) as session: sampler = Sampler(session=session) job1 = sampler.run(circuits=ReferenceCircuits.bell()) - with warnings.catch_warnings(record=True) as warn: + with warnings.catch_warnings(record=True): job2 = backend.run(circuits=ReferenceCircuits.bell()) - self.assertIn( - "IBMBackend will not be run within a Primitive session", str(warn[0].message) - ) self.assertEqual(job1.session_id, job1.job_id()) self.assertIsNone(job2.session_id) with backend.open_session() as session: - with warnings.catch_warnings(record=True) as warn: + with warnings.catch_warnings(record=True): sampler = Sampler(backend=backend) - self.assertIn( - "Primitives will not be run within an IBMBackend session", str(warn[0].message) - ) job1 = backend.run(ReferenceCircuits.bell()) job2 = sampler.run(circuits=ReferenceCircuits.bell()) session_id = session.session_id