Skip to content

Commit

Permalink
Merge pull request #547 from nonhermitian/configrc
Browse files Browse the repository at this point in the history
Improve user authentication handling
  • Loading branch information
diego-plan9 authored Jul 20, 2018
2 parents 9de5b98 + 46286a6 commit 42a5744
Show file tree
Hide file tree
Showing 14 changed files with 759 additions and 97 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ The format is based on `Keep a Changelog`_.

Added
-----
- Introduced new options for handling credentials (qiskitrc file, environment
variables) and automatic registration. (#547)

Changed
-------
Expand Down
23 changes: 0 additions & 23 deletions Qconfig.py.default

This file was deleted.

43 changes: 19 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,43 +126,38 @@ your IBM Q Experience account:

#### Configure your API token and QX credentials


1. Create an _[IBM Q Experience](https://quantumexperience.ng.bluemix.net) > Account_ if you haven't already done so.

2. Get an API token from the IBM Q Experience website under _My Account > Advanced > API Token_. This API token allows you to execute your programs with the IBM Q Experience backends. See: [Example](doc/example_real_backend.rst).
3. We are going to create a new file called `Qconfig.py` and insert the API token into it. This file must have these contents:

```python
APItoken = 'MY_API_TOKEN'
3. We are now going to add the necessary credentials to QISKit. Take your token
from step 2, here called `MY_API_TOKEN`, and pass it to the
`store_credentials` function:

config = {
'url': 'https://quantumexperience.ng.bluemix.net/api',
# The following should only be needed for IBM Q Network users.
'hub': 'MY_HUB',
'group': 'MY_GROUP',
'project': 'MY_PROJECT'
}
```
```python
from qiskit import store_credentials

4. Substitute `MY_API_TOKEN` with your real API Token extracted in step 2.
store_credentials('MY_API_TOKEN')
```

5. If you have access to the IBM Q Network features, you also need to setup the
values for your hub, group, and project. You can do so by filling the
`config` variable with the values you can find on your IBM Q account
page.
4. If you have access to the IBM Q Network features, you also need to pass the
values for your url, hub, group, and project found on your IBM Q account
page to `store_credentials`.

Once the `Qconfig.py` file is set up, you have to move it under the same directory/folder where your program/tutorial resides, so it can be imported and be used to authenticate with the `register()` function. For example:
After calling `store_credentials()`, your credentials will be stored into disk.
Once they are stored, Qiskit will automatically load and use them in your program
via:

```python
from qiskit import register
import Qconfig

register(Qconfig.APItoken, Qconfig.config["url"],
hub=Qconfig.config["hub"],
group=Qconfig.config["group"],
project=Qconfig.config["project"])
register()
```

For more details on this and more information see
For more details on installing Qiskit and for alternative methods for passing
the IBM QX credentials, such as using environment variables, sending them
explicitly and support for the `Qconfig.py` method available in previous
versions, please check
[our Qiskit documentation](https://www.qiskit.org/documentation/).


Expand Down
143 changes: 126 additions & 17 deletions doc/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,113 @@ This will install the latest stable release along with all the dependencies.
you haven't already done so
- Get an API token from the IBM Q experience website under “My
Account” > “Personal Access Token”
- The API token needs to be placed in a file called ``Qconfig.py``. For
convenience, we provide a default version of this file that you
can use as a reference: `Qconfig.py.default`_. After downloading that
file, copy it into the folder where you will be invoking the SDK (on
Windows, replace ``cp`` with ``copy``):

.. code:: sh

cp Qconfig.py.default Qconfig.py
3.1 Automatically loading credentials
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Since Qiskit 0.6, an automatic method that looks for the credentials in several
places can be used for streamlining the setting up of the IBM Q authentication.
This implies that you can set or store your API credentials once after
installation, and when you want to use them, you can simply run:

.. code:: python
from qiskit import register
register()
This ``register()`` call (without parameters) performs the automatic loading
of the credentials from several sources, and authenticates against IBM Q,
making the online devices available to your program. Please use one of the
following methods for storing the credentials before calling the automatic
registration:

3.1.1 Store API credentials locally
"""""""""""""""""""""""""""""""""""

For most users, storing your API credentials is the most convenient approach.
Your information is stored locally in a configuration file called `qiskitrc`,
and once stored, you can use the credentials without explicitly passing them
to your program.

To store your information, simply run:

.. code:: python
from qiskit import store_credentials
store_credentials('MY_API_TOKEN')
where `MY_API_TOKEN` should be replaced with your token.

If you are on the IBM Q network, you must also pass `url`,
`hub`, `group`, and `project` arguments to `store_credentials`:


.. code:: python
from qiskit import store_credentials
store_credentials('MY_API_TOKEN', url='http://...', hub='HUB',
group='GROUP', project='PROJECT')
3.1.2 Load API credentials from environment variables
"""""""""""""""""""""""""""""""""""""""""""""""""""""

- Open your ``Qconfig.py``, remove the ``#`` from the beginning of the API
token line, and copy/paste your API token into the space between the
quotation marks on that line. Save and close the file.
For more advanced users, it is possible to load API credentials from
environment variables. Specifically, you can set the following environment
variables:

* `QE_TOKEN`,
* `QE_URL`
* `QE_HUB`
* `QE_GROUP`
* `QE_PROJECT`.

Note that if they are present in your environment, they will take precedence
over the credentials stored in disk.

3.1.3 Load API credentials from Qconfig.py
""""""""""""""""""""""""""""""""""""""""""

For compatibility with configurations set for Qiskit versions earlier than 0.6,
the credentials can also be stored in a file called ``Qconfig.py`` placed in
the directory where your program is invoked from. For convenience, we provide
a default version of this file you can use as a reference - using your favorite
editor, create a ``Qconfig.py`` file in the folder of your program with the
following contents:

.. code:: python
APItoken = 'PUT_YOUR_API_TOKEN_HERE'
config = {
'url': 'https://quantumexperience.ng.bluemix.net/api',
# If you have access to IBM Q features, you also need to fill the "hub",
# "group", and "project" details. Replace "None" on the lines below
# with your details from Quantum Experience, quoting the strings, for
# example: 'hub': 'my_hub'
# You will also need to update the 'url' above, pointing it to your custom
# URL for IBM Q.
'hub': None,
'group': None,
'project': None
}
if 'APItoken' not in locals():
raise Exception('Please set up your access token. See Qconfig.py.')
And customize the following lines:

* copy/paste your API token into the space between the quotation marks on the
first line (``APItoken = 'PUT_YOUR_API_TOKEN_HERE'``).
* if you have access to the IBM Q features, you also need to setup the
values for your url, hub, group, and project. You can do so by filling the
``config`` variable with the values you can find on your IBM Q account
page.

For example, a valid and fully configured ``Qconfig.py`` file would look like:

Expand All @@ -65,13 +159,8 @@ For example, a valid and fully configured ``Qconfig.py`` file would look like:
'url': 'https://quantumexperience.ng.bluemix.net/api'
}
- If you have access to the IBM Q features, you also need to setup the
values for your hub, group, and project. You can do so by filling the
``config`` variable with the values you can find on your IBM Q account
page.

For example, a valid and fully configured ``Qconfig.py`` file for IBM Q
users would look like:
For IBM Q users, a valid and fully configured ``Qconfig.py`` file would look
like:

.. code:: python
Expand All @@ -85,6 +174,26 @@ users would look like:
'project': 'MY_PROJECT'
}
Note that if a ``Qconfig.py`` file is present in your directory, it will take
precedence over the environment variables or the credentials stored in disk.

3.2 Manually loading credentials
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In more complex scenarios or for users that need finer control over multiple
accounts, please note that you can pass the API token and the other parameters
directly to the ``register()`` function, which will ignore the automatic
loading of the credentials and use the arguments directly. For example::

.. code:: python
from qiskit import register
register('MY_API_TOKEN', url='https://my.url')
will try to authenticate using ``MY_API_TOKEN`` and the specified URL,
regardless of the configuration stored in the config file, the environment
variables, or the ``Qconfig.py`` file, if any.

Install Jupyter-based tutorials
===============================
Expand Down
7 changes: 4 additions & 3 deletions qiskit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

"""Main QISKit public functionality."""

import os

# First, check for required Python and API version
from . import _util

Expand All @@ -35,13 +37,12 @@
from .wrapper._wrapper import (
available_backends, local_backends, remote_backends,
get_backend, compile, execute, register, unregister,
registered_providers, load_qasm_string, load_qasm_file, least_busy)
registered_providers, load_qasm_string, load_qasm_file, least_busy,
store_credentials)

