Coverage for mindsdb / integrations / handlers / google_books_handler / google_books_handler.py: 0%

97 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-21 00:36 +0000

1import os 

2from google.auth.transport.requests import Request 

3from google.oauth2 import service_account 

4from google.oauth2.credentials import Credentials 

5from googleapiclient.discovery import build 

6import pandas as pd 

7from pandas import DataFrame 

8from mindsdb.api.executor.data_types.response_type import RESPONSE_TYPE 

9from .google_books_tables import BookshelvesTable, VolumesTable 

10from mindsdb.integrations.libs.api_handler import APIHandler, FuncParser 

11from mindsdb.integrations.libs.response import ( 

12 HandlerStatusResponse as StatusResponse, 

13 HandlerResponse as Response, 

14) 

15from mindsdb.utilities import log 

16 

17logger = log.getLogger(__name__) 

18 

19 

20class GoogleBooksHandler(APIHandler): 

21 """ 

22 A class for handling connections and interactions with the Google Books API. 

23 """ 

24 

25 name = "google_books" 

26 

27 def __init__(self, name: str, **kwargs): 

28 """ 

29 Initialize the Google Books API handler. 

30 Args: 

31 name (str): name of the handler 

32 kwargs (dict): additional arguments 

33 """ 

34 super().__init__(name) 

35 self.token = None 

36 self.service = None 

37 self.connection_data = kwargs.get("connection_data", {}) 

38 self.credentials_file = self.connection_data.get("credentials", None) 

39 self.credentials = None 

40 self.scopes = ["https://www.googleapis.com/auth/books"] 

41 self.is_connected = False 

42 self.connection = None 

43 bookshelves = BookshelvesTable(self) 

44 self.bookshelves = bookshelves 

45 self._register_table("bookshelves", bookshelves) 

46 volumes = VolumesTable(self) 

47 self.volumes = volumes 

48 self._register_table("volumes", volumes) 

49 

50 def connect(self): 

51 """ 

52 Set up any connections required by the handler 

53 Should return output of check_connection() method after attempting 

54 connection. Should switch self.is_connected. 

55 Returns: 

56 HandlerStatusResponse 

57 """ 

58 

59 if self.is_connected is True: 

60 return self.service 

61 if self.credentials_file: 

62 if os.path.exists("token_books.json"): 

63 self.credentials = Credentials.from_authorized_user_file("token_books.json", self.scopes) 

64 if not self.credentials or not self.credentials.valid: 

65 if self.credentials and self.credentials.expired and self.credentials.refresh_token: 

66 self.credentials.refresh(Request()) 

67 else: 

68 self.credentials = service_account.Credentials.from_service_account_file( 

69 self.credentials_file, scopes=self.scopes 

70 ) 

71 # Save the credentials for the next run 

72 with open("token_books.json", "w") as token: 

73 token.write(self.credentials.to_json()) 

74 self.service = build("books", "v1", credentials=self.credentials) 

75 return self.service 

76 

77 def check_connection(self) -> StatusResponse: 

78 """ 

79 Check connection to the handler 

80 Returns: 

81 HandlerStatusResponse 

82 """ 

83 

84 response = StatusResponse(False) 

85 

86 try: 

87 self.connect() 

88 response.success = True 

89 except Exception as e: 

90 logger.error(f"Error connecting to Google Books API: {e}!") 

91 response.error_message = e 

92 

93 self.is_connected = response.success 

94 return response 

95 

96 def native_query(self, query: str = None) -> Response: 

97 """ 

98 Receive raw query and act upon it somehow. 

99 Args: 

100 query (Any): query in native format (str for sql databases, 

101 api's json etc) 

102 Returns: 

103 HandlerResponse 

104 """ 

105 method_name, params = FuncParser().from_string(query) 

106 

107 df = self.call_application_api(method_name, params) 

108 

109 return Response(RESPONSE_TYPE.TABLE, data_frame=df) 

110 

111 def get_bookshelves(self, params: dict = None) -> DataFrame: 

112 """ 

113 Get bookshelf from Google Books API 

114 Args: 

115 params (dict): query parameters 

116 Returns: 

117 DataFrame 

118 """ 

119 service = self.connect() 

120 minShelf = None 

121 maxShelf = None 

122 if params["shelf"]: 

123 shelf = int(params["shelf"]) 

124 if params["source"]: 

125 df = ( 

126 service.mylibrary() 

127 .bookshelves() 

128 .get(shelf=shelf, userid=params["userid"], source=params["source"]) 

129 .execute() 

130 ) 

131 else: 

132 df = service.mylibrary().bookshelves().get(shelf=shelf, userid=params["userid"]).execute() 

133 

134 df = pd.DataFrame(df, columns=self.bookshelves.get_columns()) 

135 return df 

136 elif not params["minShelf"] and params["maxShelf"]: 

137 minShelf = int(params["maxShelf"]) - 10 

138 maxShelf = int(params["maxShelf"]) 

139 elif not params["maxShelf"] and params["minShelf"]: 

140 minShelf = int(params["minShelf"]) 

141 maxShelf = int(params["minShelf"]) + 10 

142 elif params["maxShelf"] and params["minShelf"]: 

143 minShelf = int(params["minShelf"]) 

144 maxShelf = int(params["maxShelf"]) 

145 

146 args = { 

147 key: value for key, value in params.items() if key not in ["minShelf", "maxShelf"] and value is not None 

148 } 

149 bookshelves = service.bookshelves().list(userid=params["userid"], **args).execute() 

150 

151 df = pd.DataFrame(bookshelves["items"], columns=self.bookshelves.get_columns()) 

152 if minShelf is not None or maxShelf is not None: 

153 # Drop bookshelves that are not in the id range 

154 df = df.drop(df[(df["id"] < minShelf) | (df["id"] > maxShelf)].index) 

155 

156 return df 

157 

158 def get_volumes(self, params: dict = None) -> DataFrame: 

159 """ 

160 Get volumes from Google Books API 

161 Args: 

162 params (dict): query parameters 

163 Returns: 

164 DataFrame 

165 """ 

166 service = self.connect() 

167 args = {key: value for key, value in params.items() if value is not None} 

168 volumes = service.volumes().list(**args).execute() 

169 df = pd.DataFrame(volumes["items"], columns=self.volumes.get_columns()) 

170 return df 

171 

172 def call_application_api(self, method_name: str = None, params: dict = None) -> DataFrame: 

173 """ 

174 Call Google Books API and map the data to pandas DataFrame 

175 Args: 

176 method_name (str): method name 

177 params (dict): query parameters 

178 Returns: 

179 DataFrame 

180 """ 

181 if method_name == "get_bookshelves": 

182 return self.get_bookshelves(params) 

183 elif method_name == "get_volumes": 

184 return self.get_volumes(params) 

185 else: 

186 raise NotImplementedError(f"Unknown method {method_name}")