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

28 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-10-05 09:33 -0700

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

2 

3"""artemis_sg.app_creds 

4 

5Obtains Google API Application Credentials.""" 

6 

7import os.path 

8 

9from google.auth.exceptions import RefreshError 

10from google.auth.transport.requests import Request 

11from google.oauth2.credentials import Credentials 

12from google_auth_oauthlib.flow import InstalledAppFlow 

13 

14from artemis_sg.config import CFG 

15 

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

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

18 

19 

20def 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 

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

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

68 token.write(creds.to_json())