Skip to content

Commit

Permalink
Deprecating Provider ABC, as abstraction is not very useful (#12145)
Browse files Browse the repository at this point in the history
* Provider abstraction is not very useful

* udpate docs

* ignore deprecations

* not triggered on CI

* deprecation warnings in visual tests

* set up

* set up without warning?

* setUpClass

* more test adjust

* raise at setUpClass

* warms

* test_circuit_matplotlib_drawer.py

* skip Aer warning

* Apply suggestions from code review

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>

* reno

* Run black

* Update release note

* linter

---------

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
  • Loading branch information
1ucian0 and mtreinish committed Apr 23, 2024
1 parent 291fa09 commit 4d95d94
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 32 deletions.
35 changes: 17 additions & 18 deletions qiskit/providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
===============
Expand All @@ -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
Expand All @@ -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).
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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__()
Expand Down
4 changes: 2 additions & 2 deletions qiskit/providers/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 11 additions & 5 deletions qiskit/providers/fake_provider/generic_backend_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -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", {})
Expand Down
16 changes: 16 additions & 0 deletions qiskit/providers/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from abc import ABC, abstractmethod

from qiskit.providers.exceptions import QiskitBackendNotFoundError
from qiskit.utils import deprecate_func


class Provider:
Expand All @@ -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.
Expand Down
18 changes: 18 additions & 0 deletions releasenotes/notes/deprecate_providerV1-ba17d7b4639d1cc5.yaml
Original file line number Diff line number Diff line change
@@ -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]
3 changes: 2 additions & 1 deletion test/python/primitives/test_backend_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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")
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion test/python/transpiler/test_sabre_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
3 changes: 2 additions & 1 deletion test/utils/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down

0 comments on commit 4d95d94

Please sign in to comment.