Skip to content
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

Merged
merged 8 commits into from
Jun 27, 2018

Conversation

diego-plan9
Copy link
Member

Summary

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.

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.

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`.
@@ -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.
Copy link
Contributor

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.
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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.

Copy link
Member Author

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
Copy link
Contributor

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, makes sense!


def test_register_unknown_name(self):
"""Test registering a provider with not explicit name."""
with self.assertRaises(QISKitError):
Copy link
Contributor

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.

@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,
Copy link
Contributor

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 unregistering."""
qiskit.wrapper.register(QE_TOKEN, QE_URL, hub, group, project,
provider_name='provider1')
self.assertEqual(['local', 'provider1'],
Copy link
Contributor

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.


def test_unregister_non_existent(self):
"""Test unregistering a non existent provider."""
with self.assertRaises(QISKitError):
Copy link
Contributor

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).
Copy link
Contributor

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.
@diego-plan9
Copy link
Member Author

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 unregister().

delapuente
delapuente previously approved these changes Jun 21, 2018
Copy link
Contributor

@delapuente delapuente left a 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.
@@ -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()}
Copy link
Contributor

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
Copy link
Contributor

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.',
Copy link
Contributor

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.

provider_name='provider1')
initial_providers = registered_providers()
initial_backends = qiskit.wrapper.available_backends()
with self.assertLogs(level=logging.WARNING) as context:
Copy link
Contributor

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,
Copy link
Contributor

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.
@delapuente delapuente force-pushed the feature/unregister branch from eb0c355 to d62d938 Compare June 27, 2018 20:30
@delapuente delapuente modified the milestones: 0.6, 0.5.5 Jun 27, 2018
@diego-plan9 diego-plan9 merged commit e51b4fd into Qiskit:master Jun 27, 2018
@diego-plan9 diego-plan9 deleted the feature/unregister branch June 28, 2018 19:26
lia-approves pushed a commit to edasgupta/qiskit-terra that referenced this pull request Jul 30, 2019
* 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants