Coverage for src/artemis_sg/app_creds.py: 72%

1# -*- coding: utf-8 -*-

2

3"""artemis_sg.app_creds

4

5 Obtains Google API Application Credentials."""

6

7 import os.path

8

9 from google.auth.exceptions import RefreshError

10 from google.auth.transport.requests import Request

11 from google.oauth2.credentials import Credentials

12 from google_auth_oauthlib.flow import InstalledAppFlow

13

14 from artemis_sg.config import CFG

15

16 app_token = CFG["google"]["docs"]["api_creds_token"]

17 google_credentials = CFG["google"]["docs"]["api_creds_file"]

18

19

20 def app_creds(app_token_filename: str = app_token) -> str:

21 """Obtain Google API application credentials.

22

23 Check given `app_token_filename` for valid credentials. If they don't

24 exist or are not valid, then use

25 `google_auth_oauthlib.flow.InstalledAppFlow` to let the user manually

26 approve the credential request. When successful, the credentials are saved

27 to the given `app_token_filename` and returned.

28

29 :param app_token_filename:

30 The filename used to inspect and save the credentials in (default is

31 app_creds_token.json). In practice this would not be set, but is given

32 here as a parameter for unittesting purposes.

33 :returns: a json string of the credentials

34 """

35

36 scopes = (

37 "https://www.googleapis.com/auth/spreadsheets.readonly",

38 "https://www.googleapis.com/auth/presentations",

39 )

40 creds = None

41 # The file `app_token_filename` stores the user's access and refresh tokens, and is

42 # created automatically when the authorization flow completes for the first

43 # time.

44

45 if os.path.exists(app_token_filename):

46 creds = Credentials.from_authorized_user_file(app_token_filename, scopes)

47 # If there are no (valid) credentials available, let the user log in.

48 if not creds or not creds.valid:

49 if creds and creds.expired and creds.refresh_token: 49 ↛ 50line 49 didn't jump to line 50, because the condition on line 49 was never true

50 try:

51 creds.refresh(Request())

52 except RefreshError:

53 flow = InstalledAppFlow.from_client_secrets_file(

54 google_credentials, scopes

55 )

56 creds = flow.run_local_server(port=0)

57 else:

58 flow = InstalledAppFlow.from_client_secrets_file(google_credentials, scopes)

59 creds = flow.run_local_server(port=0)

60 # Save the credentials for the next run

61 _write_token_file(app_token_filename, creds)

62

63 return creds

64

65

66 def _write_token_file(filename: str, creds: str):

67 with open(filename, "w", encoding="utf-8") as token:

68 token.write(creds.to_json())