-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Add ProviderV2 a second version of Provider abstract class #5629
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -75,3 +75,108 @@ def __eq__(self, other): | |
| equal. Subclassed providers can override this behavior. | ||
| """ | ||
| return type(self).__name__ == type(other).__name__ | ||
|
|
||
|
|
||
| class ProviderV2(Provider, ABC): | ||
| """Base class for a Backend Provider.""" | ||
| version = 2 | ||
|
|
||
| def get_backend(self, name=None, **kwargs): | ||
| """Return a single backend matching the specified filtering. | ||
|
|
||
| Args: | ||
| name (str): name of the backend. | ||
| **kwargs: dict used for filtering. | ||
|
|
||
| Returns: | ||
| Backend: a backend matching the filtering. | ||
|
|
||
| Raises: | ||
| QiskitBackendNotFoundError: if no backend could be found or | ||
| more than one backend matches the filtering criteria. | ||
| """ | ||
| backends = 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] | ||
|
|
||
| @abstractmethod | ||
| @property | ||
| def backends(self): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Based on the docstring, shouldn't this be |
||
| """The backends provided by this provider. | ||
|
|
||
| This can be accessed by name via attributes for example:: | ||
|
|
||
| my_provider = Provider() | ||
| my_provider.backend.backend_name | ||
|
|
||
| or called with the signature that matches | ||
| :meth:`~qiskit.providers.ProviderV1.backends`, for example:: | ||
|
|
||
| my_provider = Provider() | ||
| my_provider.backend(name='backend_name') | ||
|
|
||
| Returns: | ||
| BackendsList: A :class:`~qiskit.providers.BackendsList` object | ||
| """ | ||
| pass | ||
|
|
||
| def __eq__(self, other): | ||
| """Equality comparison. | ||
|
|
||
| By default, it is assumed that two `Providers` from the same class are | ||
| equal. Subclassed providers can override this behavior. | ||
| """ | ||
| return type(self).__name__ == type(other).__name__ | ||
|
|
||
|
|
||
| class BackendList: | ||
| """A service class that allows for autocompletion of backends from a provider. | ||
|
|
||
| Each backend can be accessed as attribute by backend directly for example for two | ||
| backends ``BackendA`` (with a name ``'backend_a'``) and ``BackendB`` (with | ||
| a name ``'backend_b'``):: | ||
|
|
||
| from qiskit.providers import BackendV1 | ||
|
|
||
| backends = BackendList([BackendA, BackendB]) | ||
| backend_a = backends.backend_a.configuration() | ||
|
|
||
| would get the backend configuration object for backend_a. For backwards | ||
| compatibility a ``BackendList`` object is callable just as | ||
| :meth:`qiskit.providers.ProviderV1.backends`. For example:: | ||
|
|
||
| backends = BackendList([BackendA, BackendB]) | ||
| backend_list = backends(name='backend_a') | ||
|
|
||
| """ | ||
|
|
||
| def __init__(self, backends): | ||
| """Initialize a new ``BackendList`` object. | ||
|
|
||
| Args: | ||
| backends (list): List of :class:`~qiskit.providers.Backend` instances. | ||
| """ | ||
| self._backends = backends | ||
| for backend in backends: | ||
| setattr(self, backend.name(), backend) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really a risk right now, but it's possible the backend name doesn't conform to Python identifier standard. ibmq has an |
||
|
|
||
| def __call__(self, name=None, filters=None, **kwargs): | ||
| """A listing of all backends from this provider. | ||
|
|
||
| Args: | ||
| name (str): The name of a given backend. | ||
| filters (callable): A filter function. | ||
| Returns: | ||
| list: A list of backends, if any. | ||
| """ | ||
| # pylint: disable=arguments-differ | ||
| backends = self._backends | ||
| if name: | ||
| backends = [ | ||
| backend for backend in backends if backend.name() == name] | ||
|
|
||
| return filter_backends(backends, filters=filters, **kwargs) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| --- | ||
| features: | ||
| - | | ||
| A new version of the :class:`~qiskit.providers.Provider` abstract interface, | ||
| :class:`~qiskit.providers.ProviderV2`. This new version is fully compatible | ||
| with v1 except that :attr:`~qiskit.providers.ProviderV2.backends` is an | ||
| attribute that contains a :class:`~qiskit.providers.BackendsList` object | ||
| which is callable to retain the behavior of the | ||
| :class:`~qiskit.providers.ProviderV1` method | ||
| :meth:`~qiskit.providers.ProviderV1.backends` but also enables attribute | ||
| access by name for all the backends provided by the ``Provider``. | ||
| Implementers of :class:`~qiskit.providers.Provider` should upgrade to | ||
| this new version to add the extra functionality. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think Jay wants to move away from getters and setters - e.g. use
provider.backned()for a single backend andprovider.backends()for multiple.