-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Add unregister() via DefaultQISKitProvider changes #584
Conversation
Add `wrapper.unregister()` for removing previously registered providers, by delegating into `DefaultQISKitProvider` internal tracking of provider instances: * use a dict instead of a list for `self.providers`, introducing the ability to assign a user name to a provider instance at the wrapper level. * update `register(...,provider_name)` parameter so it is set by the user explicitly (with "weak" fallbacks for the two main use cases, for backwards compatibility). * add `wrapper.registered_providers()` for convenience, displaying the list of currently registered providers. Regroup wrapper tests, adding basic ones for the new functionality and fixing an issue with global variables and imports via `tearDown`.
2450fd2
to
bfd4ea9
Compare
qiskit/wrapper/_wrapper.py
Outdated
@@ -38,17 +37,33 @@ def register(token, url='https://quantumexperience.ng.bluemix.net/api', | |||
proxies (dict): Proxy configuration for the API, as a dict with | |||
'urls' and credential keys. | |||
verify (bool): If False, ignores SSL certificates errors. | |||
provider_name (str): the unique name for the online backend | |||
provider (for example, 'ibmq' for the IBM Quantum Experience). | |||
provider_name (str): the user name for the registered provider. |
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.
Can you replace the user name for
with a user-provided name for
.
""" | ||
Add a new provider to the list of known providers. | ||
|
||
Args: | ||
provider (BaseProvider): Provider instance. | ||
provider_name (str): User name for the provider. |
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.
Again, replace User name for
with a user-provided name for
.
|
||
Args: | ||
credentials_dict (dict): dictionary of credentials for a provider. | ||
provider_name (str): User name for the provider. A name will |
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.
Same here.
Args: | ||
credentials_dict (dict): dictionary of credentials for a provider. | ||
provider_name (str): User name for the provider. A name will | ||
automatically |
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 this is an incomplete sentence.
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.
Yep 🤦♂️
'A provider with name "%s" is already registered.' | ||
% provider_name) | ||
|
||
self.providers[provider_name] = provider |
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.
Non-blocking: should we return the provider to keep it consistent with add_ibmq_provider
?
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.
Sure, makes sense!
test/python/test_wrapper.py
Outdated
|
||
def test_register_unknown_name(self): | ||
"""Test registering a provider with not explicit name.""" | ||
with self.assertRaises(QISKitError): |
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.
Non-blocking: I'd relax this constraint by asserting the list before and after the intent to register are equal:
before_attempt = qiskit.wrapper.registered_providers()
with self.assertRaises(QISKitError):
qiskit.wtapper.register('FAKE_TOKEN', 'http://unknown')
self.assertEqual(sorted(qiskit.wrapper.registered_providers()), sorted(before_attempt))
This way you're checking that a failing operation does not alter the list of providers, instead of tying yourself to a particular implementation such as the 'local'
name.
test/python/test_wrapper.py
Outdated
@requires_qe_access | ||
def test_unregister(self, QE_TOKEN, QE_URL, hub, group, project): | ||
"""Test unregistering.""" | ||
qiskit.wrapper.register(QE_TOKEN, QE_URL, hub, group, project, |
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.
Same here, we could relax the test by replacing the last assertion with a comparison between the current registered_providers
and those before registering anything and...
test/python/test_wrapper.py
Outdated
"""Test unregistering.""" | ||
qiskit.wrapper.register(QE_TOKEN, QE_URL, hub, group, project, | ||
provider_name='provider1') | ||
self.assertEqual(['local', 'provider1'], |
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.
...replacing this one with an inclusion assertion.
test/python/test_wrapper.py
Outdated
|
||
def test_unregister_non_existent(self): | ||
"""Test unregistering a non existent provider.""" | ||
with self.assertRaises(QISKitError): |
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.
Same here.
@@ -20,6 +20,7 @@ The format is based on `Keep a Changelog`_. | |||
|
|||
Added | |||
----- | |||
- Add ``unregister()`` for removing previously registered providers (#584). |
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.
If changing the signatures or register()
and unregister()
for them to return the provider instances, consider adding that here too.
* Revise docstrings with reference to user-provided name. * Make tests more robust. * Misc fixes.
Thanks for the review, @delapuente ! I have addressed most of the issues, keeping some of them still open with the idea of further discussing and addressing them when #540 is tackled while still providing a functional |
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.
LGTM, let's discuss the non-blocking matters after getting more insight about the original PR.
Add a check during backend registration that prints a warning if a backend name clash is detected.
28449c5
to
cec2fdf
Compare
@@ -103,6 +110,16 @@ def add_provider(self, provider, provider_name): | |||
'A provider with name "%s" is already registered.' | |||
% provider_name) | |||
|
|||
# Check for backend name clashes, emitting a warning. | |||
current_backends = {str(backend) for backend in self.available_backends()} | |||
added_backends = {str(backend) for backend in provider.available_backends()} |
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.
Non-blocking: can we make it clear with the name that we did not add the backends yet? That they are incoming_backends
or new_provider_backends
or something like this?
@@ -87,6 +88,12 @@ def add_provider(self, provider, provider_name): | |||
""" | |||
Add a new provider to the list of known providers. | |||
|
|||
Note: | |||
If a backend from the new provider has a name that is in use by an |
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.
Non-blocking but what about: If some backend of the new provider has a name in use by an already registered provider, the backend will not be available, and the name will always refer to that previously registered.
if common_backends: | ||
logger.warning( | ||
'The backend names "%s" (provided by "%s") are already in use. ' | ||
'Consider using unregister() for avoiding namespace conflicts.', |
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.
Non-blocking but I would seriously consider changing namespace
with simply name
.
test/python/test_wrapper.py
Outdated
provider_name='provider1') | ||
initial_providers = registered_providers() | ||
initial_backends = qiskit.wrapper.available_backends() | ||
with self.assertLogs(level=logging.WARNING) as context: |
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.
Can we rename context
with logger_output
or simply output
? Does it make sense?
self.assertCountEqual(initial_providers + ['provider2'], | ||
registered_providers()) | ||
# Check that no new backends have been added. | ||
self.assertCountEqual(initial_backends, |
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.
We should also assert that the backend name still refers to the already registered backend:
initial_backends = qiskit.wrapper.available_backends()
original_backend = qiskit.wrapper.get_backend('ibmqx4')
# ...
with self.assertLogs(level=logging.WARNING) as context:
qiskit.wrapper.register(QE_TOKEN, QE_URL, hub, group, project, provider_name='provider2')
# ...
self.assertEqual(original_backend, qiskit.wrapper.get_backend('ibmqx4'))
Test now check if, after registering a provider with colliding backend names, an specific backend name still refers to that available before registering the provider.
eb0c355
to
d62d938
Compare
* Add unregister() via DefaultQISKitProvider changes Add `wrapper.unregister()` for removing previously registered providers, by delegating into `DefaultQISKitProvider` internal tracking of provider instances: * use a dict instead of a list for `self.providers`, introducing the ability to assign a user name to a provider instance at the wrapper level. * update `register(...,provider_name)` parameter so it is set by the user explicitly (with "weak" fallbacks for the two main use cases, for backwards compatibility). * add `wrapper.registered_providers()` for convenience, displaying the list of currently registered providers. Regroup wrapper tests, adding basic ones for the new functionality and fixing an issue with global variables and imports via `tearDown`. * Fixes wrapper unregister and tests after review * Revise docstrings with reference to user-provided name. * Make tests more robust. * Misc fixes. * Add warning if backend name clash when registering Add a check during backend registration that prints a warning if a backend name clash is detected. * Polishing names and improving tests. Test now check if, after registering a provider with colliding backend names, an specific backend name still refers to that available before registering the provider.
Summary
Add
wrapper.unregister()
for removing previously registered providers,by delegating into
DefaultQISKitProvider
internal tracking ofprovider instances:
self.providers
, introducing theability to assign a user name to a provider instance at the wrapper
level.
register(...,provider_name)
parameter so it is set by theuser explicitly (with "weak" fallbacks for the two main use cases,
for backwards compatibility).
wrapper.registered_providers()
for convenience, displaying thelist of currently registered providers.
Regroup wrapper tests, adding basic ones for the new functionality and
fixing an issue with global variables and imports via
tearDown
.Details and comments
Even if a related functionality was included in #540, after discussion with Jay I'm moving this feature to its own PR for being able to incorporate it into the codebase independently and hopefully cater to the urgency, as #540 is ongoing a refactoring and has a wider scope. The modifications for
DefaultQiskitProvider
are actually part of that refactor - once this PR is merged, changes will be moved onto the other pull request.