# Import the wrapper, to make it available when doing "import qiskit".
from . import wrapper

import os

ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
with open(os.path.join(ROOT_DIR, "VERSION.txt"), "r") as version_file:
__version__ = version_file.read().strip()
2 changes: 1 addition & 1 deletion qiskit/wrapper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@
from ._wrapper import (available_backends, local_backends, remote_backends,
get_backend, compile, execute, register, unregister,
registered_providers, load_qasm_string, load_qasm_file,
least_busy)
least_busy, store_credentials)
56 changes: 53 additions & 3 deletions qiskit/wrapper/_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

"""Helper module for simplified QISKit usage."""

import logging
import warnings
from qiskit import transpiler, QISKitError
from qiskit.backends.ibmq import IBMQProvider
from qiskit.wrapper import credentials
from qiskit.wrapper.defaultqiskitprovider import DefaultQISKitProvider
from ._circuittoolkit import circuit_from_qasm_file, circuit_from_qasm_string

Expand All @@ -19,11 +21,22 @@
_DEFAULT_PROVIDER = DefaultQISKitProvider()


logger = logging.getLogger(__name__)


def register(*args, provider_class=IBMQProvider, **kwargs):
"""
Authenticate against an online backend provider.
This is a factory method that returns the provider that gets registered.
Note that if no parameters are passed, this method will try to
automatically discover the credentials for IBMQ in the following places,
in order::
1. in the `Qconfig.py` file in the current working directory.
2. in the environment variables.
3. in the `qiskitrc` configuration file.
Args:
args (tuple): positional arguments passed to provider class initialization
provider_class (BaseProvider): provider class
Expand All @@ -45,9 +58,18 @@ def register(*args, provider_class=IBMQProvider, **kwargs):
BaseProvider: the provider instance that was just registered.
Raises:
QISKitError: if the provider could not be registered
(e.g. due to conflict)
QISKitError: if the provider could not be registered (e.g. due to
conflict, or if no credentials were provided.)
"""
# Try to autodiscover credentials if not passed.
if not args and not kwargs and provider_class == IBMQProvider:
kwargs = credentials.discover_credentials().get(
credentials.get_account_name(IBMQProvider)) or {}
if not kwargs:
raise QISKitError(
'No IBMQ credentials found. Please pass them explicitly or '
'store them before calling register() with store_credentials()')

