faori's picture
Upload folder using huggingface_hub
550665c verified
raw
history blame
6.53 kB
import pickle
import os.path
import glob
from typing import List
from googleapiclient import discovery
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.auth.credentials import Credentials
class AuthenticatedService:
"""Handles authentication of the `GoogleCalendar`"""
_READ_WRITE_SCOPES = 'https://www.googleapis.com/auth/calendar'
_LIST_ORDERS = ("startTime", "updated")
def __init__(
self,
*,
credentials: Credentials = None,
credentials_path: str = None,
token_path: str = None,
save_token: bool = True,
read_only: bool = False,
authentication_flow_host: str = 'localhost',
authentication_flow_port: int = 8080,
authentication_flow_bind_addr: str = None
):
"""
Specify ``credentials`` to use in requests or ``credentials_path`` and ``token_path`` to get credentials from.
:param credentials:
Credentials with token and refresh token.
If specified, ``credentials_path``, ``token_path``, and ``save_token`` are ignored.
If not specified, credentials are retrieved from "token.pickle" file (specified in ``token_path`` or
default path) or with authentication flow using secret from "credentials.json" ("client_secret_*.json")
(specified in ``credentials_path`` or default path)
:param credentials_path:
Path to "credentials.json" ("client_secret_*.json") file.
Default: ~/.credentials/credentials.json or ~/.credentials/client_secret*.json
:param token_path:
Existing path to load the token from, or path to save the token after initial authentication flow.
Default: "token.pickle" in the same directory as the credentials_path
:param save_token:
Whether to pickle token after authentication flow for future uses
:param read_only:
If require read only access. Default: False
:param authentication_flow_host:
Host to receive response during authentication flow
:param authentication_flow_port:
Port to receive response during authentication flow
:param authentication_flow_bind_addr:
Optional IP address for the redirect server to listen on when it is not the same as host
(e.g. in a container)
"""
if credentials:
self.credentials = self._ensure_refreshed(credentials)
else:
credentials_path = credentials_path or self._get_default_credentials_path()
credentials_dir, credentials_file = os.path.split(credentials_path)
token_path = token_path or os.path.join(credentials_dir, 'token.pickle')
scopes = [self._READ_WRITE_SCOPES + ('.readonly' if read_only else '')]
self.credentials = self._get_credentials(
token_path,
credentials_dir,
credentials_file,
scopes,
save_token,
authentication_flow_host,
authentication_flow_port,
authentication_flow_bind_addr
)
self.service = discovery.build('calendar', 'v3', credentials=self.credentials)
@staticmethod
def _ensure_refreshed(
credentials: Credentials
) -> Credentials:
if not credentials.valid and credentials.expired:
credentials.refresh(Request())
return credentials
@staticmethod
def _get_credentials(
token_path: str,
credentials_dir: str,
credentials_file: str,
scopes: List[str],
save_token: bool,
host: str,
port: int,
bind_addr: str
) -> Credentials:
credentials = None
if os.path.exists(token_path):
with open(token_path, 'rb') as token_file:
credentials = pickle.load(token_file)
if not credentials or not credentials.valid:
if credentials and credentials.expired and credentials.refresh_token:
credentials.refresh(Request())
else:
credentials_path = os.path.join(credentials_dir, credentials_file)
flow = InstalledAppFlow.from_client_secrets_file(credentials_path, scopes)
credentials = flow.run_local_server(host=host, port=port, bind_addr=bind_addr)
if save_token:
with open(token_path, 'wb') as token_file:
pickle.dump(credentials, token_file)
return credentials
@staticmethod
def _get_default_credentials_path() -> str:
"""Checks if `.credentials` folder in home directory exists and contains `credentials.json` or
`client_secret*.json` file.
:raises ValueError: if `.credentials` folder does not exist, none of `credentials.json` or `client_secret*.json`
files do not exist, or there are multiple `client_secret*.json` files.
:return: expanded path to `credentials.json` or `client_secret*.json` file
"""
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
raise FileNotFoundError(f'Default credentials directory "{credential_dir}" does not exist.')
credential_path = os.path.join(credential_dir, 'credentials.json')
if os.path.exists(credential_path):
return credential_path
else:
credentials_files = glob.glob(credential_dir + '/client_secret*.json')
if len(credentials_files) > 1:
raise ValueError(f"Multiple credential files found in {credential_dir}.\n"
f"Try specifying the credentials file, e.x.:\n"
f"GoogleCalendar(credentials_path='{credentials_files[0]}')")
elif not credentials_files:
raise FileNotFoundError(f'Credentials file (credentials.json or client_secret*.json)'
f'not found in the default path: "{credential_dir}".')
else:
return credentials_files[0]