From b84b2d5111ba5816640e2dc6be9f781b52934f76 Mon Sep 17 00:00:00 2001 From: ElePT Date: Tue, 19 Aug 2025 11:51:33 +0200 Subject: [PATCH 1/7] - remove ibm_quantum from list of allowed client channels - change default channel to ibm_quantum_platform - update unit and integration tests to include instance (mandatory with cloud channels) --- .../core/clients/serverless_client.py | 10 ++--- client/requirements.txt | 2 +- .../tests/core/test_ibm_serverless_client.py | 40 +++---------------- client/tests/core/test_job.py | 8 +++- tests/basic/01_running_program.py | 1 + tests/basic/02_arguments_and_results.py | 1 + tests/basic/03_dependencies.py | 1 + tests/basic/04_distributed_workloads.py | 1 + tests/basic/05_retrieving_past_results.py | 1 + tests/basic/06_function.py | 1 + tests/docker/conftest.py | 1 + 11 files changed, 25 insertions(+), 42 deletions(-) diff --git a/client/qiskit_serverless/core/clients/serverless_client.py b/client/qiskit_serverless/core/clients/serverless_client.py index 921ab9fa7..389ec8367 100644 --- a/client/qiskit_serverless/core/clients/serverless_client.py +++ b/client/qiskit_serverless/core/clients/serverless_client.py @@ -100,7 +100,7 @@ def __init__( # pylint: disable=too-many-positional-arguments version: Optional[str] = None, token: Optional[str] = None, instance: Optional[str] = None, - channel: str = Channel.IBM_QUANTUM.value, + channel: str = Channel.IBM_QUANTUM_PLATFORM.value, ): """ Initializes the ServerlessClient instance. @@ -133,7 +133,7 @@ def __init__( # pylint: disable=too-many-positional-arguments except ValueError as error: raise ValueError( "Your channel value is not correct. Use one of the available channels: " - f"{Channel.LOCAL.value}, {Channel.IBM_QUANTUM.value}, " + f"{Channel.LOCAL.value}, " f"{Channel.IBM_CLOUD.value}, {Channel.IBM_QUANTUM_PLATFORM.value}" ) from error @@ -587,7 +587,7 @@ def __init__( token: Optional[str] = None, name: Optional[str] = None, instance: Optional[str] = None, - channel: str = Channel.IBM_QUANTUM.value, + channel: str = Channel.IBM_QUANTUM_PLATFORM.value, ): """ Initialize a client with access to an IBMQ-provided remote cluster. @@ -648,7 +648,7 @@ def _discover_account( except ValueError as error: raise ValueError( "Your channel value is not correct. Use one of the available channels: " - f"{Channel.LOCAL.value}, {Channel.IBM_QUANTUM.value}, " + f"{Channel.LOCAL.value}, " f"{Channel.IBM_CLOUD.value}, {Channel.IBM_QUANTUM_PLATFORM.value}" ) from error @@ -688,7 +688,7 @@ def save_account( name: Optional[str] = None, overwrite: Optional[bool] = False, instance: Optional[str] = None, - channel: str = Channel.IBM_QUANTUM.value, + channel: str = Channel.IBM_QUANTUM_PLATFORM.value, ) -> None: """ Save the account to disk for future use. diff --git a/client/requirements.txt b/client/requirements.txt index a12a1fdda..911586916 100644 --- a/client/requirements.txt +++ b/client/requirements.txt @@ -2,7 +2,7 @@ ray[default]>=2.30, <3 requests>=2.32.2, <3 importlib-metadata>=5.2.0, <9 qiskit[qpy-compat]>=1.4, <3 -qiskit-ibm-runtime~=0.40.1 +qiskit-ibm-runtime>=0.41.0 # Make sure ray node and notebook node have the same version of cloudpickle cloudpickle==2.2.1 tqdm>=4.66.3, <5 diff --git a/client/tests/core/test_ibm_serverless_client.py b/client/tests/core/test_ibm_serverless_client.py index 28f21c373..25f466338 100644 --- a/client/tests/core/test_ibm_serverless_client.py +++ b/client/tests/core/test_ibm_serverless_client.py @@ -16,9 +16,10 @@ import tempfile from unittest.mock import patch +from qiskit_ibm_runtime.accounts.exceptions import InvalidAccountError + from qiskit_serverless import IBMServerlessClient from qiskit_serverless.core.enums import Channel -from qiskit_serverless.exception import QiskitServerlessException class TestIBMServerlessClient(unittest.TestCase): @@ -39,7 +40,6 @@ def test_save_load_account(self, mock_file_path, mock_verify_credentials): mock_file_path.return_value = temp_file.name channels_to_test = [ - Channel.IBM_QUANTUM.value, Channel.IBM_CLOUD.value, Channel.IBM_QUANTUM_PLATFORM.value, ] @@ -64,43 +64,15 @@ def test_save_load_account(self, mock_file_path, mock_verify_credentials): self.assertEqual(client.account.token, use_token) self.assertEqual(client.account.instance, use_instance) - @patch("qiskit_ibm_runtime.accounts.management._DEFAULT_ACCOUNT_CONFIG_JSON_FILE") - def test_save_wrong_instance(self, mock_file_path): - """Test saving with wrong instance format (ibm_quantum channel).""" - - # Save config in a temporary file - with tempfile.NamedTemporaryFile() as temp_file: - mock_file_path.return_value = temp_file.name - - use_channel = Channel.IBM_QUANTUM.value - use_instance = "wrong_ibm_quantum_instance" - use_token = "save_token" - use_name = f"test_save_account_{uuid.uuid4().hex}" - - with self.assertRaisesRegex( - QiskitServerlessException, - r"Invalid format in account inputs - 'Invalid `instance` value\. " - "Expected hub/group/project format, got wrong_ibm_quantum_instance'", - ): - - IBMServerlessClient.save_account( - token=use_token, - name=use_name, - instance=use_instance, - channel=use_channel, - ) - - def test_init_wrong_instance(self): - """Test initializing account with wrong instance format (ibm_quantum channel).""" + def test_ibm_quantum_channel(self): + """Test error raised when initializing account with `ibm_quantum` channel.""" use_channel = Channel.IBM_QUANTUM.value - use_instance = "wrong_ibm_quantum_instance" + use_instance = "h/g/p" use_token = "save_token" with self.assertRaisesRegex( - QiskitServerlessException, - r"Invalid format in account inputs - 'Invalid `instance` value\. " - "Expected hub/group/project format, got wrong_ibm_quantum_instance'", + InvalidAccountError, r"Invalid `channel` value.*got 'ibm_quantum'" ): IBMServerlessClient( diff --git a/client/tests/core/test_job.py b/client/tests/core/test_job.py index d78a64a98..10208bc64 100644 --- a/client/tests/core/test_job.py +++ b/client/tests/core/test_job.py @@ -91,7 +91,9 @@ def test_update_sub_status(self, job_env_variables): @patch("requests.get", Mock(return_value=ResponseMock())) def test_filtered_logs(self): """Tests job filtered log.""" - client = ServerlessClient(host="host", token="token", version="version") + client = ServerlessClient( + host="host", token="token", instance="crn", version="version" + ) client.logs = MagicMock( return_value="This is the line 1\nThis is the second line\nOK. This is the last line.\n", # pylint: disable=line-too-long ) @@ -108,7 +110,9 @@ def test_filtered_logs(self): @patch("requests.get", Mock(return_value=ResponseMock())) def test_error_message(self): """Tests job filtered log.""" - client = ServerlessClient(host="host", token="token", version="version") + client = ServerlessClient( + host="host", token="token", instance="crn", version="version" + ) client.status = MagicMock( return_value="ERROR", ) diff --git a/tests/basic/01_running_program.py b/tests/basic/01_running_program.py index e48301e44..49f34889a 100644 --- a/tests/basic/01_running_program.py +++ b/tests/basic/01_running_program.py @@ -7,6 +7,7 @@ serverless = ServerlessClient( token=os.environ.get("GATEWAY_TOKEN", "awesome_token"), host=os.environ.get("GATEWAY_HOST", "http://localhost:8000"), + instance=os.environ.get("GATEWAY_INSTANCE", "an_awesome_crn"), ) print(serverless) diff --git a/tests/basic/02_arguments_and_results.py b/tests/basic/02_arguments_and_results.py index 383a7cdd3..d279faec4 100644 --- a/tests/basic/02_arguments_and_results.py +++ b/tests/basic/02_arguments_and_results.py @@ -14,6 +14,7 @@ serverless = ServerlessClient( token=os.environ.get("GATEWAY_TOKEN", "awesome_token"), host=os.environ.get("GATEWAY_HOST", "http://localhost:8000"), + instance=os.environ.get("GATEWAY_INSTANCE", "an_awesome_crn"), ) print(serverless) diff --git a/tests/basic/03_dependencies.py b/tests/basic/03_dependencies.py index 1666440cf..a44b0d5e6 100644 --- a/tests/basic/03_dependencies.py +++ b/tests/basic/03_dependencies.py @@ -15,6 +15,7 @@ serverless = ServerlessClient( token=os.environ.get("GATEWAY_TOKEN", "awesome_token"), host=os.environ.get("GATEWAY_HOST", "http://localhost:8000"), + instance=os.environ.get("GATEWAY_INSTANCE", "an_awesome_crn"), ) print(serverless) diff --git a/tests/basic/04_distributed_workloads.py b/tests/basic/04_distributed_workloads.py index 910f1e744..001809757 100644 --- a/tests/basic/04_distributed_workloads.py +++ b/tests/basic/04_distributed_workloads.py @@ -6,6 +6,7 @@ serverless = ServerlessClient( token=os.environ.get("GATEWAY_TOKEN", "awesome_token"), host=os.environ.get("GATEWAY_HOST", "http://localhost:8000"), + instance=os.environ.get("GATEWAY_INSTANCE", "an_awesome_crn"), ) print(serverless) diff --git a/tests/basic/05_retrieving_past_results.py b/tests/basic/05_retrieving_past_results.py index 9401ee023..adb2a027d 100644 --- a/tests/basic/05_retrieving_past_results.py +++ b/tests/basic/05_retrieving_past_results.py @@ -6,6 +6,7 @@ serverless = ServerlessClient( token=os.environ.get("GATEWAY_TOKEN", "awesome_token"), host=os.environ.get("GATEWAY_HOST", "http://localhost:8000"), + instance=os.environ.get("GATEWAY_INSTANCE", "an_awesome_crn"), ) print(serverless) diff --git a/tests/basic/06_function.py b/tests/basic/06_function.py index 1481f2d07..14e228d53 100644 --- a/tests/basic/06_function.py +++ b/tests/basic/06_function.py @@ -4,6 +4,7 @@ serverless = ServerlessClient( token=os.environ.get("GATEWAY_TOKEN", "awesome_token"), host=os.environ.get("GATEWAY_HOST", "http://localhost:8000"), + instance=os.environ.get("GATEWAY_INSTANCE", "an_awesome_crn"), ) help = """ diff --git a/tests/docker/conftest.py b/tests/docker/conftest.py index fda2e3492..6b3ae4971 100644 --- a/tests/docker/conftest.py +++ b/tests/docker/conftest.py @@ -44,6 +44,7 @@ def set_up_serverless_client(): serverless = ServerlessClient( token=os.environ.get("GATEWAY_TOKEN", "awesome_token"), host=os.environ.get("GATEWAY_HOST", connection_url), + instance=os.environ.get("GATEWAY_INSTANCE", "an_awesome_crn"), ) # Initialize serverless folder for current user From e8705051396ddadb520eb671f82edc679f5bfb62 Mon Sep 17 00:00:00 2001 From: ElePT Date: Tue, 26 Aug 2025 14:23:00 +0200 Subject: [PATCH 2/7] Fix experimental tests --- tests/experimental/file_download.py | 1 + tests/experimental/manage_data_directory.py | 1 + tests/experimental/running_programs_using_decorators.py | 1 + 3 files changed, 3 insertions(+) diff --git a/tests/experimental/file_download.py b/tests/experimental/file_download.py index 658740577..290fae3f2 100644 --- a/tests/experimental/file_download.py +++ b/tests/experimental/file_download.py @@ -6,6 +6,7 @@ serverless = ServerlessClient( token=os.environ.get("GATEWAY_TOKEN", "awesome_token"), host=os.environ.get("GATEWAY_HOST", "http://localhost:8000"), + instance=os.environ.get("GATEWAY_INSTANCE", "an_awesome_crn"), ) print(serverless) diff --git a/tests/experimental/manage_data_directory.py b/tests/experimental/manage_data_directory.py index 9abbf563d..75ecd4e4a 100644 --- a/tests/experimental/manage_data_directory.py +++ b/tests/experimental/manage_data_directory.py @@ -6,6 +6,7 @@ serverless = ServerlessClient( token=os.environ.get("GATEWAY_TOKEN", "awesome_token"), host=os.environ.get("GATEWAY_HOST", "http://localhost:8000"), + instance=os.environ.get("GATEWAY_INSTANCE", "an_awesome_crn"), ) print(serverless) diff --git a/tests/experimental/running_programs_using_decorators.py b/tests/experimental/running_programs_using_decorators.py index b831df49f..4f4f5651f 100644 --- a/tests/experimental/running_programs_using_decorators.py +++ b/tests/experimental/running_programs_using_decorators.py @@ -16,6 +16,7 @@ provider = ServerlessClient( token=os.environ.get("GATEWAY_TOKEN", "awesome_token"), host=os.environ.get("GATEWAY_HOST", "http://localhost:8000"), + instance=os.environ.get("GATEWAY_INSTANCE", "an_awesome_crn"), ) print(provider) From 73ff472524d6c2c5db81953eb32f221d425d3c99 Mon Sep 17 00:00:00 2001 From: ElePT Date: Thu, 28 Aug 2025 16:16:44 +0200 Subject: [PATCH 3/7] Remove IBM_QUANTUM from channel enum --- client/qiskit_serverless/core/enums.py | 1 - client/tests/core/test_ibm_serverless_client.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/client/qiskit_serverless/core/enums.py b/client/qiskit_serverless/core/enums.py index d8bfad352..8b1d355ae 100644 --- a/client/qiskit_serverless/core/enums.py +++ b/client/qiskit_serverless/core/enums.py @@ -10,6 +10,5 @@ class Channel(str, Enum): """ LOCAL = "local" - IBM_QUANTUM = "ibm_quantum" IBM_CLOUD = "ibm_cloud" IBM_QUANTUM_PLATFORM = "ibm_quantum_platform" diff --git a/client/tests/core/test_ibm_serverless_client.py b/client/tests/core/test_ibm_serverless_client.py index 25f466338..8b1209510 100644 --- a/client/tests/core/test_ibm_serverless_client.py +++ b/client/tests/core/test_ibm_serverless_client.py @@ -67,7 +67,7 @@ def test_save_load_account(self, mock_file_path, mock_verify_credentials): def test_ibm_quantum_channel(self): """Test error raised when initializing account with `ibm_quantum` channel.""" - use_channel = Channel.IBM_QUANTUM.value + use_channel = "ibm_quantum" use_instance = "h/g/p" use_token = "save_token" From 74619e8e4ccd9828593ee94c883932aedcb98349 Mon Sep 17 00:00:00 2001 From: ElePT Date: Thu, 28 Aug 2025 16:21:55 +0200 Subject: [PATCH 4/7] Update requirements pin --- client/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/requirements.txt b/client/requirements.txt index 431959829..783308c78 100644 --- a/client/requirements.txt +++ b/client/requirements.txt @@ -2,7 +2,7 @@ ray[default]>=2.30, <3 requests>=2.32.2, <3 importlib-metadata>=5.2.0, <9 qiskit[qpy-compat]>=1.4, <3 -qiskit-ibm-runtime>=0.41.0 +qiskit-ibm-runtime>=0.40.1, <1 # Make sure ray node and notebook node have the same version of cloudpickle cloudpickle==2.2.1 tqdm>=4.66.3, <5 From 0ad4da0044aeefde161a185765c5630c42c866ff Mon Sep 17 00:00:00 2001 From: ElePT Date: Thu, 28 Aug 2025 16:39:55 +0200 Subject: [PATCH 5/7] Address test --- client/tests/core/test_ibm_serverless_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/tests/core/test_ibm_serverless_client.py b/client/tests/core/test_ibm_serverless_client.py index 8b1209510..328cb34ee 100644 --- a/client/tests/core/test_ibm_serverless_client.py +++ b/client/tests/core/test_ibm_serverless_client.py @@ -72,7 +72,7 @@ def test_ibm_quantum_channel(self): use_token = "save_token" with self.assertRaisesRegex( - InvalidAccountError, r"Invalid `channel` value.*got 'ibm_quantum'" + ValueError, r"Your channel value is not correct" ): IBMServerlessClient( From 61f2e6cbbcb77a16471853ad3defb469e4df6cd2 Mon Sep 17 00:00:00 2001 From: ElePT Date: Thu, 28 Aug 2025 16:42:16 +0200 Subject: [PATCH 6/7] Fix black --- client/tests/core/test_ibm_serverless_client.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/tests/core/test_ibm_serverless_client.py b/client/tests/core/test_ibm_serverless_client.py index 328cb34ee..151b0c6e0 100644 --- a/client/tests/core/test_ibm_serverless_client.py +++ b/client/tests/core/test_ibm_serverless_client.py @@ -71,9 +71,7 @@ def test_ibm_quantum_channel(self): use_instance = "h/g/p" use_token = "save_token" - with self.assertRaisesRegex( - ValueError, r"Your channel value is not correct" - ): + with self.assertRaisesRegex(ValueError, r"Your channel value is not correct"): IBMServerlessClient( channel=use_channel, instance=use_instance, token=use_token From d83fcf26f17e367c617191eedc355949728417a0 Mon Sep 17 00:00:00 2001 From: ElePT Date: Thu, 28 Aug 2025 16:44:42 +0200 Subject: [PATCH 7/7] Fix lint --- client/tests/core/test_ibm_serverless_client.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/tests/core/test_ibm_serverless_client.py b/client/tests/core/test_ibm_serverless_client.py index 151b0c6e0..99cd75798 100644 --- a/client/tests/core/test_ibm_serverless_client.py +++ b/client/tests/core/test_ibm_serverless_client.py @@ -16,8 +16,6 @@ import tempfile from unittest.mock import patch -from qiskit_ibm_runtime.accounts.exceptions import InvalidAccountError - from qiskit_serverless import IBMServerlessClient from qiskit_serverless.core.enums import Channel