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

Update docstrings in credential_storage.py #516

Merged
merged 5 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,12 @@ Consult the `notebooks <https://github.com/CQCL/pytket-quantinuum/tree/develop/e
.. automodule:: pytket.extensions.quantinuum.backends.leakage_gadget
:members:

.. automodule:: pytket.extensions.quantinuum.backends.credential_storage
:members: MemoryCredentialStorage, QuantinuumConfigCredentialStorage
.. autoclass:: pytket.extensions.quantinuum.backends.credential_storage.CredentialStorage
:special-members: __init__
:members:

.. autoclass:: pytket.extensions.quantinuum.backends.credential_storage.MemoryCredentialStorage
:show-inheritance:

.. autoclass:: pytket.extensions.quantinuum.backends.credential_storage.QuantinuumConfigCredentialStorage
:show-inheritance:
18 changes: 18 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ Following a successful login, the refresh token and the ID token, which are requ
This means you won't need to re-enter your credentials until these tokens expire. By default, these tokens are only stored in memory and will be removed once the Python session ends or if you manually log out.

For more persistent storage, consider using the ``QuantinuumConfigCredentialStorage``. This storage option saves your username and the authentication tokens to the ``pytket`` configuration file, ensuring they persist beyond the current session.
To enable this, pass ``QuantinuumConfigCredentialStorage`` as an argument to ``QuantinuumAPI``, which is then provided to ``QuantinuumBackend``.

::

from pytket.extensions.quantinuum.backends.api_wrappers import QuantinuumAPI
Expand All @@ -202,6 +204,22 @@ For more persistent storage, consider using the ``QuantinuumConfigCredentialStor
device_name=machine,
api_handler=QuantinuumAPI(token_store=QuantinuumConfigCredentialStorage()),
)
backend.login() # username and tokens saved to the configuration file.
# A new QuantinuumAPI instance with QuantinuumConfigCredentialStorage
# will automatically load the credential from the configuration file.
backend2 = QuantinuumBackend(
device_name=machine,
api_handler=QuantinuumAPI(token_store=QuantinuumConfigCredentialStorage()),
)
backend2.backend_info # No need to login again

Class methods use in-memory credential storage by default, so you need to explicitly set the ``api_handler``:
::

QuantinuumBackend.available_devices(
api_handler=QuantinuumAPI(token_store=QuantinuumConfigCredentialStorage())
)


Partial Results Retrieval
-------------------------
Expand Down
83 changes: 71 additions & 12 deletions pytket/extensions/quantinuum/backends/credential_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,61 +22,101 @@


class CredentialStorage(ABC):
"""Storage for Quantinuum username and tokens"""
"""Base class for storing Quantinuum username and authentication tokens.

``pytket-quantinuum`` interacts with Quantinuum services by making API requests,
such as submitting quantum programs and retrieving results. These requests
often require an ID token, which is obtained through the Quantinuum login API.
The login process also returns a refresh token, allowing the ID token to be
refreshed without requiring a new login.

``CredentialStorage`` defines the interface for storing and accessing these
credentials, with derived classes providing specific implementations.
"""

def __init__(
self,
id_token_timedelt: timedelta = timedelta(minutes=55),
refresh_token_timedelt: timedelta = timedelta(days=29),
) -> None:
"""
:param id_token_timedelt: The time duration for which the ID token is valid.
Defaults to 55 minutes.
:param refresh_token_timedelt: The time duration for which the refresh token
is valid. Defaults to 29 days.
"""
self._id_timedelt = id_token_timedelt
self._refresh_timedelt = refresh_token_timedelt

@abstractmethod
def save_refresh_token(self, refresh_token: str) -> None:
"""save refresh token"""
"""Save refresh token.

:param refresh_token: refresh token.
"""

@abstractmethod
def save_id_token(self, id_token: str) -> None:
"""save ID token"""
"""Save ID token.

:param id_token: ID token.
"""

@abstractmethod
def save_user_name(self, user_name: str) -> None:
"""save user_name"""
"""Save username.

:param user_name: Quantinuum username.
"""

def save_tokens(self, id_token: str, refresh_token: str) -> None:
"""Save ID token and refresh token.

:param id_token: ID token.
:param refresh_token: refresh token.
"""
self.save_id_token(id_token)
self.save_refresh_token(refresh_token)

@abstractmethod
def delete_credential(self) -> None:
"""delete credential"""
"""Delete credential."""

@property
def id_token(self) -> Optional[str]:
"""returns a ID token if valid"""
"""Return the ID token if valid."""

@property
def refresh_token(self) -> Optional[str]:
"""returns a refresh token if valid"""
"""Return the refresh token if valid."""

@property
def user_name(self) -> Optional[str]:
"""returns the user name"""
"""Return the username if exists."""


class MemoryCredentialStorage(CredentialStorage):
"""In memory credential storage. Intended use is only to store id tokens,
refresh tokens and user_name. Password storage is only included for debug
purposes."""
"""In-memory credential storage.

This storage option allows credentials to be temporarily stored in memory during
the application's runtime.
"""

def __init__(
self,
id_token_timedelt: timedelta = timedelta(minutes=55),
refresh_token_timedelt: timedelta = timedelta(days=29),
) -> None:
"""Construct a MemoryCredentialStorage instance.

:param id_token_timedelt: The time duration for which the ID token is valid.
Defaults to 55 minutes.
:param refresh_token_timedelt: The time duration for which the refresh token
is valid. Defaults to 29 days.
"""
super().__init__(id_token_timedelt, refresh_token_timedelt)
self._user_name: Optional[str] = None
# Password storage is only included for debug purposes
self._password: Optional[str] = None
self._id_token: Optional[str] = None
self._refresh_token: Optional[str] = None
Expand Down Expand Up @@ -141,13 +181,32 @@ def delete_credential(self) -> None:


class QuantinuumConfigCredentialStorage(CredentialStorage):
"""Store tokens in the default pytket configuration file."""
"""Store username and tokens in the default pytket configuration file.

This storage option allows authentication status to persist beyond the current
session, reducing the need to re-enter credentials when constructing new
backends.

Example:

>>> backend = QuantinuumBackend(
>>> device_name=machine,
>>> api_handler=QuantinuumAPI(token_store=QuantinuumConfigCredentialStorage()),
>>> )
"""

def __init__(
self,
id_token_timedelt: timedelta = timedelta(minutes=55),
refresh_token_timedelt: timedelta = timedelta(days=29),
) -> None:
"""Construct a QuantinuumConfigCredentialStorage instance.

:param id_token_timedelt: The time duration for which the ID token is valid.
Defaults to 55 minutes.
:param refresh_token_timedelt: The time duration for which the refresh token
is valid. Defaults to 29 days.
"""
super().__init__(id_token_timedelt, refresh_token_timedelt)

def save_user_name(self, user_name: str) -> None:
Expand Down
Loading