diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4ceeebd92..ae7bc92d46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -111,7 +111,7 @@ jobs: matrix: python-version: [ 3.9 ] os: [ "ubuntu-latest" ] - environment: [ "legacy-production", "cloud-production" ] + environment: [ "ibm-quantum-production", "ibm-cloud-production" ] environment: ${{ matrix.environment }} env: QISKIT_IBM_TOKEN: ${{ secrets.QISKIT_IBM_TOKEN }} diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 42d8158dd6..1b057caf1a 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -26,7 +26,7 @@ jobs: matrix: python-version: [ 3.9 ] os: [ "ubuntu-latest" ] - environment: [ "legacy-production", "legacy-staging", "cloud-production", "cloud-staging" ] + environment: [ "ibm-quantum-production", "ibm-quantum-staging", "ibm-cloud-production", "ibm-cloud-staging" ] environment: ${{ matrix.environment }} env: QISKIT_IBM_TOKEN: ${{ secrets.QISKIT_IBM_TOKEN }} diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index e282957cd3..2c24c98a26 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -26,7 +26,7 @@ jobs: matrix: python-version: [ 3.9 ] os: [ "ubuntu-latest" ] - environment: [ "legacy-production", "legacy-staging", "cloud-production", "cloud-staging" ] + environment: [ "ibm-quantum-production", "ibm-quantum-staging", "ibm-cloud-production", "ibm-cloud-staging" ] environment: ${{ matrix.environment }} env: QISKIT_IBM_TOKEN: ${{ secrets.QISKIT_IBM_TOKEN }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 645c398500..c9616d5142 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -227,7 +227,7 @@ $ make e2e-test #### Configuration -Integration and E2E tests require an environment configuration and can either be run against IBM Quantum APIs ("Legacy") or IBM Cloud Quantum Service APIs. +Integration and E2E tests require an environment configuration and can either be run against IBM Quantum APIs ("ibm_quantum") or IBM Cloud ("ibm_cloud") Quantum Service APIs. Sample configuration for IBM Quantum diff --git a/README.md b/README.md index 5f682d5065..dff68c7d17 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ IBM Cloud API key and Cloud Resource Name (CRN), which you will need for authent ### Qiskit Runtime on IBM Quantum Prior to becoming an IBM Cloud service, Qiskit Runtime was offered on IBM Quantum. If you have an -existing IBM Quantum account, you can continue using Qiskit Runtime on IBM Quantum, which is referred to as legacy runtime. +existing IBM Quantum account, you can continue using Qiskit Runtime on IBM Quantum. You will need your IBM Quantum API token to authenticate with the Qiskit Runtime service: @@ -65,10 +65,10 @@ them each time. The credentials are saved in the `$HOME/.qiskit/qiskit-ibm.json` from qiskit_ibm_runtime import IBMRuntimeService # Save an IBM Cloud account. -IBMRuntimeService.save_account(auth="cloud", token="MY_IBM_CLOUD_API_KEY", instance="MY_IBM_CLOUD_CRN") +IBMRuntimeService.save_account(channel="ibm_cloud", token="MY_IBM_CLOUD_API_KEY", instance="MY_IBM_CLOUD_CRN") # Save an IBM Quantum account. -IBMRuntimeService.save_account(auth="legacy", token="MY_IBM_QUANTUM_TOKEN") +IBMRuntimeService.save_account(channel="ibm_quantum", token="MY_IBM_QUANTUM_TOKEN") ``` Once the account is saved on disk, you can instantiate the service without any arguments: @@ -101,10 +101,10 @@ service with your credentials. from qiskit_ibm_runtime import IBMRuntimeService # For an IBM Cloud account. -cloud_service = IBMRuntimeService(auth="cloud", token="MY_IBM_CLOUD_API_KEY", instance="MY_IBM_CLOUD_CRN") +ibm_cloud_service = IBMRuntimeService(channel="ibm_cloud", token="MY_IBM_CLOUD_API_KEY", instance="MY_IBM_CLOUD_CRN") # For an IBM Quantum account. -legacy_service = IBMRuntimeService(auth="legacy", token="MY_IBM_QUANTUM_TOKEN") +ibm_quantum_service = IBMRuntimeService(channel="ibm_quantum", token="MY_IBM_QUANTUM_TOKEN") ``` ## Accessing Qiskit Runtime Programs diff --git a/constraints.txt b/constraints.txt index 15b72fd0bb..e69de29bb2 100644 --- a/constraints.txt +++ b/constraints.txt @@ -1,2 +0,0 @@ -# 3.1.0 is buggy -Jinja2!=3.1.0 \ No newline at end of file diff --git a/docs/max_time.rst b/docs/max_time.rst index 479b2390d7..cdfe5c515e 100644 --- a/docs/max_time.rst +++ b/docs/max_time.rst @@ -16,8 +16,8 @@ Qiskit Runtime on IBM Cloud The system limit on the job execution time is 3 hours for a job running on a simulator and 8 hours for a job running on a physical system. -Qiskit Runtime on IBM Quantum (legacy) --------------------------------------- +Qiskit Runtime on IBM Quantum +----------------------------- The system limit on the job execution time is diff --git a/docs/release_notes.rst b/docs/release_notes.rst index d02fe5fb6d..ec77acc34c 100644 --- a/docs/release_notes.rst +++ b/docs/release_notes.rst @@ -1,2 +1 @@ .. release-notes:: Release Notes - :version: 0.2.0, 0.1.0, 0.1.0rc2, 0.1.0rc1 diff --git a/docs/tutorials/01_introduction_cloud_runtime.ipynb b/docs/tutorials/01_introduction_ibm_cloud_runtime.ipynb similarity index 99% rename from docs/tutorials/01_introduction_cloud_runtime.ipynb rename to docs/tutorials/01_introduction_ibm_cloud_runtime.ipynb index f25142f580..3f6aada994 100644 --- a/docs/tutorials/01_introduction_cloud_runtime.ipynb +++ b/docs/tutorials/01_introduction_ibm_cloud_runtime.ipynb @@ -107,7 +107,7 @@ "from qiskit_ibm_runtime import IBMRuntimeService\n", "\n", "# Save account on disk.\n", - "# IBMRuntimeService.save_account(auth=\"cloud\", token=, instance= or )\n", + "# IBMRuntimeService.save_account(channel=\"ibm_cloud\", token=, instance= or )\n", "\n", "service = IBMRuntimeService()" ] @@ -689,11 +689,11 @@ "source": [ "There are additional tutorials in this directory:\n", "\n", - "- [02_introduction_legacy_runtime.ipynb](02_introduction_legacy_runtime.ipynb) is the corresponding tutorial on using legacy Qiskit Runtime. You can skip this tutorial if you don't plan on using legacy runtime.\n", + "- [02_introduction_ibm_quantum_runtime.ipynb](02_introduction_ibm_quantum_runtime.ipynb) is the corresponding tutorial on using Qiskit Runtime on IBM Quantum. You can skip this tutorial if you don't plan on using Qiskit Runtime on IBM Quantum.\n", "- [03_backends.ipynb](03_backends.ipynb) describes how to find a target backend for the Qiskit Runtime program you want to invoke. \n", "- [04_account_management.ipynb](04_account_management.ipynb) describes how to save, load, and delete your account credentials on disk.\n", "- [qiskit_runtime_vqe_program.ipynb](sample_vqe_program/qiskit_runtime_vqe_program.ipynb) goes into more details on uploading a real-world program (VQE). \n", - "- [qka.ipynb](qka.ipynb), [vqe.ipynb](vqe.ipynb), and [qiskit_runtime_expval_program.ipynb](sample_expval_program/qiskit_runtime_expval_program.ipynb) describe how to use the public programs `qka`, `vqe`, and `sample-expval`, respectively. These programs are currently only available on legacy Qiskit Runtime." + "- [qka.ipynb](qka.ipynb), [vqe.ipynb](vqe.ipynb), and [qiskit_runtime_expval_program.ipynb](sample_expval_program/qiskit_runtime_expval_program.ipynb) describe how to use the public programs `qka`, `vqe`, and `sample-expval`, respectively. These programs are currently only available in Qiskit Runtime on IBM Quantum." ] }, { diff --git a/docs/tutorials/02_introduction_legacy_runtime.ipynb b/docs/tutorials/02_introduction_ibm_quantum_runtime.ipynb similarity index 98% rename from docs/tutorials/02_introduction_legacy_runtime.ipynb rename to docs/tutorials/02_introduction_ibm_quantum_runtime.ipynb index a8c4f51f49..a72d921b6b 100644 --- a/docs/tutorials/02_introduction_legacy_runtime.ipynb +++ b/docs/tutorials/02_introduction_ibm_quantum_runtime.ipynb @@ -18,7 +18,7 @@ "id": "1de4634b", "metadata": {}, "source": [ - "# Legacy Qiskit Runtime" + "# Qiskit Runtime on IBM Quantum" ] }, { @@ -26,7 +26,7 @@ "id": "5affe56b", "metadata": {}, "source": [ - "Prior to becoming an IBM Cloud service, Qiskit Runtime was offered on IBM Quantum. If you have an existing IBM Quantum account, you can continue using Qiskit Runtime on IBM Quantum, which is referred to as _legacy runtime_. \n" + "Prior to becoming an IBM Cloud service, Qiskit Runtime was offered on IBM Quantum. If you have an existing IBM Quantum account, you can continue using Qiskit Runtime on IBM Quantum. \n" ] }, { @@ -80,7 +80,7 @@ "source": [ "Before you can start using Qiskit Runtime, you need to initialize your account. You can do this by calling `IBMRuntimeService` with your IBM Quantum API token, which can be found on the [IBM Quantum accounts page](https://quantum-computing.ibm.com/account).\n", "\n", - "You can also choose to save your credentials on disk (in the `$HOME/.qiskit/qiskit-ibm.json` file). By doing so, you only need to use `IBMRuntimeService(auth=\"legacy\")` in the future to initialize your account.\n", + "You can also choose to save your credentials on disk (in the `$HOME/.qiskit/qiskit-ibm.json` file). By doing so, you only need to use `IBMRuntimeService(channel=\"ibm_quantum\")` in the future to initialize your account.\n", "\n", "For more information about account management, such as how to delete or view an account, see [04_account_management.ipynb](04_account_management.ipynb)." ] @@ -95,10 +95,10 @@ "from qiskit_ibm_runtime import IBMRuntimeService\n", "\n", "# Save account on disk.\n", - "# IBMRuntimeService.save_account(auth=\"legacy\", token=)\n", + "# IBMRuntimeService.save_account(channel=\"ibm_quantum\", token=)\n", "\n", - "# The \"auth\" keyword is not needed if you have only 1 type (legacy or cloud) of account saved.\n", - "service = IBMRuntimeService(auth=\"legacy\")" + "# The \"channel\" keyword is not needed if you have only 1 type (ibm_quantum or ibm_cloud) of account saved.\n", + "service = IBMRuntimeService(channel=\"ibm_quantum\")" ] }, { @@ -417,7 +417,7 @@ "metadata": {}, "source": [ "
\n", - "Note: To ensure fairness, there is a maximum execution time for each Qiskit Runtime job. Refer to this documentation on what the time limit is.\n", + "Note: To ensure fairness, there is a maximum execution time for each Qiskit Runtime job. Refer to this documentation on what the time limit is.\n", "
" ] }, @@ -535,7 +535,7 @@ "- [04_account_management.ipynb](04_account_management.ipynb) describes how to save, load, and delete your account credentials on disk.\n", "- [05_uploading_program.ipynb](05_uploading_program.ipynb) is an introduction on uploading your custom Qiskit Runtime program.\n", "- [qiskit_runtime_vqe_program.ipynb](sample_vqe_program/qiskit_runtime_vqe_program.ipynb) goes into more details on uploading a real-world program (VQE). \n", - "- [qka.ipynb](qka.ipynb), [vqe.ipynb](vqe.ipynb), and [qiskit_runtime_expval_program.ipynb](sample_expval_program/qiskit_runtime_expval_program.ipynb) describe how to use the public programs `qka`, `vqe`, and `sample-expval`, respectively. These programs are currently only available on legacy Qiskit Runtime." + "- [qka.ipynb](qka.ipynb), [vqe.ipynb](vqe.ipynb), and [qiskit_runtime_expval_program.ipynb](sample_expval_program/qiskit_runtime_expval_program.ipynb) describe how to use the public programs `qka`, `vqe`, and `sample-expval`, respectively. These programs are currently only available on Qiskit Runtime on IBM Quantum." ] }, { diff --git a/docs/tutorials/03_backends.ipynb b/docs/tutorials/03_backends.ipynb index 88853c3e11..8fd5b9e97a 100644 --- a/docs/tutorials/03_backends.ipynb +++ b/docs/tutorials/03_backends.ipynb @@ -227,9 +227,8 @@ } ], "source": [ - "# This program currently is only available on legacy Qiskit Runtime.\n", - "legacy_service = IBMRuntimeService(auth=\"legacy\")\n", - "program = legacy_service.program(\"hello-world\")\n", + "ibm_quantum_service = IBMRuntimeService(channel=\"ibm_quantum\")\n", + "program = ibm_quantum_service.program(\"hello-world\")\n", "print(program.backend_requirements)" ] }, @@ -269,7 +268,7 @@ } ], "source": [ - "legacy_service.backends(min_num_qubits=5)" + "ibm_quantum_service.backends(min_num_qubits=5)" ] }, { diff --git a/docs/tutorials/04_account_management.ipynb b/docs/tutorials/04_account_management.ipynb index 1fa2c6978f..2bc8935dcc 100644 --- a/docs/tutorials/04_account_management.ipynb +++ b/docs/tutorials/04_account_management.ipynb @@ -26,7 +26,7 @@ "id": "c22a29f4", "metadata": {}, "source": [ - "Qiskit Runtime is available on both IBM Cloud and IBM Quantum. The former requires an IBM Cloud account and the latter an IBM Quantum account. If you don't have these accounts, please refer to [01_introduction_cloud_runtime.ipynb](01_introduction_cloud_runtime.ipynb) or [02_introduction_legacy_runtime.ipynb](02_introduction_legacy_runtime.ipynb) on how to set one up.\n", + "Qiskit Runtime is available on both IBM Cloud and IBM Quantum. The former requires an IBM Cloud account and the latter an IBM Quantum account. If you don't have these accounts, please refer to [01_introduction_ibm_cloud_runtime.ipynb](01_introduction_ibm_cloud_runtime.ipynb) or [02_introduction_ibm_quantum_runtime.ipynb](02_introduction_ibm_quantum_runtime.ipynb) on how to set one up.\n", "\n" ] }, @@ -74,7 +74,7 @@ "id": "bfb828ec", "metadata": {}, "source": [ - "Below are examples of saving an IBM Cloud and an IBM Quantum accounts. The `auth` parameter indicates the authentication type of the account. If you are saving multiple account, consider using the `name` parameter to differentiate them.\n" + "Below are examples of saving an IBM Cloud and an IBM Quantum accounts. The `channel` parameter allows to distinguish between different account types. If you are saving multiple accounts per channel, consider using the `name` parameter to differentiate them.\n" ] }, { @@ -87,10 +87,10 @@ "from qiskit_ibm_runtime import IBMRuntimeService\n", "\n", "# Save an IBM Cloud account on disk.\n", - "# IBMRuntimeService.save_account(auth=\"cloud\", token=, instance= or )\n", + "# IBMRuntimeService.save_account(channel=\"ibm_cloud\", token=, instance= or )\n", "\n", "# Save an IBM Quantum account on disk.\n", - "# IBMRuntimeService.save_account(auth=\"legacy\", token=)" + "# IBMRuntimeService.save_account(channel=\"ibm_quantum\", token=)" ] }, { @@ -125,7 +125,7 @@ "id": "9a4504f8", "metadata": {}, "source": [ - "If you have both an IBM Cloud and an IBM Quantum accounts saved, `IBMRuntimeService()` by default will load the IBM Cloud account. To load the IBM Quantum account, you can specify `IBMRuntimeService(auth=\"legacy\")` instead.\n", + "If you have both an IBM Cloud and an IBM Quantum accounts saved, `IBMRuntimeService()` by default will load the IBM Cloud account. To load the IBM Quantum account, you can specify `IBMRuntimeService(channel=\"ibm_quantum\")` instead.\n", "\n", "Alternatively, if you specified a `name` for your account when saving it, you can also specify the name of the account to load." ] @@ -138,7 +138,7 @@ "outputs": [], "source": [ "# Save an IBM Cloud account on disk and give it a name.\n", - "# IBMRuntimeService.save_account(auth=\"cloud\", token=, instance=, name=\"prod\")\n", + "# IBMRuntimeService.save_account(channel=\"ibm_cloud\", token=, instance=, name=\"prod\")\n", "\n", "# service = IBMRuntimeService(name=\"prod\")" ] @@ -159,7 +159,7 @@ "outputs": [], "source": [ "# Initialize an IBM Cloud account without saving it.\n", - "# service = IBMRuntimeService(auth=\"cloud\", token=, instance=)" + "# service = IBMRuntimeService(channel=\"ibm_cloud\", token=, instance=)" ] }, { diff --git a/docs/tutorials/qka.ipynb b/docs/tutorials/qka.ipynb index bc38daa1f5..0d55f5180a 100644 --- a/docs/tutorials/qka.ipynb +++ b/docs/tutorials/qka.ipynb @@ -85,7 +85,7 @@ "source": [ "# Load your account and get the quantum backend\n", "\n", - "We'll be using the 27-qubit device `ibmq_montreal` for this tutorial on legacy Qiskit Runtime." + "We'll be using the 27-qubit device `ibmq_montreal` for this tutorial in Qiskit Runtime on IBM Quantum." ] }, { @@ -104,7 +104,7 @@ "\n", "from qiskit_ibm_runtime import IBMRuntimeService\n", "\n", - "service = IBMRuntimeService(auth=\"legacy\")\n", + "service = IBMRuntimeService(channel=\"ibm_quantum\")\n", "backend = service.backend(\"ibmq_montreal\")" ] }, diff --git a/docs/tutorials/sample_expval_program/qiskit_runtime_expval_program.ipynb b/docs/tutorials/sample_expval_program/qiskit_runtime_expval_program.ipynb index e7bad35330..2a3cec84b5 100644 --- a/docs/tutorials/sample_expval_program/qiskit_runtime_expval_program.ipynb +++ b/docs/tutorials/sample_expval_program/qiskit_runtime_expval_program.ipynb @@ -363,7 +363,7 @@ "source": [ "from qiskit_ibm_runtime import IBMRuntimeService\n", "\n", - "service = IBMRuntimeService(auth=\"legacy\")" + "service = IBMRuntimeService(channel=\"ibm_quantum\")" ] }, { diff --git a/docs/tutorials/vqe.ipynb b/docs/tutorials/vqe.ipynb index 07145a723c..94071df41e 100644 --- a/docs/tutorials/vqe.ipynb +++ b/docs/tutorials/vqe.ipynb @@ -275,7 +275,7 @@ "source": [ "from qiskit_ibm_runtime import IBMRuntimeService\n", "\n", - "service = IBMRuntimeService(auth=\"legacy\")" + "service = IBMRuntimeService(channel=\"ibm_quantum\")" ] }, { diff --git a/qiskit_ibm_runtime/__init__.py b/qiskit_ibm_runtime/__init__.py index 9533bdba7c..00417af1d7 100644 --- a/qiskit_ibm_runtime/__init__.py +++ b/qiskit_ibm_runtime/__init__.py @@ -39,7 +39,7 @@ on disk. Qiskit Runtime is available on both IBM Cloud and IBM Quantum, and you can specify -``auth="cloud"`` for IBM Cloud and ``auth="legacy"`` for IBM Quantum. The default +``channel="ibm_cloud"`` for IBM Cloud and ``channel="ibm_quantum"`` for IBM Quantum. The default is IBM Cloud. Listing runtime programs diff --git a/qiskit_ibm_runtime/accounts/__init__.py b/qiskit_ibm_runtime/accounts/__init__.py index 75a684636c..4bc59cc4f4 100644 --- a/qiskit_ibm_runtime/accounts/__init__.py +++ b/qiskit_ibm_runtime/accounts/__init__.py @@ -14,7 +14,7 @@ Account management functionality related to the IBM Runtime Services. """ -from .account import Account, AccountType +from .account import Account, AccountType, ChannelType from .management import AccountManager from .exceptions import ( AccountNotFoundError, diff --git a/qiskit_ibm_runtime/accounts/account.py b/qiskit_ibm_runtime/accounts/account.py index 4bbc7be23b..eff4c7db2a 100644 --- a/qiskit_ibm_runtime/accounts/account.py +++ b/qiskit_ibm_runtime/accounts/account.py @@ -20,15 +20,16 @@ from typing_extensions import Literal from .exceptions import InvalidAccountError, CloudResourceNameResolutionError -from ..api.auth import LegacyAuth, CloudAuth +from ..api.auth import QuantumAuth, CloudAuth from ..proxies import ProxyConfiguration from ..utils.hgp import from_instance_format from ..utils import resolve_crn AccountType = Optional[Literal["cloud", "legacy"]] +ChannelType = Optional[Literal["ibm_cloud", "ibm_quantum"]] -LEGACY_API_URL = "https://auth.quantum-computing.ibm.com/api" -CLOUD_API_URL = "https://cloud.ibm.com" +IBM_QUANTUM_API_URL = "https://auth.quantum-computing.ibm.com/api" +IBM_CLOUD_API_URL = "https://cloud.ibm.com" logger = logging.getLogger(__name__) @@ -37,7 +38,7 @@ class Account: def __init__( self, - auth: AccountType, + channel: ChannelType, token: str, url: Optional[str] = None, instance: Optional[str] = None, @@ -47,16 +48,18 @@ def __init__( """Account constructor. Args: - auth: Authentication type, ``cloud`` or ``legacy``. + channel: Channel type, ``ibm_cloud`` or ``ibm_quantum``. token: Account token to use. url: Authentication URL. instance: Service instance to use. proxies: Proxy configuration. verify: Whether to verify server's TLS certificate. """ - resolved_url = url or (LEGACY_API_URL if auth == "legacy" else CLOUD_API_URL) + resolved_url = url or ( + IBM_QUANTUM_API_URL if channel == "ibm_quantum" else IBM_CLOUD_API_URL + ) - self.auth = auth + self.channel = channel self.token = token self.url = resolved_url self.instance = instance @@ -74,8 +77,10 @@ def to_saved_format(self) -> dict: def from_saved_format(cls, data: dict) -> "Account": """Creates an account instance from data saved on disk.""" proxies = data.get("proxies") + auth = data.get("auth") + channel = "ibm_quantum" if auth == "legacy" else "ibm_cloud" return cls( - auth=data.get("auth"), + channel=data.get("channel", channel), url=data.get("url"), token=data.get("token"), instance=data.get("instance"), @@ -87,15 +92,18 @@ def resolve_crn(self) -> None: """Resolves the corresponding unique Cloud Resource Name (CRN) for the given non-unique service instance name and updates the ``instance`` attribute accordingly. - No-op if ``auth`` attribute is set to legacy. + No-op if ``channel`` attribute is set to ``ibm_quantum``. No-op if ``instance`` attribute is set to a Cloud Resource Name (CRN). Raises: CloudResourceNameResolutionError: if CRN value cannot be resolved. """ - if self.auth == "cloud": + if self.channel == "ibm_cloud": crn = resolve_crn( - auth=self.auth, url=self.url, token=self.token, instance=self.instance + channel=self.channel, + url=self.url, + token=self.token, + instance=self.instance, ) if len(crn) == 0: raise CloudResourceNameResolutionError( @@ -115,17 +123,17 @@ def resolve_crn(self) -> None: def get_auth_handler(self) -> AuthBase: """Returns the respective authentication handler.""" - if self.auth == "cloud": + if self.channel == "ibm_cloud": return CloudAuth(api_key=self.token, crn=self.instance) - return LegacyAuth(access_token=self.token) + return QuantumAuth(access_token=self.token) def __eq__(self, other: object) -> bool: if not isinstance(other, Account): return False return all( [ - self.auth == other.auth, + self.channel == other.channel, self.token == other.token, self.url == other.url, self.instance == other.instance, @@ -144,19 +152,20 @@ def validate(self) -> "Account": This Account instance. """ - self._assert_valid_auth(self.auth) + self._assert_valid_channel(self.channel) self._assert_valid_token(self.token) self._assert_valid_url(self.url) - self._assert_valid_instance(self.auth, self.instance) + self._assert_valid_instance(self.channel, self.instance) self._assert_valid_proxies(self.proxies) return self @staticmethod - def _assert_valid_auth(auth: AccountType) -> None: - """Assert that the auth parameter is valid.""" - if not (auth in ["cloud", "legacy"]): + def _assert_valid_channel(channel: ChannelType) -> None: + """Assert that the channel parameter is valid.""" + if not (channel in ["ibm_cloud", "ibm_quantum"]): raise InvalidAccountError( - f"Invalid `auth` value. Expected one of ['cloud', 'legacy'], got '{auth}'." + f"Invalid `channel` value. Expected one of " + f"{['ibm_cloud', 'ibm_quantum']}, got '{channel}'." ) @staticmethod @@ -184,14 +193,14 @@ def _assert_valid_proxies(config: ProxyConfiguration) -> None: config.validate() @staticmethod - def _assert_valid_instance(auth: AccountType, instance: str) -> None: + def _assert_valid_instance(channel: ChannelType, instance: str) -> None: """Assert that the instance name is valid for the given account type.""" - if auth == "cloud": + if channel == "ibm_cloud": if not (isinstance(instance, str) and len(instance) > 0): raise InvalidAccountError( f"Invalid `instance` value. Expected a non-empty string, got '{instance}'." ) - if auth == "legacy": + if channel == "ibm_quantum": if instance is not None: try: from_instance_format(instance) diff --git a/qiskit_ibm_runtime/accounts/management.py b/qiskit_ibm_runtime/accounts/management.py index 08063bb6dd..f1afd5f5b2 100644 --- a/qiskit_ibm_runtime/accounts/management.py +++ b/qiskit_ibm_runtime/accounts/management.py @@ -15,7 +15,7 @@ import os from typing import Optional, Dict from .exceptions import AccountNotFoundError -from .account import Account, AccountType +from .account import Account, ChannelType from ..proxies import ProxyConfiguration from .storage import save_config, read_config, delete_config @@ -25,8 +25,10 @@ _DEFAULT_ACCOUNT_NAME = "default" _DEFAULT_ACCOUNT_NAME_LEGACY = "default-legacy" _DEFAULT_ACCOUNT_NAME_CLOUD = "default-cloud" -_DEFAULT_ACCOUNT_TYPE: AccountType = "cloud" -_ACCOUNT_TYPES = [_DEFAULT_ACCOUNT_TYPE, "legacy"] +_DEFAULT_ACCOUNT_NAME_IBM_QUANTUM = "default-ibm-quantum" +_DEFAULT_ACCOUNT_NAME_IBM_CLOUD = "default-ibm-cloud" +_DEFAULT_CHANNEL_TYPE: ChannelType = "ibm_cloud" +_CHANNEL_TYPES = [_DEFAULT_CHANNEL_TYPE, "ibm_quantum"] class AccountManager: @@ -38,23 +40,24 @@ def save( token: Optional[str] = None, url: Optional[str] = None, instance: Optional[str] = None, - auth: Optional[AccountType] = None, + channel: Optional[ChannelType] = None, name: Optional[str] = _DEFAULT_ACCOUNT_NAME, proxies: Optional[ProxyConfiguration] = None, verify: Optional[bool] = None, overwrite: Optional[bool] = False, ) -> None: """Save account on disk.""" - config_key = name or cls._get_default_account_name(auth) + cls.migrate() + name = name or cls._get_default_account_name(channel) return save_config( filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE, - name=config_key, + name=name, overwrite=overwrite, config=Account( token=token, url=url, instance=instance, - auth=auth, + channel=channel, proxies=proxies, verify=verify, ) @@ -65,22 +68,23 @@ def save( @staticmethod def list( default: Optional[bool] = None, - auth: Optional[str] = None, + channel: Optional[ChannelType] = None, name: Optional[str] = None, ) -> Dict[str, Account]: """List all accounts saved on disk.""" + AccountManager.migrate() def _matching_name(account_name: str) -> bool: return name is None or name == account_name - def _matching_auth(account: Account) -> bool: - return auth is None or account.auth == auth + def _matching_channel(account: Account) -> bool: + return channel is None or account.channel == channel def _matching_default(account_name: str) -> bool: default_accounts = [ _DEFAULT_ACCOUNT_NAME, - _DEFAULT_ACCOUNT_NAME_LEGACY, - _DEFAULT_ACCOUNT_NAME_CLOUD, + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM, + _DEFAULT_ACCOUNT_NAME_IBM_CLOUD, ] if default is None: return True @@ -91,7 +95,10 @@ def _matching_default(account_name: str) -> bool: # load all accounts all_accounts = map( - lambda kv: (kv[0], Account.from_saved_format(kv[1])), + lambda kv: ( + kv[0], + Account.from_saved_format(kv[1]), + ), read_config(filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE).items(), ) @@ -99,7 +106,7 @@ def _matching_default(account_name: str) -> bool: filtered_accounts = dict( list( filter( - lambda kv: _matching_auth(kv[1]) + lambda kv: _matching_channel(kv[1]) and _matching_default(kv[0]) and _matching_name(kv[0]), all_accounts, @@ -111,13 +118,13 @@ def _matching_default(account_name: str) -> bool: @classmethod def get( - cls, name: Optional[str] = None, auth: Optional[AccountType] = None + cls, name: Optional[str] = None, channel: Optional[ChannelType] = None ) -> Optional[Account]: """Read account from disk. Args: name: Account name. Takes precedence if `auth` is also specified. - auth: Account auth type. + channel: Channel type. Returns: Account information. @@ -125,6 +132,7 @@ def get( Raises: AccountNotFoundError: If the input value cannot be found on disk. """ + cls.migrate() if name: saved_account = read_config( filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE, name=name @@ -135,23 +143,23 @@ def get( ) return Account.from_saved_format(saved_account) - auth_ = auth or _DEFAULT_ACCOUNT_TYPE - env_account = cls._from_env_variables(auth_) + channel_ = channel or _DEFAULT_CHANNEL_TYPE + env_account = cls._from_env_variables(channel_) if env_account is not None: return env_account - if auth: + if channel: saved_account = read_config( filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE, - name=cls._get_default_account_name(auth), + name=cls._get_default_account_name(channel=channel), ) if saved_account is None: - raise AccountNotFoundError(f"No default {auth} account saved.") + raise AccountNotFoundError(f"No default {channel} account saved.") return Account.from_saved_format(saved_account) all_config = read_config(filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE) - for account_type in _ACCOUNT_TYPES: - account_name = cls._get_default_account_name(account_type) + for channel_type in _CHANNEL_TYPES: + account_name = cls._get_default_account_name(channel=channel_type) if account_name in all_config: return Account.from_saved_format(all_config[account_name]) @@ -161,30 +169,73 @@ def get( def delete( cls, name: Optional[str] = None, - auth: Optional[str] = None, + channel: Optional[ChannelType] = None, ) -> bool: """Delete account from disk.""" - - config_key = name or cls._get_default_account_name(auth) + cls.migrate() + name = name or cls._get_default_account_name(channel) return delete_config( - name=config_key, filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE + filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE, + name=name, ) @classmethod - def _from_env_variables(cls, auth: Optional[AccountType]) -> Optional[Account]: + def migrate(cls) -> None: + """Migrate accounts on disk by removing `auth` and adding `channel`.""" + data = read_config(filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE) + for key, value in data.items(): + if key == _DEFAULT_ACCOUNT_NAME_CLOUD: + value.pop("auth", None) + value.update(channel="ibm_cloud") + delete_config(filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE, name=key) + save_config( + filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE, + name=_DEFAULT_ACCOUNT_NAME_IBM_CLOUD, + config=value, + overwrite=False, + ) + elif key == _DEFAULT_ACCOUNT_NAME_LEGACY: + value.pop("auth", None) + value.update(channel="ibm_quantum") + delete_config(filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE, name=key) + save_config( + filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE, + name=_DEFAULT_ACCOUNT_NAME_IBM_QUANTUM, + config=value, + overwrite=False, + ) + else: + if hasattr(value, "auth"): + if value["auth"] == "cloud": + value.update(channel="ibm_cloud") + elif value["auth"] == "legacy": + value.update(channel="ibm_quantum") + value.pop("auth", None) + save_config( + filename=_DEFAULT_ACCOUNT_CONFIG_JSON_FILE, + name=key, + config=value, + overwrite=True, + ) + + @classmethod + def _from_env_variables(cls, channel: Optional[ChannelType]) -> Optional[Account]: """Read account from environment variable.""" token = os.getenv("QISKIT_IBM_TOKEN") url = os.getenv("QISKIT_IBM_URL") if not (token and url): return None return Account( - token=token, url=url, instance=os.getenv("QISKIT_IBM_INSTANCE"), auth=auth + token=token, + url=url, + instance=os.getenv("QISKIT_IBM_INSTANCE"), + channel=channel, ) @classmethod - def _get_default_account_name(cls, auth: AccountType) -> str: + def _get_default_account_name(cls, channel: ChannelType) -> str: return ( - _DEFAULT_ACCOUNT_NAME_LEGACY - if auth == "legacy" - else _DEFAULT_ACCOUNT_NAME_CLOUD + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM + if channel == "ibm_quantum" + else _DEFAULT_ACCOUNT_NAME_IBM_CLOUD ) diff --git a/qiskit_ibm_runtime/accounts/storage.py b/qiskit_ibm_runtime/accounts/storage.py index a3948b61fc..7e6fcdcee7 100644 --- a/qiskit_ibm_runtime/accounts/storage.py +++ b/qiskit_ibm_runtime/accounts/storage.py @@ -54,7 +54,6 @@ def read_config( return data if name in data: return data[name] - return None diff --git a/qiskit_ibm_runtime/api/auth.py b/qiskit_ibm_runtime/api/auth.py index 43a5ac955d..bb6fd849cb 100644 --- a/qiskit_ibm_runtime/api/auth.py +++ b/qiskit_ibm_runtime/api/auth.py @@ -45,14 +45,14 @@ def get_headers(self) -> Dict: return {"Service-CRN": self.crn, "Authorization": f"apikey {self.api_key}"} -class LegacyAuth(AuthBase): - """Attaches Legacy Authentication to the given Request object.""" +class QuantumAuth(AuthBase): + """Attaches IBM Quantum Authentication to the given Request object.""" def __init__(self, access_token: str): self.access_token = access_token def __eq__(self, other: object) -> bool: - if isinstance(other, LegacyAuth): + if isinstance(other, QuantumAuth): return self.access_token == other.access_token return False diff --git a/qiskit_ibm_runtime/api/client_parameters.py b/qiskit_ibm_runtime/api/client_parameters.py index c27f7f8078..3ff4911faf 100644 --- a/qiskit_ibm_runtime/api/client_parameters.py +++ b/qiskit_ibm_runtime/api/client_parameters.py @@ -15,7 +15,7 @@ from typing import Dict, Optional, Any, Union from ..utils import get_runtime_api_base_url -from ..api.auth import LegacyAuth, CloudAuth +from ..api.auth import QuantumAuth, CloudAuth from ..proxies import ProxyConfiguration TEMPLATE_IBM_HUBS = "{prefix}/Network/{hub}/Groups/{group}/Projects/{project}" @@ -27,7 +27,7 @@ class ClientParameters: def __init__( self, - auth_type: str, + channel: str, token: str, url: str = None, instance: Optional[str] = None, @@ -37,7 +37,7 @@ def __init__( """ClientParameters constructor. Args: - auth_type: Authentication type. ``cloud`` or ``legacy``. + channel: Channel type. ``ibm_cloud`` or ``ibm_quantum``. token: IBM Quantum API token. url: IBM Quantum URL (gets replaced with a new-style URL with hub, group, project). instance: Service instance to use. @@ -46,17 +46,17 @@ def __init__( """ self.token = token self.instance = instance - self.auth_type = auth_type + self.channel = channel self.url = url self.proxies = proxies self.verify = verify - def get_auth_handler(self) -> Union[CloudAuth, LegacyAuth]: + def get_auth_handler(self) -> Union[CloudAuth, QuantumAuth]: """Returns the respective authentication handler.""" - if self.auth_type == "cloud": + if self.channel == "ibm_cloud": return CloudAuth(api_key=self.token, crn=self.instance) - return LegacyAuth(access_token=self.token) + return QuantumAuth(access_token=self.token) def get_runtime_api_base_url(self) -> str: """Returns the Runtime API base url.""" diff --git a/qiskit_ibm_runtime/api/clients/auth.py b/qiskit_ibm_runtime/api/clients/auth.py index fd679b827e..fabe0840cc 100644 --- a/qiskit_ibm_runtime/api/clients/auth.py +++ b/qiskit_ibm_runtime/api/clients/auth.py @@ -15,7 +15,7 @@ from typing import Dict, List, Optional, Any, Union from requests.exceptions import RequestException -from ..auth import LegacyAuth +from ..auth import QuantumAuth from ..exceptions import AuthenticationLicenseError, RequestsApiError from ..rest import Api from ..session import RetrySession @@ -55,14 +55,14 @@ def _init_service_clients(self, **request_kwargs: Any) -> Api: """ # Request an access token. self.access_token = self._request_access_token() - self.auth_api.session.auth = LegacyAuth(access_token=self.access_token) + self.auth_api.session.auth = QuantumAuth(access_token=self.access_token) self._service_urls = self.user_urls() # Create the api server client, using the access token. base_api = Api( RetrySession( self._service_urls["http"], - auth=LegacyAuth(access_token=self.access_token), + auth=QuantumAuth(access_token=self.access_token), **request_kwargs, ) ) diff --git a/qiskit_ibm_runtime/constants.py b/qiskit_ibm_runtime/constants.py index 2031c474e4..95513ab7b4 100644 --- a/qiskit_ibm_runtime/constants.py +++ b/qiskit_ibm_runtime/constants.py @@ -16,7 +16,6 @@ QISKIT_IBM_RUNTIME_API_URL = "https://auth.quantum-computing.ibm.com/api" - API_TO_JOB_STATUS = { "QUEUED": JobStatus.QUEUED, "RUNNING": JobStatus.RUNNING, diff --git a/qiskit_ibm_runtime/ibm_backend.py b/qiskit_ibm_runtime/ibm_backend.py index 957445d330..e44a0d0b97 100644 --- a/qiskit_ibm_runtime/ibm_backend.py +++ b/qiskit_ibm_runtime/ibm_backend.py @@ -337,7 +337,7 @@ def properties( datetime: By specifying `datetime`, this function returns an instance of the :class:`BackendProperties` whose timestamp is closest to, but older than, the specified `datetime`. - Note that this is only supported using legacy runtime. + Note that this is only supported using ``ibm_quantum`` runtime. Returns: The backend properties or ``None`` if the backend properties are not diff --git a/qiskit_ibm_runtime/ibm_estimator.py b/qiskit_ibm_runtime/ibm_estimator.py index 23ccae44c0..8c2ce7a863 100644 --- a/qiskit_ibm_runtime/ibm_estimator.py +++ b/qiskit_ibm_runtime/ibm_estimator.py @@ -67,7 +67,7 @@ class IBMEstimator(BasePrimitive): from qiskit_ibm_runtime import IBMRuntimeService, IBMEstimator - service = IBMRuntimeService(auth="cloud") + service = IBMRuntimeService(channel="ibm_cloud") estimator_factory = IBMEstimator(service=service, backend="ibmq_qasm_simulator") psi1 = RealAmplitudes(num_qubits=2, reps=2) diff --git a/qiskit_ibm_runtime/ibm_runtime_service.py b/qiskit_ibm_runtime/ibm_runtime_service.py index 007f3a2099..fd8283f531 100644 --- a/qiskit_ibm_runtime/ibm_runtime_service.py +++ b/qiskit_ibm_runtime/ibm_runtime_service.py @@ -24,7 +24,7 @@ from qiskit.providers.providerutils import filter_backends from qiskit_ibm_runtime import ibm_backend -from .accounts import AccountManager, Account, AccountType +from .accounts import AccountManager, Account, AccountType, ChannelType from .proxies import ProxyConfiguration from .api.clients import AuthClient, VersionClient from .api.clients.runtime import RuntimeClient @@ -112,6 +112,7 @@ class IBMRuntimeService: def __init__( self, + channel: Optional[ChannelType] = None, auth: Optional[AccountType] = None, token: Optional[str] = None, url: Optional[str] = None, @@ -125,25 +126,26 @@ def __init__( An account is selected in the following order: - Account with the input `name`, if specified. - - Default account for the `auth` type, if `auth` is specified but `token` is not. - - Account defined by the input `auth` and `token`, if specified. + - Default account for the `channel` type, if `channel` is specified but `token` is not. + - Account defined by the input `channel` and `token`, if specified. - Account defined by the environment variables, if defined. - - Default account for the cloud account, if one is available. - - Default account for the legacy account, if one is available. + - Default account for the ``ibm_cloud`` account, if one is available. + - Default account for the ``ibm_quantum`` account, if one is available. `instance`, `proxies`, and `verify` can be used to overwrite corresponding values in the loaded account. Args: - auth: Authentication type. ``cloud`` or ``legacy``. + channel: Channel type. ``ibm_cloud`` or ``ibm_quantum``. + auth: (DEPRECATED, use `channel` instead) Authentication type. ``cloud`` or ``legacy``. token: IBM Cloud API key or IBM Quantum API token. url: The API URL. - Defaults to https://cloud.ibm.com (cloud) or - https://auth.quantum-computing.ibm.com/api (legacy). + Defaults to https://cloud.ibm.com (ibm_cloud) or + https://auth.quantum-computing.ibm.com/api (ibm_quantum). name: Name of the account to load. instance: The service instance to use. - For cloud runtime, this is the Cloud Resource Name (CRN) or the service name. - For legacy runtime, this is the hub/group/project in that format. + For ``ibm_cloud`` runtime, this is the Cloud Resource Name (CRN) or the service name. + For ``ibm_quantum`` runtime, this is the hub/group/project in that format. proxies: Proxy configuration. Supported optional keys are ``urls`` (a dictionary mapping protocol or protocol and host to the URL of the proxy, documented at https://docs.python-requests.org/en/latest/api/#requests.Session.proxies), @@ -159,10 +161,14 @@ def __init__( """ super().__init__() + if auth: + self._auth_warning() + self._account = self._discover_account( token=token, url=url, instance=instance, + channel=channel, auth=auth, name=name, proxies=ProxyConfiguration(**proxies) if proxies else None, @@ -170,7 +176,7 @@ def __init__( ) self._client_params = ClientParameters( - auth_type=self._account.auth, + channel=self._account.channel, token=self._account.token, url=self._account.url, instance=self._account.instance, @@ -178,17 +184,17 @@ def __init__( verify=self._account.verify, ) - self._auth = self._account.auth + self._channel = self._account.channel self._programs: Dict[str, RuntimeProgram] = {} self._backends: Dict[str, "ibm_backend.IBMBackend"] = {} - if self._auth == "cloud": + if self._channel == "ibm_cloud": self._api_client = RuntimeClient(self._client_params) # TODO: We can make the backend discovery lazy self._backends = self._discover_cloud_backends() return else: - auth_client = self._authenticate_legacy_account(self._client_params) + auth_client = self._authenticate_ibm_quantum_account(self._client_params) # Update client parameters to use authenticated values. self._client_params.url = auth_client.current_service_urls()["services"][ "runtime" @@ -205,11 +211,23 @@ def __init__( # just seems wrong since backends are not runtime service instances. # self._discover_backends() + @staticmethod + def _auth_warning() -> None: + warnings.warn( + "Use of `auth` parameter is deprecated and will " + "be removed in a future release. " + "You can now use channel='ibm_cloud' or " + "channel='ibm_quantum' instead.", + DeprecationWarning, + stacklevel=3, + ) + def _discover_account( self, token: Optional[str] = None, url: Optional[str] = None, instance: Optional[str] = None, + channel: Optional[ChannelType] = None, auth: Optional[AccountType] = None, name: Optional[str] = None, proxies: Optional[ProxyConfiguration] = None, @@ -219,18 +237,22 @@ def _discover_account( account = None verify_ = verify or True if name: - if any([auth, token, url]): + if any([auth, channel, token, url]): logger.warning( - "Loading account with name %s. Any input 'auth', 'token', 'url' are ignored.", + "Loading account with name %s. Any input 'auth', " + "'channel', 'token' or 'url' are ignored.", name, ) account = AccountManager.get(name=name) - elif auth: - if auth not in ["legacy", "cloud"]: + elif auth or channel: + if auth and auth not in ["legacy", "cloud"]: raise ValueError("'auth' can only be 'cloud' or 'legacy'") + if channel and channel not in ["ibm_cloud", "ibm_quantum"]: + raise ValueError("'channel' can only be 'ibm_cloud' or 'ibm_quantum'") + channel = channel or self._get_channel_for_auth(auth=auth) if token: account = Account( - auth=auth, + channel=channel, token=token, url=url, instance=instance, @@ -240,13 +262,13 @@ def _discover_account( else: if url: logger.warning( - "Loading default %s account. Input 'url' is ignored.", auth + "Loading default %s account. Input 'url' is ignored.", channel ) - account = AccountManager.get(auth=auth) + account = AccountManager.get(channel=channel) elif any([token, url]): # Let's not infer based on these attributes as they may change in the future. raise ValueError( - "'auth' is required if 'token', or 'url' is specified but 'name' is not." + "'channel' or 'auth' is required if 'token', or 'url' is specified but 'name' is not." ) if account is None: @@ -260,7 +282,7 @@ def _discover_account( account.verify = verify # resolve CRN if needed - if account.auth == "cloud": + if account.channel == "ibm_cloud": self._resolve_crn(account) # ensure account is valid, fail early if not @@ -294,7 +316,7 @@ def _discover_cloud_backends(self) -> Dict[str, "ibm_backend.IBMBackend"]: def _resolve_crn(self, account: Account) -> None: account.resolve_crn() - def _authenticate_legacy_account( + def _authenticate_ibm_quantum_account( self, client_params: ClientParameters ) -> AuthClient: """Authenticate against IBM Quantum and populate the hub/group/projects. @@ -322,7 +344,7 @@ def _authenticate_legacy_account( service_urls = auth_client.current_service_urls() if not service_urls.get("services", {}).get(SERVICE_NAME): raise IBMNotAuthorizedError( - "This account is not authorized to use legacy runtime service." + "This account is not authorized to use ``ibm_quantum`` runtime service." ) return auth_client @@ -349,7 +371,7 @@ def _initialize_hgps( for hub_info in user_hubs: # Build credentials. hgp_params = ClientParameters( - auth_type=self._account.auth, + channel=self._account.channel, token=auth_client.current_access_token(), url=service_urls["http"], instance=to_instance_format( @@ -477,7 +499,7 @@ def backends( Args: name: Backend name to filter by. min_num_qubits: Minimum number of qubits the backend has to have. - instance: This is only supported for legacy runtime and is in the + instance: This is only supported for ``ibm_quantum`` runtime and is in the hub/group/project format. filters: More complex filters, such as lambda functions. For example:: @@ -497,7 +519,7 @@ def backends( IBMInputValueError: If an input is invalid. """ # TODO filter out input_allowed not having runtime - if self._auth == "legacy": + if self._channel == "ibm_quantum": if instance: backends = list(self._get_hgp(instance=instance).backends.values()) else: @@ -505,7 +527,7 @@ def backends( else: if instance: raise IBMInputValueError( - "The 'instance' keyword is only supported for legacy runtime." + "The 'instance' keyword is only supported for ``ibm_quantum`` runtime." ) backends = list(self._backends.values()) @@ -526,26 +548,43 @@ def active_account(self) -> Optional[Dict[str, str]]: return self._account.to_saved_format() @staticmethod - def delete_account(name: Optional[str] = None, auth: Optional[str] = None) -> bool: + def delete_account( + name: Optional[str] = None, + auth: Optional[str] = None, + channel: Optional[ChannelType] = None, + ) -> bool: """Delete a saved account from disk. Args: name: Name of the saved account to delete. - auth: Authentication type of the default account to delete. + auth: (DEPRECATED, use `channel` instead) Authentication type of the default + account to delete. Ignored if account name is provided. + channel: Channel type of the default account to delete. Ignored if account name is provided. Returns: True if the account was deleted. False if no account was found. """ + if auth: + IBMRuntimeService._auth_warning() + channel = channel or IBMRuntimeService._get_channel_for_auth(auth=auth) - return AccountManager.delete(name=name, auth=auth) + return AccountManager.delete(name=name, channel=channel) + + @staticmethod + def _get_channel_for_auth(auth: str) -> str: + """Returns channel type based on auth""" + if auth == "legacy": + return "ibm_quantum" + return "ibm_cloud" @staticmethod def save_account( token: Optional[str] = None, url: Optional[str] = None, instance: Optional[str] = None, + channel: Optional[ChannelType] = None, auth: Optional[AccountType] = None, name: Optional[str] = None, proxies: Optional[dict] = None, @@ -557,10 +596,11 @@ def save_account( Args: token: IBM Cloud API key or IBM Quantum API token. url: The API URL. - Defaults to https://cloud.ibm.com (cloud) or - https://auth.quantum-computing.ibm.com/api (legacy). - instance: The CRN (cloud) or hub/group/project (legacy). - auth: Authentication type. `cloud` or `legacy`. + Defaults to https://cloud.ibm.com (ibm_cloud) or + https://auth.quantum-computing.ibm.com/api (ibm_quantum). + instance: The CRN (ibm_cloud) or hub/group/project (ibm_quantum). + channel: Channel type. `ibm_cloud` or `ibm_quantum`. + auth: (DEPRECATED, use `channel` instead) Authentication type. `cloud` or `legacy`. name: Name of the account to save. proxies: Proxy configuration. Supported optional keys are ``urls`` (a dictionary mapping protocol or protocol and host to the URL of the proxy, @@ -570,12 +610,15 @@ def save_account( verify: Verify the server's TLS certificate. overwrite: ``True`` if the existing account is to be overwritten. """ + if auth: + IBMRuntimeService._auth_warning() + channel = channel or IBMRuntimeService._get_channel_for_auth(auth) AccountManager.save( token=token, url=url, instance=instance, - auth=auth, + channel=channel, name=name, proxies=ProxyConfiguration(**proxies) if proxies else None, verify=verify, @@ -586,13 +629,16 @@ def save_account( def saved_accounts( default: Optional[bool] = None, auth: Optional[str] = None, + channel: Optional[ChannelType] = None, name: Optional[str] = None, ) -> dict: """List the accounts saved on disk. Args: default: If set to True, only default accounts are returned. - auth: If set, only accounts with the given authentication type are returned. + auth: (DEPRECATED, use `channel` instead) If set, only accounts with the given + authentication type are returned. + channel: Channel type. `ibm_cloud` or `ibm_quantum`. name: If set, only accounts with the given name are returned. Returns: @@ -601,11 +647,15 @@ def saved_accounts( Raises: ValueError: If an invalid account is found on disk. """ - + if auth: + IBMRuntimeService._auth_warning() + channel = channel or IBMRuntimeService._get_channel_for_auth(auth) return dict( map( lambda kv: (kv[0], Account.to_saved_format(kv[1])), - AccountManager.list(default=default, auth=auth, name=name).items(), + AccountManager.list( + default=default, channel=channel, name=name + ).items(), ), ) @@ -618,7 +668,7 @@ def backend( Args: name: Name of the backend. - instance: This is only supported for legacy runtime and is in the + instance: This is only supported for ``ibm_quantum`` runtime and is in the hub/group/project format. Returns: @@ -795,7 +845,7 @@ def run( result_decoder: A :class:`ResultDecoder` subclass used to decode job results. ``ResultDecoder`` is used if not specified. - instance: This is only supported for legacy runtime and is in the + instance: This is only supported for ``ibm_quantum`` runtime and is in the hub/group/project format. session_id: Job ID of the first job in a runtime session. @@ -807,9 +857,9 @@ def run( RuntimeProgramNotFound: If the program cannot be found. IBMRuntimeError: An error occurred running the program. """ - if instance and self._auth != "legacy": + if instance and self._channel != "ibm_quantum": raise IBMInputValueError( - "The 'instance' keyword is only supported for legacy runtime. " + "The 'instance' keyword is only supported for ``ibm_quantum`` runtime. " ) # If using params object, extract as dictionary @@ -822,11 +872,11 @@ def run( if isinstance(options, dict): options = RuntimeOptions(**options) - options.validate(self.auth) + options.validate(channel=self.channel) backend = None hgp_name = None - if self._auth == "legacy": + if self._channel == "ibm_quantum": # Find the right hgp hgp = self._get_hgp(instance=instance, backend_name=options.backend_name) backend = hgp.backend(options.backend_name) @@ -1166,7 +1216,7 @@ def jobs( jobs are included. If ``False``, 'DONE', 'CANCELLED' and 'ERROR' jobs are included. program_id: Filter by Program ID. - instance: This is only supported for legacy runtime and is in the + instance: This is only supported for ``ibm_quantum`` runtime and is in the hub/group/project format. Returns: @@ -1177,9 +1227,9 @@ def jobs( """ hub = group = project = None if instance: - if self._auth == "cloud": + if self._channel == "ibm_cloud": raise IBMInputValueError( - "The 'instance' keyword is only supported for legacy runtime." + "The 'instance' keyword is only supported for ``ibm_quantum`` runtime." ) hub, group, project = from_instance_format(instance) @@ -1296,7 +1346,7 @@ def least_busy( Args: min_num_qubits: Minimum number of qubits the backend has to have. - instance: This is only supported for legacy runtime and is in the + instance: This is only supported for ``ibm_quantum`` runtime and is in the hub/group/project format. filters: More complex filters, such as lambda functions. For example:: @@ -1336,7 +1386,17 @@ def auth(self) -> str: Returns: The authentication type used. """ - return self._auth + self._auth_warning() + return "cloud" if self._channel == "ibm_cloud" else "legacy" + + @property + def channel(self) -> str: + """Return the channel type used. + + Returns: + The channel type used. + """ + return self._channel def __repr__(self) -> str: return "<{}>".format(self.__class__.__name__) diff --git a/qiskit_ibm_runtime/ibm_sampler.py b/qiskit_ibm_runtime/ibm_sampler.py index 9c9a291aa9..b344129eb4 100644 --- a/qiskit_ibm_runtime/ibm_sampler.py +++ b/qiskit_ibm_runtime/ibm_sampler.py @@ -62,7 +62,7 @@ class IBMSampler(BasePrimitive): from qiskit_ibm_runtime import IBMRuntimeService, IBMSampler - service = IBMRuntimeService(auth="cloud") + service = IBMRuntimeService(channel="ibm_cloud") sampler_factory = IBMSampler(service=service, backend="ibmq_qasm_simulator") bell = QuantumCircuit(2) diff --git a/qiskit_ibm_runtime/runtime_options.py b/qiskit_ibm_runtime/runtime_options.py index 7c94dceadd..a287956988 100644 --- a/qiskit_ibm_runtime/runtime_options.py +++ b/qiskit_ibm_runtime/runtime_options.py @@ -25,7 +25,7 @@ class RuntimeOptions: """Class for representing runtime execution options. Args: - backend_name: target backend to run on. This is required for legacy runtime. + backend_name: target backend to run on. This is required for ``ibm_quantum`` runtime. image: the runtime image used to execute the program, specified in the form of ``image_name:tag``. Not all accounts are authorized to select a different image. @@ -38,11 +38,11 @@ class RuntimeOptions: image: Optional[str] = None log_level: Optional[str] = None - def validate(self, auth: str) -> None: + def validate(self, channel: str) -> None: """Validate options. Args: - auth: authentication type. + channel: channel type. Raises: IBMInputValueError: If one or more option is invalid. @@ -53,9 +53,9 @@ def validate(self, auth: str) -> None: ): raise IBMInputValueError('"image" needs to be in form of image_name:tag') - if auth == "legacy" and not self.backend_name: + if channel == "ibm_quantum" and not self.backend_name: raise IBMInputValueError( - '"backend_name" is required field in "options" for legacy runtime.' + '"backend_name" is required field in "options" for ``ibm_quantum`` runtime.' ) if self.log_level and not isinstance( diff --git a/qiskit_ibm_runtime/utils/utils.py b/qiskit_ibm_runtime/utils/utils.py index a06c57ed82..f7d4fd975c 100644 --- a/qiskit_ibm_runtime/utils/utils.py +++ b/qiskit_ibm_runtime/utils/utils.py @@ -38,9 +38,9 @@ def get_resource_controller_api_url(cloud_url: str) -> str: return f"{parsed_url.scheme}://resource-controller.{parsed_url.hostname}" -def resolve_crn(auth: str, url: str, instance: str, token: str) -> List[str]: +def resolve_crn(channel: str, url: str, instance: str, token: str) -> List[str]: """Resolves the Cloud Resource Name (CRN) for the given cloud account.""" - if auth != "cloud": + if channel != "ibm_cloud": raise ValueError("CRN value can only be resolved for cloud accounts.") if is_crn(instance): @@ -85,7 +85,7 @@ def get_runtime_api_base_url(url: str, instance: str) -> str: Runtime API base URL """ - # legacy: no need to resolve runtime API URL + # ibm_quantum: no need to resolve runtime API URL api_host = url # cloud: compute runtime API URL based on crn and URL diff --git a/releasenotes/notes/add-channel-deprecate-auth-4e021efeb527818c.yaml b/releasenotes/notes/add-channel-deprecate-auth-4e021efeb527818c.yaml new file mode 100644 index 0000000000..089b27b2db --- /dev/null +++ b/releasenotes/notes/add-channel-deprecate-auth-4e021efeb527818c.yaml @@ -0,0 +1,17 @@ +--- +upgrade: + - | + A new parameter ``channel`` has now been added to :class:`qiskit_ibm_runtime.IBMRuntimeService` + class and also to methods like :meth:`~qiskit_ibm_runtime.IBMRuntimeService.save_account`, + :meth:`~qiskit_ibm_runtime.IBMRuntimeService.saved_accounts` and + :meth:`~qiskit_ibm_runtime.IBMRuntimeService.delete_account`. It can be set to ``ibm_quantum`` + or ``ibm_cloud`` to authenticate to either of the two different channels through which + Qiskit Runtime service is currently offered. ``channel`` replaces the ``auth`` parameter which + has now been deprecated. +deprecations: + - | + The ``auth`` parameter to :class:`qiskit_ibm_runtime.IBMRuntimeService` class + and also to methods like :meth:`~qiskit_ibm_runtime.IBMRuntimeService.save_account`, + :meth:`~qiskit_ibm_runtime.IBMRuntimeService.saved_accounts` and + :meth:`~qiskit_ibm_runtime.IBMRuntimeService.delete_account` has now been deprecated + and will be removed in a future release. Please use the new ``channel`` parameter instead. diff --git a/test/account.py b/test/account.py index a649d7ad9e..a30d4761e0 100644 --- a/test/account.py +++ b/test/account.py @@ -20,7 +20,7 @@ from unittest.mock import patch from qiskit_ibm_runtime.accounts import management -from qiskit_ibm_runtime.accounts.account import CLOUD_API_URL, LEGACY_API_URL +from qiskit_ibm_runtime.accounts.account import IBM_CLOUD_API_URL, IBM_QUANTUM_API_URL class custom_envs(ContextDecorator): @@ -127,7 +127,7 @@ def __exit__(self, *exc): def get_account_config_contents( name=None, - auth="cloud", + channel="ibm_cloud", token=None, url=None, instance=None, @@ -136,19 +136,19 @@ def get_account_config_contents( ): """Generate qiskitrc content""" if instance is None: - instance = "some_instance" if auth == "cloud" else "hub/group/project" + instance = "some_instance" if channel == "ibm_cloud" else "hub/group/project" token = token or uuid.uuid4().hex if name is None: name = ( - management._DEFAULT_ACCOUNT_NAME_CLOUD - if auth == "cloud" - else management._DEFAULT_ACCOUNT_NAME_LEGACY + management._DEFAULT_ACCOUNT_NAME_IBM_CLOUD + if channel == "ibm_cloud" + else management._DEFAULT_ACCOUNT_NAME_IBM_QUANTUM ) if url is None: - url = CLOUD_API_URL if auth == "cloud" else LEGACY_API_URL + url = IBM_CLOUD_API_URL if channel == "ibm_cloud" else IBM_QUANTUM_API_URL out = { name: { - "auth": auth, + "channel": channel, "url": url, "token": token, "instance": instance, diff --git a/test/decorators.py b/test/decorators.py index c467f10fe3..278a1c99cd 100644 --- a/test/decorators.py +++ b/test/decorators.py @@ -19,24 +19,25 @@ from unittest import SkipTest from qiskit_ibm_runtime import IBMRuntimeService + from .unit.mock.fake_runtime_service import FakeRuntimeService -def run_legacy_and_cloud_fake(func): - """Decorator that runs a test using both legacy and cloud fake services.""" +def run_quantum_and_cloud_fake(func): + """Decorator that runs a test using both quantum and cloud fake services.""" @wraps(func) def _wrapper(self, *args, **kwargs): - legacy_service = FakeRuntimeService( - auth="legacy", token="my_token", instance="h/g/p" + ibm_quantum_service = FakeRuntimeService( + channel="ibm_quantum", token="my_token", instance="h/g/p" ) cloud_service = FakeRuntimeService( - auth="cloud", + channel="ibm_cloud", token="my_token", instance="crn:v1:bluemix:public:quantum-computing:my-region:a/...:...::", ) - for service in [legacy_service, cloud_service]: - with self.subTest(service=service.auth): + for service in [ibm_quantum_service, cloud_service]: + with self.subTest(service=service.channel): kwargs["service"] = service func(self, *args, **kwargs) @@ -49,14 +50,16 @@ def _get_integration_test_config(): os.getenv("QISKIT_IBM_URL"), os.getenv("QISKIT_IBM_INSTANCE"), ) - auth: Any = "legacy" if url.find("quantum-computing.ibm.com") >= 0 else "cloud" - return auth, token, url, instance + channel: Any = ( + "ibm_quantum" if url.find("quantum-computing.ibm.com") >= 0 else "ibm_cloud" + ) + return channel, token, url, instance def run_integration_test(func): """Decorator that injects preinitialized service and device parameters. - To be used in combinatino with the integration_test_setup decorator function.""" + To be used in combination with the integration_test_setup decorator function.""" @wraps(func) def _wrapper(self, *args, **kwargs): @@ -69,13 +72,13 @@ def _wrapper(self, *args, **kwargs): def integration_test_setup( - supported_auth: Optional[List[str]] = None, + supported_channel: Optional[List[str]] = None, init_service: Optional[bool] = True, ) -> Callable: """Returns a decorator for integration test initialization. Args: - supported_auth: a list of auth types that this test supports + supported_channel: a list of channel types that this test supports init_service: to initialize the IBMRuntimeService based on the current environment configuration and return it via the test dependencies @@ -86,26 +89,28 @@ def integration_test_setup( def _decorator(func): @wraps(func) def _wrapper(self, *args, **kwargs): - _supported_auth = ( - ["cloud", "legacy"] if supported_auth is None else supported_auth + _supported_channel = ( + ["ibm_cloud", "ibm_quantum"] + if supported_channel is None + else supported_channel ) - auth, token, url, instance = _get_integration_test_config() - if not all([auth, token, url]): + channel, token, url, instance = _get_integration_test_config() + if not all([channel, token, url]): raise Exception("Configuration Issue") - if auth not in _supported_auth: + if channel not in _supported_channel: raise SkipTest( - f"Skipping integration test. Test does not support auth type {auth}" + f"Skipping integration test. Test does not support channel type {channel}" ) service = None if init_service: service = IBMRuntimeService( - auth=auth, token=token, url=url, instance=instance + channel=channel, token=token, url=url, instance=instance ) dependencies = IntegrationTestDependencies( - auth=auth, + channel=channel, token=token, url=url, instance=instance, @@ -126,5 +131,5 @@ class IntegrationTestDependencies: service: IBMRuntimeService instance: Optional[str] token: str - auth: str + channel: str url: str diff --git a/test/e2e/test_tutorials.py b/test/e2e/test_tutorials.py index e84306e76e..74bdcfcdcf 100644 --- a/test/e2e/test_tutorials.py +++ b/test/e2e/test_tutorials.py @@ -20,26 +20,29 @@ from nbconvert.preprocessors import ExecutePreprocessor from qiskit_ibm_runtime.utils.utils import to_python_identifier + from ..ibm_test_case import IBMIntegrationTestCase TUTORIAL_PATH = "docs/tutorials/**/*.ipynb" SUPPORTED_TUTORIALS = ["04_account_management"] -SUPPORTED_TUTORIALS_CLOUD = [ - "01_introduction_cloud_runtime.ipynb", +SUPPORTED_TUTORIALS_IBM_CLOUD = [ + "01_introduction_ibm_cloud_runtime.ipynb", *SUPPORTED_TUTORIALS, ] -SUPPORTED_TUTORIALS_LEGACY = [ - "02_introduction_legacy_runtime.ipynb", +SUPPORTED_TUTORIALS_IBM_QUANTUM = [ + "02_introduction_ibm_quantum_runtime.ipynb", *SUPPORTED_TUTORIALS, ] -def _is_supported(auth: str, tutorial_filename: str) -> bool: - """Not all tutorials work for all auth types. Check if the given tutorial is supported by the +def _is_supported(channel: str, tutorial_filename: str) -> bool: + """Not all tutorials work for all channel types. Check if the given tutorial is supported by the targeted environment.""" allowlist = ( - SUPPORTED_TUTORIALS_LEGACY if auth == "legacy" else SUPPORTED_TUTORIALS_CLOUD + SUPPORTED_TUTORIALS_IBM_QUANTUM + if channel == "ibm_quantum" + else SUPPORTED_TUTORIALS_IBM_CLOUD ) return any(tutorial_filename.endswith(filename) for filename in allowlist) @@ -70,9 +73,9 @@ class TestTutorials(IBMIntegrationTestCase, metaclass=TutorialsTestCaseMeta): """Tests for tutorials.""" def _run_notebook(self, filename): - if not _is_supported(self.dependencies.auth, filename): + if not _is_supported(self.dependencies.channel, filename): self.skipTest( - f"Tutorial {filename} not supported on {self.dependencies.auth}" + f"Tutorial {filename} not supported on {self.dependencies.channel}" ) # Create the preprocessor. diff --git a/test/ibm_test_case.py b/test/ibm_test_case.py index 398a86d984..3a57561fca 100644 --- a/test/ibm_test_case.py +++ b/test/ibm_test_case.py @@ -93,12 +93,12 @@ def tearDown(self) -> None: super().tearDown() # Delete programs service = self.service - for prog in self.to_delete[service.auth]: + for prog in self.to_delete[service.channel]: with suppress(Exception): service.delete_program(prog) # Cancel and delete jobs. - for job in self.to_cancel[service.auth]: + for job in self.to_cancel[service.channel]: with suppress(Exception): job.cancel() with suppress(Exception): @@ -120,7 +120,7 @@ def _upload_program( metadata["max_execution_time"] = max_execution_time metadata["is_public"] = is_public program_id = service.upload_program(data=data, metadata=metadata) - self.to_delete[service.auth].append(program_id) + self.to_delete[service.channel].append(program_id) return program_id @@ -143,11 +143,11 @@ def tearDownClass(cls) -> None: # Delete default program. with suppress(Exception): service = cls.service - service.delete_program(cls.program_ids[service.auth]) + service.delete_program(cls.program_ids[service.channel]) cls.log.debug( "Deleted %s program %s", - service.auth, - cls.program_ids[service.auth], + service.channel, + cls.program_ids[service.channel], ) @classmethod @@ -160,15 +160,15 @@ def _create_default_program(cls): service = cls.service try: prog_id = service.upload_program(data=RUNTIME_PROGRAM, metadata=metadata) - cls.log.debug("Uploaded %s program %s", service.auth, prog_id) - cls.program_ids[service.auth] = prog_id + cls.log.debug("Uploaded %s program %s", service.channel, prog_id) + cls.program_ids[service.channel] = prog_id except IBMNotAuthorizedError: raise unittest.SkipTest("No upload access.") @classmethod def _find_sim_backends(cls): """Find a simulator backend for each service.""" - cls.sim_backends[cls.service.auth] = cls.service.backends(simulator=True)[ + cls.sim_backends[cls.service.channel] = cls.service.backends(simulator=True)[ 0 ].name @@ -185,7 +185,7 @@ def _run_program( log_level=None, ): """Run a program.""" - self.log.debug("Running program on %s", service.auth) + self.log.debug("Running program on %s", service.channel) inputs = ( inputs if inputs is not None @@ -195,14 +195,14 @@ def _run_program( "final_result": final_result or {}, } ) - pid = program_id or self.program_ids[service.auth] + pid = program_id or self.program_ids[service.channel] backend_name = ( - backend if backend is not None else self.sim_backends[service.auth] + backend if backend is not None else self.sim_backends[service.channel] ) options = {"backend_name": backend_name, "log_level": log_level} job = service.run( program_id=pid, inputs=inputs, options=options, callback=callback ) self.log.info("Runtime job %s submitted.", job.job_id) - self.to_cancel[service.auth].append(job) + self.to_cancel[service.channel].append(job) return job diff --git a/test/integration/test_account.py b/test/integration/test_account.py index 50b2fe3c56..d4d2fb622e 100644 --- a/test/integration/test_account.py +++ b/test/integration/test_account.py @@ -49,18 +49,18 @@ def _get_service_instance_name_for_crn( class TestIntegrationAccount(IBMIntegrationTestCase): """Integration tests for account management.""" - def _skip_on_legacy(self): - if self.dependencies.auth == "legacy": - self.skipTest("Not supported on legacy") + def _skip_on_ibm_quantum(self): + if self.dependencies.channel == "ibm_quantum": + self.skipTest("Not supported on ibm_quantum") def test_resolve_crn_for_valid_service_instance_name(self): """Verify if CRN is transparently resolved based for an existing service instance name.""" - self._skip_on_legacy() + self._skip_on_ibm_quantum() service_instance_name = _get_service_instance_name_for_crn(self.dependencies) with self.subTest(instance=service_instance_name): service = IBMRuntimeService( - auth="cloud", + channel="ibm_cloud", url=self.dependencies.url, token=self.dependencies.token, instance=service_instance_name, @@ -72,14 +72,14 @@ def test_resolve_crn_for_valid_service_instance_name(self): def test_resolve_crn_for_invalid_service_instance_name(self): """Verify if CRN resolution fails for non-existing service instance name.""" - self._skip_on_legacy() + self._skip_on_ibm_quantum() service_instance_name = "-non-existing-service-name-" with self.subTest(instance="-non-existing-service-name-"), self.assertRaises( CloudResourceNameResolutionError ): IBMRuntimeService( - auth="cloud", + channel="ibm_cloud", url=self.dependencies.url, token=self.dependencies.token, instance=service_instance_name, diff --git a/test/integration/test_auth_client.py b/test/integration/test_auth_client.py index 6178f4c25c..0fce1d77cd 100644 --- a/test/integration/test_auth_client.py +++ b/test/integration/test_auth_client.py @@ -24,41 +24,41 @@ class TestAuthClient(IBMTestCase): """Tests for the AuthClient.""" - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_valid_login(self, dependencies: IntegrationTestDependencies) -> None: """Test valid authentication.""" client = self._init_auth_client(dependencies.token, dependencies.url) self.assertTrue(client.access_token) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_url_404(self, dependencies: IntegrationTestDependencies) -> None: """Test login against a 404 URL""" url_404 = re.sub(r"/api.*$", "/api/TEST_404", dependencies.url) with self.assertRaises(ApiError): _ = self._init_auth_client(dependencies.token, url_404) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_invalid_token(self, dependencies: IntegrationTestDependencies) -> None: """Test login using invalid token.""" qe_token = "INVALID_TOKEN" with self.assertRaises(ApiError): _ = self._init_auth_client(qe_token, dependencies.url) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_url_unreachable(self, dependencies: IntegrationTestDependencies) -> None: """Test login against an invalid (malformed) URL.""" qe_url = "INVALID_URL" with self.assertRaises(ApiError): _ = self._init_auth_client(dependencies.token, qe_url) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_api_version(self, dependencies: IntegrationTestDependencies) -> None: """Check the version of the QX API.""" client = self._init_auth_client(dependencies.token, dependencies.url) version = client.api_version() self.assertIsNotNone(version) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_user_urls(self, dependencies: IntegrationTestDependencies) -> None: """Check the user urls of the QX API.""" client = self._init_auth_client(dependencies.token, dependencies.url) @@ -66,7 +66,7 @@ def test_user_urls(self, dependencies: IntegrationTestDependencies) -> None: self.assertIsNotNone(user_urls) self.assertTrue("http" in user_urls and "ws" in user_urls) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_user_hubs(self, dependencies: IntegrationTestDependencies) -> None: """Check the user hubs of the QX API.""" client = self._init_auth_client(dependencies.token, dependencies.url) @@ -80,5 +80,5 @@ def test_user_hubs(self, dependencies: IntegrationTestDependencies) -> None: def _init_auth_client(self, token, url): """Return an AuthClient.""" - params = ClientParameters(auth_type="legacy", token=token, url=url) + params = ClientParameters(channel="ibm_quantum", token=token, url=url) return AuthClient(params) diff --git a/test/integration/test_backend.py b/test/integration/test_backend.py index 86d039272c..52ed519b91 100644 --- a/test/integration/test_backend.py +++ b/test/integration/test_backend.py @@ -15,6 +15,7 @@ from unittest import SkipTest from qiskit.transpiler.target import Target + from ..ibm_test_case import IBMIntegrationTestCase from ..decorators import run_integration_test @@ -51,10 +52,10 @@ def setUpClass(cls): # pylint: disable=arguments-differ # pylint: disable=no-value-for-parameter super().setUpClass() - if cls.dependencies.auth == "cloud": + if cls.dependencies.channel == "ibm_cloud": # TODO use real device when cloud supports it cls.backend = cls.dependencies.service.least_busy(min_num_qubits=5) - if cls.dependencies.auth == "legacy": + if cls.dependencies.channel == "ibm_quantum": cls.backend = cls.dependencies.service.least_busy( simulator=False, min_num_qubits=5, instance=cls.dependencies.instance ) diff --git a/test/integration/test_backend_serialization.py b/test/integration/test_backend_serialization.py index 3efd6af58d..967409c216 100644 --- a/test/integration/test_backend_serialization.py +++ b/test/integration/test_backend_serialization.py @@ -28,7 +28,9 @@ class TestSerialization(IBMIntegrationTestCase): @run_integration_test def test_backend_configuration(self, service): """Test deserializing backend configuration.""" - instance = self.dependencies.instance if service.auth == "legacy" else None + instance = ( + self.dependencies.instance if service.channel == "ibm_quantum" else None + ) backends = service.backends( operational=True, simulator=False, instance=instance ) @@ -56,7 +58,9 @@ def test_backend_configuration(self, service): @run_integration_test def test_pulse_defaults(self, service): """Test deserializing backend configuration.""" - instance = self.dependencies.instance if service.auth == "legacy" else None + instance = ( + self.dependencies.instance if service.channel == "ibm_quantum" else None + ) backends = service.backends( operational=True, open_pulse=True, instance=instance ) @@ -73,7 +77,9 @@ def test_pulse_defaults(self, service): @run_integration_test def test_backend_properties(self, service): """Test deserializing backend properties.""" - instance = self.dependencies.instance if service.auth == "legacy" else None + instance = ( + self.dependencies.instance if service.channel == "ibm_quantum" else None + ) backends = service.backends( operational=True, simulator=False, instance=instance ) diff --git a/test/integration/test_basic_server_paths.py b/test/integration/test_basic_server_paths.py index aa8f705a34..ea4f79c2c5 100644 --- a/test/integration/test_basic_server_paths.py +++ b/test/integration/test_basic_server_paths.py @@ -20,7 +20,7 @@ class TestBasicServerPaths(IBMTestCase): """Test the basic server endpoints using both a public and premium provider.""" @classmethod - @integration_test_setup(supported_auth=["legacy"]) + @integration_test_setup(supported_channel=["ibm_quantum"]) def setUpClass(cls, dependencies: IntegrationTestDependencies) -> None: # pylint: disable=arguments-differ super().setUpClass() diff --git a/test/integration/test_job.py b/test/integration/test_job.py index 715dc5dd4c..4ae42bdbf1 100644 --- a/test/integration/test_job.py +++ b/test/integration/test_job.py @@ -59,8 +59,8 @@ def test_run_program_real_device(self, service): def test_run_program_cloud_no_backend(self, service): """Test running a cloud program with no backend.""" - if self.dependencies.auth == "legacy": - self.skipTest("Not supported on legacy") + if self.dependencies.channel == "ibm_quantum": + self.skipTest("Not supported on ibm_quantum") job = self._run_program(service, backend="") self.assertTrue(job.backend, f"Job {job.job_id} has no backend.") @@ -205,13 +205,13 @@ def test_job_inputs(self, service): def test_job_backend(self, service): """Test job backend.""" job = self._run_program(service) - self.assertEqual(self.sim_backends[service.auth], job.backend.name) + self.assertEqual(self.sim_backends[service.channel], job.backend.name) @run_integration_test def test_job_program_id(self, service): """Test job program ID.""" job = self._run_program(service) - self.assertEqual(self.program_ids[service.auth], job.program_id) + self.assertEqual(self.program_ids[service.channel], job.program_id) @run_integration_test def test_wait_for_final_state(self, service): diff --git a/test/integration/test_proxies.py b/test/integration/test_proxies.py index 1021a3c491..7feb3119f4 100644 --- a/test/integration/test_proxies.py +++ b/test/integration/test_proxies.py @@ -55,7 +55,7 @@ def tearDown(self): # wait for the process to terminate self.proxy_process.wait() - @integration_test_setup(supported_auth=["cloud"]) + @integration_test_setup(supported_channel=["ibm_cloud"]) def test_proxies_cloud_runtime_client( self, dependencies: IntegrationTestDependencies ) -> None: @@ -70,13 +70,13 @@ def test_proxies_cloud_runtime_client( proxy_output = self.proxy_process.stdout.read().decode("utf-8") self.assertIn(api_line, proxy_output) - @integration_test_setup(supported_auth=["legacy"], init_service=False) - def test_proxies_legacy_runtime_client( + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) + def test_proxies_ibm_quantum_runtime_client( self, dependencies: IntegrationTestDependencies ) -> None: """Should reach the proxy using RuntimeClient.""" service = IBMRuntimeService( - auth="legacy", + channel="ibm_quantum", token=dependencies.token, url=dependencies.url, proxies={"urls": VALID_PROXIES}, @@ -94,13 +94,13 @@ def test_proxies_legacy_runtime_client( # Check if the API call (querying providers list) went through proxy. self.assertIn(api_line, proxy_output) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_proxies_account_client( self, dependencies: IntegrationTestDependencies ) -> None: """Should reach the proxy using AccountClient.""" service = IBMRuntimeService( - auth="legacy", + channel="ibm_quantum", token=dependencies.token, url=dependencies.url, proxies={"urls": VALID_PROXIES}, @@ -118,7 +118,7 @@ def test_proxies_account_client( # Check if the API call (querying providers list) went through proxy. self.assertIn(api_line, proxy_output) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_proxies_authclient( self, dependencies: IntegrationTestDependencies ) -> None: @@ -127,7 +127,7 @@ def test_proxies_authclient( dependencies.url ) params = ClientParameters( - auth_type="legacy", + channel="ibm_quantum", token=dependencies.token, url=dependencies.url, proxies=ProxyConfiguration(urls=VALID_PROXIES), @@ -141,7 +141,7 @@ def test_proxies_authclient( self.proxy_process.stdout.read().decode("utf-8"), ) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_proxies_versionclient( self, dependencies: IntegrationTestDependencies ) -> None: @@ -159,13 +159,13 @@ def test_proxies_versionclient( self.proxy_process.stdout.read().decode("utf-8"), ) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_invalid_proxy_port_runtime_client( self, dependencies: IntegrationTestDependencies ) -> None: """Should raise RequestApiError with ProxyError using RuntimeClient.""" params = ClientParameters( - auth_type="legacy", + channel="ibm_quantum", token=dependencies.token, url=dependencies.url, proxies=ProxyConfiguration(urls=INVALID_PORT_PROXIES), @@ -175,13 +175,13 @@ def test_invalid_proxy_port_runtime_client( client.list_programs(limit=1) self.assertIsInstance(context_manager.exception.__cause__, ProxyError) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_invalid_proxy_port_authclient( self, dependencies: IntegrationTestDependencies ) -> None: """Should raise RequestApiError with ProxyError using AuthClient.""" params = ClientParameters( - auth_type="legacy", + channel="ibm_quantum", token=dependencies.token, url=dependencies.url, proxies=ProxyConfiguration(urls=INVALID_PORT_PROXIES), @@ -191,7 +191,7 @@ def test_invalid_proxy_port_authclient( self.assertIsInstance(context_manager.exception.__cause__, ProxyError) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_invalid_proxy_port_versionclient( self, dependencies: IntegrationTestDependencies ) -> None: @@ -204,13 +204,13 @@ def test_invalid_proxy_port_versionclient( self.assertIsInstance(context_manager.exception.__cause__, ProxyError) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_invalid_proxy_address_runtime_client( self, dependencies: IntegrationTestDependencies ) -> None: """Should raise RequestApiError with ProxyError using RuntimeClient.""" params = ClientParameters( - auth_type="legacy", + channel="ibm_quantum", token=dependencies.token, url=dependencies.url, proxies=ProxyConfiguration(urls=INVALID_ADDRESS_PROXIES), @@ -221,13 +221,13 @@ def test_invalid_proxy_address_runtime_client( self.assertIsInstance(context_manager.exception.__cause__, ProxyError) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_invalid_proxy_address_authclient( self, dependencies: IntegrationTestDependencies ) -> None: """Should raise RequestApiError with ProxyError using AuthClient.""" params = ClientParameters( - auth_type="legacy", + channel="ibm_quantum", token=dependencies.token, url=dependencies.url, proxies=ProxyConfiguration(urls=INVALID_ADDRESS_PROXIES), @@ -237,7 +237,7 @@ def test_invalid_proxy_address_authclient( self.assertIsInstance(context_manager.exception.__cause__, ProxyError) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_invalid_proxy_address_versionclient( self, dependencies: IntegrationTestDependencies ) -> None: @@ -250,7 +250,7 @@ def test_invalid_proxy_address_versionclient( self.assertIsInstance(context_manager.exception.__cause__, ProxyError) - @integration_test_setup(supported_auth=["legacy"], init_service=False) + @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) def test_proxy_urls(self, dependencies: IntegrationTestDependencies) -> None: """Test different forms of the proxy urls.""" test_urls = [ @@ -261,7 +261,7 @@ def test_proxy_urls(self, dependencies: IntegrationTestDependencies) -> None: for proxy_url in test_urls: with self.subTest(proxy_url=proxy_url): params = ClientParameters( - auth_type="legacy", + channel="ibm_quantum", token=dependencies.token, url=dependencies.url, proxies=ProxyConfiguration(urls={"https": proxy_url}), diff --git a/test/integration/test_retrieve_job.py b/test/integration/test_retrieve_job.py index b2b4a1a91c..ee94c4bc2b 100644 --- a/test/integration/test_retrieve_job.py +++ b/test/integration/test_retrieve_job.py @@ -33,7 +33,7 @@ def test_retrieve_job_queued(self, service): wait_for_status(job, JobStatus.QUEUED) rjob = service.job(job.job_id) self.assertEqual(job.job_id, rjob.job_id) - self.assertEqual(self.program_ids[service.auth], rjob.program_id) + self.assertEqual(self.program_ids[service.channel], rjob.program_id) @run_integration_test def test_retrieve_job_running(self, service): @@ -42,7 +42,7 @@ def test_retrieve_job_running(self, service): wait_for_status(job, JobStatus.RUNNING) rjob = service.job(job.job_id) self.assertEqual(job.job_id, rjob.job_id) - self.assertEqual(self.program_ids[service.auth], rjob.program_id) + self.assertEqual(self.program_ids[service.channel], rjob.program_id) @run_integration_test def test_retrieve_job_done(self, service): @@ -51,7 +51,7 @@ def test_retrieve_job_done(self, service): job.wait_for_final_state() rjob = service.job(job.job_id) self.assertEqual(job.job_id, rjob.job_id) - self.assertEqual(self.program_ids[service.auth], rjob.program_id) + self.assertEqual(self.program_ids[service.channel], rjob.program_id) @run_integration_test def test_retrieve_all_jobs(self, service): @@ -74,7 +74,7 @@ def test_retrieve_jobs_limit(self, service): for _ in range(3): jobs.append(self._run_program(service)) - rjobs = service.jobs(limit=2, program_id=self.program_ids[service.auth]) + rjobs = service.jobs(limit=2, program_id=self.program_ids[service.channel]) self.assertEqual(len(rjobs), 2, f"Retrieved jobs: {[j.job_id for j in rjobs]}") job_ids = {job.job_id for job in jobs} rjob_ids = {rjob.job_id for rjob in rjobs} @@ -130,8 +130,8 @@ def test_retrieve_jobs_by_program_id(self, service): @run_integration_test def test_jobs_filter_by_hgp(self, service): """Test retrieving jobs by hgp.""" - if self.dependencies.auth == "cloud": - self.skipTest("Not supported on cloud") + if self.dependencies.channel == "ibm_cloud": + self.skipTest("Not supported on ibm_cloud") default_hgp = list(service._hgps.keys())[0] program_id = self._upload_program(service) diff --git a/test/unit/mock/fake_legacy_auth_client.py b/test/unit/mock/fake_quantum_auth_client.py similarity index 98% rename from test/unit/mock/fake_legacy_auth_client.py rename to test/unit/mock/fake_quantum_auth_client.py index 05865857a7..dd65a1919a 100644 --- a/test/unit/mock/fake_legacy_auth_client.py +++ b/test/unit/mock/fake_quantum_auth_client.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -"""Fake legacy AuthClient.""" +"""Fake ibm_quantum AuthClient.""" from typing import Dict, List, Union, Optional diff --git a/test/unit/mock/fake_runtime_client.py b/test/unit/mock/fake_runtime_client.py index bb4775d0e5..01606da058 100644 --- a/test/unit/mock/fake_runtime_client.py +++ b/test/unit/mock/fake_runtime_client.py @@ -27,12 +27,12 @@ def cloud_only(func): - """Decorator that runs a test using both legacy and cloud services.""" + """Decorator that runs a test using only ibm_cloud services.""" @wraps(func) def _wrapper(self, *args, **kwargs): - if self._auth_type != "cloud": - raise ValueError(f"Method {func} called by a legacy client!") + if self._channel != "ibm_cloud": + raise ValueError(f"Method {func} called by an ibm_quantum client!") return func(self, *args, **kwargs) return _wrapper @@ -264,7 +264,7 @@ def __init__(self, *args, **kwargs): self._backend_client = test_options.get( "backend_client", BaseFakeAccountClient() ) - self._auth_type = test_options.get("auth_type", "legacy") + self._channel = test_options.get("channel", "ibm_quantum") def set_job_classes(self, classes): """Set job classes to use.""" @@ -514,5 +514,5 @@ def backend_pulse_defaults(self, backend_name: str) -> Dict[str, Any]: @cloud_only def _check_cloud_only(self): - if self._auth_type != "cloud": - raise ValueError("A backend method is called by a legacy client!") + if self._channel != "ibm_cloud": + raise ValueError("A backend method is called by an ibm_quantum client!") diff --git a/test/unit/mock/fake_runtime_service.py b/test/unit/mock/fake_runtime_service.py index a766fd5ec5..eacac82702 100644 --- a/test/unit/mock/fake_runtime_service.py +++ b/test/unit/mock/fake_runtime_service.py @@ -52,7 +52,7 @@ def __init__(self, *args, **kwargs): ): super().__init__(*args, **kwargs) - def _authenticate_legacy_account( + def _authenticate_ibm_quantum_account( self, client_params: ClientParameters ) -> "FakeAuthClient": """Mock authentication.""" @@ -73,7 +73,7 @@ def _initialize_hgps( hgp_name = self.DEFAULT_HGPS[idx] hgp_params = ClientParameters( - auth_type="legacy", + channel="ibm_quantum", token="some_token", url="some_url", instance=hgp_name, @@ -113,7 +113,7 @@ def _discover_cloud_backends(self): test_options = { "backend_client": self._fake_account_client, - "auth_type": "cloud", + "channel": "ibm_cloud", } self._api_client = BaseFakeRuntimeClient(test_options=test_options) return super()._discover_cloud_backends() @@ -128,7 +128,10 @@ def __init__(self): # pylint: disable=super-init-not-called def current_service_urls(self): """Return service urls.""" - return {"http": "legacy_api_url", "services": {"runtime": "legacy_runtime_url"}} + return { + "http": "IBM_QUANTUM_API_URL", + "services": {"runtime": "ibm_quantum_runtime_url"}, + } def current_access_token(self): """Return access token.""" diff --git a/test/unit/test_account.py b/test/unit/test_account.py index 659aeb2554..fd3dc2655f 100644 --- a/test/unit/test_account.py +++ b/test/unit/test_account.py @@ -22,12 +22,17 @@ from qiskit_ibm_runtime.accounts import ( AccountManager, Account, - management, AccountAlreadyExistsError, AccountNotFoundError, InvalidAccountError, ) -from qiskit_ibm_runtime.accounts.account import CLOUD_API_URL, LEGACY_API_URL +from qiskit_ibm_runtime.accounts.account import IBM_CLOUD_API_URL, IBM_QUANTUM_API_URL +from qiskit_ibm_runtime.accounts.management import ( + _DEFAULT_ACCOUNT_NAME_LEGACY, + _DEFAULT_ACCOUNT_NAME_CLOUD, + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM, + _DEFAULT_ACCOUNT_NAME_IBM_CLOUD, +) from qiskit_ibm_runtime.proxies import ProxyConfiguration from .mock.fake_runtime_service import FakeRuntimeService from ..ibm_test_case import IBMTestCase @@ -38,15 +43,15 @@ custom_envs, ) -_TEST_LEGACY_ACCOUNT = Account( - auth="legacy", +_TEST_IBM_QUANTUM_ACCOUNT = Account( + channel="ibm_quantum", token="token-x", url="https://auth.quantum-computing.ibm.com/api", instance="ibm-q/open/main", ) -_TEST_CLOUD_ACCOUNT = Account( - auth="cloud", +_TEST_IBM_CLOUD_ACCOUNT = Account( + channel="ibm_cloud", token="token-y", url="https://cloud.ibm.com", instance="crn:v1:bluemix:public:quantum-computing:us-east:a/...::", @@ -55,29 +60,50 @@ ), ) +_TEST_LEGACY_ACCOUNT = { + "auth": "legacy", + "token": "token-x", + "url": "https://auth.quantum-computing.ibm.com/api", + "instance": "ibm-q/open/main", +} + +_TEST_CLOUD_ACCOUNT = { + "auth": "cloud", + "token": "token-y", + "url": "https://cloud.ibm.com", + "instance": "crn:v1:bluemix:public:quantum-computing:us-east:a/...::", + "proxies": { + "username_ntlm": "bla", + "password_ntlm": "blub", + "urls": {"https": "127.0.0.1"}, + }, +} + class TestAccount(IBMTestCase): """Tests for Account class.""" dummy_token = "123" - dummy_cloud_url = "https://us-east.quantum-computing.cloud.ibm.com" - dummy_legacy_url = "https://auth.quantum-computing.ibm.com/api" + dummy_ibm_cloud_url = "https://us-east.quantum-computing.cloud.ibm.com" + dummy_ibm_quantum_url = "https://auth.quantum-computing.ibm.com/api" def test_skip_crn_resolution_for_crn(self): """Test that CRN resolution is skipped if the instance value is already a CRN.""" - account = copy.deepcopy(_TEST_CLOUD_ACCOUNT) + account = copy.deepcopy(_TEST_IBM_CLOUD_ACCOUNT) account.resolve_crn() - self.assertEqual(account.instance, _TEST_CLOUD_ACCOUNT.instance) + self.assertEqual(account.instance, _TEST_IBM_CLOUD_ACCOUNT.instance) - def test_invalid_auth(self): - """Test invalid values for auth parameter.""" + def test_invalid_channel(self): + """Test invalid values for channel parameter.""" with self.assertRaises(InvalidAccountError) as err: - invalid_auth: Any = "phantom" + invalid_channel: Any = "phantom" Account( - auth=invalid_auth, token=self.dummy_token, url=self.dummy_cloud_url + channel=invalid_channel, + token=self.dummy_token, + url=self.dummy_ibm_cloud_url, ).validate() - self.assertIn("Invalid `auth` value.", str(err.exception)) + self.assertIn("Invalid `channel` value.", str(err.exception)) def test_invalid_token(self): """Test invalid values for token parameter.""" @@ -87,7 +113,9 @@ def test_invalid_token(self): with self.subTest(token=token): with self.assertRaises(InvalidAccountError) as err: Account( - auth="cloud", token=token, url=self.dummy_cloud_url + channel="ibm_cloud", + token=token, + url=self.dummy_ibm_cloud_url, ).validate() self.assertIn("Invalid `token` value.", str(err.exception)) @@ -95,7 +123,7 @@ def test_invalid_url(self): """Test invalid values for url parameter.""" subtests = [ - {"auth": "cloud", "url": 123}, + {"channel": "ibm_cloud", "url": 123}, ] for params in subtests: with self.subTest(params=params): @@ -107,15 +135,15 @@ def test_invalid_instance(self): """Test invalid values for instance parameter.""" subtests = [ - {"auth": "cloud", "instance": ""}, - {"auth": "cloud"}, - {"auth": "legacy", "instance": "no-hgp-format"}, + {"channel": "ibm_cloud", "instance": ""}, + {"channel": "ibm_cloud"}, + {"channel": "ibm_quantum", "instance": "no-hgp-format"}, ] for params in subtests: with self.subTest(params=params): with self.assertRaises(InvalidAccountError) as err: Account( - **params, token=self.dummy_token, url=self.dummy_cloud_url + **params, token=self.dummy_token, url=self.dummy_ibm_cloud_url ).validate() self.assertIn("Invalid `instance` value.", str(err.exception)) @@ -138,9 +166,9 @@ def test_invalid_proxy_config(self): with self.assertRaises(ValueError) as err: Account( **params, - auth="legacy", + channel="ibm_quantum", token=self.dummy_token, - url=self.dummy_cloud_url, + url=self.dummy_ibm_cloud_url, ).validate() self.assertIn("Invalid proxy configuration", str(err.exception)) @@ -151,22 +179,169 @@ class TestAccountManager(IBMTestCase): """Tests for AccountManager class.""" @temporary_account_config_file( - contents={"conflict": _TEST_CLOUD_ACCOUNT.to_saved_format()} + contents={"conflict": _TEST_IBM_CLOUD_ACCOUNT.to_saved_format()} ) - def test_save_without_override(self): - """Test to override an existing account without setting overwrite=True.""" + def test_save_without_overwrite(self): + """Test to overwrite an existing account without setting overwrite=True.""" with self.assertRaises(AccountAlreadyExistsError): AccountManager.save( name="conflict", - token=_TEST_CLOUD_ACCOUNT.token, - url=_TEST_CLOUD_ACCOUNT.url, - instance=_TEST_CLOUD_ACCOUNT.instance, - auth="cloud", + token=_TEST_IBM_CLOUD_ACCOUNT.token, + url=_TEST_IBM_CLOUD_ACCOUNT.url, + instance=_TEST_IBM_CLOUD_ACCOUNT.instance, + channel="ibm_cloud", + overwrite=False, + ) + + # TODO remove test when removing auth parameter + @temporary_account_config_file( + contents={_DEFAULT_ACCOUNT_NAME_CLOUD: _TEST_CLOUD_ACCOUNT} + ) + @no_envs(["QISKIT_IBM_TOKEN"]) + def test_save_channel_ibm_cloud_over_auth_cloud_without_overwrite(self): + """Test to overwrite an existing auth "cloud" account with channel "ibm_cloud" + and without setting overwrite=True.""" + with self.assertRaises(AccountAlreadyExistsError): + AccountManager.save( + token=_TEST_IBM_CLOUD_ACCOUNT.token, + url=_TEST_IBM_CLOUD_ACCOUNT.url, + instance=_TEST_IBM_CLOUD_ACCOUNT.instance, + channel="ibm_cloud", + name=None, overwrite=False, ) + # TODO remove test when removing auth parameter @temporary_account_config_file( - contents={"conflict": _TEST_CLOUD_ACCOUNT.to_saved_format()} + contents={_DEFAULT_ACCOUNT_NAME_LEGACY: _TEST_LEGACY_ACCOUNT} + ) + @no_envs(["QISKIT_IBM_TOKEN"]) + def test_save_channel_ibm_quantum_over_auth_legacy_without_overwrite(self): + """Test to overwrite an existing auth "legacy" account with channel "ibm_quantum" + and without setting overwrite=True.""" + with self.assertRaises(AccountAlreadyExistsError): + AccountManager.save( + token=_TEST_IBM_QUANTUM_ACCOUNT.token, + url=_TEST_IBM_QUANTUM_ACCOUNT.url, + instance=_TEST_IBM_QUANTUM_ACCOUNT.instance, + channel="ibm_quantum", + name=None, + overwrite=False, + ) + + # TODO remove test when removing auth parameter + @temporary_account_config_file( + contents={_DEFAULT_ACCOUNT_NAME_LEGACY: _TEST_LEGACY_ACCOUNT} + ) + @no_envs(["QISKIT_IBM_TOKEN"]) + def test_save_channel_ibm_quantum_over_auth_legacy_with_overwrite(self): + """Test to overwrite an existing auth "legacy" account with channel "ibm_quantum" + and with setting overwrite=True.""" + AccountManager.save( + token=_TEST_IBM_QUANTUM_ACCOUNT.token, + url=_TEST_IBM_QUANTUM_ACCOUNT.url, + instance=_TEST_IBM_QUANTUM_ACCOUNT.instance, + channel="ibm_quantum", + name=None, + overwrite=True, + ) + self.assertEqual( + _TEST_IBM_QUANTUM_ACCOUNT, AccountManager.get(channel="ibm_quantum") + ) + + # TODO remove test when removing auth parameter + @temporary_account_config_file( + contents={_DEFAULT_ACCOUNT_NAME_CLOUD: _TEST_CLOUD_ACCOUNT} + ) + @no_envs(["QISKIT_IBM_TOKEN"]) + def test_save_channel_ibm_cloud_over_auth_cloud_with_overwrite(self): + """Test to overwrite an existing auth "cloud" account with channel "ibm_cloud" + and with setting overwrite=True.""" + AccountManager.save( + token=_TEST_IBM_CLOUD_ACCOUNT.token, + url=_TEST_IBM_CLOUD_ACCOUNT.url, + instance=_TEST_IBM_CLOUD_ACCOUNT.instance, + channel="ibm_cloud", + proxies=_TEST_IBM_CLOUD_ACCOUNT.proxies, + name=None, + overwrite=True, + ) + self.assertEqual( + _TEST_IBM_CLOUD_ACCOUNT, AccountManager.get(channel="ibm_cloud") + ) + + # TODO remove test when removing auth parameter + @temporary_account_config_file(contents={"personal-account": _TEST_CLOUD_ACCOUNT}) + def test_save_channel_ibm_cloud_with_name_over_auth_cloud_with_overwrite(self): + """Test to overwrite an existing named auth "cloud" account with channel "ibm_cloud" + and with setting overwrite=True.""" + AccountManager.save( + token=_TEST_IBM_CLOUD_ACCOUNT.token, + url=_TEST_IBM_CLOUD_ACCOUNT.url, + instance=_TEST_IBM_CLOUD_ACCOUNT.instance, + channel="ibm_cloud", + proxies=_TEST_IBM_CLOUD_ACCOUNT.proxies, + name="personal-account", + overwrite=True, + ) + self.assertEqual( + _TEST_IBM_CLOUD_ACCOUNT, AccountManager.get(name="personal-account") + ) + + # TODO remove test when removing auth parameter + @temporary_account_config_file(contents={"personal-account": _TEST_CLOUD_ACCOUNT}) + def test_save_channel_ibm_cloud_with_name_over_auth_cloud_without_overwrite(self): + """Test to overwrite an existing named auth "cloud" account with channel "ibm_cloud" + and without setting overwrite=True.""" + with self.assertRaises(AccountAlreadyExistsError): + AccountManager.save( + token=_TEST_IBM_CLOUD_ACCOUNT.token, + url=_TEST_IBM_CLOUD_ACCOUNT.url, + instance=_TEST_IBM_CLOUD_ACCOUNT.instance, + channel="ibm_cloud", + proxies=_TEST_IBM_CLOUD_ACCOUNT.proxies, + name="personal-account", + overwrite=False, + ) + + # TODO remove test when removing auth parameter + @temporary_account_config_file(contents={"personal-account": _TEST_LEGACY_ACCOUNT}) + def test_save_channel_ibm_quantum_with_name_over_auth_legacy_with_overwrite(self): + """Test to overwrite an existing named auth "legacy" account with channel "ibm_quantum" + and with setting overwrite=True.""" + AccountManager.save( + token=_TEST_IBM_QUANTUM_ACCOUNT.token, + url=_TEST_IBM_QUANTUM_ACCOUNT.url, + instance=_TEST_IBM_QUANTUM_ACCOUNT.instance, + channel="ibm_quantum", + proxies=_TEST_IBM_QUANTUM_ACCOUNT.proxies, + name="personal-account", + overwrite=True, + ) + self.assertEqual( + _TEST_IBM_QUANTUM_ACCOUNT, AccountManager.get(name="personal-account") + ) + + # TODO remove test when removing auth parameter + @temporary_account_config_file(contents={"personal-account": _TEST_LEGACY_ACCOUNT}) + def test_save_channel_ibm_quantum_with_name_over_auth_legacy_without_overwrite( + self, + ): + """Test to overwrite an existing named auth "legacy" account with channel "ibm_quantum" + and without setting overwrite=True.""" + with self.assertRaises(AccountAlreadyExistsError): + AccountManager.save( + token=_TEST_IBM_QUANTUM_ACCOUNT.token, + url=_TEST_IBM_QUANTUM_ACCOUNT.url, + instance=_TEST_IBM_QUANTUM_ACCOUNT.instance, + channel="ibm_quantum", + proxies=_TEST_IBM_QUANTUM_ACCOUNT.proxies, + name="personal-account", + overwrite=False, + ) + + @temporary_account_config_file( + contents={"conflict": _TEST_IBM_CLOUD_ACCOUNT.to_saved_format()} ) def test_get_none(self): """Test to get an account with an invalid name.""" @@ -184,27 +359,31 @@ def test_save_get(self): # - the name passed to AccountManager.get sub_tests = [ # verify accounts can be saved and retrieved via custom names - (_TEST_LEGACY_ACCOUNT, "acct-1", "acct-1"), - (_TEST_CLOUD_ACCOUNT, "acct-2", "acct-2"), - # verify default account name handling for cloud accounts - (_TEST_CLOUD_ACCOUNT, None, management._DEFAULT_ACCOUNT_NAME_CLOUD), - (_TEST_CLOUD_ACCOUNT, None, None), - # verify default account name handling for legacy accounts - (_TEST_LEGACY_ACCOUNT, None, management._DEFAULT_ACCOUNT_NAME_LEGACY), + (_TEST_IBM_QUANTUM_ACCOUNT, "acct-1", "acct-1"), + (_TEST_IBM_CLOUD_ACCOUNT, "acct-2", "acct-2"), + # verify default account name handling for ibm_cloud accounts + (_TEST_IBM_CLOUD_ACCOUNT, None, _DEFAULT_ACCOUNT_NAME_IBM_CLOUD), + (_TEST_IBM_CLOUD_ACCOUNT, None, None), + # verify default account name handling for ibm_quantum accounts + ( + _TEST_IBM_QUANTUM_ACCOUNT, + None, + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM, + ), # verify account override - (_TEST_LEGACY_ACCOUNT, "acct", "acct"), - (_TEST_CLOUD_ACCOUNT, "acct", "acct"), + (_TEST_IBM_QUANTUM_ACCOUNT, "acct", "acct"), + (_TEST_IBM_CLOUD_ACCOUNT, "acct", "acct"), ] for account, name_save, name_get in sub_tests: with self.subTest( - f"for account type '{account.auth}' " + f"for account type '{account.channel}' " f"using `save(name={name_save})` and `get(name={name_get})`" ): AccountManager.save( token=account.token, url=account.url, instance=account.instance, - auth=account.auth, + channel=account.channel, proxies=account.proxies, verify=account.verify, name=name_save, @@ -215,8 +394,8 @@ def test_save_get(self): @temporary_account_config_file( contents=json.dumps( { - "cloud": _TEST_CLOUD_ACCOUNT.to_saved_format(), - "legacy": _TEST_LEGACY_ACCOUNT.to_saved_format(), + "ibm_cloud": _TEST_IBM_CLOUD_ACCOUNT.to_saved_format(), + "ibm_quantum": _TEST_IBM_QUANTUM_ACCOUNT.to_saved_format(), } ) ) @@ -225,15 +404,31 @@ def test_list(self): with temporary_account_config_file( contents={ - "key1": _TEST_CLOUD_ACCOUNT.to_saved_format(), - "key2": _TEST_LEGACY_ACCOUNT.to_saved_format(), + "key1": _TEST_IBM_CLOUD_ACCOUNT.to_saved_format(), + "key2": _TEST_IBM_QUANTUM_ACCOUNT.to_saved_format(), } ), self.subTest("non-empty list of accounts"): accounts = AccountManager.list() self.assertEqual(len(accounts), 2) - self.assertEqual(accounts["key1"], _TEST_CLOUD_ACCOUNT) - self.assertTrue(accounts["key2"], _TEST_LEGACY_ACCOUNT) + self.assertEqual(accounts["key1"], _TEST_IBM_CLOUD_ACCOUNT) + self.assertTrue(accounts["key2"], _TEST_IBM_QUANTUM_ACCOUNT) + + with temporary_account_config_file( + contents={ + _DEFAULT_ACCOUNT_NAME_CLOUD: _TEST_CLOUD_ACCOUNT, + _DEFAULT_ACCOUNT_NAME_LEGACY: _TEST_CLOUD_ACCOUNT, + } + ), self.subTest("non-empty list of auth accounts"): + accounts = AccountManager.list() + + self.assertEqual(len(accounts), 2) + self.assertEqual( + accounts[_DEFAULT_ACCOUNT_NAME_IBM_CLOUD], _TEST_IBM_CLOUD_ACCOUNT + ) + self.assertTrue( + accounts[_DEFAULT_ACCOUNT_NAME_IBM_QUANTUM], _TEST_IBM_QUANTUM_ACCOUNT + ) with temporary_account_config_file(contents={}), self.subTest( "empty list of accounts" @@ -242,33 +437,66 @@ def test_list(self): with temporary_account_config_file( contents={ - "key1": _TEST_CLOUD_ACCOUNT.to_saved_format(), - "key2": _TEST_LEGACY_ACCOUNT.to_saved_format(), - management._DEFAULT_ACCOUNT_NAME_CLOUD: Account( - "cloud", "token-cloud", instance="crn:123" + "key1": _TEST_IBM_CLOUD_ACCOUNT.to_saved_format(), + "key2": _TEST_IBM_QUANTUM_ACCOUNT.to_saved_format(), + _DEFAULT_ACCOUNT_NAME_IBM_CLOUD: Account( + "ibm_cloud", "token-ibm-cloud", instance="crn:123" ).to_saved_format(), - management._DEFAULT_ACCOUNT_NAME_LEGACY: Account( - "legacy", "token-legacy" + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM: Account( + "ibm_quantum", "token-ibm-quantum" ).to_saved_format(), } ), self.subTest("filtered list of accounts"): - accounts = list(AccountManager.list(auth="cloud").keys()) + accounts = list(AccountManager.list(channel="ibm_cloud").keys()) self.assertEqual(len(accounts), 2) - self.assertListEqual( - accounts, ["key1", management._DEFAULT_ACCOUNT_NAME_CLOUD] - ) + self.assertListEqual(accounts, ["key1", _DEFAULT_ACCOUNT_NAME_IBM_CLOUD]) - accounts = list(AccountManager.list(auth="legacy").keys()) + accounts = list(AccountManager.list(channel="ibm_quantum").keys()) self.assertEqual(len(accounts), 2) - self.assertListEqual( - accounts, ["key2", management._DEFAULT_ACCOUNT_NAME_LEGACY] + self.assertListEqual(accounts, ["key2", _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM]) + + accounts = list( + AccountManager.list(channel="ibm_cloud", default=True).keys() + ) + self.assertEqual(len(accounts), 1) + self.assertListEqual(accounts, [_DEFAULT_ACCOUNT_NAME_IBM_CLOUD]) + + accounts = list( + AccountManager.list(channel="ibm_cloud", default=False).keys() ) + self.assertEqual(len(accounts), 1) + self.assertListEqual(accounts, ["key1"]) + + accounts = list(AccountManager.list(name="key1").keys()) + self.assertEqual(len(accounts), 1) + self.assertListEqual(accounts, ["key1"]) + + # TODO remove test when removing auth parameter + with temporary_account_config_file( + contents={ + "key1": _TEST_CLOUD_ACCOUNT, + "key2": _TEST_LEGACY_ACCOUNT, + _DEFAULT_ACCOUNT_NAME_CLOUD: _TEST_CLOUD_ACCOUNT, + _DEFAULT_ACCOUNT_NAME_LEGACY: _TEST_LEGACY_ACCOUNT, + } + ), self.subTest("filtered list of auth accounts"): + accounts = list(AccountManager.list(channel="ibm_cloud").keys()) + self.assertEqual(len(accounts), 2) + self.assertListEqual(accounts, [_DEFAULT_ACCOUNT_NAME_IBM_CLOUD, "key1"]) + + accounts = list(AccountManager.list(channel="ibm_quantum").keys()) + self.assertEqual(len(accounts), 2) + self.assertListEqual(accounts, [_DEFAULT_ACCOUNT_NAME_IBM_QUANTUM, "key2"]) - accounts = list(AccountManager.list(auth="cloud", default=True).keys()) + accounts = list( + AccountManager.list(channel="ibm_cloud", default=True).keys() + ) self.assertEqual(len(accounts), 1) - self.assertListEqual(accounts, [management._DEFAULT_ACCOUNT_NAME_CLOUD]) + self.assertListEqual(accounts, [_DEFAULT_ACCOUNT_NAME_IBM_CLOUD]) - accounts = list(AccountManager.list(auth="cloud", default=False).keys()) + accounts = list( + AccountManager.list(channel="ibm_cloud", default=False).keys() + ) self.assertEqual(len(accounts), 1) self.assertListEqual(accounts, ["key1"]) @@ -278,9 +506,9 @@ def test_list(self): @temporary_account_config_file( contents={ - "key1": _TEST_CLOUD_ACCOUNT.to_saved_format(), - management._DEFAULT_ACCOUNT_NAME_LEGACY: _TEST_LEGACY_ACCOUNT.to_saved_format(), - management._DEFAULT_ACCOUNT_NAME_CLOUD: _TEST_CLOUD_ACCOUNT.to_saved_format(), + "key1": _TEST_IBM_CLOUD_ACCOUNT.to_saved_format(), + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM: _TEST_IBM_QUANTUM_ACCOUNT.to_saved_format(), + _DEFAULT_ACCOUNT_NAME_IBM_CLOUD: _TEST_IBM_CLOUD_ACCOUNT.to_saved_format(), } ) def test_delete(self): @@ -290,10 +518,32 @@ def test_delete(self): self.assertTrue(AccountManager.delete(name="key1")) self.assertFalse(AccountManager.delete(name="key1")) - with self.subTest("delete default legacy account"): - self.assertTrue(AccountManager.delete(auth="legacy")) + with self.subTest("delete default ibm_quantum account"): + self.assertTrue(AccountManager.delete(channel="ibm_quantum")) - with self.subTest("delete default cloud account"): + with self.subTest("delete default ibm_cloud account"): + self.assertTrue(AccountManager.delete()) + + self.assertTrue(len(AccountManager.list()) == 0) + + @temporary_account_config_file( + contents={ + "key1": _TEST_CLOUD_ACCOUNT, + _DEFAULT_ACCOUNT_NAME_LEGACY: _TEST_LEGACY_ACCOUNT, + _DEFAULT_ACCOUNT_NAME_CLOUD: _TEST_CLOUD_ACCOUNT, + } + ) + def test_delete_auth(self): + """Test delete accounts already saved using auth.""" + + with self.subTest("delete named account"): + self.assertTrue(AccountManager.delete(name="key1")) + self.assertFalse(AccountManager.delete(name="key1")) + + with self.subTest("delete default auth='legacy' account using channel"): + self.assertTrue(AccountManager.delete(channel="ibm_quantum")) + + with self.subTest("delete default auth='cloud' account using channel"): self.assertTrue(AccountManager.delete()) self.assertTrue(len(AccountManager.list()) == 0) @@ -317,13 +567,13 @@ def test_enable_account_by_name(self): self.assertTrue(service._account) self.assertEqual(service._account.token, token) - def test_enable_account_by_auth(self): - """Test initializing account by auth.""" - for auth in ["cloud", "legacy"]: - with self.subTest(auth=auth), no_envs(["QISKIT_IBM_TOKEN"]): + def test_enable_account_by_channel(self): + """Test initializing account by channel.""" + for channel in ["ibm_cloud", "ibm_quantum"]: + with self.subTest(channel=channel), no_envs(["QISKIT_IBM_TOKEN"]): token = uuid.uuid4().hex - with temporary_account_config_file(auth=auth, token=token): - service = FakeRuntimeService(auth=auth) + with temporary_account_config_file(channel=channel, token=token): + service = FakeRuntimeService(channel=channel) self.assertTrue(service._account) self.assertEqual(service._account.token, token) @@ -343,10 +593,10 @@ def test_enable_account_by_token_url(self): def test_enable_account_by_name_and_other(self): """Test initializing account by name and other.""" subtests = [ - {"auth": "cloud"}, + {"channel": "ibm_cloud"}, {"token": "some_token"}, {"url": "some_url"}, - {"auth": "cloud", "token": "some_token", "url": "some_url"}, + {"channel": "ibm_cloud", "token": "some_token", "url": "some_url"}, ] name = "foo" @@ -362,70 +612,76 @@ def test_enable_account_by_name_and_other(self): self.assertEqual(service._account.token, token) self.assertIn("are ignored", logged.output[0]) - def test_enable_cloud_account_by_auth_token_url(self): - """Test initializing cloud account by auth, token, url.""" + def test_enable_cloud_account_by_channel_token_url(self): + """Test initializing cloud account by channel, token, url.""" # Enable account will fail due to missing CRN. urls = [None, "some_url"] for url in urls: with self.subTest(url=url), no_envs(["QISKIT_IBM_TOKEN"]): token = uuid.uuid4().hex with self.assertRaises(InvalidAccountError) as err: - _ = FakeRuntimeService(auth="cloud", token=token, url=url) + _ = FakeRuntimeService(channel="ibm_cloud", token=token, url=url) self.assertIn("instance", str(err.exception)) - def test_enable_legacy_account_by_auth_token_url(self): - """Test initializing legacy account by auth, token, url.""" - urls = [(None, LEGACY_API_URL), ("some_url", "some_url")] + def test_enable_ibm_quantum_account_by_channel_token_url(self): + """Test initializing ibm_quantum account by channel, token, url.""" + urls = [(None, IBM_QUANTUM_API_URL), ("some_url", "some_url")] for url, expected in urls: with self.subTest(url=url), no_envs(["QISKIT_IBM_TOKEN"]): token = uuid.uuid4().hex - service = FakeRuntimeService(auth="legacy", token=token, url=url) + service = FakeRuntimeService( + channel="ibm_quantum", token=token, url=url + ) self.assertTrue(service._account) self.assertEqual(service._account.token, token) self.assertEqual(service._account.url, expected) - def test_enable_account_by_auth_url(self): - """Test initializing legacy account by auth, token, url.""" - subtests = ["legacy", "cloud"] - for auth in subtests: - with self.subTest(auth=auth): + def test_enable_account_by_channel_url(self): + """Test initializing ibm_quantum account by channel, token, url.""" + subtests = ["ibm_cloud", "ibm_quantum"] + for channel in subtests: + with self.subTest(channel=channel): token = uuid.uuid4().hex - with temporary_account_config_file(auth=auth, token=token), no_envs( - ["QISKIT_IBM_TOKEN"] - ): + with temporary_account_config_file( + channel=channel, token=token + ), no_envs(["QISKIT_IBM_TOKEN"]): with self.assertLogs( "qiskit_ibm_runtime", logging.WARNING ) as logged: - service = FakeRuntimeService(auth=auth, url="some_url") + service = FakeRuntimeService(channel=channel, url="some_url") self.assertTrue(service._account) self.assertEqual(service._account.token, token) - expected = CLOUD_API_URL if auth == "cloud" else LEGACY_API_URL + expected = ( + IBM_CLOUD_API_URL if channel == "ibm_cloud" else IBM_QUANTUM_API_URL + ) self.assertEqual(service._account.url, expected) self.assertIn("url", logged.output[0]) - def test_enable_account_by_only_auth(self): + def test_enable_account_by_only_channel(self): """Test initializing account with single saved account.""" - subtests = ["legacy", "cloud"] - for auth in subtests: - with self.subTest(auth=auth): + subtests = ["ibm_cloud", "ibm_quantum"] + for channel in subtests: + with self.subTest(channel=channel): token = uuid.uuid4().hex - with temporary_account_config_file(auth=auth, token=token), no_envs( - ["QISKIT_IBM_TOKEN"] - ): + with temporary_account_config_file( + channel=channel, token=token + ), no_envs(["QISKIT_IBM_TOKEN"]): service = FakeRuntimeService() self.assertTrue(service._account) self.assertEqual(service._account.token, token) - expected = CLOUD_API_URL if auth == "cloud" else LEGACY_API_URL + expected = ( + IBM_CLOUD_API_URL if channel == "ibm_cloud" else IBM_QUANTUM_API_URL + ) self.assertEqual(service._account.url, expected) - self.assertEqual(service._account.auth, auth) + self.assertEqual(service._account.channel, channel) - def test_enable_account_both_auth(self): + def test_enable_account_both_channel(self): """Test initializing account with both saved types.""" token = uuid.uuid4().hex - contents = get_account_config_contents(auth="cloud", token=token) + contents = get_account_config_contents(channel="ibm_cloud", token=token) contents.update( - get_account_config_contents(auth="legacy", token=uuid.uuid4().hex) + get_account_config_contents(channel="ibm_quantum", token=uuid.uuid4().hex) ) with temporary_account_config_file(contents=contents), no_envs( ["QISKIT_IBM_TOKEN"] @@ -433,29 +689,31 @@ def test_enable_account_both_auth(self): service = FakeRuntimeService() self.assertTrue(service._account) self.assertEqual(service._account.token, token) - self.assertEqual(service._account.url, CLOUD_API_URL) - self.assertEqual(service._account.auth, "cloud") - - def test_enable_account_by_env_auth(self): - """Test initializing account by environment variable and auth.""" - subtests = ["legacy", "cloud", None] - for auth in subtests: - with self.subTest(auth=auth): + self.assertEqual(service._account.url, IBM_CLOUD_API_URL) + self.assertEqual(service._account.channel, "ibm_cloud") + + def test_enable_account_by_env_channel(self): + """Test initializing account by environment variable and channel.""" + subtests = ["ibm_quantum", "ibm_cloud", None] + for channel in subtests: + with self.subTest(channel=channel): token = uuid.uuid4().hex url = uuid.uuid4().hex envs = { "QISKIT_IBM_TOKEN": token, "QISKIT_IBM_URL": url, - "QISKIT_IBM_INSTANCE": "h/g/p" if auth == "legacy" else "crn:123", + "QISKIT_IBM_INSTANCE": "h/g/p" + if channel == "ibm_quantum" + else "crn:12", } with custom_envs(envs): - service = FakeRuntimeService(auth=auth) + service = FakeRuntimeService(channel=channel) self.assertTrue(service._account) self.assertEqual(service._account.token, token) self.assertEqual(service._account.url, url) - auth = auth or "cloud" - self.assertEqual(service._account.auth, auth) + channel = channel or "ibm_cloud" + self.assertEqual(service._account.channel, channel) def test_enable_account_by_env_token_url(self): """Test initializing account by environment variable and extra.""" @@ -482,12 +740,12 @@ def test_enable_account_bad_name(self): _ = FakeRuntimeService(name=name) self.assertIn(name, str(err.exception)) - def test_enable_account_bad_auth(self): + def test_enable_account_bad_channel(self): """Test initializing account by bad name.""" - auth = "phantom" + channel = "phantom" with temporary_account_config_file() as _, self.assertRaises(ValueError) as err: - _ = FakeRuntimeService(auth=auth) - self.assertIn("auth", str(err.exception)) + _ = FakeRuntimeService(channel=channel) + self.assertIn("channel", str(err.exception)) def test_enable_account_by_name_pref(self): """Test initializing account by name and preferences.""" @@ -507,24 +765,24 @@ def test_enable_account_by_name_pref(self): self.assertTrue(service._account) self._verify_prefs(extra, service._account) - def test_enable_account_by_auth_pref(self): - """Test initializing account by auth and preferences.""" + def test_enable_account_by_channel_pref(self): + """Test initializing account by channel and preferences.""" subtests = [ {"proxies": MOCK_PROXY_CONFIG_DICT}, {"verify": False}, {"instance": "h/g/p"}, {"proxies": MOCK_PROXY_CONFIG_DICT, "verify": False, "instance": "h/g/p"}, ] - for auth in ["cloud", "legacy"]: + for channel in ["ibm_cloud", "ibm_quantum"]: for extra in subtests: with self.subTest( - auth=auth, extra=extra + channel=channel, extra=extra ), temporary_account_config_file( - auth=auth, verify=True, proxies="some proxies" + channel=channel, verify=True, proxies="some proxies" ), no_envs( ["QISKIT_IBM_TOKEN"] ): - service = FakeRuntimeService(auth=auth, **extra) + service = FakeRuntimeService(channel=channel, **extra) self.assertTrue(service._account) self._verify_prefs(extra, service._account) @@ -560,11 +818,11 @@ def test_enable_account_by_name_input_instance(self): self.assertTrue(service._account) self.assertEqual(service._account.instance, instance) - def test_enable_account_by_auth_input_instance(self): - """Test initializing account by auth and input instance.""" + def test_enable_account_by_channel_input_instance(self): + """Test initializing account by channel and input instance.""" instance = uuid.uuid4().hex - with temporary_account_config_file(auth="cloud", instance="bla"): - service = FakeRuntimeService(auth="cloud", instance=instance) + with temporary_account_config_file(channel="ibm_cloud", instance="bla"): + service = FakeRuntimeService(channel="ibm_cloud", instance=instance) self.assertTrue(service._account) self.assertEqual(service._account.instance, instance) @@ -577,7 +835,7 @@ def test_enable_account_by_env_input_instance(self): "QISKIT_IBM_INSTANCE": "some_instance", } with custom_envs(envs): - service = FakeRuntimeService(auth="cloud", instance=instance) + service = FakeRuntimeService(channel="ibm_cloud", instance=instance) self.assertTrue(service._account) self.assertEqual(service._account.instance, instance) diff --git a/test/unit/test_account_client.py b/test/unit/test_account_client.py index 0942e62fce..84ff8310f9 100644 --- a/test/unit/test_account_client.py +++ b/test/unit/test_account_client.py @@ -15,6 +15,7 @@ from qiskit_ibm_runtime.api.client_parameters import ClientParameters from qiskit_ibm_runtime.api.clients import AccountClient from qiskit_ibm_runtime.api.exceptions import RequestsApiError + from .mock.http_server import SimpleServer, ClientErrorHandler from ..ibm_test_case import IBMTestCase from ..account import custom_envs, no_envs @@ -38,7 +39,10 @@ def _get_client(self): """Helper for instantiating an AccountClient.""" # pylint: disable=no-value-for-parameter params = ClientParameters( - auth_type="legacy", url=SimpleServer.URL, token="foo", instance="h/g/p" + channel="ibm_quantum", + url=SimpleServer.URL, + token="foo", + instance="h/g/p", ) return AccountClient(params) diff --git a/test/unit/test_backend_retrieval.py b/test/unit/test_backend_retrieval.py index 628be6a563..652057c990 100644 --- a/test/unit/test_backend_retrieval.py +++ b/test/unit/test_backend_retrieval.py @@ -18,20 +18,20 @@ from .mock.fake_account_client import BaseFakeAccountClient from .mock.fake_runtime_service import FakeRuntimeService from ..ibm_test_case import IBMTestCase -from ..decorators import run_legacy_and_cloud_fake +from ..decorators import run_quantum_and_cloud_fake class TestBackendFilters(IBMTestCase): """Qiskit Backend Filtering Tests.""" - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_no_filter(self, service): """Test no filtering.""" # FakeRuntimeService by default creates 3 backends. backend_name = [back.name for back in service.backends()] self.assertEqual(len(backend_name), 3) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_filter_by_name(self, service): """Test filtering by name.""" for name in [ @@ -42,9 +42,9 @@ def test_filter_by_name(self, service): backend_name = [back.name for back in service.backends(name=name)] self.assertEqual(len(backend_name), 1) - def test_filter_by_instance_legacy(self): - """Test filtering by instance.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + def test_filter_by_instance_ibm_quantum(self): + """Test filtering by instance (works only on ibm_quantum).""" + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") for hgp in FakeRuntimeService.DEFAULT_HGPS: with self.subTest(hgp=hgp): backends = service.backends(instance=hgp) @@ -64,7 +64,7 @@ def test_filter_config_properties(self): services = self._get_services(fake_backends) for service in services: - with self.subTest(service=service.auth): + with self.subTest(service=service.channel): filtered_backends = service.backends(n_qubits=n_qubits, local=False) self.assertTrue(len(filtered_backends), 1) self.assertEqual( @@ -83,7 +83,7 @@ def test_filter_status_dict(self): services = self._get_services(fake_backends) for service in services: - with self.subTest(service=service.auth): + with self.subTest(service=service.channel): filtered_backends = service.backends( operational=True, # from status simulator=True, # from configuration @@ -104,7 +104,7 @@ def test_filter_config_callable(self): services = self._get_services(fake_backends) for service in services: - with self.subTest(service=service.auth): + with self.subTest(service=service.channel): filtered_backends = service.backends( filters=lambda x: (x.configuration().n_qubits >= 5) ) @@ -126,7 +126,7 @@ def test_filter_least_busy(self): services = self._get_services(fake_backends) for service in services: - with self.subTest(service=service.auth): + with self.subTest(service=service.channel): backend = service.least_busy() self.assertEqual(backend.name, "bingo") @@ -141,7 +141,7 @@ def test_filter_min_num_qubits(self): services = self._get_services(fake_backends) for service in services: - with self.subTest(service=service.auth): + with self.subTest(service=service.channel): filtered_backends = service.backends(min_num_qubits=n_qubits) self.assertTrue(len(filtered_backends), 2) for backend in filtered_backends: @@ -154,13 +154,13 @@ def test_filter_by_hgp(self): "account_client": BaseFakeAccountClient(num_backends=num_backends), "num_hgps": 2, } - legacy_service = FakeRuntimeService( - auth="legacy", + ibm_quantum_service = FakeRuntimeService( + channel="ibm_quantum", token="my_token", instance="h/g/p", test_options=test_options, ) - backends = legacy_service.backends(instance="hub0/group0/project0") + backends = ibm_quantum_service.backends(instance="hub0/group0/project0") self.assertEqual(len(backends), num_backends) def _get_specs(self, **kwargs): @@ -177,49 +177,49 @@ def _get_specs(self, **kwargs): return specs def _get_services(self, fake_backends): - """Get both cloud and legacy services initialized with fake backends.""" + """Get both ibm_cloud and ibm_quantum services initialized with fake backends.""" test_options = {"account_client": BaseFakeAccountClient(specs=fake_backends)} - legacy_service = FakeRuntimeService( - auth="legacy", + ibm_quantum_service = FakeRuntimeService( + channel="ibm_quantum", token="my_token", instance="h/g/p", test_options=test_options, ) cloud_service = FakeRuntimeService( - auth="cloud", + channel="ibm_cloud", token="my_token", instance="my_instance", test_options=test_options, ) - return [legacy_service, cloud_service] + return [ibm_quantum_service, cloud_service] class TestGetBackend(IBMTestCase): - """Test getting a backend via legacy api.""" + """Test getting a backend via ibm_quantum api.""" def test_get_common_backend(self): """Test getting a backend that is in default and non-default hgp.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") backend = service.backend(FakeRuntimeService.DEFAULT_COMMON_BACKEND) self.assertEqual(backend._api_client.hgp, list(service._hgps.keys())[0]) def test_get_unique_backend_default_hgp(self): """Test getting a backend in the default hgp.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") backend_name = FakeRuntimeService.DEFAULT_UNIQUE_BACKEND_PREFIX + "0" backend = service.backend(backend_name) self.assertEqual(backend._api_client.hgp, list(service._hgps.keys())[0]) def test_get_unique_backend_non_default_hgp(self): """Test getting a backend in the non default hgp.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") backend_name = FakeRuntimeService.DEFAULT_UNIQUE_BACKEND_PREFIX + "1" backend = service.backend(backend_name) self.assertEqual(backend._api_client.hgp, list(service._hgps.keys())[1]) def test_get_phantom_backend(self): """Test getting a phantom backend.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") with self.assertRaises(QiskitBackendNotFoundError): service.backend("phantom") @@ -227,7 +227,7 @@ def test_get_backend_by_hgp(self): """Test getting a backend by hgp.""" hgp = FakeRuntimeService.DEFAULT_HGPS[1] backend_name = FakeRuntimeService.DEFAULT_COMMON_BACKEND - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") backend = service.backend(backend_name, instance=hgp) self.assertEqual(backend._api_client.hgp, hgp) @@ -235,6 +235,6 @@ def test_get_backend_by_bad_hgp(self): """Test getting a backend not in hgp.""" hgp = FakeRuntimeService.DEFAULT_HGPS[1] backend_name = FakeRuntimeService.DEFAULT_UNIQUE_BACKEND_PREFIX + "0" - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") with self.assertRaises(QiskitBackendNotFoundError): _ = service.backend(backend_name, instance=hgp) diff --git a/test/unit/test_client_parameters.py b/test/unit/test_client_parameters.py index 8757a511d0..65dc2315aa 100644 --- a/test/unit/test_client_parameters.py +++ b/test/unit/test_client_parameters.py @@ -15,9 +15,10 @@ import uuid from requests_ntlm import HttpNtlmAuth + from qiskit_ibm_runtime.proxies import ProxyConfiguration from qiskit_ibm_runtime.api.client_parameters import ClientParameters -from qiskit_ibm_runtime.api.auth import CloudAuth, LegacyAuth +from qiskit_ibm_runtime.api.auth import CloudAuth, QuantumAuth from ..ibm_test_case import IBMTestCase @@ -53,29 +54,29 @@ def test_get_runtime_api_base_url(self) -> None: """Test resolution of runtime API base URL.""" test_specs = [ ( - "cloud", + "ibm_cloud", "crn:v1:bluemix:public:quantum-computing:us-east:a/...:...::", "https://cloud.ibm.com", "https://us-east.quantum-computing.cloud.ibm.com", ), ( - "cloud", + "ibm_cloud", "crn:v1:bluemix:public:quantum-computing:my-region:a/...:...::", "https://cloud.ibm.com", "https://my-region.quantum-computing.cloud.ibm.com", ), ( - "legacy", + "ibm_quantum", "h/g/p", "https://auth.quantum-computing.ibm.com/api", "https://auth.quantum-computing.ibm.com/api", ), ] for spec in test_specs: - auth, instance, url, expected = spec + channel, instance, url, expected = spec with self.subTest(instance=instance, url=url): params = self._get_client_params( - auth_type=auth, instance=instance, url=url + channel=channel, instance=instance, url=url ) self.assertEqual(params.get_runtime_api_base_url(), expected) @@ -122,12 +123,12 @@ def test_malformed_ntlm_params(self) -> None: with self.assertRaises(AttributeError): _ = malformed_ntlm_credentials.connection_parameters() - def test_auth_handler_legacy(self): - """Test getting legacy auth handler.""" + def test_auth_handler_quantum(self): + """Test getting quantum auth handler.""" token = uuid.uuid4().hex - params = self._get_client_params(auth_type="legacy", token=token) + params = self._get_client_params(channel="ibm_quantum", token=token) handler = params.get_auth_handler() - self.assertIsInstance(handler, LegacyAuth) + self.assertIsInstance(handler, QuantumAuth) self.assertIn(token, handler.get_headers().values()) def test_auth_handler_cloud(self): @@ -135,7 +136,7 @@ def test_auth_handler_cloud(self): token = uuid.uuid4().hex instance = uuid.uuid4().hex params = self._get_client_params( - auth_type="cloud", token=token, instance=instance + channel="ibm_cloud", token=token, instance=instance ) handler = params.get_auth_handler() self.assertIsInstance(handler, CloudAuth) @@ -144,7 +145,7 @@ def test_auth_handler_cloud(self): def _get_client_params( self, - auth_type="legacy", + channel="ibm_quantum", token="dummy_token", url="https://dummy_url", instance=None, @@ -155,7 +156,7 @@ def _get_client_params( if verify is None: verify = True return ClientParameters( - auth_type=auth_type, + channel=channel, token=token, url=url, instance=instance, diff --git a/test/unit/test_data_serialization.py b/test/unit/test_data_serialization.py index 2aa1921fd3..1f843337f3 100644 --- a/test/unit/test_data_serialization.py +++ b/test/unit/test_data_serialization.py @@ -287,13 +287,17 @@ def test_result_decoder(self): custom_result = get_complex_types() job_cls = CustomResultRuntimeJob job_cls.custom_result = custom_result - legacy_service = FakeRuntimeService(auth="legacy", token="some_token") + ibm_quantum_service = FakeRuntimeService( + channel="ibm_quantum", token="some_token" + ) sub_tests = [(SerializableClassDecoder, None), (None, SerializableClassDecoder)] for result_decoder, decoder in sub_tests: with self.subTest(decoder=decoder): job = run_program( - service=legacy_service, job_classes=job_cls, decoder=result_decoder + service=ibm_quantum_service, + job_classes=job_cls, + decoder=result_decoder, ) result = job.result(decoder=decoder) self.assertIsInstance(result["serializable_class"], SerializableClass) diff --git a/test/unit/test_job_retrieval.py b/test/unit/test_job_retrieval.py index 937a63bb88..826c2a248c 100644 --- a/test/unit/test_job_retrieval.py +++ b/test/unit/test_job_retrieval.py @@ -15,7 +15,7 @@ from qiskit_ibm_runtime.exceptions import IBMInputValueError from .mock.fake_runtime_service import FakeRuntimeService from ..ibm_test_case import IBMTestCase -from ..decorators import run_legacy_and_cloud_fake +from ..decorators import run_quantum_and_cloud_fake from ..program import run_program, upload_program from ..utils import mock_wait_for_final_state @@ -26,9 +26,11 @@ class TestRetrieveJobs(IBMTestCase): def setUp(self): """Initial test setup.""" super().setUp() - self._legacy_service = FakeRuntimeService(auth="legacy", token="my_token") + self._ibm_quantum_service = FakeRuntimeService( + channel="ibm_quantum", token="my_token" + ) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_retrieve_job(self, service): """Test retrieving a job.""" program_id = upload_program(service) @@ -38,7 +40,7 @@ def test_retrieve_job(self, service): self.assertEqual(job.job_id, rjob.job_id) self.assertEqual(program_id, rjob.program_id) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_jobs_no_limit(self, service): """Test retrieving jobs without limit.""" program_id = upload_program(service) @@ -49,7 +51,7 @@ def test_jobs_no_limit(self, service): rjobs = service.jobs(limit=None) self.assertEqual(25, len(rjobs)) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_jobs_limit(self, service): """Test retrieving jobs with limit.""" program_id = upload_program(service) @@ -65,7 +67,7 @@ def test_jobs_limit(self, service): rjobs = service.jobs(limit=limit) self.assertEqual(min(limit, job_count), len(rjobs)) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_jobs_skip(self, service): """Test retrieving jobs with skip.""" program_id = upload_program(service) @@ -78,7 +80,7 @@ def test_jobs_skip(self, service): def test_jobs_skip_limit(self): """Test retrieving jobs with skip and limit.""" - service = self._legacy_service + service = self._ibm_quantum_service program_id = upload_program(service) jobs = [] @@ -87,7 +89,7 @@ def test_jobs_skip_limit(self): rjobs = service.jobs(skip=4, limit=2) self.assertEqual(2, len(rjobs)) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_jobs_pending(self, service): """Test retrieving pending jobs (QUEUED, RUNNING).""" program_id = upload_program(service) @@ -100,7 +102,7 @@ def test_jobs_pending(self, service): def test_jobs_limit_pending(self): """Test retrieving pending jobs (QUEUED, RUNNING) with limit.""" - service = self._legacy_service + service = self._ibm_quantum_service program_id = upload_program(service) self._populate_jobs_with_all_statuses(service, program_id=program_id) @@ -110,7 +112,7 @@ def test_jobs_limit_pending(self): def test_jobs_skip_pending(self): """Test retrieving pending jobs (QUEUED, RUNNING) with skip.""" - service = self._legacy_service + service = self._ibm_quantum_service program_id = upload_program(service) _, pending_jobs_count, _ = self._populate_jobs_with_all_statuses( @@ -122,7 +124,7 @@ def test_jobs_skip_pending(self): def test_jobs_limit_skip_pending(self): """Test retrieving pending jobs (QUEUED, RUNNING) with limit and skip.""" - service = self._legacy_service + service = self._ibm_quantum_service program_id = upload_program(service) self._populate_jobs_with_all_statuses(service, program_id=program_id) @@ -133,7 +135,7 @@ def test_jobs_limit_skip_pending(self): def test_jobs_returned(self): """Test retrieving returned jobs (COMPLETED, FAILED, CANCELLED).""" - service = self._legacy_service + service = self._ibm_quantum_service program_id = upload_program(service) _, _, returned_jobs_count = self._populate_jobs_with_all_statuses( @@ -144,7 +146,7 @@ def test_jobs_returned(self): def test_jobs_limit_returned(self): """Test retrieving returned jobs (COMPLETED, FAILED, CANCELLED) with limit.""" - service = self._legacy_service + service = self._ibm_quantum_service program_id = upload_program(service) self._populate_jobs_with_all_statuses(service, program_id=program_id) @@ -154,7 +156,7 @@ def test_jobs_limit_returned(self): def test_jobs_skip_returned(self): """Test retrieving returned jobs (COMPLETED, FAILED, CANCELLED) with skip.""" - service = self._legacy_service + service = self._ibm_quantum_service program_id = upload_program(service) _, _, returned_jobs_count = self._populate_jobs_with_all_statuses( @@ -166,7 +168,7 @@ def test_jobs_skip_returned(self): def test_jobs_limit_skip_returned(self): """Test retrieving returned jobs (COMPLETED, FAILED, CANCELLED) with limit and skip.""" - service = self._legacy_service + service = self._ibm_quantum_service program_id = upload_program(service) self._populate_jobs_with_all_statuses(service, program_id=program_id) @@ -175,7 +177,7 @@ def test_jobs_limit_skip_returned(self): rjobs = service.jobs(limit=limit, skip=skip, pending=False) self.assertEqual(limit, len(rjobs)) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_jobs_filter_by_program_id(self, service): """Test retrieving jobs by Program ID.""" program_id = upload_program(service) @@ -192,7 +194,7 @@ def test_jobs_filter_by_program_id(self, service): def test_jobs_filter_by_instance(self): """Test retrieving jobs by instance.""" - service = self._legacy_service + service = self._ibm_quantum_service program_id = upload_program(service) instance = FakeRuntimeService.DEFAULT_HGPS[1] @@ -210,7 +212,7 @@ def test_jobs_filter_by_instance(self): def test_jobs_bad_instance(self): """Test retrieving jobs with bad instance values.""" - service = self._legacy_service + service = self._ibm_quantum_service with self.assertRaises(IBMInputValueError): _ = service.jobs(instance="foo") @@ -218,7 +220,7 @@ def test_different_hgps(self): """Test retrieving job submitted with different hgp.""" # Initialize with hgp0 service = FakeRuntimeService( - auth="legacy", + channel="ibm_quantum", token="some_token", instance=FakeRuntimeService.DEFAULT_HGPS[0], ) diff --git a/test/unit/test_jobs.py b/test/unit/test_jobs.py index aeb3002bc1..b949cc0603 100644 --- a/test/unit/test_jobs.py +++ b/test/unit/test_jobs.py @@ -34,7 +34,7 @@ ) from .mock.fake_runtime_service import FakeRuntimeService from ..ibm_test_case import IBMTestCase -from ..decorators import run_legacy_and_cloud_fake +from ..decorators import run_quantum_and_cloud_fake from ..program import run_program, upload_program from ..serialization import get_complex_types from ..utils import mock_wait_for_final_state @@ -43,7 +43,7 @@ class TestRuntimeJob(IBMTestCase): """Class for testing runtime jobs.""" - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_run_program(self, service): """Test running program.""" params = {"param1": "foo"} @@ -57,28 +57,28 @@ def test_run_program(self, service): self.assertEqual(job.status(), JobStatus.DONE) self.assertTrue(job.result()) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_run_phantom_program(self, service): """Test running a phantom program.""" with self.assertRaises(RuntimeProgramNotFound): _ = run_program(service=service, program_id="phantom_program") - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_run_program_phantom_backend(self, service): """Test running on a phantom backend.""" with self.assertRaises(QiskitBackendNotFoundError): _ = run_program(service=service, backend_name="phantom_backend") - def test_run_program_missing_backend_legacy(self): - """Test running a legacy program with no backend.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + def test_run_program_missing_backend_ibm_quantum(self): + """Test running an ibm_quantum program with no backend.""" + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") with self.assertRaises(IBMInputValueError): _ = run_program(service=service, backend_name="") - def test_run_program_missing_backend_cloud(self): - """Test running a cloud program with no backend.""" + def test_run_program_missing_backend_ibm_cloud(self): + """Test running an ibm_cloud program with no backend.""" service = FakeRuntimeService( - auth="cloud", + channel="ibm_cloud", token="my_token", instance="crn:v1:bluemix:public:quantum-computing:my-region:a/...:...::", ) @@ -87,7 +87,7 @@ def test_run_program_missing_backend_cloud(self): def test_run_program_default_hgp_backend(self): """Test running a program with a backend in default hgp.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") backend = FakeRuntimeService.DEFAULT_COMMON_BACKEND default_hgp = list(service._hgps.values())[0] self.assertIn(backend, default_hgp.backends.keys()) @@ -99,7 +99,7 @@ def test_run_program_default_hgp_backend(self): def test_run_program_non_default_hgp_backend(self): """Test running a program with a backend in non-default hgp.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") backend = FakeRuntimeService.DEFAULT_UNIQUE_BACKEND_PREFIX + "1" default_hgp = list(service._hgps.values())[0] self.assertNotIn(backend, default_hgp.backends.keys()) @@ -108,7 +108,7 @@ def test_run_program_non_default_hgp_backend(self): def test_run_program_by_hgp_backend(self): """Test running a program with both backend and hgp.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") backend = FakeRuntimeService.DEFAULT_COMMON_BACKEND non_default_hgp = list(service._hgps.keys())[1] job = run_program( @@ -119,7 +119,7 @@ def test_run_program_by_hgp_backend(self): def test_run_program_by_hgp_bad_backend(self): """Test running a program with backend not in hgp.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") backend = FakeRuntimeService.DEFAULT_UNIQUE_BACKEND_PREFIX + "1" default_hgp = list(service._hgps.values())[0] self.assertNotIn(backend, default_hgp.backends.keys()) @@ -130,17 +130,17 @@ def test_run_program_by_hgp_bad_backend(self): def test_run_program_by_phantom_hgp(self): """Test running a program with a phantom hgp.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") with self.assertRaises(IBMInputValueError): _ = run_program(service=service, instance="h/g/p") def test_run_program_by_bad_hgp(self): """Test running a program with a bad hgp.""" - service = FakeRuntimeService(auth="legacy", token="my_token") + service = FakeRuntimeService(channel="ibm_quantum", token="my_token") with self.assertRaises(IBMInputValueError): _ = run_program(service=service, instance="foo") - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_run_program_with_custom_runtime_image(self, service): """Test running program with a custom image.""" params = {"param1": "foo"} @@ -156,14 +156,14 @@ def test_run_program_with_custom_runtime_image(self, service): self.assertEqual(job.status(), JobStatus.DONE) self.assertEqual(job.image, image) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_run_program_with_custom_log_level(self, service): """Test running program with a custom image.""" job = run_program(service=service, log_level="DEBUG") job_raw = service._api_client._get_job(job.job_id) self.assertEqual(job_raw.log_level, "DEBUG") - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_run_program_failed(self, service): """Test a failed program execution.""" job = run_program(service=service, job_classes=FailedRuntimeJob) @@ -178,7 +178,7 @@ def test_run_program_failed(self, service): with self.assertRaises(RuntimeJobFailureError): job.result() - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_run_program_failed_ran_too_long(self, service): """Test a program that failed since it ran longer than maximum execution time.""" job = run_program(service=service, job_classes=FailedRanTooLongRuntimeJob) @@ -195,7 +195,7 @@ def test_run_program_failed_ran_too_long(self, service): with self.assertRaises(RuntimeJobFailureError): job.result() - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_program_params_namespace(self, service): """Test running a program using parameter namespace.""" program_id = upload_program(service) @@ -203,7 +203,7 @@ def test_program_params_namespace(self, service): params.param1 = "Hello World" run_program(service, program_id, inputs=params) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_cancel_job(self, service): """Test canceling a job.""" job = run_program(service, job_classes=CancelableRuntimeJob) @@ -213,7 +213,7 @@ def test_cancel_job(self, service): rjob = service.job(job.job_id) self.assertEqual(rjob.status(), JobStatus.CANCELLED) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_final_result(self, service): """Test getting final result.""" job = run_program(service) @@ -221,7 +221,7 @@ def test_final_result(self, service): result = job.result() self.assertTrue(result) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_interim_results(self, service): """Test getting interim results.""" job = run_program(service) @@ -229,28 +229,28 @@ def test_interim_results(self, service): interim_results = job.interim_results() self.assertTrue(interim_results) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_job_status(self, service): """Test job status.""" job = run_program(service) time.sleep(random.randint(1, 5)) self.assertTrue(job.status()) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_job_inputs(self, service): """Test job inputs.""" inputs = {"param1": "foo", "param2": "bar"} job = run_program(service, inputs=inputs) self.assertEqual(inputs, job.inputs) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_job_program_id(self, service): """Test job program ID.""" program_id = upload_program(service) job = run_program(service, program_id=program_id) self.assertEqual(program_id, job.program_id) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_wait_for_final_state(self, service): """Test wait for final state.""" job = run_program(service) @@ -258,7 +258,7 @@ def test_wait_for_final_state(self, service): job.wait_for_final_state() self.assertEqual(JobStatus.DONE, job.status()) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_get_result_twice(self, service): """Test getting results multiple times.""" custom_result = get_complex_types() @@ -270,7 +270,7 @@ def test_get_result_twice(self, service): _ = job.result() _ = job.result() - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_delete_job(self, service): """Test deleting a job.""" params = {"param1": "foo"} diff --git a/test/unit/test_programs.py b/test/unit/test_programs.py index 16e041beff..77c3f56b26 100644 --- a/test/unit/test_programs.py +++ b/test/unit/test_programs.py @@ -24,14 +24,14 @@ from qiskit_ibm_runtime.exceptions import RuntimeProgramNotFound from qiskit_ibm_runtime.runtime_program import ParameterNamespace from ..ibm_test_case import IBMTestCase -from ..decorators import run_legacy_and_cloud_fake +from ..decorators import run_quantum_and_cloud_fake from ..program import upload_program, DEFAULT_DATA, DEFAULT_METADATA class TestPrograms(IBMTestCase): """Class for testing runtime modules.""" - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_list_programs(self, service): """Test listing programs.""" program_id = upload_program(service) @@ -39,7 +39,7 @@ def test_list_programs(self, service): all_ids = [prog.program_id for prog in programs] self.assertIn(program_id, all_ids) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_list_programs_with_limit_skip(self, service): """Test listing programs with limit and skip.""" program_ids = [] @@ -54,14 +54,14 @@ def test_list_programs_with_limit_skip(self, service): all_ids = [prog.program_id for prog in programs] self.assertIn(program_ids[0], all_ids) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_list_program(self, service): """Test listing a single program.""" program_id = upload_program(service) program = service.program(program_id) self.assertEqual(program_id, program.program_id) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_print_programs(self, service): """Test printing programs.""" ids = [] @@ -85,7 +85,7 @@ def test_print_programs(self, service): self.assertIn(str(prog.max_execution_time), stdout_detailed) self.assertIn("Backend requirements", stdout_detailed) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_upload_program(self, service): """Test uploading a program.""" max_execution_time = 3000 @@ -99,7 +99,7 @@ def test_upload_program(self, service): self.assertEqual(max_execution_time, program.max_execution_time) self.assertEqual(program.is_public, is_public) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_update_program(self, service): """Test updating program.""" new_data = "def main() {foo=bar}" @@ -144,7 +144,7 @@ def test_update_program(self, service): raw_program = service._api_client.program_get(program_id) self.assertEqual(new_spec, raw_program["spec"]) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_update_program_no_new_fields(self, service): """Test updating a program without any new data.""" program_id = upload_program(service) @@ -152,13 +152,13 @@ def test_update_program_no_new_fields(self, service): service.update_program(program_id=program_id) self.assertEqual(len(warn_cm), 1) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_update_phantom_program(self, service): """Test updating a phantom program.""" with self.assertRaises(RuntimeProgramNotFound): service.update_program("phantom_program", name="foo") - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_delete_program(self, service): """Test deleting program.""" program_id = upload_program(service) @@ -166,7 +166,7 @@ def test_delete_program(self, service): with self.assertRaises(RuntimeProgramNotFound): service.program(program_id, refresh=True) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_double_delete_program(self, service): """Test deleting a deleted program.""" program_id = upload_program(service) @@ -174,7 +174,7 @@ def test_double_delete_program(self, service): with self.assertRaises(RuntimeProgramNotFound): service.delete_program(program_id) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_retrieve_program_data(self, service): """Test retrieving program data""" program_id = upload_program(service, name="qiskit-test") @@ -183,7 +183,7 @@ def test_retrieve_program_data(self, service): self.assertEqual(program.data, DEFAULT_DATA) self._validate_program(program) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_program_params_validation(self, service): """Test program parameters validation process""" program_id = upload_program(service) @@ -201,7 +201,7 @@ def test_program_params_validation(self, service): params.validate() params.param1 = "foo" - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_program_metadata(self, service): """Test program metadata.""" temp_fp = tempfile.NamedTemporaryFile(mode="w+", delete=False) @@ -221,7 +221,7 @@ def test_program_metadata(self, service): finally: os.remove(temp_fp.name) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_set_program_visibility(self, service): """Test setting program visibility.""" program_id = upload_program(service, is_public=False) @@ -229,7 +229,7 @@ def test_set_program_visibility(self, service): program = service.program(program_id) self.assertTrue(program.is_public) - @run_legacy_and_cloud_fake + @run_quantum_and_cloud_fake def test_set_program_visibility_phantom_program(self, service): """Test setting program visibility for a phantom program.""" with self.assertRaises(RuntimeProgramNotFound): diff --git a/test/unit/test_runtime_ws.py b/test/unit/test_runtime_ws.py index 44be86a860..e71d79738a 100644 --- a/test/unit/test_runtime_ws.py +++ b/test/unit/test_runtime_ws.py @@ -187,7 +187,7 @@ def result_callback(job_id, interim_result): def _get_job(self, callback=None, job_id=JOB_ID_PROGRESS_DONE): """Get a runtime job.""" params = ClientParameters( - auth_type="legacy", token="my_token", url=MockWsServer.VALID_WS_URL + channel="ibm_quantum", token="my_token", url=MockWsServer.VALID_WS_URL ) job = RuntimeJob( backend=FakeQasmSimulator(), diff --git a/test/utils.py b/test/utils.py index 9564aa513e..573193ec8f 100644 --- a/test/utils.py +++ b/test/utils.py @@ -87,7 +87,7 @@ def get_hgp(qe_token: str, qe_url: str, default: bool = True) -> HubGroupProject A HubGroupProject, as specified by `default`. """ service = IBMRuntimeService( - auth="legacy", token=qe_token, url=qe_url + channel="ibm_quantum", token=qe_token, url=qe_url ) # Default hub/group/project. open_hgp = service._get_hgp() # Open access hgp hgp_to_return = open_hgp