diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1bde4e56a9..41c6ad8566 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -40,7 +40,7 @@ pip install -e ".[dev]" ### Open an issue -* For documentation issues relating to pages in the Start, Build, Transpile, Verify, Run, and Migration guides sections of https://docs.quantum.ibm.com, please open an issue in the [Qiskit/documentation repo](https://github.com/Qiskit/documentation/issues/new/choose) rather than the Qiskit/qiskit-ibm-runtime repo. In other words, any page that DOES NOT have `/api/` in the url should be addressed in the Qiskit/documentation repo. (Exception: the Migration guide urls contain `/api/` but are managed in the Qiskit/documentation repo.) +* For documentation issues relating to pages in the Guides, Tutorials, and Migration guides sections of https://quantum.cloud.ibm.com/docs, please open an issue in the [Qiskit/documentation repo](https://github.com/Qiskit/documentation/issues/new/choose) rather than the Qiskit/qiskit-ibm-runtime repo. In other words, any page that DOES NOT have `/api/` in the url should be addressed in the Qiskit/documentation repo. (Exception: the Migration guide urls contain `/api/` but are managed in the Qiskit/documentation repo.) * For issues relating to API reference pages (any page that contains /api/ in the url), please open an issue in the repo specific to that API reference. ### Pull request checklist @@ -219,7 +219,7 @@ Integration tests require an environment configuration and can be run against th Sample configuration for IBM Cloud (ibm_quantum_platform) ```bash QISKIT_IBM_TOKEN=... # IBM Cloud API key -QISKIT_IBM_URL=https://cloud.ibm.com # Cloud URL +QISKIT_IBM_URL=https://quantum.cloud.ibm.com # Cloud URL QISKIT_IBM_INSTANCE=crn:v1:bluemix:... # The CRN value of the Quantum service instance QISKIT_IBM_QPU=... # The Quantum Processing Unit to use ``` diff --git a/DEPRECATION.md b/DEPRECATION.md index 785e340a39..b89eb04c53 100644 --- a/DEPRECATION.md +++ b/DEPRECATION.md @@ -34,11 +34,11 @@ The guiding principles are: The public API comprises all *publicly documented* packages, modules, classes, functions, methods, and attributes. -An object is *publicly documented* if and only if it appears in [the hosted API documentation](https://docs.quantum.ibm.com/api/qiskit-ibm-runtime) for `qiskit-ibm-runtime`. +An object is *publicly documented* if and only if it appears in [the hosted API documentation](https://quantum.cloud.ibm.com/docs/api/qiskit-ibm-runtime) for `qiskit-ibm-runtime`. The presence of a docstring in the Python source (or a `__doc__` attribute) is not sufficient to make an object publicly documented; this documentation must also be rendered in the public API documentation. -As well as the objects themselves needing to be publicly documented, the only public-API *import locations* for a given object is the location it is documented at in [the public API documentation](https://docs.quantum.ibm.com/api/qiskit-ibm-runtime), and parent modules or packages that re-export the object (if any). -For example, while it is possible to import `RuntimeEncoder` from `qiskit_ibm_runtime.utils.json`, this is not a supported part of the public API because the[`RuntimeEncoder` object is documented as being in `qiskit_ibm_runtime`](https://docs.quantum.ibm.com/api/qiskit-ibm-runtime/qiskit_ibm_runtime.RuntimeEncoder). +As well as the objects themselves needing to be publicly documented, the only public-API *import locations* for a given object is the location it is documented at in [the public API documentation](https://quantum.cloud.ibm.com/docs/api/qiskit-ibm-runtime), and parent modules or packages that re-export the object (if any). +For example, while it is possible to import `RuntimeEncoder` from `qiskit_ibm_runtime.utils.json`, this is not a supported part of the public API because the[`RuntimeEncoder` object is documented as being in `qiskit_ibm_runtime`](https://quantum.cloud.ibm.com/docs/api/qiskit-ibm-runtime/runtime-encoder). As a rule of thumb, if you are using `qiskit-ibm-runtime`, you should import objects from the highest-level package that exports that object. diff --git a/README.md b/README.md index 7fb34721d2..26790290a9 100644 --- a/README.md +++ b/README.md @@ -113,15 +113,15 @@ All quantum applications and algorithms level are fundamentally built using thes **Primitives** are base-level functions that serve as building blocks for many quantum algorithms and applications. Primitives accept vectorized inputs, where single circuits can be grouped with array-valued specifications. That is, one circuit can be executed for arrays of n parameter sets, n observables, or both (in the case of the estimator). Each group is called a Primitive Unified Bloc (PUB), and can be represented as a tuple. -The [primitive interfaces](https://docs.quantum.ibm.com/api/qiskit/primitives) are defined in Qiskit. +The [primitive interfaces](https://quantum.cloud.ibm.com/docs/api/qiskit/primitives) are defined in Qiskit. The IBM Runtime service offers these primitives with additional features, such as built-in error suppression and mitigation. -There are several different options you can specify when calling the primitives. See [Primitive options](https://docs.quantum.ibm.com/api/qiskit-ibm-runtime/options) for more information. +There are several different options you can specify when calling the primitives. See [Primitive options](https://quantum.cloud.ibm.com/docs/api/qiskit-ibm-runtime/options) for more information. ### Primitive versions -Version 2 of the primitives is introduced by `qiskit-ibm-runtime` release 0.21.0. Version 1 of the primitives is no longer supported. Refer to [Migrate to the V2 primitives](https://docs.quantum.ibm.com/migration-guides/v2-primitives) on how to migratie to V2 primitives. The examples below all use V2 primitives. +Version 2 of the primitives is introduced by `qiskit-ibm-runtime` release 0.21.0. Version 1 of the primitives is no longer supported. Refer to [Migrate to the V2 primitives](https://quantum.cloud.ibm.com/docs/migration-guides/v2-primitives) on how to migratie to V2 primitives. The examples below all use V2 primitives. ### Sampler @@ -279,7 +279,7 @@ This code returns `Job result is [4.] at theta = 1.575674623307102` using only n Access to IBM Quantum Platform channel is controlled by the instances (previously called providers) to which you are assigned. An instance is defined by a hierarchical organization of hub, group, and project. A hub is the top level of a given hierarchy (organization) and contains within it one or more groups. These groups are in turn populated with projects. The combination of hub/group/project is called an instance. Users can belong to more than one instance at any time. -> **_NOTE:_** IBM Cloud instances are different from IBM Quantum Platform instances. IBM Cloud does not use the hub/group/project structure for user management. To view and create IBM Cloud instances, visit the [IBM Cloud Quantum Instances page](https://cloud.ibm.com/quantum/instances). +> **_NOTE:_** IBM Cloud instances are different from IBM Quantum Platform classic instances. IBM Cloud does not use the hub/group/project structure for user management. To view and create IBM Cloud instances, visit the [IBM Cloud Quantum Instances page](https://cloud.ibm.com/quantum/instances). To view a list of your instances, visit your [account settings page](https://www.quantum.ibm.com/account) or use the `instances()` method. diff --git a/docs/conf.py b/docs/conf.py index 7cb5f991d1..1b60a00a9a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -131,7 +131,7 @@ # Even though alabaster isn't very pretty, we use it # over the normal qiskit-ecosystem theme because it's # faster to build and these docs are only necessary -# so the API docs can be integrated into docs.quantum.ibm.com. +# so the API docs can be integrated into quantum.cloud.ibm.com/docs. html_theme = "alabaster" html_title = f"{project} {release}" diff --git a/docs/index.rst b/docs/index.rst index 4b184482a3..0154b0573f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,7 +2,7 @@ Qiskit Runtime |release| API Docs Preview ######################################### -Qiskit Runtime docs live at docs.quantum.ibm.com and come from https://github.com/Qiskit/documentation. +Qiskit Runtime docs live at http://quantum.cloud.ibm.com/docs and come from https://github.com/Qiskit/documentation. This site is only used to generate our API docs, which then get migrated to https://github.com/Qiskit/documentation. diff --git a/pyproject.toml b/pyproject.toml index 1502729a20..30c3d35d22 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,7 +99,7 @@ ibm_dynamic_circuits = "qiskit_ibm_runtime.transpiler.plugin:IBMDynamicTranslati ibm_fractional = "qiskit_ibm_runtime.transpiler.plugin:IBMFractionalTranslationPlugin" [project.urls] -documentation = "https://docs.quantum.ibm.com/" +documentation = "https://quantum.cloud.ibm.com/docs/" repository = "https://github.com/Qiskit/qiskit-ibm-runtime" issues = "https://github.com/Qiskit/qiskit-ibm-runtime/issues" diff --git a/qiskit_ibm_runtime/__init__.py b/qiskit_ibm_runtime/__init__.py index 68e344cc86..6db45afc53 100644 --- a/qiskit_ibm_runtime/__init__.py +++ b/qiskit_ibm_runtime/__init__.py @@ -143,7 +143,7 @@ can use the :meth:`QiskitRuntimeService.save_account` method to save the credentials on disk. -Qiskit Runtime is available on IBM Cloud, and you can specify the channel with +Qiskit Runtime is available on IBM Cloud, and you can specify the channel with ``channel="ibm_cloud"`` or ``channel="ibm_quantum_platform"``. Runtime Jobs diff --git a/qiskit_ibm_runtime/accounts/account.py b/qiskit_ibm_runtime/accounts/account.py index e1a7bf25be..90dcc0ed02 100644 --- a/qiskit_ibm_runtime/accounts/account.py +++ b/qiskit_ibm_runtime/accounts/account.py @@ -46,8 +46,9 @@ ] ] -IBM_QUANTUM_API_URL = "https://auth.quantum.ibm.com/api" +IBM_QUANTUM_PLATFORM_API_URL = "https://quantum.cloud.ibm.com" IBM_CLOUD_API_URL = "https://cloud.ibm.com" +IBM_QUANTUM_API_URL = "https://auth.quantum.ibm.com/api" logger = logging.getLogger(__name__) @@ -65,9 +66,8 @@ def __init__( """Account constructor. Args: - channel: Channel type, ``ibm_cloud``, ``ibm_quantum``, ``ibm_quantum_platform``. + channel: Channel type, ``ibm_quantum_platform``, ``ibm_cloud``, ``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. @@ -148,6 +148,7 @@ def create_account( private_endpoint=private_endpoint, region=region, plans_preference=plans_preference, + channel=channel, ) else: raise InvalidAccountError( @@ -276,7 +277,7 @@ def _assert_valid_instance(instance: str) -> None: class CloudAccount(Account): - """Class that represents an account with channel 'ibm_cloud'.""" + """Class that represents an account with channel 'ibm_cloud' or 'ibm_quantum_platform'.""" def __init__( self, @@ -288,6 +289,7 @@ def __init__( private_endpoint: Optional[bool] = False, region: Optional[str] = None, plans_preference: Optional[List[str]] = None, + channel: Optional[str] = "ibm_quantum_platform", ): """Account constructor. @@ -298,10 +300,16 @@ def __init__( proxies: Proxy configuration. verify: Whether to verify server's TLS certificate. private_endpoint: Connect to private API URL. + region: Set a region preference. Accepted values are ``us-east`` or ``eu-de``. + plans_preference: A list of account types, ordered by preference. + channel: Channel identifier. Accepted values are ``ibm_cloud`` or ``ibm_quantum_platform``. + Defaults to ``ibm_quantum_platform``. """ super().__init__(token, instance, proxies, verify) - resolved_url = url or IBM_CLOUD_API_URL - self.channel = "ibm_quantum_platform" # should this be ibm_quantum_platform? + resolved_url = url or ( + IBM_CLOUD_API_URL if channel == "ibm_cloud" else IBM_QUANTUM_PLATFORM_API_URL + ) + self.channel = channel self.url = resolved_url self.private_endpoint = private_endpoint self.region = region @@ -320,9 +328,10 @@ def resolve_crn(self) -> None: Raises: CloudResourceNameResolutionError: if CRN value cannot be resolved. """ + cloud_url = self.url if "quantum" not in self.url else IBM_CLOUD_API_URL crn = resolve_crn( - channel="ibm_cloud", - url=self.url, + channel=self.channel, + url=cloud_url, token=self.token, instance=self.instance, ) @@ -343,12 +352,13 @@ def resolve_crn(self) -> None: def list_instances(self) -> List[Dict[str, str]]: """Retrieve all crns with the IBM Cloud Global Search API.""" - iam_url = get_iam_api_url(self.url) + cloud_url = self.url if "quantum" not in self.url else IBM_CLOUD_API_URL + iam_url = get_iam_api_url(cloud_url) authenticator = IAMAuthenticator(self.token, url=iam_url) client = GlobalSearchV2(authenticator=authenticator) catalog = GlobalCatalogV1(authenticator=authenticator) - client.set_service_url(get_global_search_api_url(self.url)) - catalog.set_service_url(get_global_catalog_api_url(self.url)) + client.set_service_url(get_global_search_api_url(cloud_url)) + catalog.set_service_url(get_global_catalog_api_url(cloud_url)) search_cursor = None all_crns = [] while True: diff --git a/qiskit_ibm_runtime/accounts/management.py b/qiskit_ibm_runtime/accounts/management.py index f73c3b8bdb..2a2dfe274f 100644 --- a/qiskit_ibm_runtime/accounts/management.py +++ b/qiskit_ibm_runtime/accounts/management.py @@ -28,8 +28,9 @@ _DEFAULT_ACCOUNT_NAME = "default" _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM = "default-ibm-quantum" _DEFAULT_ACCOUNT_NAME_IBM_CLOUD = "default-ibm-cloud" +_DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM = "default-ibm-quantum-platform" _DEFAULT_CHANNEL_TYPE: ChannelType = "ibm_quantum_platform" -_CHANNEL_TYPES = [_DEFAULT_CHANNEL_TYPE, "ibm_quantum"] +_CHANNEL_TYPES = [_DEFAULT_CHANNEL_TYPE, "ibm_cloud", "ibm_quantum"] logger = logging.getLogger(__name__) @@ -102,6 +103,7 @@ def _matching_default(account_name: str) -> bool: default_accounts = [ _DEFAULT_ACCOUNT_NAME, _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM, + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM, _DEFAULT_ACCOUNT_NAME_IBM_CLOUD, ] if default is None: @@ -119,7 +121,6 @@ def _matching_default(account_name: str) -> bool: ), read_config(filename=filename).items(), ) - # filter based on input parameters filtered_accounts = dict( list( @@ -131,7 +132,6 @@ def _matching_default(account_name: str) -> bool: ) ) ) - return filtered_accounts @classmethod @@ -266,5 +266,9 @@ def _get_default_account_name(cls, channel: ChannelType) -> str: return ( _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM if channel == "ibm_quantum" - else _DEFAULT_ACCOUNT_NAME_IBM_CLOUD + else ( + _DEFAULT_ACCOUNT_NAME_IBM_CLOUD + if channel == "ibm_cloud" + else _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM + ) ) diff --git a/qiskit_ibm_runtime/accounts/storage.py b/qiskit_ibm_runtime/accounts/storage.py index 127d92a81e..b92d3e418f 100644 --- a/qiskit_ibm_runtime/accounts/storage.py +++ b/qiskit_ibm_runtime/accounts/storage.py @@ -64,7 +64,6 @@ def read_config( """Read configuration data from a JSON file.""" logger.debug("Read configuration data for '%s' from '%s'", name, filename) _ensure_file_exists(filename) - with open(filename, encoding="utf-8") as json_file: data = json.load(json_file) if name is None: diff --git a/qiskit_ibm_runtime/api/clients/runtime.py b/qiskit_ibm_runtime/api/clients/runtime.py index c36b2fe880..9b0b1f48c5 100644 --- a/qiskit_ibm_runtime/api/clients/runtime.py +++ b/qiskit_ibm_runtime/api/clients/runtime.py @@ -46,6 +46,7 @@ def __init__( ) self._api = Runtime(self._session) self._configuration_registry: Dict[str, Dict[str, Any]] = {} + self._instance = params.instance def program_run( self, diff --git a/qiskit_ibm_runtime/api/rest/runtime.py b/qiskit_ibm_runtime/api/rest/runtime.py index 829f73fcb3..256d9c2f34 100644 --- a/qiskit_ibm_runtime/api/rest/runtime.py +++ b/qiskit_ibm_runtime/api/rest/runtime.py @@ -228,6 +228,7 @@ def backends( params = {} if hgp: params["provider"] = hgp + return self.session.get( url, params=params, timeout=timeout, headers=self._HEADER_JSON_ACCEPT ).json() diff --git a/qiskit_ibm_runtime/batch.py b/qiskit_ibm_runtime/batch.py index b6aadd9a7e..2759576581 100644 --- a/qiskit_ibm_runtime/batch.py +++ b/qiskit_ibm_runtime/batch.py @@ -79,7 +79,7 @@ class Batch(Session): jobs.append(job) For more details, check the "`Run jobs in a batch - `_" page. + `_" page. """ def __init__( @@ -99,7 +99,7 @@ def __init__( forcibly closed. Can be specified as seconds (int) or a string like "2h 30m 40s". This value must be less than the `system imposed maximum - `_. + `_. create_new: If True, the POST session API endpoint will be called to create a new session. Prevents creating a new session when ``from_id()`` is called. Raises: @@ -111,7 +111,7 @@ def __init__( def _create_session(self, *, create_new: Optional[bool] = True) -> Optional[str]: """Create a session.""" if isinstance(self._service, QiskitRuntimeService) and create_new: - session = self._service._api_client.create_session( + session = self._service._get_api_client(self._instance).create_session( self.backend(), self._instance, self._max_time, self._service.channel, "batch" ) return session.get("id") diff --git a/qiskit_ibm_runtime/debug_tools/neat_results.py b/qiskit_ibm_runtime/debug_tools/neat_results.py index f4523a4b45..53e02fe959 100644 --- a/qiskit_ibm_runtime/debug_tools/neat_results.py +++ b/qiskit_ibm_runtime/debug_tools/neat_results.py @@ -10,7 +10,7 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -""" A class to store Neat results.""" +"""A class to store Neat results.""" from __future__ import annotations diff --git a/qiskit_ibm_runtime/estimator.py b/qiskit_ibm_runtime/estimator.py index f5bf805d6c..a4904bb4aa 100644 --- a/qiskit_ibm_runtime/estimator.py +++ b/qiskit_ibm_runtime/estimator.py @@ -112,7 +112,8 @@ def __init__( * A :class:`Batch` if you are using batch execution mode. Refer to the - `Qiskit Runtime documentation `_. + `Qiskit Runtime documentation + `_. for more information about the ``Execution modes``. options: Estimator options, see :class:`EstimatorOptions` for detailed description. diff --git a/qiskit_ibm_runtime/execution_span/__init__.py b/qiskit_ibm_runtime/execution_span/__init__.py index c5a26d7be1..73eb030f19 100644 --- a/qiskit_ibm_runtime/execution_span/__init__.py +++ b/qiskit_ibm_runtime/execution_span/__init__.py @@ -20,8 +20,8 @@ Overview ======== -An :class:`~.ExecutionSpans` class instance is an iterable of :class:`~.ExecutionSpan`\\s, where -each iterand gives timing information about a chunk of data. Execution spans are returned as part +An :class:`~.ExecutionSpans` class instance is an iterable of :class:`~.ExecutionSpan`\\s, where +each iterand gives timing information about a chunk of data. Execution spans are returned as part of the metadata of a primitive job result. Classes diff --git a/qiskit_ibm_runtime/fake_provider/__init__.py b/qiskit_ibm_runtime/fake_provider/__init__.py index e5259b2da1..b9b0d8cc91 100644 --- a/qiskit_ibm_runtime/fake_provider/__init__.py +++ b/qiskit_ibm_runtime/fake_provider/__init__.py @@ -58,7 +58,7 @@ :include-source: :context: close-figs - # Transpile the ideal circuit to a circuit that can be + # Transpile the ideal circuit to a circuit that can be # directly executed by the backend transpiled_circuit = transpile(circuit, backend) transpiled_circuit.draw('mpl', style="iqp") @@ -67,7 +67,7 @@ :alt: Histogram output by the previous code. :include-source: :context: close-figs - + # Run the transpiled circuit using the simulated fake backend sampler = SamplerV2(backend) job = sampler.run([transpiled_circuit]) @@ -79,14 +79,14 @@ Please note that the simulation is done using a noise model generated from system snapshots obtained in the past (sometimes a few years ago) and the results are not representative of the - latest behaviors of the real quantum system that the fake backend is mimicking. If you want + latest behaviors of the real quantum system that the fake backend is mimicking. If you want to run noisy simulations with the latest backend snapshots, you can use the ``refresh()`` method. .. code-block:: python from qiskit_ibm_runtime import QiskitRuntimeService from qiskit_ibm_runtime.fake_provider import FakeSherbrooke - + # initialize service to access real backends service = QiskitRuntimeService() diff --git a/qiskit_ibm_runtime/fake_provider/fake_backend.py b/qiskit_ibm_runtime/fake_provider/fake_backend.py index 26e6b13db8..d97bb233ef 100644 --- a/qiskit_ibm_runtime/fake_provider/fake_backend.py +++ b/qiskit_ibm_runtime/fake_provider/fake_backend.py @@ -289,7 +289,7 @@ def max_circuits(self) -> int: "max_circuits is deprecated", "0.37.0", "Please see our documentation on job limits " - "https://docs.quantum.ibm.com/guides/job-limits#job-limits.", + "https://quantum.cloud.ibm.com/docs/guides/job-limits#job-limits.", ) return self.configuration().max_experiments @@ -476,7 +476,7 @@ def refresh(self, service: QiskitRuntimeService) -> None: real_props = real_backend.properties(refresh=True) real_config = configuration_from_server_data( - raw_config=service._api_client.backend_configuration(prod_name, refresh=True) + raw_config=service._get_api_client().backend_configuration(prod_name, refresh=True) ) real_defs = real_backend.defaults(refresh=True) diff --git a/qiskit_ibm_runtime/ibm_backend.py b/qiskit_ibm_runtime/ibm_backend.py index da36ca7069..2549e7a508 100644 --- a/qiskit_ibm_runtime/ibm_backend.py +++ b/qiskit_ibm_runtime/ibm_backend.py @@ -215,7 +215,7 @@ def __getattr__(self, name: str) -> Any: f"{name} is deprecated", "0.37.0", "Please see our documentation on job limits " - "https://docs.quantum.ibm.com/guides/job-limits#job-limits.", + "https://quantum.cloud.ibm.com/docs/guides/job-limits#job-limits.", ) # Lazy load properties and pulse defaults and construct the target object. self.properties() @@ -293,7 +293,7 @@ def max_circuits(self) -> int: "max_circuits is deprecated", "0.37.0", "Please see our documentation on job limits " - "https://docs.quantum.ibm.com/guides/job-limits#job-limits.", + "https://quantum.cloud.ibm.com/docs/guides/job-limits#job-limits.", ) return self._max_circuits @@ -317,7 +317,6 @@ def target(self) -> Target: Target """ self.properties() - self.defaults() self._convert_to_target() return self._target @@ -336,7 +335,9 @@ def target_history(self, datetime: Optional[python_datetime] = None) -> Target: def refresh(self) -> None: """Retrieve the newest backend configuration and refresh the current backend target.""" if config := configuration_from_server_data( - raw_config=self._service._api_client.backend_configuration(self.name, refresh=True), + raw_config=self._service._get_api_client(self._instance).backend_configuration( + self.name, refresh=True + ), instance=self._instance, use_fractional_gates=self.options.use_fractional_gates, ): @@ -468,7 +469,7 @@ def configuration( `_. More details about backend configuration properties can be found here `QasmBackendConfiguration - `_. + `_. IBM backends may also include the following properties: * ``supported_features``: a list of strings of supported features like "qasm3" for dynamic @@ -568,7 +569,7 @@ def run(self, *args, **kwargs) -> None: # type: ignore[no-untyped-def] """ raise IBMBackendError( "Support for backend.run() has been removed. Please see our migration guide " - "https://docs.quantum.ibm.com/migration-guides/qiskit-runtime for instructions " + "https://quantum.cloud.ibm.com/docs/migration-guides/qiskit-runtime for instructions " "on how to migrate to the primitives interface." ) diff --git a/qiskit_ibm_runtime/noise_learner/noise_learner.py b/qiskit_ibm_runtime/noise_learner/noise_learner.py index 2816427465..d7f75335be 100644 --- a/qiskit_ibm_runtime/noise_learner/noise_learner.py +++ b/qiskit_ibm_runtime/noise_learner/noise_learner.py @@ -106,7 +106,7 @@ class NoiseLearner: * A :class:`Batch` if you are using batch execution mode. Refer to the - `Qiskit Runtime documentation `__ + `Qiskit Runtime documentation `__ for more information about the execution modes. options: :class:`NoiseLearnerOptions`. Alternatively, :class:`EstimatorOptions` can be diff --git a/qiskit_ibm_runtime/options/dynamical_decoupling_options.py b/qiskit_ibm_runtime/options/dynamical_decoupling_options.py index 2476976f71..f6b4cc9990 100644 --- a/qiskit_ibm_runtime/options/dynamical_decoupling_options.py +++ b/qiskit_ibm_runtime/options/dynamical_decoupling_options.py @@ -24,34 +24,34 @@ class DynamicalDecouplingOptions: enable: Union[UnsetType, bool] = Unset r"""Whether to enable DD as specified by the other options in this class. - Default: False. + Default: ``False``. """ sequence_type: Union[UnsetType, Literal["XX", "XpXm", "XY4"]] = Unset r"""Which dynamical decoupling sequence to use. - Default: "XX". + Default: ``"XX"``. * ``"XX"``: use the sequence ``tau/2 - (+X) - tau - (+X) - tau/2`` * ``"XpXm"``: use the sequence ``tau/2 - (+X) - tau - (-X) - tau/2`` - * ``"XY4"``: : use the sequence - ``tau/2 - (+X) - tau - (+Y) - tau (-X) - tau - (-Y) - tau/2`` + * ``"XY4"``: use the sequence + ``tau/2 - (+X) - tau - (+Y) - tau (-X) - tau - (-Y) - tau/2`` """ extra_slack_distribution: Union[UnsetType, Literal["middle", "edges"]] = Unset r"""Where to put extra timing delays due to rounding issues. Rounding issues arise because the discrete time step ``dt`` of the system cannot be divided. This option takes following values. - Default: "middle". + Default: ``"middle"``. * ``"middle"``: Put the extra slack to the interval at the middle of the sequence. * ``"edges"``: Divide the extra slack as evenly as possible into intervals at - beginning and end of the sequence. + beginning and end of the sequence. """ scheduling_method: Union[UnsetType, Literal["alap", "asap"]] = Unset r"""Whether to schedule gates as soon as ("asap") or as late as ("alap") possible. - Default: "alap". + Default: ``"alap"``. """ skip_reset_qubits: Union[UnsetType, bool] = Unset r"""Whether to insert DD on idle periods that immediately follow initialized/reset qubits. @@ -59,5 +59,5 @@ class DynamicalDecouplingOptions: Since qubits in the ground state are less susceptible to decoherence, it can be beneficial to let them be while they are known to be in this state. - Default: False. + Default: ``False``. """ diff --git a/qiskit_ibm_runtime/options/estimator_options.py b/qiskit_ibm_runtime/options/estimator_options.py index ebd608be3e..7e2c9a2ccc 100644 --- a/qiskit_ibm_runtime/options/estimator_options.py +++ b/qiskit_ibm_runtime/options/estimator_options.py @@ -75,7 +75,7 @@ class EstimatorOptions(OptionsV2): Refer to the `Configure error mitigation for Qiskit Runtime - `_ guide + `_ guide for more information about the error mitigation methods used at each level. Default: 1. diff --git a/qiskit_ibm_runtime/options/options.py b/qiskit_ibm_runtime/options/options.py index 6634d75a28..1fba169fdb 100644 --- a/qiskit_ibm_runtime/options/options.py +++ b/qiskit_ibm_runtime/options/options.py @@ -126,7 +126,7 @@ class OptionsV2(BaseOptions): Refer to the `Max execution time documentation - `_. + `_. for more information. environment: Options related to the execution environment. See diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index e65bf1c793..dd92cd1633 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -79,43 +79,55 @@ def __init__( region: Optional[str] = None, plans_preference: Optional[List[str]] = None, ) -> None: - """QiskitRuntimeService constructor + """QiskitRuntimeService constructor. An account is selected in the following order: - - - Account with the input `name`, 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 `default_channel` if defined in filename - - Account defined by the environment variables, if defined. - - 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. + - If a ``filename`` is specified, account details will be loaded from ``filename``, + else they will be loaded from the default configuration file. + - If ``name`` is specified, the corresponding account details will be loaded from + the configuration file, including ``channel``, ``token``, ``instance``, ``region`` + (only ``"ibm_cloud"`` and ``"ibm_quantum_platform"``), + ``plans_preference` (only ``"ibm_cloud"`` and ``"ibm_quantum_platform"``), + and the advanced configuration parameters: ``url``, ``url_resolver``, + ``private_endpoint``, ``verify``, and ``proxies``. + - If ``channel`` is specified, the default account details for that channel will be + loaded from the configuration file, else, the account details will be loaded + from the ``default_channel`` defined in the configuration file. + - Any loaded details will be overwritten by the corresponding parameter in the + service constructor. + + The minimum required information for service authentication to a non-local channel is the + ``token``. The ``local`` channel doesn't require authentication. + For the ``"ibm_cloud"`` and ``"ibm_quantum_platform"`` channels it is recommended + to provide the relevant ``instance`` to minimize API calls. If an ``instance`` is not defined, + the service will fetch all instances accessible within the account, filtered by + ``region`` and ``plans_preference``. Args: - Optional[ChannelType] channel: Channel type. ``ibm_cloud``, ``ibm_quantum_platform`` - or ``local``. If ``local`` is selected, the local testing mode will be used, and + Optional[ChannelType] channel: Channel type. ``ibm_quantum``, ``ibm_cloud``, + ``ibm_quantum_platform`` or ``local``. + The ``ibm_quantum`` channel is deprecated and will be removed no earlier than + July 1st 2025, ``ibm_quantum_platform``, which points to the new Quantum Platform + cloud API (https://quantum.cloud.ibm.com) should be used instead. + For help migrating to the alternative channels, review the `migration guide. + `_ + If ``local`` is selected, the local testing mode will be used, and primitive queries will run on a local simulator. For more details, check the `Qiskit Runtime local testing mode - `_ documentation. - The ``ibm_quantum`` channel is deprecated and ``ibm_cloud`` or ``ibm_quantum_platform`` - should be used instead. Note that ``ibm_cloud`` and ``ibm_quantum_platform`` point to - the same channel. For more information, review the `migration guide - `_. + `_ documentation. Optional[str] token: IBM Cloud API key or IBM Quantum API token. Optional[str] url: The API URL. - Defaults to https://cloud.ibm.com (ibm_cloud) or - https://auth.quantum.ibm.com/api (ibm_quantum). + Defaults to https://cloud.ibm.com (``ibm_cloud``), + https://quantum.cloud.ibm.com (``ibm_quantum_platform``) or + https://auth.quantum.ibm.com/api (``ibm_quantum``). Optional[str] filename: Full path of the file where the account is created. Default: _DEFAULT_ACCOUNT_CONFIG_JSON_FILE Optional[str] name: Name of the account to load. Optional[str] instance: The service instance to use. - For ``ibm_cloud`` runtime, this is the Cloud Resource + For ``ibm_cloud`` and ``ibm_quantum_platform``, this is the Cloud Resource Name (CRN) or the service name. If set, it will define a default instance for service instantiation, if not set, the service will fetch all instances accessible - within the account. + within the account. For ``ibm_quantum``, this is the hub/group/project specification. Optional[dict] 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), @@ -124,9 +136,12 @@ def __init__( Optional[bool] verify: Whether to verify the server's TLS certificate. Optional[bool] private_endpoint: Connect to private API URL. Optional[Callable] url_resolver: Function used to resolve the runtime url. - Optional[str] region: Set a region preference. `us-east` or `eu-de`. An instance with + Optional[str] region: Set a region preference for the ``ibm_cloud`` or + ``ibm_quantum_platform`` channel. Accepted values are ``us-east`` or ``eu-de``. + An instance with this region will be prioritized if an instance is not passed in. - Optional[List[str]] plans_preference: A list of account types, ordered by preference. + Optional[List[str]] plans_preference: A list of account types, ordered by preference, + for the ``ibm_cloud`` or ``ibm_quantum_platform`` channel. An instance with the first value in the list will be prioritized if an instance is not passed in. @@ -170,8 +185,12 @@ def __init__( self._backend_configs: Dict[str, QasmBackendConfiguration] = {} if self._channel in ["ibm_cloud", "ibm_quantum_platform"]: - self._api_client = RuntimeClient(self._client_params) self._default_instance = False + self._active_api_client = RuntimeClient(self._client_params) + if instance is not None: + self._api_clients = {instance: RuntimeClient(self._client_params)} + else: + self._api_clients = {} self._cached_backend_objs: List[IBMBackend] = [] if self._account.instance: self._default_instance = True @@ -193,36 +212,40 @@ def __init__( # Update client parameters to use authenticated values. self._client_params.url = auth_client.current_service_urls()["services"]["runtime"] self._client_params.token = auth_client.current_access_token() - self._api_client = RuntimeClient(self._client_params) self._hgps = self._initialize_hgps(auth_client) - self._backend_allowed_list = sorted( set(sum([hgp.backends for hgp in self._hgps.values()], [])) ) + self._active_api_client = RuntimeClient(self._client_params) + self._api_clients = {} + for hgp in self._hgps: + self._api_clients.update({hgp: self._active_api_client}) + self._current_instance = self._account.instance if not self._current_instance: self._current_instance = self._get_hgp().name logger.info("Default instance: %s", self._current_instance) def _discover_backends_from_instance(self, instance: str) -> List[str]: - """Retrieve all backends from the given instance.""" - + """Retrieve all backends from the given instance for + ibm_cloud and ibm_quantum_platform channels.""" # TODO refactor this, this is the slowest part # ntc 5779 would make things a lot faster - get list of backends # from global search API call - - # I don't think we should overwrite the api client like this - # but we can't access the backend config without the right instance try: - self._create_new_cloud_api_client(instance) - return self._api_client.list_backends() + if instance not in self._api_clients: + new_client = self._create_new_cloud_api_client(instance) + self._api_clients.update({instance: new_client}) + self._active_api_client = new_client + return self._active_api_client.list_backends() # On staging there some invalid instances returned that 403 when retrieving backends except Exception: # pylint: disable=broad-except - logger.warning("Invalind instance %s", instance) + logger.warning("Invalid instance %s", instance) return [] - def _create_new_cloud_api_client(self, instance: str) -> None: - """Create a new api_client given an instance.""" + def _create_new_cloud_api_client(self, instance: str) -> RuntimeClient: + """Create a new api_client given an instance for + ibm_cloud and ibm_quantum_platform channels.""" self._client_params = ClientParameters( channel=self._account.channel, token=self._account.token, @@ -233,10 +256,11 @@ def _create_new_cloud_api_client(self, instance: str) -> None: private_endpoint=self._account.private_endpoint, url_resolver=self._url_resolver, ) - self._api_client = RuntimeClient(self._client_params) + return RuntimeClient(self._client_params) def _filter_instances_by_saved_preferences(self) -> None: - """Filter instances by saved region and plan preferences.""" + """Filter instances by saved region and plan preferences + for ibm_cloud and ibm_quantum_platform channels.""" if self._region: self._backend_instance_groups = [ d for d in self._backend_instance_groups if self._region in d["crn"] @@ -253,7 +277,10 @@ def _filter_instances_by_saved_preferences(self) -> None: filtered_groups, key=lambda d: plans.index(d["plan"]) ) else: - logger.warning("No matching plans found.") + raise IBMRuntimeError( + "No matching plan found for any of the plans listed in the", + f"preference list: {self._plans_preference}", + ) def _discover_account( self, @@ -266,10 +293,9 @@ def _discover_account( proxies: Optional[ProxyConfiguration] = None, verify: Optional[bool] = None, ) -> Account: - """Discover account.""" + """Discover account for ibm_quantum, ibm_cloud and ibm_quantum_platform channels.""" account = None verify_ = verify or True - if name: if filename: if any([channel, token, url]): @@ -337,7 +363,8 @@ def _discover_account( return account def _get_crn_from_instance_name(self, account: Account, instance: str) -> str: - """Get the crn from the instance service name.""" + """Get the crn from the instance service name for ibm_cloud and ibm_quantum_platform channels.""" + if not self._all_instances: self._all_instances = account.list_instances() matching_instances = [item for item in self._all_instances if item["name"] == instance] @@ -352,19 +379,8 @@ def _get_crn_from_instance_name(self, account: Account, instance: str) -> str: f"The instance specified ({instance}) is not a valid " "instance name." ) - def _discover_cloud_backends(self) -> List[str]: - """Return the remote backends available for this service instance. - - Returns: - A list of the remote backend names. - """ - return self._api_client.list_backends() - - def _resolve_crn(self, account: Account) -> None: - account.resolve_crn() - def _authenticate_ibm_quantum_account(self, client_params: ClientParameters) -> AuthClient: - """Authenticate against IBM Quantum and populate the hub/group/projects. + """Authenticate against IBM Quantum and populate the hub/group/projects for ibm_quantum channel. Args: client_params: Parameters used for server connection. @@ -398,7 +414,7 @@ def _initialize_hgps( self, auth_client: AuthClient, ) -> Dict: - """Authenticate against IBM Quantum and populate the hub/group/projects. + """Authenticate against IBM Quantum and populate the hub/group/projects for ibm_quantum channel. Args: auth_client: Authentication data. @@ -465,7 +481,7 @@ def _initialize_hgps( @staticmethod def _check_api_version(params: ClientParameters) -> Dict[str, Union[bool, str]]: - """Check the version of the remote server in a set of client parameters. + """Check the version of the remote server in a set of client parameters for all channels. Args: params: Parameters used for server connection. @@ -481,7 +497,7 @@ def _get_hgp( instance: Optional[str] = None, backend_name: Optional[Any] = None, ) -> HubGroupProject: - """Return an instance of `HubGroupProject`. + """Return an instance of `HubGroupProject` for ibm_quantum channel. This function also allows to find the `HubGroupProject` that contains a backend `backend_name`. @@ -528,6 +544,37 @@ def _get_hgp( raise QiskitBackendNotFoundError(error_message) + def _get_api_client(self, instance=None) -> RuntimeClient: + """Return the saved api client for a given instance for all channels. + If no instance is provided, return the current active api client. + + Args: + instance: The hub/group/project to use ("ibm_quantum") or CRN ("ibm_cloud", + "ibm_quantum_platform") + + Returns: + An instance of ``RuntimeClient`` that matches the specified instance. + + Raises: + IBMInputValueError: If no saved api client matches the given instance. + """ + if instance is None: + return self._active_api_client + else: + client = self._api_clients.get(instance, None) + if client is None: + raise IBMInputValueError(f"No API client found for given instance: {instance}") + return client + + def _get_api_clients(self) -> dict[str, RuntimeClient]: + """Return dictionary of saved api clients identified by their corresponding instance + for all channels. + + Returns: + An dictionary of {instance: RuntimeClient} + """ + return self._api_clients + # pylint: disable=arguments-differ def backends( self, @@ -546,7 +593,8 @@ def backends( name: Backend name to filter by. min_num_qubits: Minimum number of qubits the backend has to have. instance: In hub/group/project format if on the ``ibm_quantum`` channel. - IBM Cloud account crn if on the ``ibm_cloud`` channel. + IBM Cloud account CRN if on the ``ibm_cloud`` and + ``ibm_quantum_platform`` channels dynamic_circuits: Filter by whether the backend supports dynamic circuits. filters: More complex filters, such as lambda functions. For example:: @@ -583,7 +631,7 @@ def backends( QiskitRuntimeService.backends(open_pulse=True) For the full list of backend attributes, see the `IBMBackend` class documentation - + Returns: The list of available backends that match the filter. @@ -618,92 +666,24 @@ def backends( ): backends.append(backend) else: - current_instances: List[str] = [] - unique_backends = [] - if instance: - if not is_crn(instance): - instance = self._get_crn_from_instance_name(self._account, instance) - if not instance: - raise IBMInputValueError(f"{instance} is not a valid instance.") - # if an instance name is passed in and there are multiple crns - if self._saved_instances: - current_instances = self._saved_instances - else: - current_instances = [instance] - - elif self._default_instance: - # handle if the instance name passed in at init has multiple matching crns - if self._saved_instances: - current_instances = self._saved_instances - else: - current_instances = [self._account.instance] - else: - if not self._all_instances: - self._all_instances = self._account.list_instances() - logger.warning( - "Default instance not set. Searching all available instances.", - ) - if not self._backend_instance_groups: - for instance_dict in self._all_instances: - self._backend_instance_groups.append( - { - "crn": instance_dict["crn"], - "plan": instance_dict["plan"], - "backends": self._discover_backends_from_instance( - instance_dict["crn"] - ), - } - ) - self._filter_instances_by_saved_preferences() - - for inst_dict in self._backend_instance_groups: - if name: - if name in inst_dict["backends"]: - self._create_new_cloud_api_client(inst_dict["crn"]) - if backend := self._create_backend_obj( - name, - instance=inst_dict["crn"], - use_fractional_gates=use_fractional_gates, - ): - backends.append(backend) - break - - else: - for backend_name in inst_dict["backends"]: - if backend_name not in unique_backends: - unique_backends.append(backend_name) - self._create_new_cloud_api_client(inst_dict["crn"]) - if backend := self._create_backend_obj( - backend_name, - instance=inst_dict["crn"], - use_fractional_gates=use_fractional_gates, - ): - backends.append(backend) - - for inst in current_instances: - backends_available = self._discover_backends_from_instance(inst) + unique_backends = set() + instance_backends = self._resolve_cloud_instances(instance) + for inst, backends_available in instance_backends: if name: - if name in backends_available: - self._create_new_cloud_api_client(inst) - if backend := self._create_backend_obj( - name, - instance=inst, - use_fractional_gates=use_fractional_gates, - ): - backends.append(backend) - break - - else: - for backend_name in backends_available: - if backend_name not in unique_backends: - unique_backends.append(backend_name) - self._create_new_cloud_api_client(inst) - if backend := self._create_backend_obj( - backend_name, - instance=inst, - use_fractional_gates=use_fractional_gates, - ): - backends.append(backend) + if name not in backends_available: + continue + backends_available = [name] + for backend_name in backends_available: + if backend_name in unique_backends: + continue + unique_backends.add(backend_name) + self._get_or_create_cloud_client(inst) + if backend := self._create_backend_obj( + backend_name, + instance=inst, + use_fractional_gates=use_fractional_gates, + ): + backends.append(backend) if name: kwargs["backend_name"] = name if min_num_qubits: @@ -724,6 +704,56 @@ def backends( backend.options.use_fractional_gates = use_fractional_gates return filter_backends(backends, filters=filters, **kwargs) + def _resolve_cloud_instances(self, instance: Optional[str]) -> List[str]: + if instance: + if not is_crn(instance): + instance = self._get_crn_from_instance_name(self._account, instance) + if not instance: + raise IBMInputValueError(f"{instance} is not a valid instance.") + # if an instance name is passed in and there are multiple crns, + # return all matching crns (stored in self._saved_instances) + if self._saved_instances: + return [ + (inst, self._discover_backends_from_instance(inst)) + for inst in self._saved_instances + ] + return [(instance, self._discover_backends_from_instance(instance))] + if self._default_instance: + # if an instance name is passed in and there are multiple crns, + # return all matching crns (stored in self._saved_instances) + default_crn = self._account.instance + if self._saved_instances: + return [ + (inst, self._discover_backends_from_instance(inst)) + for inst in self._saved_instances + ] + return [(default_crn, self._discover_backends_from_instance(default_crn))] + if not self._all_instances: + self._all_instances = self._account.list_instances() + logger.warning( + "Default instance not set. Searching all available instances.", + ) + if not self._backend_instance_groups: + self._backend_instance_groups = [ + { + "crn": inst["crn"], + "plan": inst["plan"], + "backends": self._discover_backends_from_instance(inst["crn"]), + } + for inst in self._all_instances + ] + self._filter_instances_by_saved_preferences() + return [(inst["crn"], inst["backends"]) for inst in self._backend_instance_groups] + + def _get_or_create_cloud_client(self, instance: str): + """Find relevant cloud client for a given instance and set active api client.""" + if instance != self._active_api_client._instance: + client = self._api_clients.get(instance) + if client is None: + client = self._create_new_cloud_api_client(instance) + self._api_clients[instance] = client + self._active_api_client = client + def _create_backend_obj( self, backend_name: str, @@ -734,7 +764,7 @@ def _create_backend_obj( Args: backend_name: Name of backend to instantiate. - instance: the current h/g/p. + instance: the current h/g/p (ibm_quantum) or CRN (ibm_cloud, ibm_quantum_platform). use_fractional_gates: Set True to allow for the backends to include fractional gates, False to include control flow operations, and None to include both fractional gates and control flow @@ -755,7 +785,7 @@ def _create_backend_obj( config = self._backend_configs[backend_name] else: config = configuration_from_server_data( - raw_config=self._api_client.backend_configuration(backend_name), + raw_config=self._active_api_client.backend_configuration(backend_name), instance=instance, use_fractional_gates=use_fractional_gates, ) @@ -792,14 +822,14 @@ def _create_backend_obj( instance=instance, configuration=config, service=self, - api_client=self._api_client, + api_client=self._active_api_client, ) else: # cloud backend doesn't set hgp instance return ibm_backend.IBMBackend( configuration=config, service=self, - api_client=self._api_client, + api_client=self._active_api_client, ) return None @@ -852,13 +882,19 @@ def save_account( Args: token: IBM Cloud API key or IBM Quantum API token. url: The API URL. - Defaults to https://cloud.ibm.com (ibm_cloud) or - instance: The CRN (ibm_cloud) or the service name. This is an optional parameter. + Defaults to https://cloud.ibm.com (``ibm_cloud``), + https://quantum.cloud.ibm.com (``ibm_quantum_platform``) or + https://auth.quantum.ibm.com/api (``ibm_quantum``). + instance: This is an optional parameter to specify the CRN or service name + for ``ibm_cloud`` and ``ibm_quantum_platform``, and the hub/group/project for + ``ibm_quantum``. If set, it will define a default instance for service instantiation, if not set, the service will fetch all instances accessible within the account. - channel: Channel type. `ibm_cloud` or `ibm_quantum_platform`. - The ``ibm_quantum`` channel is deprecated. For help migrating to the ``ibm_cloud`` - channel, review the `migration guide. + channel: Channel type. ``ibm_quantum``, ``ibm_cloud`` or ``ibm_quantum_platform``. + The ``ibm_quantum`` channel is deprecated and will be removed no earlier than + July 1st 2025. ``ibm_quantum_platform`` should be used instead. + Note that ``ibm_cloud`` and ``ibm_quantum_platform`` point to the same url. + For help migrating to the alternative channels, review the `migration guide. `_ filename: Full path of the file where the account is saved. name: Name of the account to save. @@ -907,10 +943,12 @@ def saved_accounts( Args: default: If set to True, only default accounts are returned. - channel: Channel type. `ibm_cloud` or `ibm_quantum_platform`. - The ``ibm_quantum`` channel is deprecated. For help migrating to the ``ibm_cloud`` - channel, review the `migration guide - `__. + channel: Channel type. ``ibm_quantum``, ``ibm_cloud`` or ``ibm_quantum_platform``. + The ``ibm_quantum`` channel is deprecated and will be removed no earlier than + July 1st 2025. ``ibm_quantum_platform`` should be used instead. + Note that ``ibm_cloud`` and ``ibm_quantum_platform`` point to the same url. + For help migrating to the alternative channels, review the `migration guide. + `_ filename: Name of file whose accounts are returned. name: If set, only accounts with the given name are returned. @@ -967,7 +1005,7 @@ def backend( if self._channel in ["ibm_cloud", "ibm_quantum_platform"]: cloud_msg_url = ( " Learn more about available backends here " - "https://cloud.ibm.com/docs/quantum-computing?topic=quantum-computing-choose-backend" + "https://quantum.cloud.ibm.com/docs/en/guides/qpu-information#view-your-resources" ) raise QiskitBackendNotFoundError("No backend matches the criteria." + cloud_msg_url) return backends[0] @@ -1046,7 +1084,7 @@ def _run( version = inputs.get("version", 1) if inputs else 1 try: - response = self._api_client.program_run( + response = self._active_api_client.program_run( program_id=program_id, backend_name=qrt_options.get_backend_name(), params=inputs, @@ -1076,7 +1114,7 @@ def _run( return RuntimeJobV2( backend=backend, - api_client=self._api_client, + api_client=self._active_api_client, job_id=response["id"], program_id=program_id, user_callback=callback, @@ -1129,11 +1167,23 @@ def job(self, job_id: str) -> Union[RuntimeJob, RuntimeJobV2]: IBMRuntimeError: If the request failed. """ try: - response = self._api_client.job_get(job_id, exclude_params=False) + response = self._active_api_client.job_get(job_id, exclude_params=False) except RequestsApiError as ex: - if ex.status_code == 404: - raise RuntimeJobNotFound(f"Job not found: {ex.message}") from None - raise IBMRuntimeError(f"Failed to delete job: {ex}") from None + if ex.status_code != 404: + raise IBMRuntimeError(f"Failed to retrieve job: {ex}") from None + response = None + for instance, client in self._api_clients.items(): + if instance is not None and instance != self._active_api_client._instance: + try: + self._active_api_client = client + response = self._active_api_client.job_get(job_id, exclude_params=False) + break + except RequestsApiError: + continue + if response is not None: + return self._decode_job(response) + raise RuntimeJobNotFound(f"Job not found: {job_id}") from None + return self._decode_job(response) def jobs( @@ -1195,7 +1245,7 @@ def jobs( offset = skip while True: - jobs_response = self._api_client.jobs_get( + jobs_response = self._active_api_client.jobs_get( limit=current_page_limit, skip=offset, backend_name=backend_name, @@ -1246,7 +1296,7 @@ def delete_job(self, job_id: str) -> None: IBMRuntimeError: If the request failed. """ try: - self._api_client.job_delete(job_id) + self._active_api_client.job_delete(job_id) except RequestsApiError as ex: if ex.status_code == 404: raise RuntimeJobNotFound(f"Job not found: {ex.message}") from None @@ -1265,7 +1315,7 @@ def usage(self) -> Dict[str, Any]: raise IBMInputValueError( "Usage is only available for the ``ibm_quantum`` channel open plan." ) - return self._api_client.usage() + return self._active_api_client.usage() def _decode_job(self, raw_data: Dict) -> Union[RuntimeJob, RuntimeJobV2]: """Decode job data received from the server. @@ -1283,6 +1333,8 @@ def _decode_job(self, raw_data: Dict) -> Union[RuntimeJob, RuntimeJobV2]: project = raw_data.get("project") if all([hub, group, project]): instance = to_instance_format(hub, group, project) + else: + instance = self._active_api_client._instance # Try to find the right backend try: if "backend" in raw_data: @@ -1309,7 +1361,7 @@ def _decode_job(self, raw_data: Dict) -> Union[RuntimeJob, RuntimeJobV2]: if version == 1: return RuntimeJob( backend=backend, - api_client=self._api_client, + api_client=self._active_api_client, service=self, job_id=raw_data["id"], program_id=raw_data.get("program", {}).get("id", ""), @@ -1319,7 +1371,7 @@ def _decode_job(self, raw_data: Dict) -> Union[RuntimeJob, RuntimeJobV2]: ) return RuntimeJobV2( backend=backend, - api_client=self._api_client, + api_client=self._active_api_client, service=self, job_id=raw_data["id"], program_id=raw_data.get("program", {}).get("id", ""), diff --git a/qiskit_ibm_runtime/sampler.py b/qiskit_ibm_runtime/sampler.py index f186876ea3..7963f558c0 100644 --- a/qiskit_ibm_runtime/sampler.py +++ b/qiskit_ibm_runtime/sampler.py @@ -73,7 +73,8 @@ def __init__( * A :class:`Batch` if you are using batch execution mode. Refer to the - `Qiskit Runtime documentation `_. + `Qiskit Runtime documentation + `_. for more information about the ``Execution modes``. options: Sampler options, see :class:`SamplerOptions` for detailed description. diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index 4314fc9fd5..57e8c0c61b 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -21,6 +21,7 @@ from qiskit.providers.backend import BackendV2 from qiskit_ibm_runtime import QiskitRuntimeService +from .api.exceptions import RequestsApiError from .exceptions import IBMInputValueError, IBMRuntimeError from .runtime_job import RuntimeJob from .runtime_job_v2 import RuntimeJobV2 @@ -98,7 +99,7 @@ def __init__( forcibly closed. Can be specified as seconds (int) or a string like "2h 30m 40s". This value must be less than the `system imposed maximum - `_. + `_. create_new: If True, the POST session API endpoint will be called to create a new session. Prevents creating a new session when ``from_id()`` is called. Raises: @@ -133,7 +134,7 @@ def __init__( def _create_session(self, *, create_new: Optional[bool] = True) -> Optional[str]: """Create a session.""" if isinstance(self._service, QiskitRuntimeService) and create_new: - session = self._service._api_client.create_session( + session = self._service._get_api_client(self._instance).create_session( self.backend(), self._instance, self._max_time, self._service.channel, "dedicated" ) return session.get("id") @@ -193,7 +194,7 @@ def cancel(self) -> None: """Cancel all pending jobs in a session.""" self._active = False if self._session_id and isinstance(self._service, QiskitRuntimeService): - self._service._api_client.cancel_session(self._session_id) + self._service._get_api_client(self._instance).cancel_session(self._session_id) def close(self) -> None: """Close the session so new jobs will no longer be accepted, but existing @@ -201,7 +202,7 @@ def close(self) -> None: are no more pending jobs.""" self._active = False if self._session_id and isinstance(self._service, QiskitRuntimeService): - self._service._api_client.close_session(self._session_id) + self._service._get_api_client(self._instance).close_session(self._session_id) def backend(self) -> Optional[str]: """Return backend for this session. @@ -249,7 +250,9 @@ def usage(self) -> Optional[float]: Batch usage is the amount of time all jobs spend on the QPU. """ if self._session_id and isinstance(self._service, QiskitRuntimeService): - response = self._service._api_client.session_details(self._session_id) + response = self._service._get_api_client(self._instance).session_details( + self._session_id + ) if response: return response.get("elapsed_time") return None @@ -278,7 +281,9 @@ def details(self) -> Optional[Dict[str, Any]]: Usage is defined as the time a quantum system is committed to complete a job. """ if self._session_id and isinstance(self._service, QiskitRuntimeService): - response = self._service._api_client.session_details(self._session_id) + response = self._service._get_api_client(self._instance).session_details( + self._session_id + ) if response: return { "id": response.get("id"), @@ -333,8 +338,24 @@ def from_id(cls, session_id: str, service: QiskitRuntimeService) -> "Session": A new Session with the given ``session_id`` """ - - response = service._api_client.session_details(session_id) + current_client = service._get_api_client() + try: + response = current_client.session_details(session_id) + except RequestsApiError as ex: + if ex.status_code == 404: + response = None + for instance, client in service._get_api_clients().items(): + if client != current_client and instance is not None: + try: + service._active_api_client = client + response = client.session_details(session_id) + break + except RequestsApiError as _: + continue + if response is None: + raise IBMInputValueError(f"Session not found: {ex.message}") from None + + response = service._get_api_client().session_details(session_id) backend_name = response.get("backend_name") if not backend_name: raise IBMRuntimeError( diff --git a/qiskit_ibm_runtime/transpiler/passes/__init__.py b/qiskit_ibm_runtime/transpiler/passes/__init__.py index 3720889f31..da3699d1bc 100644 --- a/qiskit_ibm_runtime/transpiler/passes/__init__.py +++ b/qiskit_ibm_runtime/transpiler/passes/__init__.py @@ -18,7 +18,7 @@ .. currentmodule:: qiskit_ibm_runtime.transpiler.passes A collection of transpiler passes. Refer to -https://docs.quantum.ibm.com/guides/transpile to learn more about +https://quantum.cloud.ibm.com/docs/guides/transpile to learn more about transpilation and passes. .. autosummary:: diff --git a/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py b/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py index b181348296..33499ed199 100644 --- a/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py +++ b/qiskit_ibm_runtime/transpiler/passes/scheduling/__init__.py @@ -340,7 +340,7 @@ PadDynamicalDecoupling(durations, dd_sequence), ] ) - + qc_dd = pm.run(qc) qc_dd.draw(output="mpl", style="iqp") diff --git a/qiskit_ibm_runtime/utils/utils.py b/qiskit_ibm_runtime/utils/utils.py index deeb97dc03..39ab145cd5 100644 --- a/qiskit_ibm_runtime/utils/utils.py +++ b/qiskit_ibm_runtime/utils/utils.py @@ -336,7 +336,11 @@ def default_runtime_url_resolver(url: str, instance: str, private_endpoint: bool f"{parsed_url.scheme}://private.{_location_from_crn(instance)}" f".quantum-computing.{parsed_url.hostname}" ) + elif "quantum" in url: + # ibm_quantum_platform url + api_host = f"{parsed_url.scheme}://{parsed_url.hostname}/api/v1" else: + # ibm_cloud url api_host = ( f"{parsed_url.scheme}://{_location_from_crn(instance)}" f".quantum-computing.{parsed_url.hostname}" diff --git a/qiskit_ibm_runtime/utils/validations.py b/qiskit_ibm_runtime/utils/validations.py index 2deda7bafc..366e9c81ff 100644 --- a/qiskit_ibm_runtime/utils/validations.py +++ b/qiskit_ibm_runtime/utils/validations.py @@ -97,9 +97,9 @@ def validate_isa_circuits(circuits: Sequence[QuantumCircuit], target: Target) -> message + " Circuits that do not match the target hardware definition are no longer " "supported after March 4, 2024. See the transpilation documentation " - "(https://docs.quantum.ibm.com/guides/transpile) for instructions " + "(https://quantum.cloud.ibm.com/docs/guides/transpile) for instructions " "to transform circuits and the primitive examples " - "(https://docs.quantum.ibm.com/guides/primitives-examples) to see " + "(https://quantum.cloud.ibm.com/docs/guides/primitives-examples) to see " "this coupled with operator transformations." ) diff --git a/release-notes/0.1.0.rst b/release-notes/0.1.0.rst index 9155c48682..28928db9fd 100644 --- a/release-notes/0.1.0.rst +++ b/release-notes/0.1.0.rst @@ -49,7 +49,7 @@ Upgrade Notes from qiskit_ibm_runtime import IBMRuntimeService service = IBMRuntimeService(auth="cloud", token="abc", instance="IBM Cloud CRN or Service instance name") -- `qiskit_ibm_runtime.IBMBackend `__ +- `qiskit_ibm_runtime.IBMBackend `__ class now implements the ``qiskit.providers.BackendV2`` interface and provides flatter access to the configuration of a backend, for example: @@ -66,7 +66,7 @@ Upgrade Notes now an attribute instead of a method. Refer to the - `qiskit_ibm_runtime.IBMBackend `__ + `qiskit_ibm_runtime.IBMBackend `__ class doc string for a list of all available attributes. - If you used qiskit.providers.ibmq.AccountProvider.get_backend method @@ -111,11 +111,11 @@ Upgrade Notes - ``qiskit_ibm_runtime.IBMRuntimeService.run()`` method now accepts runtime execution options as - `qiskit_ibm_runtime.RuntimeOptions `__ + `qiskit_ibm_runtime.RuntimeOptions `__ class in addition to already supported Dict. backend_name, image and log_level are the currently available options. - Final result is also streamed now after interim results when you specify a ``callback`` to ``qiskit_ibm_runtime.IBMRuntimeService.run()`` or - `qiskit_ibm_runtime.RuntimeJob.stream_results() `__. + `qiskit_ibm_runtime.RuntimeJob.stream_results() `__. diff --git a/release-notes/0.1.0rc1.rst b/release-notes/0.1.0rc1.rst index 1a663b4ff4..2dfa2fca77 100644 --- a/release-notes/0.1.0rc1.rst +++ b/release-notes/0.1.0rc1.rst @@ -9,7 +9,7 @@ New Features jobs. Currently only supported for legacy authentication. - You can now use the - `qiskit_ibm_runtime.RuntimeJob.interim_results() `__ + `qiskit_ibm_runtime.RuntimeJob.interim_results() `__ method to retrieve runtime program interim results. Note that interim results will only be available for up to two days. @@ -17,7 +17,7 @@ Upgrade Notes ------------- - In order to be consistent with other properties in - `qiskit_ibm_runtime.RuntimeJob `__ + `qiskit_ibm_runtime.RuntimeJob `__ class the job_id and backend methods have been converted to properties. diff --git a/release-notes/0.1.0rc2.rst b/release-notes/0.1.0rc2.rst index b62cf9a942..5a60b14a5c 100644 --- a/release-notes/0.1.0rc2.rst +++ b/release-notes/0.1.0rc2.rst @@ -14,14 +14,14 @@ New Features Bug Fixes --------- -- `qiskit_ibm_runtime.utils.json.RuntimeEncoder `__ +- `qiskit_ibm_runtime.utils.json.RuntimeEncoder `__ and - `qiskit_ibm_runtime.utils.json.RuntimeDecoder `__ + `qiskit_ibm_runtime.utils.json.RuntimeDecoder `__ have been updated to handle instances of the Instruction class. - Fixed an issue where numpy ndarrays with object types could not be serialized. - `qiskit_ibm_runtime.utils.json.RuntimeEncoder `__ + `qiskit_ibm_runtime.utils.json.RuntimeEncoder `__ and - `qiskit_ibm_runtime.utils.json.RuntimeDecoder `__ + `qiskit_ibm_runtime.utils.json.RuntimeDecoder `__ have been updated to handle these ndarrays. diff --git a/release-notes/0.11.0.rst b/release-notes/0.11.0.rst index 8e5576220e..84e4552a93 100644 --- a/release-notes/0.11.0.rst +++ b/release-notes/0.11.0.rst @@ -8,7 +8,7 @@ New Features ``qiskit_ibm_runtime.IBMRuntimeService.job()`` the ``params`` will no longer be returned from the API. They will instead be loaded loazily when they are actually needed in - `qiskit_ibm_runtime.RuntimeJob.inputs() `__. + `qiskit_ibm_runtime.RuntimeJob.inputs() `__. - Added warning when the backend is not active in QiskitRuntimeService.run. @@ -31,16 +31,16 @@ Upgrade Notes - A default session is no longer open for you if you pass a backend name or backend instance to - `qiskit_ibm_runtime.Sampler `__ or - `qiskit_ibm_runtime.Estimator `__ + `qiskit_ibm_runtime.Sampler `__ or + `qiskit_ibm_runtime.Estimator `__ constructors. The primitive will instead run without a session. In addition, you should now use the ``backend`` parameter to pass a backend name or instance instead of the ``session`` parameter (which can continue to be used to pass a session). - The first parameter of the - `qiskit_ibm_runtime.Sampler `__ and - `qiskit_ibm_runtime.Estimator `__ + `qiskit_ibm_runtime.Sampler `__ and + `qiskit_ibm_runtime.Estimator `__ constructors is now ``backend`` instead of ``session``. Deprecation Notes @@ -48,7 +48,7 @@ Deprecation Notes - Passing a backend name or backend instance to the ``session`` parameter when initializing a - `qiskit_ibm_runtime.Sampler `__ or - `qiskit_ibm_runtime.Estimator `__ + `qiskit_ibm_runtime.Sampler `__ or + `qiskit_ibm_runtime.Estimator `__ has been deprecated. Please use the ``backend`` parameter instead. You can continue to pass a session using the ``session`` parameter. diff --git a/release-notes/0.11.1.rst b/release-notes/0.11.1.rst index 271c933382..680e6ce954 100644 --- a/release-notes/0.11.1.rst +++ b/release-notes/0.11.1.rst @@ -5,5 +5,5 @@ Deprecation Notes ----------------- - In - `qiskit_ibm_runtime.RuntimeJob.metrics() `__, + `qiskit_ibm_runtime.RuntimeJob.metrics() `__, the bss field will be replaced by usage. diff --git a/release-notes/0.11.2.rst b/release-notes/0.11.2.rst index 222f06e7c3..f04ca284c0 100644 --- a/release-notes/0.11.2.rst +++ b/release-notes/0.11.2.rst @@ -8,7 +8,7 @@ New Features exception rather than returning None. - A new method, - `qiskit_ibm_runtime.options.SimulatorOptions.set_backend() `__, + `qiskit_ibm_runtime.options.SimulatorOptions.set_backend() `__, allows users to more easily set simulator options for a backend. .. code:: python diff --git a/release-notes/0.11.3.rst b/release-notes/0.11.3.rst index c237bfe209..5eaf0acbca 100644 --- a/release-notes/0.11.3.rst +++ b/release-notes/0.11.3.rst @@ -5,10 +5,10 @@ New Features ------------ - Added reason for failure when invoking the method - `error_message() `__. + `error_message() `__. - Added a new property, - `usage_estimation() `__ + `usage_estimation() `__ that returns the estimated system execution time, ``quantum_seconds``. System execution time represents the amount of time that the system is dedicated to processing your job. @@ -18,11 +18,11 @@ New Features backend. - There is a new method - `update_tags() `__ + `update_tags() `__ that can be used to update the ``job_tags`` of a job. - If ``instance`` is provided as parameter to - `qiskit_ibm_runtime.QiskitRuntimeService `__, + `qiskit_ibm_runtime.QiskitRuntimeService `__, then this is used as a filter in ``QiskitRuntimeService.backends()``. If ``instance`` is not recognized as one of the provider instances, an exception will be raised. Previously, we only issued a warning. diff --git a/release-notes/0.12.0.rst b/release-notes/0.12.0.rst index a698e18e8f..a997bb64de 100644 --- a/release-notes/0.12.0.rst +++ b/release-notes/0.12.0.rst @@ -16,7 +16,7 @@ New Features sampler = Sampler(backend="ibmq_qasm_simulator") - Added a new method, - `qiskit_ibm_runtime.QiskitRuntimeService.instances() `__ + `qiskit_ibm_runtime.QiskitRuntimeService.instances() `__ that returns all instances(hub/group/project) the user is in. This is only for the ``ibm_quantum`` channel since the ``ibm_cloud`` channel does not have multiple instances. @@ -27,9 +27,9 @@ New Features - There is a new parameter, ``channel_strategy`` that can be set in the initialization of - `qiskit_ibm_runtime.QiskitRuntimeService `__ + `qiskit_ibm_runtime.QiskitRuntimeService `__ or saved in - `qiskit_ibm_runtime.QiskitRuntimeService.save_account() `__. + `qiskit_ibm_runtime.QiskitRuntimeService.save_account() `__. If ``channel_strategy`` is set to ``q-ctrl``, all jobs within the service will use the Q-CTRL error mitigation strategy. @@ -38,7 +38,7 @@ Upgrade Notes - Circuits and other input parameters will no longer be automatically stored in runtime jobs. They can still be retrieved with - `qiskit_ibm_runtime.RuntimeJob.inputs() `__. + `qiskit_ibm_runtime.RuntimeJob.inputs() `__. Deprecation Notes diff --git a/release-notes/0.12.1.rst b/release-notes/0.12.1.rst index 56881e2ecf..cb5387d747 100644 --- a/release-notes/0.12.1.rst +++ b/release-notes/0.12.1.rst @@ -11,7 +11,7 @@ New Features - Users can now pass in a value of ``default`` to the ``channel_strategy`` parameter in - `qiskit_ibm_runtime.QiskitRuntimeService `__. + `qiskit_ibm_runtime.QiskitRuntimeService `__. Now, if an account is configured with a certain channel strategy, the user can override it by passing in ``default``. @@ -26,12 +26,12 @@ Bug Fixes --------- - Retrieving backend properties with - `properties() `__ now + `properties() `__ now supports passing a ``datetime`` parameter to retrieve properties from a past date. - The ``noise_factors`` and ``extrapolator`` options in - `qiskit_ibm_runtime.options.ResilienceOptions `__ + `qiskit_ibm_runtime.options.ResilienceOptions `__ will now default to ``None`` unless ``resilience_level`` is set to 2. Only options relevant to the resilience level will be set, so when using ``resilience_level`` 2, ``noise_factors`` will still default to diff --git a/release-notes/0.12.2.rst b/release-notes/0.12.2.rst index c181632e78..7f762246c4 100644 --- a/release-notes/0.12.2.rst +++ b/release-notes/0.12.2.rst @@ -24,4 +24,4 @@ Upgrade Notes ------------- - Job error messages now include the error code. Error codes can be - found in `errors `__. + found in `errors `__. diff --git a/release-notes/0.13.0.rst b/release-notes/0.13.0.rst index 15f45a75c5..00f4bc4e29 100644 --- a/release-notes/0.13.0.rst +++ b/release-notes/0.13.0.rst @@ -5,12 +5,12 @@ New Features ------------ - Added a new method, - `details() `__ that returns + `details() `__ that returns information about a session, including: maximum session time, active time remaining, the current state, and whether or not the session is accepting jobs. - Also added `status() `__, + Also added `status() `__, which returns the current status of the session. - At initialization, if not passed in directly, the default @@ -22,7 +22,7 @@ New Features Upgrade Notes ------------- -- `qiskit_ibm_runtime.Session.close() `__ +- `qiskit_ibm_runtime.Session.close() `__ has been updated to mark a ``Session`` as no longer accepting new jobs. The session won’t accept more jobs but it will continue to run any queued jobs until they are done or the max time expires. This @@ -32,7 +32,7 @@ Upgrade Notes jobs rather than wait for the interactive timeout. The old close method behavior has been moved to a new method, - `qiskit_ibm_runtime.Session.cancel() `__, + `qiskit_ibm_runtime.Session.cancel() `__, where all queued jobs within a session are cancelled and terminated. Bug Fixes @@ -42,6 +42,6 @@ Bug Fixes serialized correctly. - Fixed a bug in - `target_history() `__ + `target_history() `__ where the datetime parameter was not being used to retrieve backend properties from the specified date. diff --git a/release-notes/0.14.0.rst b/release-notes/0.14.0.rst index 6401c8f6b5..9b2730b433 100644 --- a/release-notes/0.14.0.rst +++ b/release-notes/0.14.0.rst @@ -6,7 +6,7 @@ New Features - There is a new class, ``qiskit_ibm_runtime.Batch`` that currently works the same way as - `qiskit_ibm_runtime.Session `__ but + `qiskit_ibm_runtime.Session `__ but will later be updated to better support submitting multiple jobs at once. diff --git a/release-notes/0.15.0.rst b/release-notes/0.15.0.rst index 53783e468e..c848610aec 100644 --- a/release-notes/0.15.0.rst +++ b/release-notes/0.15.0.rst @@ -67,13 +67,13 @@ Bug Fixes being used since not all features are supported there. - The ``backend`` parameter in - `from_id() `__ is being + `from_id() `__ is being deprecated because sessions do not support multiple backends. Additionally, the ``service`` parameter is no longer optional. - The ``circuit_indices`` and ``observable_indices`` run inputs for - `Estimator `__ and - `Sampler `__ have been completely + `Estimator `__ and + `Sampler `__ have been completely removed. Other Notes diff --git a/release-notes/0.15.1.rst b/release-notes/0.15.1.rst index 641fc83de0..65556a9a6a 100644 --- a/release-notes/0.15.1.rst +++ b/release-notes/0.15.1.rst @@ -5,5 +5,5 @@ Bug Fixes --------- - Reverting 0.15.0 changes to - `from_id() `__ because it was + `from_id() `__ because it was a breaking change without proper deprecation. diff --git a/release-notes/0.17.0.rst b/release-notes/0.17.0.rst index ea34314b2b..29421f0c9a 100644 --- a/release-notes/0.17.0.rst +++ b/release-notes/0.17.0.rst @@ -5,11 +5,11 @@ New Features ------------ - Added a new method - `properties() `__ which + `properties() `__ which returns the backend properties of the job at the time the job was run. -- `details() `__ has a new +- `details() `__ has a new field, activated_at, which is the timestamp of when the session was changed to active. diff --git a/release-notes/0.18.0.rst b/release-notes/0.18.0.rst index 417dede1c0..0089c190c0 100644 --- a/release-notes/0.18.0.rst +++ b/release-notes/0.18.0.rst @@ -5,7 +5,7 @@ New Features ------------ - Added a new parameter, dynamic_circuits to - `backends() `__ + `backends() `__ to allow filtering of backends that support dynamic circuits. - Added ``max_time`` parameter to ``IBMBackend.open_session()``. @@ -17,14 +17,14 @@ New Features Deprecation Notes ----------------- -- `runtime() `__ +- `runtime() `__ has been deprecated. Bug Fixes --------- -- Many methods in `RuntimeJob `__ +- Many methods in `RuntimeJob `__ require retrieving the job data from the API with ``job_get()``. This API call will now exclude the ``params`` field by default because they are only necessary in - `qiskit_ibm_runtime.RuntimeJob.inputs() `__. + `qiskit_ibm_runtime.RuntimeJob.inputs() `__. diff --git a/release-notes/0.2.0.rst b/release-notes/0.2.0.rst index b4b0487f17..4041dcdaa2 100644 --- a/release-notes/0.2.0.rst +++ b/release-notes/0.2.0.rst @@ -14,7 +14,7 @@ Bug Fixes --------- - Fixed a bug where - `qiskit_ibm_runtime.RuntimeJob.wait_for_final_state() `__ + `qiskit_ibm_runtime.RuntimeJob.wait_for_final_state() `__ would result in a NoneType error if the job already completed and - `qiskit_ibm_runtime.RuntimeJob.status() `__ + `qiskit_ibm_runtime.RuntimeJob.status() `__ was called beforehand. diff --git a/release-notes/0.20.0.rst b/release-notes/0.20.0.rst index aa6a02c36b..0d40c338df 100644 --- a/release-notes/0.20.0.rst +++ b/release-notes/0.20.0.rst @@ -5,7 +5,7 @@ New Features ------------ - Add ``dd_barrier`` optional input to - `PadDynamicalDecoupling `__ + `PadDynamicalDecoupling `__ constructor to identify portions of the circuit to apply dynamical decoupling (dd) on selectively. If this string is contained in the label of a barrier in the circuit, dd is applied on the delays ending @@ -15,9 +15,9 @@ New Features - Sessions will now be started with a new ``/sessions`` endpoint that allows for different execution modes. Batch mode is now supported - through ``Batch``, and `Session `__ + through ``Batch``, and `Session `__ will work the same as way as before. Please see - `run/sessions `__ for more information. + `run/sessions `__ for more information. Note that ``Session`` and ``Batch`` created from ``qiskit-ibm-runtime`` prior to this release will no longer be @@ -29,7 +29,7 @@ New Features a session will not actually be created. There will be no session ID. - Sessions started with - `qiskit_ibm_runtime.IBMBackend.open_session() `__ + `qiskit_ibm_runtime.IBMBackend.open_session() `__ will use the new ``/sessions`` endpoint. The sessions functionality will not change but note that @@ -42,9 +42,9 @@ Deprecation Notes - Circuits that do not match the target hardware definition will no longer be supported after March 1, 2024. See the transpilation - documentation (`transpile `__) for instructions to + documentation (`transpile `__) for instructions to transform circuits and the primitive examples - (`run/primitives-examples `__) to see this + (`run/primitives-examples `__) to see this coupled with operator transformations. Bug Fixes diff --git a/release-notes/0.21.0.rst b/release-notes/0.21.0.rst index 50560c2ecf..c143da1f32 100644 --- a/release-notes/0.21.0.rst +++ b/release-notes/0.21.0.rst @@ -7,9 +7,9 @@ Upgrade Notes - Circuits that do not match the target hardware definition are no longer supported by Qiskit Runtime primitives, unless ``channel_strategy="q-ctrl"`` is used. See the transpilation - documentation (`transpile `__) for instructions to + documentation (`transpile `__) for instructions to transform circuits and the primitive examples - (`run/primitives-examples `__) to see this + (`run/primitives-examples `__) to see this coupled with operator transformations. Deprecation Notes diff --git a/release-notes/0.23.0.rst b/release-notes/0.23.0.rst index e3c1543f80..d79c98906e 100644 --- a/release-notes/0.23.0.rst +++ b/release-notes/0.23.0.rst @@ -4,9 +4,9 @@ Deprecation Notes ----------------- -- `backend.run() `__ has been deprecated. Please use the primitives instead. More details - can be found in the `migration guide `__ . (`1561 `__) -- In a future release, the ``service`` parameter in `from_id() `__ +- `backend.run() `__ has been deprecated. Please use the primitives instead. More details + can be found in the `migration guide `__ . (`1561 `__) +- In a future release, the ``service`` parameter in `from_id() `__ will be required. (`1311 `__) New Features @@ -24,7 +24,7 @@ New Features inadvertently disabling Q-CTRL's performance enhancements. (`1550 `__) - :class:`.SamplerV2` now supports twirling. Twirling will only be applied to those measurement registers not involved within a conditional logic. (`1557 `__) -- Session `details() `__ +- Session `details() `__ now includes a new field, ``usage_time``. Usage is defined as the time a quantum system is committed to complete a job. (`1567 `__) @@ -37,6 +37,6 @@ Bug Fixes from the API will directly be returned. (`1476 `__) - Fixed a bug where custom headers were not being sent in the ``/jobs`` request. (`1508 `__) - Fixed a bug with encoding/decoding ``ParameterExpression``. (`1521 `__) -- Fixed an issue where the `in_final_state() `__ +- Fixed an issue where the `in_final_state() `__ method in :class:`.RuntimeJobV2` would not update the status when called. (`1547 `__) diff --git a/release-notes/0.24.0.rst b/release-notes/0.24.0.rst index 9b8eab762e..4b7f361152 100644 --- a/release-notes/0.24.0.rst +++ b/release-notes/0.24.0.rst @@ -5,7 +5,7 @@ Deprecation Notes ----------------- - ``name`` will now be a required parameter in - `backend() `__. + `backend() `__. ``backend()`` will no longer return the first backend out of all backends if ``name`` is not provided. (`1147 `__) - After the removal of custom programs, the following methods are being deprecated and renamed. :meth:`qiskit_ibm_runtime.QiskitRuntimeService.run` is deprecated and will be replaced by a private method @@ -16,11 +16,11 @@ Deprecation Notes :meth:`qiskit_ibm_runtime.RuntimeJob.program_id` is deprecated and will be replaced by :meth:`qiskit_ibm_runtime.RuntimeJob.primitive_id`. (`1238 `__) -- The ``backend`` argument in `Sampler `__ - and `Estimator `__ has been deprecated. +- The ``backend`` argument in `Sampler `__ + and `Estimator `__ has been deprecated. Please use ``mode`` instead. - The ``session`` argument in `Sampler `__ - and `Estimator `__ has also been deprecated. + The ``session`` argument in `Sampler `__ + and `Estimator `__ has also been deprecated. Please use ``mode`` instead. (`1556 `__) - :meth:`qiskit_ibm_runtime.QiskitRuntimeService.get_backend` is deprecated. Please :meth:`qiskit_ibm_runtime.QiskitRuntimeService.backend` use instead. @@ -97,8 +97,8 @@ Bug Fixes --------- - Fixed an issue where retrieving jobs with - `job() `__ - and `jobs() `__ + `job() `__ + and `jobs() `__ would only return ``RuntimeJob`` instances, even if the job was run with a V2 primitive. Now, V2 primitive jobs will be returned correctly as ``RuntimeJobV2`` instances. (`1471 `__) - To avoid network disruptions during long job processes, websocket errors will no longer be raised. (`1518 `__) @@ -110,5 +110,5 @@ Bug Fixes - Fixed measurement twirling docstring which incorrectly indicated it's enabled by default for Sampler. (`1722 `__) - Fixed nested experimental suboptions override non-experimental suboptions. (`1731 `__) - The backend utils method ``convert_to_target`` has been replaced with the - `convert_to_target `__ method from Qiskit. + `convert_to_target `__ method from Qiskit. This fixes some issues related to target generation and calibration data. (`1600 `__) diff --git a/release-notes/0.28.0.rst b/release-notes/0.28.0.rst index 502f1a6e68..3cc809167c 100644 --- a/release-notes/0.28.0.rst +++ b/release-notes/0.28.0.rst @@ -13,5 +13,5 @@ Upgrade Notes ------------- - The V1 Primitives ``SamplerV1`` and ``EstimatorV1`` have been completely removed. Please see the - `migration guide `__ and use the V2 Primitives instead. (`1857 `__) + `migration guide `__ and use the V2 Primitives instead. (`1857 `__) - The ``service`` parameter is now required in ``Session.from_id()``. (`1868 `__) diff --git a/release-notes/0.30.0.rst b/release-notes/0.30.0.rst index 01761d0d99..77286ac420 100644 --- a/release-notes/0.30.0.rst +++ b/release-notes/0.30.0.rst @@ -27,7 +27,7 @@ New Features - Added new methods ``Session.usage()``, ``Batch.usage()``, and ``Job.usage()`` that all return information regarding job and session usage. - Please find more information `here `__. (`1827 `__) + Please find more information `here `__. (`1827 `__) - Added ``ConvertISAToClifford`` transpilation pass to convert the gates of a circuit to Clifford gates. (`1887 `__) - Added ``url_resolver`` optional input to :class:`.QiskitRuntimeService` constructor to enable custom generation of the Qiskit Runtime API URL diff --git a/release-notes/0.37.0.rst b/release-notes/0.37.0.rst index f78850f065..c37ba54a39 100644 --- a/release-notes/0.37.0.rst +++ b/release-notes/0.37.0.rst @@ -30,7 +30,7 @@ Bug Fixes --------- - Fixed support for custom scheduling transpiler stages with Qiskit 2.x. (`2153 `__) -- `ConvertConditionsToIfOps `__ now correctly runs at +- `ConvertConditionsToIfOps `__ now correctly runs at all optimization levels of the scheduling plugins for dynamic circuits, when using Qiskit 1.x. (`2154 `__) - When retrieving jobs with :meth:`~.QiskitRuntimeService.jobs`, there is no way to distinguish between v1 and v2 primitives. Since the v1 primitives were completely removed over 6 months ago diff --git a/release-notes/0.4.0.rst b/release-notes/0.4.0.rst index 636127be68..d5c27c7b44 100644 --- a/release-notes/0.4.0.rst +++ b/release-notes/0.4.0.rst @@ -25,7 +25,7 @@ Upgrade Notes service = QiskitRuntimeService(channel="ibm_cloud", token="...", instance="...") - ``IBMEstimator`` class is now deprecated and will be removed in a - future release. Use `Estimator `__ + future release. Use `Estimator `__ class going forward. Example: @@ -59,7 +59,7 @@ Upgrade Notes result = estimator(circuit_indices=[0], ...) - ``IBMSampler`` class is now deprecated and will be removed in a - future release. Use `Sampler `__ + future release. Use `Sampler `__ class going forward. Example: @@ -96,7 +96,7 @@ Deprecation Notes - ``IBMRuntimeService``, ``IBMEstimator`` and ``IBMSampler`` classes have been deprecated and will be removed in a future release. Use - `QiskitRuntimeService `__, - `Estimator `__ and - `Sampler `__ classes instead. See + `QiskitRuntimeService `__, + `Estimator `__ and + `Sampler `__ classes instead. See upgrade notes section for a detailed explanation with examples. diff --git a/release-notes/0.5.0.rst b/release-notes/0.5.0.rst index 1f2f6833e7..78c8e95f0b 100644 --- a/release-notes/0.5.0.rst +++ b/release-notes/0.5.0.rst @@ -14,9 +14,9 @@ New Features ------------ - The ``service`` object which is an instance of - `QiskitRuntimeService `__ + `QiskitRuntimeService `__ class can now be accessed from - `IBMBackend `__ class using the + `IBMBackend `__ class using the ``service`` property. Ex: @@ -29,7 +29,7 @@ New Features Upgrade Notes ------------- -- `jobs() `__ has two +- `jobs() `__ has two new parameters, ``created_after`` and ``created_before``. These can be used to filter jobs by creation date in local time. @@ -76,38 +76,38 @@ Upgrade Notes - The ``session_id``, which is the Job ID of the first job in a runtime session can now be used as a filter in - `jobs() `__ with + `jobs() `__ with the parameter ``session_id``. -- `run() `__ now +- `run() `__ now supports a new parameter, ``job_tags``. These tags can be used when filtering jobs with - `jobs() `__. + `jobs() `__. -- `run() `__ now +- `run() `__ now supports a new parameter, ``max_execution_time``, which can be used to override the default program maximum execution time. It should be less than or equal to the program maximum execution time. -- `jobs() `__ has a +- `jobs() `__ has a new parameter, ``descending``. This parameter defaults to ``True``, where jobs will be returned in descending order based on creation date. - ``RuntimeJobTimeoutError`` is now raised when the ``timeout`` set in - `result() `__ or - `wait_for_final_state() `__ + `result() `__ or + `wait_for_final_state() `__ expires. - When initializing - `QiskitRuntimeService `__ + `QiskitRuntimeService `__ and an invalid token is used, ``IBMNotAuthorizedError`` will be raised instead of ``RequestsApiError``. - ``IBMSampler`` class which was deprecated earlier is now removed. Use - `Sampler `__ class going forward. + `Sampler `__ class going forward. -- `qubit_properties() `__ +- `qubit_properties() `__ will now return a sub class of ``QubitProperties`` called ``IBMQubitProperties`` and will expose anharmonicity in addition to the t1, t2 and frequency already exposed by the ``QubitProperties`` diff --git a/release-notes/0.6.0.rst b/release-notes/0.6.0.rst index d71e1dc3c9..965f6d324f 100644 --- a/release-notes/0.6.0.rst +++ b/release-notes/0.6.0.rst @@ -8,7 +8,7 @@ Upgrade Notes channel credentials will get automatically copied over from the qiskitrc file and a qiskit-ibm.json file will get created if one doesn’t exist. You have to just initialize - `QiskitRuntimeService `__ + `QiskitRuntimeService `__ class without passing any parameters to use this copied over default ``ibm_quantum`` account. @@ -20,10 +20,10 @@ Upgrade Notes service = QiskitRuntimeService() - ``IBMEstimator`` class which was deprecated earlier is now removed. - Use `Estimator `__ class going + Use `Estimator `__ class going forward. - ``IBMRuntimeService`` class which was deprecated earlier is now removed. Use - `QiskitRuntimeService `__ + `QiskitRuntimeService `__ class going forward. diff --git a/release-notes/0.7.0.rst b/release-notes/0.7.0.rst index 20bd42a6c0..6b1ebd40fa 100644 --- a/release-notes/0.7.0.rst +++ b/release-notes/0.7.0.rst @@ -10,14 +10,14 @@ New Features keyword arguments, however, are not validated. - The - `qiskit_ibm_runtime.options.EnvironmentOptions `__ + `qiskit_ibm_runtime.options.EnvironmentOptions `__ class now accepts a ``callback`` parameter. This parameter can be used to stream the interim and final results of the primitives. - The ``qiskit_ibm_runtime.Options`` class now accepts ``max_execution_time`` as a first level option and ``job_tags`` as an option under ``environment``. - `qiskit_ibm_runtime.RuntimeOptions `__ + `qiskit_ibm_runtime.RuntimeOptions `__ has also been updated to include these two parameters. Upgrade Notes @@ -35,12 +35,12 @@ Deprecation Notes ``quantum_kernal_alignment`` have been deprecated due to low usage. - Passing ``instance`` parameter to the - `qiskit_ibm_runtime.QiskitRuntimeService.run() `__ + `qiskit_ibm_runtime.QiskitRuntimeService.run() `__ has been deprecated. Instead, you can pass the ``instance`` parameter inside the ``options`` parameter. - Passing ``job_tags`` and ``max_execution_time`` as parameters to - `qiskit_ibm_runtime.QiskitRuntimeService `__ + `qiskit_ibm_runtime.QiskitRuntimeService `__ has been deprecated. Please pass them inside ``options``. Bug Fixes diff --git a/release-notes/0.7.0rc1.rst b/release-notes/0.7.0rc1.rst index 6f3033cf5a..632b66a74b 100644 --- a/release-notes/0.7.0rc1.rst +++ b/release-notes/0.7.0rc1.rst @@ -65,14 +65,14 @@ New Features # Or at job level. job = sampler.run(circuits=ReferenceCircuits.bell(), shots=4000) -- `qiskit_ibm_runtime.RuntimeJob `__ +- `qiskit_ibm_runtime.RuntimeJob `__ has a new method - `metrics() `__. This + `metrics() `__. This method returns the metrics of a job, which includes timestamp information. - The - `qiskit_ibm_runtime.QiskitRuntimeService `__ + `qiskit_ibm_runtime.QiskitRuntimeService `__ ``channel`` can now be stored as an environment variable, ``QISKIT_IBM_CHANNEL``. This way, when using Runtime Primitives, the service does not have to be instantiated manually and can instead be @@ -87,7 +87,7 @@ Upgrade Notes - The experimental parameters ``transpilation_settings``, ``resilience_settings``, and ``max_time`` to the :class:\`qiskit_ibm_runtime.Sampler and - `qiskit_ibm_runtime.Estimator `__ + `qiskit_ibm_runtime.Estimator `__ constructors have been removed. You can instead use the ``qiskit_ibm_runtime.Options`` class to specify the settings, and ``max_time`` can be specified when starting a new session. For @@ -115,8 +115,8 @@ Deprecation Notes ----------------- - Invoking - `qiskit_ibm_runtime.Sampler `__ and - `qiskit_ibm_runtime.Estimator `__ + `qiskit_ibm_runtime.Sampler `__ and + `qiskit_ibm_runtime.Estimator `__ as context managers has been deprecated. You can instead use the qiskit_ibm_runtime.Session class to create a new session and invoke one or more primitives within the session. @@ -126,12 +126,12 @@ Deprecation Notes the constructors of ``Sampler`` and ``Estimator`` has also been deprecated. The inputs can now be passed to the ``run()`` method of the primitive classes, and ``service`` can be passed to - `qiskit_ibm_runtime.Session `__ when + `qiskit_ibm_runtime.Session `__ when starting a new session. - Passing ``skip_transpilation`` to the :class:\`qiskit_ibm_runtime.Sampler and - `qiskit_ibm_runtime.Estimator `__ + `qiskit_ibm_runtime.Estimator `__ constructors has been deprecated. You can instead use the ``qiskit_ibm_runtime.Options`` class to specify this option. For example: diff --git a/release-notes/0.7.0rc2.rst b/release-notes/0.7.0rc2.rst index 5e9bde0dd6..6f2ea099e4 100644 --- a/release-notes/0.7.0rc2.rst +++ b/release-notes/0.7.0rc2.rst @@ -5,29 +5,29 @@ Upgrade Notes ------------- - Added a validation check to - `run() `__. It raises an error if + `run() `__. It raises an error if there is no classical bit. -- `Sampler `__ is updated to return +- `Sampler `__ is updated to return ``SamplerResult`` with ``SamplerResult.quasi_dists`` as a list of ``QuasiDistrbution``. It used to set a list of ``dict`` as ``SamplerResult.quasi_dists``, but it did not follow the design of ``SamplerResult``. -- The `RuntimeJob `__ class is now a +- The `RuntimeJob `__ class is now a subclass of ``qiskit.providers.Job``. Deprecation Notes ----------------- - ``job_id`` and ``backend`` attributes of - `qiskit_ibm_runtime.RuntimeJob `__ + `qiskit_ibm_runtime.RuntimeJob `__ have been deprecated. Please use - `qiskit_ibm_runtime.RuntimeJob.job_id() `__ + `qiskit_ibm_runtime.RuntimeJob.job_id() `__ and - `qiskit_ibm_runtime.RuntimeJob.backend() `__ + `qiskit_ibm_runtime.RuntimeJob.backend() `__ methods instead. - The ``backend_name`` attribute in - `qiskit_ibm_runtime.RuntimeOptions `__ + `qiskit_ibm_runtime.RuntimeOptions `__ is deprecated and replaced by ``backend``. diff --git a/release-notes/0.8.0.rst b/release-notes/0.8.0.rst index 78d30f25bd..18e2055d84 100644 --- a/release-notes/0.8.0.rst +++ b/release-notes/0.8.0.rst @@ -8,12 +8,12 @@ New Features - Advanced resilience options can now be set under ``options.resilience``. See - `qiskit_ibm_runtime.options.ResilienceOptions `__ + `qiskit_ibm_runtime.options.ResilienceOptions `__ for all available options. - You can now specify a pair of result decoders for the ``result_decoder`` parameter of - `qiskit_ibm_runtime.QiskitRuntimeService.run() `__ + `qiskit_ibm_runtime.QiskitRuntimeService.run() `__ method. If a pair is specified, the first one is used to decode interim results and the second the final results. @@ -34,9 +34,9 @@ Bug Fixes --------- - If a - `qiskit_ibm_runtime.IBMBackend `__ + `qiskit_ibm_runtime.IBMBackend `__ instance is passed to the - `qiskit_ibm_runtime.Session `__ + `qiskit_ibm_runtime.Session `__ constructor, the service used to initialize the ``IBMBackend`` instance is used for the session instead of the default account service. diff --git a/release-notes/0.9.0.rst b/release-notes/0.9.0.rst index c891511616..23faed75a6 100644 --- a/release-notes/0.9.0.rst +++ b/release-notes/0.9.0.rst @@ -11,8 +11,8 @@ Upgrade Notes set to 1 and ``resilience_level`` is set to 0; Otherwise, they are be set to 3 and 1 respectively. -- `session_id() `__ and - `tags() `__ were added for an +- `session_id() `__ and + `tags() `__ were added for an easy way to return the session_id and job_tags of a job. Bug Fixes diff --git a/release-notes/0.9.1.rst b/release-notes/0.9.1.rst index de1b73be48..5db962d8b8 100644 --- a/release-notes/0.9.1.rst +++ b/release-notes/0.9.1.rst @@ -4,7 +4,7 @@ Upgrade Notes ------------- -- `qiskit_ibm_runtime.QiskitRuntimeService.jobs() `__ +- `qiskit_ibm_runtime.QiskitRuntimeService.jobs() `__ now has a ``backend_name`` parameter that can be used to only return jobs run with the specified backend. @@ -26,7 +26,7 @@ Deprecation Notes ----------------- - ``backend`` is no longer a supported option when using - `qiskit_ibm_runtime.Session.run() `__. + `qiskit_ibm_runtime.Session.run() `__. Sessions do not support multiple cross backends. Additionally, an exception will be raised if a backend passed in through options does not match the original session backend in an active session. diff --git a/release-notes/0.9.2.rst b/release-notes/0.9.2.rst index bad419b99d..fbd7684df7 100644 --- a/release-notes/0.9.2.rst +++ b/release-notes/0.9.2.rst @@ -6,15 +6,15 @@ New Features - Added a new argument called ``session_time`` to the program_run method and - `qiskit_ibm_runtime.RuntimeOptions `__. + `qiskit_ibm_runtime.RuntimeOptions `__. Now values entered by the user for session ``max_time`` will be sent to the server side as ``session_time``. This allows users to specify different values for session ``max_time`` and ``max_execution_time``. - Added the method - `target_history() `__. + `target_history() `__. This method is similar to - `target() `__. The + `target() `__. The difference is that the new method enables the user to pass a datetime parameter, to retrieve historical data from the backend. @@ -29,11 +29,11 @@ Upgrade Notes - If a job is returned without a backend, retrieving the backend through - `qiskit_ibm_runtime.RuntimeJob.backend() `__ + `qiskit_ibm_runtime.RuntimeJob.backend() `__ will re-retrieve data from the server and attempt to update the backend. Additionally, ``job_id`` and ``backend``, which were deprecated attributes of - `qiskit_ibm_runtime.RuntimeJob `__ + `qiskit_ibm_runtime.RuntimeJob `__ have now been removed. - Added a user warning when the user passes an option that is not @@ -50,7 +50,7 @@ Bug Fixes ``None``, causing the job to fail. - If an instance is passed in to - `qiskit_ibm_runtime.QiskitRuntimeService.get_backend() `__ + `qiskit_ibm_runtime.QiskitRuntimeService.get_backend() `__ and then the backend is used in a session, all jobs within the session will be run from the original instance passed in. diff --git a/release-notes/0.9.3.rst b/release-notes/0.9.3.rst index 856447d20f..2391081f31 100644 --- a/release-notes/0.9.3.rst +++ b/release-notes/0.9.3.rst @@ -13,12 +13,12 @@ Upgrade Notes used to control validation. If set, validation will be skipped. - Backend configurations are no longer loaded when - `QiskitRuntimeService `__ + `QiskitRuntimeService `__ is initialized. Instead, the configuration is only loaded and cached during - `get_backend() `__ + `get_backend() `__ and - `backends() `__. + `backends() `__. Bug Fixes --------- diff --git a/release-notes/0.9.4.rst b/release-notes/0.9.4.rst index cada7f49a1..da330e1e8d 100644 --- a/release-notes/0.9.4.rst +++ b/release-notes/0.9.4.rst @@ -18,22 +18,22 @@ Deprecation Notes - The deprecated arguments ``circuits``, ``parameters``, ``service``, and ``skip_transpilation`` have been removed from - `Sampler `__. + `Sampler `__. Similarly, the deprecated arguments ``circuits``, ``observables``, ``parameters``, ``service``, and ``skip_transpilation`` have been - removed from `Estimator `__. + removed from `Estimator `__. In - `QiskitRuntimeService `__, + `QiskitRuntimeService `__, the ``auth`` parameter has been removed. Additionally, the ``instance``, ``job_tags``, and ``max_execution_time`` paramters have been removed from - `qiskit_ibm_runtime.QiskitRuntimeService.run() `__. + `qiskit_ibm_runtime.QiskitRuntimeService.run() `__. They can be passed in through - `RuntimeOptions `__ instead. + `RuntimeOptions `__ instead. - Within `RuntimeOptions `__, + Within `RuntimeOptions `__, ``backend_name`` is no longer supported. Please use ``backend`` instead. diff --git a/release-notes/unreleased/2261.bug.rst b/release-notes/unreleased/2261.bug.rst new file mode 100644 index 0000000000..d5c447bcef --- /dev/null +++ b/release-notes/unreleased/2261.bug.rst @@ -0,0 +1,2 @@ +The call to :meth:`~.IBMBackend.defaults` in :meth:`~.IBMBackend.target` was removed +because backend defaults are no longer used in the target generation. \ No newline at end of file diff --git a/test/account.py b/test/account.py index 961a137479..ad4566e086 100644 --- a/test/account.py +++ b/test/account.py @@ -20,7 +20,11 @@ from unittest.mock import patch from qiskit_ibm_runtime.accounts import management -from qiskit_ibm_runtime.accounts.account import IBM_CLOUD_API_URL, IBM_QUANTUM_API_URL +from qiskit_ibm_runtime.accounts.account import ( + IBM_CLOUD_API_URL, + IBM_QUANTUM_API_URL, + IBM_QUANTUM_PLATFORM_API_URL, +) class custom_envs(ContextDecorator): @@ -123,7 +127,7 @@ def __exit__(self, *exc): def get_account_config_contents( name=None, - channel="ibm_cloud", + channel="ibm_quantum_platform", token=None, url=None, instance=None, @@ -142,14 +146,18 @@ def get_account_config_contents( if name is None: name = ( management._DEFAULT_ACCOUNT_NAME_IBM_CLOUD - if channel in ["ibm_cloud", "ibm_quantum_platform"] - else management._DEFAULT_ACCOUNT_NAME_IBM_QUANTUM + if channel == "ibm_cloud" + else ( + management._DEFAULT_ACCOUNT_NAME_IBM_QUANTUM + if channel == "ibm_quantum" + else management._DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM + ) ) if url is None: url = ( IBM_CLOUD_API_URL - if channel in ["ibm_cloud", "ibm_quantum_platform"] - else IBM_QUANTUM_API_URL + if channel == "ibm_cloud" + else (IBM_QUANTUM_API_URL if channel == "ibm_quantum" else IBM_QUANTUM_PLATFORM_API_URL) ) out = { name: { diff --git a/test/integration/test_session.py b/test/integration/test_session.py index c564a3fcc1..19dd75e991 100644 --- a/test/integration/test_session.py +++ b/test/integration/test_session.py @@ -86,7 +86,7 @@ def test_session_from_id(self, service): job = sampler.run(isa_circuit) job.result() - with mock.patch.object(service._api_client, "create_session") as mock_create_session: + with mock.patch.object(service._get_api_client(), "create_session") as mock_create_session: new_session = Session.from_id(session_id=session._session_id, service=service) mock_create_session.assert_not_called() diff --git a/test/program.py b/test/program.py index 3917c1e34f..1cb98a6972 100644 --- a/test/program.py +++ b/test/program.py @@ -42,9 +42,9 @@ def run_program( "session_time": None, } if final_status is not None: - service._api_client.set_final_status(final_status) + service._get_api_client(instance).set_final_status(final_status) elif job_classes: - service._api_client.set_job_classes(job_classes) + service._get_api_client(instance).set_job_classes(job_classes) if not program_id: program_id = "sampler" job = service._run( diff --git a/test/unit/mock/fake_runtime_client.py b/test/unit/mock/fake_runtime_client.py index 0294705339..c2ea979c07 100644 --- a/test/unit/mock/fake_runtime_client.py +++ b/test/unit/mock/fake_runtime_client.py @@ -256,6 +256,7 @@ def __init__( channel="ibm_quantum", num_backends=2, backend_specs=None, + instance=None, ): """Initialize a fake runtime client.""" # pylint: disable=unused-argument @@ -267,6 +268,13 @@ def __init__( self.session_time = 0 self._sessions = set() self._params = {} + if instance is not None: + self._instance = instance + else: + if channel == "ibm_quantum": + self._instance = "hub0/group0/project0" + else: + self._instance = "crn:v1:bluemix:public:quantum-computing:my-region:a/...:...::" # Setup the available backends if not backend_specs: diff --git a/test/unit/mock/fake_runtime_service.py b/test/unit/mock/fake_runtime_service.py index 9bf4b42d8c..600bc3354f 100644 --- a/test/unit/mock/fake_runtime_service.py +++ b/test/unit/mock/fake_runtime_service.py @@ -19,6 +19,7 @@ from qiskit_ibm_runtime.accounts import Account from qiskit_ibm_runtime.api.client_parameters import ClientParameters from qiskit_ibm_runtime.api.clients import AuthClient +from qiskit_ibm_runtime.api.exceptions import RequestsApiError from qiskit_ibm_runtime.hub_group_project import HubGroupProject from qiskit_ibm_runtime.qiskit_runtime_service import QiskitRuntimeService from .fake_runtime_client import BaseFakeRuntimeClient @@ -44,16 +45,27 @@ def __init__(self, *args, num_hgps=2, runtime_client=None, backend_specs=None, * self._fake_runtime_client = runtime_client self._backend_specs = backend_specs + mock_runtime_client = mock.MagicMock() + if kwargs.get("channel", "ibm_quantum") == "ibm_quantum": + instance = kwargs.get("instance", "hub0/group0/project0") + else: + instance = kwargs.get( + "instance", "crn:v1:bluemix:public:quantum-computing:my-region:a/...:...::" + ) + mock_runtime_client._instance = instance + mock_runtime_client.job_get = mock.MagicMock() + mock_runtime_client.job_get.side_effect = RequestsApiError("Job not found", status_code=404) + with mock.patch( "qiskit_ibm_runtime.qiskit_runtime_service.RuntimeClient", - new=mock.MagicMock, + return_value=mock_runtime_client, ): super().__init__(*args, **kwargs) # Use default if api client is somehow not set. - if not isinstance(self._api_client, BaseFakeRuntimeClient): - self._api_client = self._fake_runtime_client or BaseFakeRuntimeClient( - backend_specs=self._backend_specs + if not isinstance(self._active_api_client, BaseFakeRuntimeClient): + self._active_api_client = self._fake_runtime_client or BaseFakeRuntimeClient( + backend_specs=self._backend_specs, instance=instance ) def _authenticate_ibm_quantum_account( @@ -93,23 +105,17 @@ def _initialize_hgps( # Set fake runtime clients self._set_api_client(hgps=list(hgps.keys())) for hgp in hgps.values(): - hgp._runtime_client = self._api_client + hgp._runtime_client = self._active_api_client return hgps - def _discover_cloud_backends(self): - """Mock discovery cloud backends.""" - self._api_client = self._fake_runtime_client - self._set_api_client(hgps=[None] * self._test_num_hgps) - return super()._discover_cloud_backends() - def _discover_backends_from_instance(self, instance: str) -> List[str]: """Mock discovery cloud backends.""" - job_class = self._api_client._job_classes # type: ignore - self._api_client = self._fake_runtime_client - self._set_api_client(hgps=[None] * self._test_num_hgps) - self._api_client._job_classes = job_class # type: ignore - return super()._discover_cloud_backends() + job_class = self._active_api_client._job_classes # type: ignore + self._active_api_client = self._fake_runtime_client + self._set_api_client(hgps=[None] * self._test_num_hgps, channel="ibm_quantum_platform") + self._active_api_client._job_classes = job_class # type: ignore + return self._active_api_client.list_backends() def _create_new_cloud_api_client(self, instance: str) -> None: """Create new api client.""" @@ -119,7 +125,7 @@ def _get_crn_from_instance_name(self, account: Account, instance: str) -> str: # return dummy crn return instance - def _set_api_client(self, hgps): + def _set_api_client(self, hgps, channel="ibm_quantum"): """Set api client to be the fake runtime client.""" if not self._fake_runtime_client: if not self._backend_specs: @@ -134,11 +140,11 @@ def _set_api_client(self, hgps): ) ) self._fake_runtime_client = BaseFakeRuntimeClient( - backend_specs=self._backend_specs, channel="ibm_quantum" + backend_specs=self._backend_specs, channel=channel ) # Set fake runtime clients - self._api_client = self._fake_runtime_client + self._active_api_client = self._fake_runtime_client class FakeAuthClient(AuthClient): diff --git a/test/unit/test_account.py b/test/unit/test_account.py index 64377a20ef..d7935f9dcd 100644 --- a/test/unit/test_account.py +++ b/test/unit/test_account.py @@ -18,6 +18,7 @@ import uuid from typing import Any from unittest import skipIf +from ddt import ddt, data, idata, unpack from qiskit_ibm_runtime.proxies import ProxyConfiguration from qiskit_ibm_runtime.accounts import ( @@ -27,10 +28,15 @@ AccountNotFoundError, InvalidAccountError, ) -from qiskit_ibm_runtime.accounts.account import IBM_CLOUD_API_URL, IBM_QUANTUM_API_URL +from qiskit_ibm_runtime.accounts.account import ( + IBM_CLOUD_API_URL, + IBM_QUANTUM_API_URL, + IBM_QUANTUM_PLATFORM_API_URL, +) from qiskit_ibm_runtime.accounts.management import ( _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM, _DEFAULT_ACCOUNT_NAME_IBM_CLOUD, + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM, ) from .mock.fake_runtime_service import FakeRuntimeService from ..ibm_test_case import IBMTestCase @@ -58,9 +64,20 @@ ), ) +_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT = Account.create_account( + channel="ibm_quantum_platform", + token="token-y", + url="https://quantum.cloud.ibm.com/api/v1", + instance="crn:v1:bluemix:public:quantum-computing:us-east:a/...::", + proxies=ProxyConfiguration( + username_ntlm="bla", password_ntlm="blub", urls={"https": "127.0.0.1"} + ), +) + _TEST_FILENAME = "/tmp/temp_qiskit_account.json" +@ddt class TestAccount(IBMTestCase): """Tests for Account class.""" @@ -68,11 +85,12 @@ class TestAccount(IBMTestCase): dummy_ibm_cloud_url = "https://us-east.quantum-computing.cloud.ibm.com" dummy_ibm_quantum_url = "https://auth.quantum.ibm.com/api" - def test_skip_crn_resolution_for_crn(self): + @data(_TEST_IBM_CLOUD_ACCOUNT, _TEST_IBM_QUANTUM_PLATFORM_ACCOUNT) + def test_skip_crn_resolution_for_crn(self, test_account): """Test that CRN resolution is skipped if the instance value is already a CRN.""" - account = copy.deepcopy(_TEST_IBM_CLOUD_ACCOUNT) + account = copy.deepcopy(test_account) account.resolve_crn() - self.assertEqual(account.instance, _TEST_IBM_CLOUD_ACCOUNT.instance) + self.assertEqual(account.instance, test_account.instance) def test_invalid_channel(self): """Test invalid values for channel parameter.""" @@ -158,7 +176,7 @@ class TestAccountManager(IBMTestCase): """Tests for AccountManager class.""" @temporary_account_config_file(contents={"conflict": _TEST_IBM_CLOUD_ACCOUNT.to_saved_format()}) - def test_save_without_overwrite(self): + def test_save_without_overwrite_cloud(self): """Test to overwrite an existing account without setting overwrite=True.""" with self.assertRaises(AccountAlreadyExistsError): AccountManager.save( @@ -189,6 +207,40 @@ def test_save_without_overwrite(self): overwrite=False, ) + @temporary_account_config_file( + contents={"conflict": _TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.to_saved_format()} + ) + def test_save_without_overwrite_iqp(self): + """Test to overwrite an existing account without setting overwrite=True.""" + with self.assertRaises(AccountAlreadyExistsError): + AccountManager.save( + name="conflict", + token=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.token, + url=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.url, + instance=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.instance, + channel="ibm_cloud", + overwrite=False, + ) + AccountManager.save( + filename=_TEST_FILENAME, + name="conflict", + token=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.token, + url=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.url, + instance=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.instance, + channel="ibm_cloud", + overwrite=True, + ) + with self.assertRaises(AccountAlreadyExistsError): + AccountManager.save( + filename=_TEST_FILENAME, + name="conflict", + token=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.token, + url=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.url, + instance=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.instance, + channel="ibm_cloud", + 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.""" @@ -209,9 +261,15 @@ def test_save_get(self): # verify accounts can be saved and retrieved via custom names (_TEST_IBM_QUANTUM_ACCOUNT, None, "acct-1", "acct-1"), (_TEST_IBM_CLOUD_ACCOUNT, None, "acct-2", "acct-2"), + (_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT, None, "acct-3", "acct-3"), # verify default account name handling for ibm_cloud accounts - (_TEST_IBM_CLOUD_ACCOUNT, None, None, _DEFAULT_ACCOUNT_NAME_IBM_CLOUD), - (_TEST_IBM_CLOUD_ACCOUNT, None, None, None), + ( + _TEST_IBM_QUANTUM_PLATFORM_ACCOUNT, + None, + None, + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM, + ), + (_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT, None, None, None), # verify default account name handling for ibm_quantum accounts ( _TEST_IBM_QUANTUM_ACCOUNT, @@ -222,17 +280,19 @@ def test_save_get(self): # verify account override (_TEST_IBM_QUANTUM_ACCOUNT, None, "acct", "acct"), (_TEST_IBM_CLOUD_ACCOUNT, None, "acct", "acct"), + (_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT, None, "acct", "acct"), # same as above with filename (_TEST_IBM_QUANTUM_ACCOUNT, user_filename, "acct-1", "acct-1"), (_TEST_IBM_CLOUD_ACCOUNT, user_filename, "acct-2", "acct-2"), + (_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT, user_filename, "acct-3", "acct-3"), # verify default account name handling for ibm_cloud accounts ( - _TEST_IBM_CLOUD_ACCOUNT, + _TEST_IBM_QUANTUM_PLATFORM_ACCOUNT, user_filename, None, - _DEFAULT_ACCOUNT_NAME_IBM_CLOUD, + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM, ), - (_TEST_IBM_CLOUD_ACCOUNT, user_filename, None, None), + (_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT, user_filename, None, None), # verify default account name handling for ibm_quantum accounts ( _TEST_IBM_QUANTUM_ACCOUNT, @@ -243,6 +303,7 @@ def test_save_get(self): # verify account override (_TEST_IBM_QUANTUM_ACCOUNT, user_filename, "acct", "acct"), (_TEST_IBM_CLOUD_ACCOUNT, user_filename, "acct", "acct"), + (_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT, user_filename, "acct", "acct"), ] for account, file_name, name_save, name_get in sub_tests: with self.subTest( @@ -267,6 +328,7 @@ def test_save_get(self): { "ibm_cloud": _TEST_IBM_CLOUD_ACCOUNT.to_saved_format(), "ibm_quantum": _TEST_IBM_QUANTUM_ACCOUNT.to_saved_format(), + "ibm_quantum_platform": _TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.to_saved_format(), } ) ) @@ -278,50 +340,49 @@ def test_list(self): contents={ "key1": _TEST_IBM_CLOUD_ACCOUNT.to_saved_format(), "key2": _TEST_IBM_QUANTUM_ACCOUNT.to_saved_format(), + "key3": _TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.to_saved_format(), } ), self.subTest("non-empty list of accounts"), ): accounts = AccountManager.list() - - self.assertEqual(len(accounts), 2) + self.assertEqual(len(accounts), 3) self.assertEqual(accounts["key1"], _TEST_IBM_CLOUD_ACCOUNT) self.assertTrue(accounts["key2"], _TEST_IBM_QUANTUM_ACCOUNT) + self.assertTrue(accounts["key3"], _TEST_IBM_QUANTUM_PLATFORM_ACCOUNT) with ( temporary_account_config_file( contents={ "key1": _TEST_IBM_CLOUD_ACCOUNT.to_saved_format(), "key2": _TEST_IBM_QUANTUM_ACCOUNT.to_saved_format(), + "key3": _TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.to_saved_format(), _DEFAULT_ACCOUNT_NAME_IBM_CLOUD: Account.create_account( channel="ibm_cloud", token="token-ibm-cloud", instance="crn:123" ).to_saved_format(), _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM: Account.create_account( channel="ibm_quantum", token="token-ibm-quantum" ).to_saved_format(), + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM: Account.create_account( + channel="ibm_quantum_platform", token="token-ibm-cloud", instance="crn:123" + ).to_saved_format(), } ), self.subTest("filtered list of accounts"), ): - accounts = list(AccountManager.list(channel="ibm_quantum_platform").keys()) - self.assertEqual(len(accounts), 2) - self.assertListEqual(accounts, ["key1", _DEFAULT_ACCOUNT_NAME_IBM_CLOUD]) - accounts = list(AccountManager.list(channel="ibm_quantum").keys()) self.assertEqual(len(accounts), 2) self.assertListEqual(accounts, ["key2", _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM]) - accounts = list( - AccountManager.list(channel="ibm_quantum_platform", default=True).keys() - ) - self.assertEqual(len(accounts), 1) - self.assertListEqual(accounts, [_DEFAULT_ACCOUNT_NAME_IBM_CLOUD]) + accounts = list(AccountManager.list(channel="ibm_quantum_platform").keys()) + self.assertEqual(len(accounts), 2) + self.assertListEqual(accounts, ["key3", _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM]) accounts = list( AccountManager.list(channel="ibm_quantum_platform", default=False).keys() ) self.assertEqual(len(accounts), 1) - self.assertListEqual(accounts, ["key1"]) + self.assertListEqual(accounts, ["key3"]) accounts = list(AccountManager.list(name="key1").keys()) self.assertEqual(len(accounts), 1) @@ -332,6 +393,7 @@ def test_list(self): "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(), + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM: _TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.to_saved_format(), } ) def test_delete(self): @@ -343,10 +405,11 @@ def test_delete(self): with self.subTest("delete default ibm_quantum account"): self.assertTrue(AccountManager.delete(channel="ibm_quantum")) - with self.subTest("delete default ibm_cloud account"): + self.assertTrue(AccountManager.delete(channel="ibm_cloud")) + self.assertTrue(len(AccountManager.list()) == 1) + with self.subTest("delete default ibm_quantum_platform account"): self.assertTrue(AccountManager.delete()) - self.assertTrue(len(AccountManager.list()) == 0) def test_delete_filename(self): @@ -385,7 +448,7 @@ def test_default_env_channel(self): # unset default_channel in the environment with temporary_account_config_file(token=token), no_envs("QISKIT_IBM_CHANNEL"): service = FakeRuntimeService() - self.assertEqual(service.channel, "ibm_quantum_platform") + self.assertEqual(service.channel, "ibm_quantum_platform") # set channel to default channel in the environment subtests = ["ibm_quantum", "ibm_quantum_platform"] @@ -420,10 +483,10 @@ def test_save_default_account(self): this account will be used""" AccountManager.save( filename=_TEST_FILENAME, - name=_DEFAULT_ACCOUNT_NAME_IBM_CLOUD, - token=_TEST_IBM_CLOUD_ACCOUNT.token, - url=_TEST_IBM_CLOUD_ACCOUNT.url, - instance=_TEST_IBM_CLOUD_ACCOUNT.instance, + name=_DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM, + token=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.token, + url=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.url, + instance=_TEST_IBM_QUANTUM_PLATFORM_ACCOUNT.instance, channel="ibm_quantum_platform", overwrite=True, set_as_default=True, @@ -470,6 +533,11 @@ def test_set_channel_precedence(self): channel_env = {"QISKIT_IBM_CHANNEL": "ibm_quantum_platform"} contents = { _DEFAULT_ACCOUNT_NAME_IBM_CLOUD: { + "channel": "ibm_cloud", + "token": cloud_token, + "instance": "some_instance", + }, + _DEFAULT_ACCOUNT_NAME_IBM_QUANTUM_PLATFORM: { "channel": "ibm_quantum_platform", "token": cloud_token, "instance": "some_instance", @@ -708,7 +776,13 @@ def test_enable_account_by_only_channel(self): self.assertTrue(service._account) self.assertEqual(service._account.token, token) expected = ( - IBM_CLOUD_API_URL if channel == "ibm_quantum_platform" else IBM_QUANTUM_API_URL + IBM_CLOUD_API_URL + if channel == "ibm_cloud" + else ( + IBM_QUANTUM_API_URL + if channel == "ibm_quantum" + else IBM_QUANTUM_PLATFORM_API_URL + ) ) self.assertEqual(service._account.url, expected) self.assertEqual(service._account.channel, channel) @@ -726,12 +800,12 @@ def test_enable_account_both_channel(self): service = FakeRuntimeService() self.assertTrue(service._account) self.assertEqual(service._account.token, token) - self.assertEqual(service._account.url, IBM_CLOUD_API_URL) + self.assertEqual(service._account.url, IBM_QUANTUM_PLATFORM_API_URL) self.assertEqual(service._account.channel, "ibm_quantum_platform") def test_enable_account_by_env_channel(self): """Test initializing account by environment variable and channel.""" - subtests = ["ibm_quantum", "ibm_quantum_platform", None] + subtests = ["ibm_quantum", "ibm_quantum_platform", "ibm_cloud", None] for channel in subtests: with self.subTest(channel=channel): token = uuid.uuid4().hex diff --git a/test/unit/test_backend_retrieval.py b/test/unit/test_backend_retrieval.py index fe84e5d2bf..56270c8792 100644 --- a/test/unit/test_backend_retrieval.py +++ b/test/unit/test_backend_retrieval.py @@ -209,7 +209,7 @@ def _get_services(self, fake_backend_specs): cloud_service = FakeRuntimeService( channel="ibm_cloud", token="my_token", - instance="my_instance", + instance="crn:v1:bluemix:public:quantum-computing:my-region:a/...:...::", backend_specs=fake_backend_specs, ) return [ibm_quantum_service, cloud_service] diff --git a/test/unit/test_jobs.py b/test/unit/test_jobs.py index 1cb462e09a..2edb55a1ab 100644 --- a/test/unit/test_jobs.py +++ b/test/unit/test_jobs.py @@ -132,7 +132,7 @@ def test_run_program_with_custom_runtime_image(self, service): 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()) + job_raw = service._get_api_client()._get_job(job.job_id()) self.assertEqual(job_raw.log_level, "DEBUG") @run_quantum_and_cloud_fake @@ -141,7 +141,7 @@ def test_run_program_failed(self, service): job = run_program(service=service, job_classes=FailedRuntimeJob) with mock_wait_for_final_state(service, job): job.wait_for_final_state() - job_result_raw = service._api_client.job_results(job.job_id()) + job_result_raw = service._get_api_client().job_results(job.job_id()) self.assertEqual("ERROR", job.status()) self.assertEqual( API_TO_JOB_ERROR_MESSAGE["FAILED"].format(job.job_id(), job_result_raw), @@ -156,7 +156,7 @@ def test_run_program_failed_ran_too_long(self, service): job = run_program(service=service, job_classes=FailedRanTooLongRuntimeJob) with mock_wait_for_final_state(service, job): job.wait_for_final_state() - job_result_raw = service._api_client.job_results(job.job_id()) + job_result_raw = service._get_api_client().job_results(job.job_id()) self.assertEqual("ERROR", job.status()) self.assertEqual( API_TO_JOB_ERROR_MESSAGE["CANCELLED - RAN TOO LONG"].format( diff --git a/test/unit/test_sampler.py b/test/unit/test_sampler.py index 63a272b774..5088138ff4 100644 --- a/test/unit/test_sampler.py +++ b/test/unit/test_sampler.py @@ -241,7 +241,7 @@ def test_gate_not_in_target(self): circ.measure(0, 0) with self.assertRaisesRegex(IBMInputValueError, " h "): - sampler.run(pubs=[(circ)]) + sampler.run(pubs=[circ]) @data(FakeSherbrooke(), FakeCusco()) def test_isa_inside_condition_block(self, backend): @@ -257,10 +257,10 @@ def test_isa_inside_condition_block(self, backend): circ.ecr(1, 2) if backend.name == "fake_sherbrooke": - SamplerV2(backend).run(pubs=[(circ)]) + SamplerV2(backend).run(pubs=[circ]) else: with self.assertRaises(IBMInputValueError): - SamplerV2(backend).run(pubs=[(circ)]) + SamplerV2(backend).run(pubs=[circ]) @data(FakeSherbrooke(), FakeCusco()) def test_isa_inside_condition_block_body_in_separate_circuit(self, backend): @@ -280,10 +280,10 @@ def test_isa_inside_condition_block_body_in_separate_circuit(self, backend): circ.if_test((circ.clbits[0], True), body, [1, 2], []) if backend.name == "fake_sherbrooke": - SamplerV2(backend).run(pubs=[(circ)]) + SamplerV2(backend).run(pubs=[circ]) else: with self.assertRaises(IBMInputValueError): - SamplerV2(backend).run(pubs=[(circ)]) + SamplerV2(backend).run(pubs=[circ]) @data(-1, 1, 2) def test_rzz_fixed_angle_validation(self, angle): @@ -294,10 +294,10 @@ def test_rzz_fixed_angle_validation(self, angle): circ.rzz(angle, 0, 1) if angle == 1: - SamplerV2(backend).run(pubs=[(circ)]) + SamplerV2(backend).run(pubs=[circ]) else: with self.assertRaisesRegex(IBMInputValueError, f"{angle}"): - SamplerV2(backend).run(pubs=[(circ)]) + SamplerV2(backend).run(pubs=[circ]) @data(-1, 1, 2) def test_rzz_parametrized_angle_validation(self, angle): diff --git a/test/utils.py b/test/utils.py index 0abf9d7bbd..c68f26c3f7 100644 --- a/test/utils.py +++ b/test/utils.py @@ -182,7 +182,7 @@ def mock_wait_for_final_state(service, job): return mock.patch.object( RuntimeJob, "wait_for_final_state", - side_effect=service._api_client.wait_for_final_state(job.job_id()), + side_effect=service._get_api_client().wait_for_final_state(job.job_id()), ) @@ -315,7 +315,8 @@ def get_mocked_backend( mock_service = mock.MagicMock(spec=QiskitRuntimeService) mock_api_client = mock.MagicMock() - mock_service._api_client = mock_api_client + mock_api_client._instance = "mock_instance" + mock_service._active_api_client = mock_api_client configuration = ( FakeManilaV2().configuration() # type: ignore[assignment] @@ -325,7 +326,7 @@ def get_mocked_backend( mock_api_client.backend_properties = lambda *args, **kwargs: properties mock_api_client.backend_pulse_defaults = lambda *args, **kwargs: defaults - mock_api_client.session_details = lambda *args, **kwargs: {"mode": "dedicated"} + mock_api_client.session_details = mock.MagicMock(return_value={"mode": "dedicated"}) mock_backend = IBMBackend( configuration=configuration, service=mock_service, api_client=mock_api_client ) @@ -334,6 +335,7 @@ def get_mocked_backend( mock_service.backend = lambda name, **kwargs: ( mock_backend if name == mock_backend.name else None ) + mock_service._get_api_client = mock.MagicMock(return_value=mock_api_client) return mock_backend