try:
provider = provider_class(*args, **kwargs)
except Exception as ex:
Expand Down Expand Up @@ -79,8 +101,36 @@ def registered_providers():
return list(_DEFAULT_PROVIDER.providers)


# Functions for inspecting and retrieving backends.
def store_credentials(token, url='https://quantumexperience.ng.bluemix.net/api',
hub=None, group=None, project=None, proxies=None,
verify=True, overwrite=False):
"""
Store credentials for the IBMQ account in the config file.
Args:
token (str): The token used to register on the online backend such
as the quantum experience.
url (str): The url used for online backend such as the quantum
experience.
hub (str): The hub used for online backend.
group (str): The group used for online backend.
project (str): The project used for online backend.
proxies (dict): Proxy configuration for the API, as a dict with
'urls' and credential keys.
verify (bool): If False, ignores SSL certificates errors.
overwrite (bool): overwrite existing credentials.
Raises:
QISKitError: if the credentials already exist and overwrite==False.
"""
credentials.store_credentials(
provider_class=IBMQProvider, overwrite=overwrite,
token=token, url=url, hub=hub, group=group, project=project,
proxies=proxies, verify=verify
)


# Functions for inspecting and retrieving backends.

def available_backends(filters=None, compact=True):
"""
Expand Down
Loading

0 comments on commit 42a5744

Please sign in to comment.