diff --git a/qiskit/providers/__init__.py b/qiskit/providers/__init__.py index 029d335695d5..19d300c9bbf6 100644 --- a/qiskit/providers/__init__.py +++ b/qiskit/providers/__init__.py @@ -17,13 +17,13 @@ .. currentmodule:: qiskit.providers -This module contains the classes used to build external providers for Terra. A -provider is anything that provides an external service to Terra. The typical +This module contains the classes used to build external providers for Qiskit. A +provider is anything that provides an external service to Qiskit. The typical example of this is a Backend provider which provides :class:`~qiskit.providers.Backend` objects which can be used for executing :class:`~qiskit.circuit.QuantumCircuit` and/or :class:`~qiskit.pulse.Schedule` objects. This module contains the abstract classes which are used to define the -interface between a provider and terra. +interface between a provider and Qiskit. Version Support =============== @@ -36,17 +36,17 @@ Version Changes ---------------- -Each minor version release of qiskit-terra **may** increment the version of any -providers interface a single version number. It will be an aggregate of all +Each minor version release of ``qiskit`` **may** increment the version of any +backend interface a single version number. It will be an aggregate of all the interface changes for that release on that interface. Version Support Policy ---------------------- To enable providers to have time to adjust to changes in this interface -Terra will support multiple versions of each class at once. Given the +Qiskit will support multiple versions of each class at once. Given the nature of one version per release the version deprecation policy is a bit -more conservative than the standard deprecation policy. Terra will support a +more conservative than the standard deprecation policy. Qiskit will support a provider interface version for a minimum of 3 minor releases or the first release after 6 months from the release that introduced a version, whichever is longer, prior to a potential deprecation. After that the standard deprecation @@ -57,17 +57,17 @@ 0.19.0 we release 0.23.0. In 0.23.0 we can deprecate BackendV2, and it needs to still be supported and can't be removed until the deprecation policy completes. -It's worth pointing out that Terra's version support policy doesn't mean +It's worth pointing out that Qiskit's version support policy doesn't mean providers themselves will have the same support story, they can (and arguably should) update to newer versions as soon as they can, the support window is -just for Terra's supported versions. Part of this lengthy window prior to +just for Qiskit's supported versions. Part of this lengthy window prior to deprecation is to give providers enough time to do their own deprecation of a potential end user impacting change in a user facing part of the interface prior to bumping their version. For example, let's say we changed the signature to ``Backend.run()`` in ``BackendV34`` in a backwards incompatible way. Before Aer could update its :class:`~qiskit_aer.AerSimulator` class to be based on version 34 they'd need to deprecate the old signature prior to switching -over. The changeover for Aer is not guaranteed to be lockstep with Terra so we +over. The changeover for Aer is not guaranteed to be lockstep with Qiskit, so we need to ensure there is a sufficient amount of time for Aer to complete its deprecation cycle prior to removing version 33 (ie making version 34 mandatory/the minimum version). @@ -131,12 +131,13 @@ .. autoexception:: JobTimeoutError .. autoexception:: BackendConfigurationError -====================== -Writing a New Provider -====================== +===================== +Writing a New Backend +===================== If you have a quantum device or simulator that you would like to integrate with -Qiskit you will need to write a provider. A provider will provide Terra with a +Qiskit you will need to write a backend. A provider is a collection of backends +and will provide Qiskit with a method to get available :class:`~qiskit.providers.BackendV2` objects. The :class:`~qiskit.providers.BackendV2` object provides both information describing a backend and its operation for the :mod:`~qiskit.transpiler` so that circuits @@ -149,8 +150,7 @@ fashion regardless of how the backend is implemented. At a high level the basic steps for writing a provider are: - * Implement a :class:`~qiskit.providers.ProviderV1` subclass that handles - access to the backend(s). + * Implement a ``Provider`` class that handles access to the backend(s). * Implement a :class:`~qiskit.providers.BackendV2` subclass and its :meth:`~qiskit.providers.BackendV2.run` method. @@ -173,12 +173,11 @@ and methods to filter and acquire backends (using the provided credentials if required). An example provider class looks like:: - from qiskit.providers import ProviderV1 as Provider from qiskit.providers.providerutils import filter_backends from .backend import MyBackend - class MyProvider(Provider): + class MyProvider: def __init__(self, token=None): super().__init__() diff --git a/qiskit/providers/backend.py b/qiskit/providers/backend.py index 5ff10b5f7f74..8ffc7765109c 100644 --- a/qiskit/providers/backend.py +++ b/qiskit/providers/backend.py @@ -40,8 +40,8 @@ class Backend: class BackendV1(Backend, ABC): """Abstract class for Backends - This abstract class is to be used for all Backend objects created by a - provider. There are several classes of information contained in a Backend. + This abstract class is to be used for Backend objects. + There are several classes of information contained in a Backend. The first are the attributes of the class itself. These should be used to defined the immutable characteristics of the backend. The ``options`` attribute of the backend is used to contain the dynamic user configurable diff --git a/qiskit/providers/fake_provider/generic_backend_v2.py b/qiskit/providers/fake_provider/generic_backend_v2.py index 3776211cc08c..7537efe01fcc 100644 --- a/qiskit/providers/fake_provider/generic_backend_v2.py +++ b/qiskit/providers/fake_provider/generic_backend_v2.py @@ -526,12 +526,18 @@ def _setup_sim(self) -> None: @classmethod def _default_options(cls) -> Options: - if _optionals.HAS_AER: - from qiskit_aer import AerSimulator + with warnings.catch_warnings(): # TODO remove catch once aer release without Provider ABC + warnings.filterwarnings( + "ignore", + category=DeprecationWarning, + message=".+abstract Provider and ProviderV1.+", + ) + if _optionals.HAS_AER: + from qiskit_aer import AerSimulator - return AerSimulator._default_options() - else: - return BasicSimulator._default_options() + return AerSimulator._default_options() + else: + return BasicSimulator._default_options() def drive_channel(self, qubit: int): drive_channels_map = getattr(self, "channels_map", {}).get("drive", {}) diff --git a/qiskit/providers/provider.py b/qiskit/providers/provider.py index 9bea69c1ea85..dc836e7f25ee 100644 --- a/qiskit/providers/provider.py +++ b/qiskit/providers/provider.py @@ -15,6 +15,7 @@ from abc import ABC, abstractmethod from qiskit.providers.exceptions import QiskitBackendNotFoundError +from qiskit.utils import deprecate_func class Provider: @@ -28,12 +29,27 @@ class Provider: version = 0 + @deprecate_func( + since=1.1, + additional_msg="The abstract Provider and ProviderV1 classes are deprecated and will be " + "removed in 2.0. You can just remove it as the parent class and a `get_backend` " + "method that returns the backends from `self.backend`.", + ) + def __init__(self): + pass + class ProviderV1(Provider, ABC): """Base class for a Backend Provider.""" version = 1 + @deprecate_func( + since=1.1, + additional_msg="The abstract Provider and ProviderV1 classes are deprecated and will be " + "removed in 2.0. You can just remove it as the parent class and a `get_backend` " + "method that returns the backends from `self.backend`.", + ) def get_backend(self, name=None, **kwargs): """Return a single backend matching the specified filtering. diff --git a/releasenotes/notes/deprecate_providerV1-ba17d7b4639d1cc5.yaml b/releasenotes/notes/deprecate_providerV1-ba17d7b4639d1cc5.yaml new file mode 100644 index 000000000000..bfec8ef89041 --- /dev/null +++ b/releasenotes/notes/deprecate_providerV1-ba17d7b4639d1cc5.yaml @@ -0,0 +1,18 @@ +--- +deprecations_providers: + - | + The abstract base classes ``Provider`` and ``ProviderV1`` are now deprecated and will be removed in Qiskit 2.0.0. + The abstraction provided by these interface definitions were not providing a huge value. solely just the attributes + ``name``, ``backends``, and a ``get_backend()``. A _provider_, as a concept, will continue existing as a collection + of backends. If you're implementing a provider currently you can adjust your + code by simply removing ``ProviderV1`` as the parent class of your + implementation. As part of this you probably would want to add an + implementation of ``get_backend`` for backwards compatibility. For example:: + + def get_backend(self, name=None, **kwargs): + backend = self.backends(name, **kwargs) + if len(backends) > 1: + raise QiskitBackendNotFoundError("More than one backend matches the criteria") + if not backends: + raise QiskitBackendNotFoundError("No backend matches the criteria") + return backends[0] diff --git a/test/python/primitives/test_backend_sampler.py b/test/python/primitives/test_backend_sampler.py index b455e6b5dc17..8d1a3e2aab2b 100644 --- a/test/python/primitives/test_backend_sampler.py +++ b/test/python/primitives/test_backend_sampler.py @@ -352,7 +352,8 @@ def test_circuit_with_dynamic_circuit(self): qc.measure(0, 0) qc.break_loop().c_if(0, True) - backend = Aer.get_backend("aer_simulator") + with self.assertWarns(DeprecationWarning): + backend = Aer.get_backend("aer_simulator") sampler = BackendSampler(backend, skip_transpilation=True) sampler.set_options(seed_simulator=15) sampler.set_transpile_options(seed_transpiler=15) diff --git a/test/python/providers/basic_provider/test_basic_provider_backends.py b/test/python/providers/basic_provider/test_basic_provider_backends.py index d761015d04e1..5c00ec87671a 100644 --- a/test/python/providers/basic_provider/test_basic_provider_backends.py +++ b/test/python/providers/basic_provider/test_basic_provider_backends.py @@ -22,7 +22,8 @@ class TestBasicProviderBackends(QiskitTestCase): def setUp(self): super().setUp() - self.provider = BasicProvider() + with self.assertWarns(DeprecationWarning): + self.provider = BasicProvider() self.backend_name = "basic_simulator" def test_backends(self): @@ -32,9 +33,11 @@ def test_backends(self): def test_get_backend(self): """Test getting a backend from the provider.""" - backend = self.provider.get_backend(name=self.backend_name) + with self.assertWarns(DeprecationWarning): + backend = self.provider.get_backend(name=self.backend_name) self.assertEqual(backend.name, self.backend_name) def test_aliases_fail(self): """Test a failing backend lookup.""" - self.assertRaises(QiskitBackendNotFoundError, BasicProvider().get_backend, "bad_name") + with self.assertWarns(DeprecationWarning): + self.assertRaises(QiskitBackendNotFoundError, BasicProvider().get_backend, "bad_name") diff --git a/test/python/providers/basic_provider/test_multi_registers_convention.py b/test/python/providers/basic_provider/test_multi_registers_convention.py index a6d114f6b5b7..8ebf559f938c 100644 --- a/test/python/providers/basic_provider/test_multi_registers_convention.py +++ b/test/python/providers/basic_provider/test_multi_registers_convention.py @@ -36,7 +36,8 @@ def test_circuit_multi(self): qc = circ.compose(meas) - backend_sim = BasicProvider().get_backend("basic_simulator") + with self.assertWarns(DeprecationWarning): + backend_sim = BasicProvider().get_backend("basic_simulator") result = backend_sim.run(qc).result() counts = result.get_counts(qc) diff --git a/test/python/transpiler/test_sabre_swap.py b/test/python/transpiler/test_sabre_swap.py index e63565c14b05..a9fec85be665 100644 --- a/test/python/transpiler/test_sabre_swap.py +++ b/test/python/transpiler/test_sabre_swap.py @@ -278,7 +278,8 @@ def test_no_infinite_loop(self, method): from qiskit_aer import Aer - sim = Aer.get_backend("aer_simulator") + with self.assertWarns(DeprecationWarning): + sim = Aer.get_backend("aer_simulator") in_results = sim.run(qc, shots=4096).result().get_counts() out_results = sim.run(routed, shots=4096).result().get_counts() self.assertEqual(set(in_results), set(out_results)) diff --git a/test/utils/base.py b/test/utils/base.py index 1b8be97641a8..747be7f66b51 100644 --- a/test/utils/base.py +++ b/test/utils/base.py @@ -174,7 +174,8 @@ def tearDown(self): # due to importing the instances from the top-level qiskit namespace. from qiskit.providers.basic_provider import BasicProvider - BasicProvider()._backends = BasicProvider()._verify_backends() + with self.assertWarns(DeprecationWarning): + BasicProvider()._backends = BasicProvider()._verify_backends() @classmethod def setUpClass(cls):