MindsDB 25.8.3.0__py3-none-any.whl → 25.9.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of MindsDB might be problematic. Click here for more details.

Files changed (109) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/__main__.py +3 -45
  3. mindsdb/api/a2a/__init__.py +52 -0
  4. mindsdb/api/a2a/agent.py +11 -12
  5. mindsdb/api/a2a/common/server/server.py +17 -36
  6. mindsdb/api/a2a/common/server/task_manager.py +14 -28
  7. mindsdb/api/a2a/task_manager.py +20 -21
  8. mindsdb/api/a2a/utils.py +1 -1
  9. mindsdb/api/common/middleware.py +106 -0
  10. mindsdb/api/executor/utilities/mysql_to_duckdb_functions.py +466 -18
  11. mindsdb/api/executor/utilities/sql.py +9 -31
  12. mindsdb/api/http/initialize.py +34 -43
  13. mindsdb/api/http/namespaces/auth.py +6 -14
  14. mindsdb/api/http/namespaces/config.py +0 -2
  15. mindsdb/api/http/namespaces/default.py +74 -106
  16. mindsdb/api/http/namespaces/file.py +9 -3
  17. mindsdb/api/http/namespaces/handlers.py +77 -87
  18. mindsdb/api/http/start.py +29 -47
  19. mindsdb/api/litellm/start.py +11 -10
  20. mindsdb/api/mcp/__init__.py +165 -0
  21. mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +33 -64
  22. mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +86 -85
  23. mindsdb/integrations/handlers/autogluon_handler/requirements.txt +1 -1
  24. mindsdb/integrations/handlers/autosklearn_handler/requirements.txt +1 -1
  25. mindsdb/integrations/handlers/crate_handler/crate_handler.py +3 -7
  26. mindsdb/integrations/handlers/derby_handler/derby_handler.py +32 -34
  27. mindsdb/integrations/handlers/documentdb_handler/requirements.txt +1 -0
  28. mindsdb/integrations/handlers/dummy_data_handler/dummy_data_handler.py +12 -13
  29. mindsdb/integrations/handlers/flaml_handler/requirements.txt +1 -1
  30. mindsdb/integrations/handlers/google_books_handler/google_books_handler.py +45 -44
  31. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_handler.py +101 -95
  32. mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_handler.py +129 -129
  33. mindsdb/integrations/handlers/google_fit_handler/google_fit_handler.py +59 -43
  34. mindsdb/integrations/handlers/google_search_handler/google_search_handler.py +38 -39
  35. mindsdb/integrations/handlers/informix_handler/informix_handler.py +5 -18
  36. mindsdb/integrations/handlers/lightfm_handler/requirements.txt +1 -1
  37. mindsdb/integrations/handlers/lightwood_handler/requirements.txt +4 -4
  38. mindsdb/integrations/handlers/maxdb_handler/maxdb_handler.py +22 -28
  39. mindsdb/integrations/handlers/monetdb_handler/monetdb_handler.py +3 -7
  40. mindsdb/integrations/handlers/mongodb_handler/mongodb_handler.py +53 -67
  41. mindsdb/integrations/handlers/mongodb_handler/requirements.txt +1 -0
  42. mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_ast.py +43 -68
  43. mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_parser.py +17 -25
  44. mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_query.py +10 -16
  45. mindsdb/integrations/handlers/mongodb_handler/utils/mongodb_render.py +43 -69
  46. mindsdb/integrations/handlers/tpot_handler/requirements.txt +1 -1
  47. mindsdb/integrations/libs/base.py +1 -1
  48. mindsdb/integrations/libs/llm/config.py +15 -0
  49. mindsdb/integrations/libs/llm/utils.py +15 -0
  50. mindsdb/interfaces/agents/constants.py +1 -0
  51. mindsdb/interfaces/agents/langchain_agent.py +4 -0
  52. mindsdb/interfaces/agents/providers.py +20 -0
  53. mindsdb/interfaces/knowledge_base/controller.py +25 -7
  54. mindsdb/utilities/config.py +15 -158
  55. mindsdb/utilities/log.py +0 -25
  56. mindsdb/utilities/render/sqlalchemy_render.py +7 -1
  57. mindsdb/utilities/starters.py +0 -39
  58. {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.1.dist-info}/METADATA +269 -267
  59. {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.1.dist-info}/RECORD +62 -105
  60. mindsdb/api/a2a/__main__.py +0 -144
  61. mindsdb/api/a2a/run_a2a.py +0 -86
  62. mindsdb/api/common/check_auth.py +0 -42
  63. mindsdb/api/http/gunicorn_wrapper.py +0 -17
  64. mindsdb/api/mcp/start.py +0 -205
  65. mindsdb/api/mongo/__init__.py +0 -0
  66. mindsdb/api/mongo/classes/__init__.py +0 -5
  67. mindsdb/api/mongo/classes/query_sql.py +0 -19
  68. mindsdb/api/mongo/classes/responder.py +0 -45
  69. mindsdb/api/mongo/classes/responder_collection.py +0 -34
  70. mindsdb/api/mongo/classes/scram.py +0 -86
  71. mindsdb/api/mongo/classes/session.py +0 -23
  72. mindsdb/api/mongo/functions/__init__.py +0 -19
  73. mindsdb/api/mongo/responders/__init__.py +0 -73
  74. mindsdb/api/mongo/responders/add_shard.py +0 -13
  75. mindsdb/api/mongo/responders/aggregate.py +0 -90
  76. mindsdb/api/mongo/responders/buildinfo.py +0 -17
  77. mindsdb/api/mongo/responders/coll_stats.py +0 -63
  78. mindsdb/api/mongo/responders/company_id.py +0 -25
  79. mindsdb/api/mongo/responders/connection_status.py +0 -22
  80. mindsdb/api/mongo/responders/count.py +0 -21
  81. mindsdb/api/mongo/responders/db_stats.py +0 -32
  82. mindsdb/api/mongo/responders/delete.py +0 -105
  83. mindsdb/api/mongo/responders/describe.py +0 -23
  84. mindsdb/api/mongo/responders/end_sessions.py +0 -13
  85. mindsdb/api/mongo/responders/find.py +0 -175
  86. mindsdb/api/mongo/responders/get_cmd_line_opts.py +0 -18
  87. mindsdb/api/mongo/responders/get_free_monitoring_status.py +0 -14
  88. mindsdb/api/mongo/responders/get_parameter.py +0 -23
  89. mindsdb/api/mongo/responders/getlog.py +0 -14
  90. mindsdb/api/mongo/responders/host_info.py +0 -28
  91. mindsdb/api/mongo/responders/insert.py +0 -270
  92. mindsdb/api/mongo/responders/is_master.py +0 -20
  93. mindsdb/api/mongo/responders/is_master_lower.py +0 -13
  94. mindsdb/api/mongo/responders/list_collections.py +0 -55
  95. mindsdb/api/mongo/responders/list_databases.py +0 -37
  96. mindsdb/api/mongo/responders/list_indexes.py +0 -22
  97. mindsdb/api/mongo/responders/ping.py +0 -13
  98. mindsdb/api/mongo/responders/recv_chunk_start.py +0 -13
  99. mindsdb/api/mongo/responders/replsetgetstatus.py +0 -13
  100. mindsdb/api/mongo/responders/sasl_continue.py +0 -34
  101. mindsdb/api/mongo/responders/sasl_start.py +0 -33
  102. mindsdb/api/mongo/responders/update_range_deletions.py +0 -12
  103. mindsdb/api/mongo/responders/whatsmyuri.py +0 -18
  104. mindsdb/api/mongo/server.py +0 -388
  105. mindsdb/api/mongo/start.py +0 -15
  106. mindsdb/api/mongo/utilities/__init__.py +0 -0
  107. {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.1.dist-info}/WHEEL +0 -0
  108. {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.1.dist-info}/licenses/LICENSE +0 -0
  109. {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.1.dist-info}/top_level.txt +0 -0
@@ -20,9 +20,10 @@ logger = log.getLogger(__name__)
20
20
 
21
21
  class GoogleContentShoppingHandler(APIHandler):
22
22
  """
23
- A class for handling connections and interactions with the Google Content API for Shopping.
23
+ A class for handling connections and interactions with the Google Content API for Shopping.
24
24
  """
25
- name = 'google_content_shopping'
25
+
26
+ name = "google_content_shopping"
26
27
 
27
28
  def __init__(self, name: str, **kwargs):
28
29
  """
@@ -34,22 +35,22 @@ class GoogleContentShoppingHandler(APIHandler):
34
35
  super().__init__(name)
35
36
  self.token = None
36
37
  self.service = None
37
- self.connection_data = kwargs.get('connection_data', {})
38
- self.fs_storage = kwargs['file_storage']
39
- self.credentials_file = self.connection_data.get('credentials', None)
40
- self.merchant_id = self.connection_data.get('merchant_id', None)
38
+ self.connection_data = kwargs.get("connection_data", {})
39
+ self.fs_storage = kwargs["file_storage"]
40
+ self.credentials_file = self.connection_data.get("credentials", None)
41
+ self.merchant_id = self.connection_data.get("merchant_id", None)
41
42
  self.credentials = None
42
- self.scopes = ['https://www.googleapis.com/auth/content']
43
+ self.scopes = ["https://www.googleapis.com/auth/content"]
43
44
  self.is_connected = False
44
45
  accounts = AccountsTable(self)
45
46
  self.accounts = accounts
46
- self._register_table('Accounts', accounts)
47
+ self._register_table("Accounts", accounts)
47
48
  orders = OrdersTable(self)
48
49
  self.orders = orders
49
- self._register_table('Orders', orders)
50
+ self._register_table("Orders", orders)
50
51
  products = ProductsTable(self)
51
52
  self.products = products
52
- self._register_table('Products', products)
53
+ self._register_table("Products", products)
53
54
 
54
55
  def connect(self):
55
56
  """
@@ -63,7 +64,7 @@ class GoogleContentShoppingHandler(APIHandler):
63
64
  return self.service
64
65
  if self.credentials_file:
65
66
  try:
66
- json_str_bytes = self.fs_storage.file_get('token_content.json')
67
+ json_str_bytes = self.fs_storage.file_get("token_content.json")
67
68
  json_str = json_str_bytes.decode()
68
69
  self.credentials = Credentials.from_authorized_user_info(info=json.loads(json_str), scopes=self.scopes)
69
70
  except Exception:
@@ -73,11 +74,12 @@ class GoogleContentShoppingHandler(APIHandler):
73
74
  self.credentials.refresh(Request())
74
75
  else:
75
76
  self.credentials = service_account.Credentials.from_service_account_file(
76
- self.credentials_file, scopes=self.scopes)
77
+ self.credentials_file, scopes=self.scopes
78
+ )
77
79
  # Save the credentials for the next run
78
80
  json_str = self.credentials.to_json()
79
- self.fs_storage.file_set('token_content.json', json_str.encode())
80
- self.service = build('content', 'v2.1', credentials=self.credentials)
81
+ self.fs_storage.file_set("token_content.json", json_str.encode())
82
+ self.service = build("content", "v2.1", credentials=self.credentials)
81
83
  return self.service
82
84
 
83
85
  def check_connection(self) -> StatusResponse:
@@ -92,7 +94,7 @@ class GoogleContentShoppingHandler(APIHandler):
92
94
  self.connect()
93
95
  response.success = True
94
96
  except Exception as e:
95
- logger.error(f'Error connecting to Google Content API for Shopping: {e}!')
97
+ logger.error(f"Error connecting to Google Content API for Shopping: {e}!")
96
98
  response.error_message = e
97
99
 
98
100
  self.is_connected = response.success
@@ -103,7 +105,7 @@ class GoogleContentShoppingHandler(APIHandler):
103
105
  Receive raw query and act upon it somehow.
104
106
  Args:
105
107
  query (Any): query in native format (str for sql databases,
106
- dict for mongo, api's json etc)
108
+ api's json etc)
107
109
  Returns:
108
110
  HandlerResponse
109
111
  """
@@ -111,10 +113,7 @@ class GoogleContentShoppingHandler(APIHandler):
111
113
 
112
114
  df = self.call_application_api(method_name, params)
113
115
 
114
- return Response(
115
- RESPONSE_TYPE.TABLE,
116
- data_frame=df
117
- )
116
+ return Response(RESPONSE_TYPE.TABLE, data_frame=df)
118
117
 
119
118
  def get_accounts(self, params: dict = None) -> DataFrame:
120
119
  """
@@ -127,33 +126,32 @@ class GoogleContentShoppingHandler(APIHandler):
127
126
  service = self.connect()
128
127
  page_token = None
129
128
  accounts = pd.DataFrame(columns=self.accounts.get_columns())
130
- if params['account_id']:
131
- result = service.accounts().get(merchantId=self.merchant_id, accountId=params['account_id']).execute()
129
+ if params["account_id"]:
130
+ result = service.accounts().get(merchantId=self.merchant_id, accountId=params["account_id"]).execute()
132
131
  accounts = pd.DataFrame(result, columns=self.accounts.get_columns())
133
132
  return accounts
134
133
  while True:
135
134
  result = service.accounts().list(merchantId=self.merchant_id, page_token=page_token, **params).execute()
136
135
  accounts = pd.concat(
137
- [accounts, pd.DataFrame(result['resources'], columns=self.accounts.get_columns())],
138
- ignore_index=True
136
+ [accounts, pd.DataFrame(result["resources"], columns=self.accounts.get_columns())], ignore_index=True
139
137
  )
140
- page_token = result.get('nextPageToken')
138
+ page_token = result.get("nextPageToken")
141
139
  if not page_token:
142
140
  break
143
141
 
144
- if params['startId'] and params['endId']:
145
- start_id = int(params['startId'])
146
- end_id = int(params['endId'])
147
- elif params['startId']:
148
- start_id = int(params['startId'])
142
+ if params["startId"] and params["endId"]:
143
+ start_id = int(params["startId"])
144
+ end_id = int(params["endId"])
145
+ elif params["startId"]:
146
+ start_id = int(params["startId"])
149
147
  end_id = start_id + 10
150
- elif params['endId']:
151
- end_id = int(params['endId'])
148
+ elif params["endId"]:
149
+ end_id = int(params["endId"])
152
150
  start_id = end_id - 10
153
151
  else:
154
- raise Exception('startId or endId must be specified')
152
+ raise Exception("startId or endId must be specified")
155
153
 
156
- accounts = accounts.drop(accounts[(accounts['id'] < start_id) | (accounts['id'] > end_id)].index)
154
+ accounts = accounts.drop(accounts[(accounts["id"] < start_id) | (accounts["id"] > end_id)].index)
157
155
 
158
156
  return accounts
159
157
 
@@ -167,25 +165,26 @@ class GoogleContentShoppingHandler(APIHandler):
167
165
  """
168
166
  service = self.connect()
169
167
  args = {}
170
- if params['force']:
171
- args = {'force': params['force']}
172
- if params['accountId']:
173
- result = service.accounts().delete(merchantId=self.merchant_id, accountId=params['accountId'],
174
- **args).execute()
168
+ if params["force"]:
169
+ args = {"force": params["force"]}
170
+ if params["accountId"]:
171
+ result = (
172
+ service.accounts().delete(merchantId=self.merchant_id, accountId=params["accountId"], **args).execute()
173
+ )
175
174
  return result
176
175
  else:
177
- df = pd.DataFrame(columns=['accountId', 'status'])
178
- if not params['startId']:
179
- start_id = int(params['endId']) - 10
180
- elif not params['endId']:
181
- end_id = int(params['startId']) + 10
176
+ df = pd.DataFrame(columns=["accountId", "status"])
177
+ if not params["startId"]:
178
+ start_id = int(params["endId"]) - 10
179
+ elif not params["endId"]:
180
+ end_id = int(params["startId"]) + 10
182
181
  else:
183
- start_id = int(params['startId'])
184
- end_id = int(params['endId'])
182
+ start_id = int(params["startId"])
183
+ end_id = int(params["endId"])
185
184
 
186
185
  for i in range(start_id, end_id):
187
186
  service.accounts().delete(merchantId=self.merchant_id, accountId=i, **args).execute()
188
- df = pd.concat([df, pd.DataFrame([{'accountId': str(i), 'status': 'deleted'}])], ignore_index=True)
187
+ df = pd.concat([df, pd.DataFrame([{"accountId": str(i), "status": "deleted"}])], ignore_index=True)
189
188
  return df
190
189
 
191
190
  def get_orders(self, params: dict = None) -> DataFrame:
@@ -200,41 +199,37 @@ class GoogleContentShoppingHandler(APIHandler):
200
199
  page_token = None
201
200
  orders = pd.DataFrame(columns=self.orders.get_columns())
202
201
  args = {
203
- key: value for key, value in params.items() if key in ['maxResults',
204
- 'statuses',
205
- 'acknowledged',
206
- 'placedDateStart',
207
- 'placedDateEnd',
208
- 'orderBy']
202
+ key: value
203
+ for key, value in params.items()
204
+ if key in ["maxResults", "statuses", "acknowledged", "placedDateStart", "placedDateEnd", "orderBy"]
209
205
  and value is not None
210
206
  }
211
- if params['order_id']:
212
- result = service.orders().get(merchantId=self.merchant_id, orderId=params['order_id'], **args).execute()
207
+ if params["order_id"]:
208
+ result = service.orders().get(merchantId=self.merchant_id, orderId=params["order_id"], **args).execute()
213
209
  orders = pd.DataFrame(result, columns=self.orders.get_columns())
214
210
  return orders
215
211
  while True:
216
212
  result = service.orders().list(merchantId=self.merchant_id, page_token=page_token, **args).execute()
217
213
  orders = pd.concat(
218
- [orders, pd.DataFrame(result['resources'], columns=self.orders.get_columns())],
219
- ignore_index=True
214
+ [orders, pd.DataFrame(result["resources"], columns=self.orders.get_columns())], ignore_index=True
220
215
  )
221
- page_token = result.get('nextPageToken')
216
+ page_token = result.get("nextPageToken")
222
217
  if not page_token:
223
218
  break
224
219
 
225
- if params['startId'] and params['endId']:
226
- start_id = int(params['startId'])
227
- end_id = int(params['endId'])
228
- elif params['startId']:
229
- start_id = int(params['startId'])
220
+ if params["startId"] and params["endId"]:
221
+ start_id = int(params["startId"])
222
+ end_id = int(params["endId"])
223
+ elif params["startId"]:
224
+ start_id = int(params["startId"])
230
225
  end_id = start_id + 10
231
- elif params['endId']:
232
- end_id = int(params['endId'])
226
+ elif params["endId"]:
227
+ end_id = int(params["endId"])
233
228
  start_id = end_id - 10
234
229
  else:
235
- raise Exception('startId or endId must be specified')
230
+ raise Exception("startId or endId must be specified")
236
231
 
237
- orders = orders.drop(orders[(orders['id'] < start_id) | (orders['id'] > end_id)].index)
232
+ orders = orders.drop(orders[(orders["id"] < start_id) | (orders["id"] > end_id)].index)
238
233
 
239
234
  return orders
240
235
 
@@ -247,22 +242,22 @@ class GoogleContentShoppingHandler(APIHandler):
247
242
  DataFrame
248
243
  """
249
244
  service = self.connect()
250
- if params['order_id']:
251
- result = service.orders().delete(merchantId=self.merchant_id, orderId=params['order_id']).execute()
245
+ if params["order_id"]:
246
+ result = service.orders().delete(merchantId=self.merchant_id, orderId=params["order_id"]).execute()
252
247
  return result
253
248
  else:
254
- df = pd.DataFrame(columns=['orderId', 'status'])
255
- if not params['startId']:
256
- start_id = int(params['endId']) - 10
257
- elif not params['endId']:
258
- end_id = int(params['startId']) + 10
249
+ df = pd.DataFrame(columns=["orderId", "status"])
250
+ if not params["startId"]:
251
+ start_id = int(params["endId"]) - 10
252
+ elif not params["endId"]:
253
+ end_id = int(params["startId"]) + 10
259
254
  else:
260
- start_id = int(params['startId'])
261
- end_id = int(params['endId'])
255
+ start_id = int(params["startId"])
256
+ end_id = int(params["endId"])
262
257
 
263
258
  for i in range(start_id, end_id):
264
259
  service.orders().delete(merchantId=self.merchant_id, orderId=i).execute()
265
- df = pd.concat([df, pd.DataFrame([{'orderId': str(i), 'status': 'deleted'}])], ignore_index=True)
260
+ df = pd.concat([df, pd.DataFrame([{"orderId": str(i), "status": "deleted"}])], ignore_index=True)
266
261
  return df
267
262
 
268
263
  def get_products(self, params: dict = None) -> DataFrame:
@@ -276,33 +271,32 @@ class GoogleContentShoppingHandler(APIHandler):
276
271
  service = self.connect()
277
272
  page_token = None
278
273
  products = pd.DataFrame(columns=self.products.get_columns())
279
- if params['product_id']:
280
- result = service.products().get(merchantId=self.merchant_id, productId=params['product_id']).execute()
274
+ if params["product_id"]:
275
+ result = service.products().get(merchantId=self.merchant_id, productId=params["product_id"]).execute()
281
276
  products = pd.DataFrame(result, columns=self.products.get_columns())
282
277
  return products
283
278
  while True:
284
279
  result = service.products().list(merchantId=self.merchant_id, page_token=page_token).execute()
285
280
  products = pd.concat(
286
- [products, pd.DataFrame(result['resources'], columns=self.products.get_columns())],
287
- ignore_index=True
281
+ [products, pd.DataFrame(result["resources"], columns=self.products.get_columns())], ignore_index=True
288
282
  )
289
- page_token = result.get('nextPageToken')
283
+ page_token = result.get("nextPageToken")
290
284
  if not page_token:
291
285
  break
292
286
 
293
- if params['startId'] and params['endId']:
294
- start_id = int(params['startId'])
295
- end_id = int(params['endId'])
296
- elif params['startId']:
297
- start_id = int(params['startId'])
287
+ if params["startId"] and params["endId"]:
288
+ start_id = int(params["startId"])
289
+ end_id = int(params["endId"])
290
+ elif params["startId"]:
291
+ start_id = int(params["startId"])
298
292
  end_id = start_id + 10
299
- elif params['endId']:
300
- end_id = int(params['endId'])
293
+ elif params["endId"]:
294
+ end_id = int(params["endId"])
301
295
  start_id = end_id - 10
302
296
  else:
303
- raise Exception('startId or endId must be specified')
297
+ raise Exception("startId or endId must be specified")
304
298
 
305
- products = products.drop(products[(products['id'] < start_id) | (products['id'] > end_id)].index)
299
+ products = products.drop(products[(products["id"] < start_id) | (products["id"] > end_id)].index)
306
300
 
307
301
  return products
308
302
 
@@ -314,29 +308,36 @@ class GoogleContentShoppingHandler(APIHandler):
314
308
  Returns:
315
309
  DataFrame
316
310
  """
317
- body = {
318
- key: value for key, value in params.items() if key in self.products.get_columns()
319
- }
311
+ body = {key: value for key, value in params.items() if key in self.products.get_columns()}
320
312
  service = self.connect()
321
- if params['product_id']:
322
- result = service.products().update(merchantId=self.merchant_id, productId=params['product_id'],
323
- updateMask=params['updateMask'], body=body).execute()
313
+ if params["product_id"]:
314
+ result = (
315
+ service.products()
316
+ .update(
317
+ merchantId=self.merchant_id,
318
+ productId=params["product_id"],
319
+ updateMask=params["updateMask"],
320
+ body=body,
321
+ )
322
+ .execute()
323
+ )
324
324
 
325
325
  return result
326
326
  else:
327
- df = pd.DataFrame(columns=['productId', 'status'])
328
- if not params['startId']:
329
- start_id = int(params['endId']) - 10
330
- elif not params['endId']:
331
- end_id = int(params['startId']) + 10
327
+ df = pd.DataFrame(columns=["productId", "status"])
328
+ if not params["startId"]:
329
+ start_id = int(params["endId"]) - 10
330
+ elif not params["endId"]:
331
+ end_id = int(params["startId"]) + 10
332
332
  else:
333
- start_id = int(params['startId'])
334
- end_id = int(params['endId'])
333
+ start_id = int(params["startId"])
334
+ end_id = int(params["endId"])
335
335
 
336
336
  for i in range(start_id, end_id):
337
- service.products().update(merchantId=self.merchant_id, productId=i,
338
- updateMask=params['updateMask'], body=body).execute()
339
- df = pd.concat([df, pd.DataFrame([{'productId': str(i), 'status': 'updated'}])], ignore_index=True)
337
+ service.products().update(
338
+ merchantId=self.merchant_id, productId=i, updateMask=params["updateMask"], body=body
339
+ ).execute()
340
+ df = pd.concat([df, pd.DataFrame([{"productId": str(i), "status": "updated"}])], ignore_index=True)
340
341
  return df
341
342
 
342
343
  def delete_products(self, params: dict = None) -> DataFrame:
@@ -348,26 +349,25 @@ class GoogleContentShoppingHandler(APIHandler):
348
349
  DataFrame
349
350
  """
350
351
  service = self.connect()
351
- args = {
352
- key: value for key, value in params.items() if key in ['feedId'] and value is not None
353
- }
354
- if params['product_id']:
355
- result = service.products().delete(merchantId=self.merchant_id, productId=params['product_id'],
356
- **args).execute()
352
+ args = {key: value for key, value in params.items() if key in ["feedId"] and value is not None}
353
+ if params["product_id"]:
354
+ result = (
355
+ service.products().delete(merchantId=self.merchant_id, productId=params["product_id"], **args).execute()
356
+ )
357
357
  return result
358
358
  else:
359
- df = pd.DataFrame(columns=['productId', 'status'])
360
- if not params['startId']:
361
- start_id = int(params['endId']) - 10
362
- elif not params['endId']:
363
- end_id = int(params['startId']) + 10
359
+ df = pd.DataFrame(columns=["productId", "status"])
360
+ if not params["startId"]:
361
+ start_id = int(params["endId"]) - 10
362
+ elif not params["endId"]:
363
+ end_id = int(params["startId"]) + 10
364
364
  else:
365
- start_id = int(params['startId'])
366
- end_id = int(params['endId'])
365
+ start_id = int(params["startId"])
366
+ end_id = int(params["endId"])
367
367
 
368
368
  for i in range(start_id, end_id):
369
369
  service.products().delete(merchantId=self.merchant_id, productId=i, **args).execute()
370
- df = pd.concat([df, pd.DataFrame([{'productId': str(i), 'status': 'deleted'}])], ignore_index=True)
370
+ df = pd.concat([df, pd.DataFrame([{"productId": str(i), "status": "deleted"}])], ignore_index=True)
371
371
  return df
372
372
 
373
373
  def call_application_api(self, method_name: str = None, params: dict = None) -> DataFrame:
@@ -379,19 +379,19 @@ class GoogleContentShoppingHandler(APIHandler):
379
379
  Returns:
380
380
  DataFrame
381
381
  """
382
- if method_name == 'get_accounts':
382
+ if method_name == "get_accounts":
383
383
  return self.get_accounts(params)
384
- elif method_name == 'delete_accounts':
384
+ elif method_name == "delete_accounts":
385
385
  return self.delete_accounts(params)
386
- elif method_name == 'get_orders':
386
+ elif method_name == "get_orders":
387
387
  return self.get_orders(params)
388
- elif method_name == 'delete_orders':
388
+ elif method_name == "delete_orders":
389
389
  return self.delete_orders(params)
390
- elif method_name == 'get_products':
390
+ elif method_name == "get_products":
391
391
  return self.get_products(params)
392
- elif method_name == 'update_products':
392
+ elif method_name == "update_products":
393
393
  return self.update_products(params)
394
- elif method_name == 'delete_products':
394
+ elif method_name == "delete_products":
395
395
  return self.delete_products(params)
396
396
  else:
397
- raise NotImplementedError(f'Unknown method {method_name}')
397
+ raise NotImplementedError(f"Unknown method {method_name}")
@@ -21,37 +21,41 @@ from mindsdb.integrations.libs.response import (
21
21
  HandlerResponse as Response,
22
22
  )
23
23
 
24
- SCOPES = ['https://www.googleapis.com/auth/fitness.activity.read']
25
- DATE_FORMAT = '%Y-%m-%d'
24
+ SCOPES = ["https://www.googleapis.com/auth/fitness.activity.read"]
25
+ DATE_FORMAT = "%Y-%m-%d"
26
26
 
27
27
  logger = log.getLogger(__name__)
28
28
 
29
29
 
30
30
  class GoogleFitHandler(APIHandler):
31
-
32
31
  def __init__(self, name: str = None, **kwargs):
33
32
  super().__init__(name)
34
- args = kwargs.get('connection_data', {})
33
+ args = kwargs.get("connection_data", {})
35
34
  self.connection_args = {}
36
35
  self.credentials_path = None
37
- if 'service_account_file' in args:
38
- if os.path.isfile(args['service_account_file']) is False:
36
+ if "service_account_file" in args:
37
+ if os.path.isfile(args["service_account_file"]) is False:
39
38
  raise Exception("service_account_file must be a path to the credentials.json file")
40
- self.credentials_path = args['service_account_file']
41
- elif 'service_account_json' in args:
42
- self.connection_args = args['service_account_json']
43
- if not isinstance(self.connection_args, dict) or (('redirect_uris' not in self.connection_args.keys()) and len(self.connection_args) != 6) or ('redirect_uris' in self.connection_args.keys()) and len(self.connection_args) != 7:
39
+ self.credentials_path = args["service_account_file"]
40
+ elif "service_account_json" in args:
41
+ self.connection_args = args["service_account_json"]
42
+ if (
43
+ not isinstance(self.connection_args, dict)
44
+ or (("redirect_uris" not in self.connection_args.keys()) and len(self.connection_args) != 6)
45
+ or ("redirect_uris" in self.connection_args.keys())
46
+ and len(self.connection_args) != 7
47
+ ):
44
48
  raise Exception("service_account_json has to be a dictionary with all 6 required fields")
45
- self.connection_args['redirect_uris'] = ['http://localhost']
46
- self.credentials_path = 'mindsdb/integrations/handlers/google_fit_handler/credentials.json'
49
+ self.connection_args["redirect_uris"] = ["http://localhost"]
50
+ self.credentials_path = "mindsdb/integrations/handlers/google_fit_handler/credentials.json"
47
51
  else:
48
- raise Exception('Connection args have to content ether service_account_file or service_account_json')
52
+ raise Exception("Connection args have to content ether service_account_file or service_account_json")
49
53
 
50
54
  self.api = None
51
55
  self.is_connected = False
52
56
 
53
57
  aggregated_data = GoogleFitTable(self)
54
- self._register_table('aggregated_data', aggregated_data)
58
+ self._register_table("aggregated_data", aggregated_data)
55
59
 
56
60
  def connect(self) -> Resource:
57
61
  if self.is_connected is True and self.api:
@@ -64,18 +68,19 @@ class GoogleFitHandler(APIHandler):
64
68
 
65
69
  creds = None
66
70
 
67
- if os.path.isfile('mindsdb/integrations/handlers/google_fit_handler/token.json'):
68
- creds = Credentials.from_authorized_user_file('mindsdb/integrations/handlers/google_fit_handler/token.json', SCOPES)
71
+ if os.path.isfile("mindsdb/integrations/handlers/google_fit_handler/token.json"):
72
+ creds = Credentials.from_authorized_user_file(
73
+ "mindsdb/integrations/handlers/google_fit_handler/token.json", SCOPES
74
+ )
69
75
  if not creds or not creds.valid:
70
76
  if creds and creds.expired and creds.refresh_token:
71
77
  creds.refresh(Request())
72
78
  else:
73
- flow = InstalledAppFlow.from_client_secrets_file(
74
- self.credentials_path, SCOPES)
79
+ flow = InstalledAppFlow.from_client_secrets_file(self.credentials_path, SCOPES)
75
80
  creds = flow.run_local_server(port=0)
76
- with open('mindsdb/integrations/handlers/google_fit_handler/token.json', 'w') as token:
81
+ with open("mindsdb/integrations/handlers/google_fit_handler/token.json", "w") as token:
77
82
  token.write(creds.to_json())
78
- self.api = build('fitness', 'v1', credentials=creds)
83
+ self.api = build("fitness", "v1", credentials=creds)
79
84
 
80
85
  self.is_connected = True
81
86
  return self.api
@@ -88,7 +93,7 @@ class GoogleFitHandler(APIHandler):
88
93
  response.success = True
89
94
 
90
95
  except Exception as e:
91
- logger.error(f'Error connecting to Google Fit API: {e}!')
96
+ logger.error(f"Error connecting to Google Fit API: {e}!")
92
97
  response.error_message = e
93
98
 
94
99
  self.is_connected = response.success
@@ -96,15 +101,20 @@ class GoogleFitHandler(APIHandler):
96
101
 
97
102
  def retrieve_data(self, service, startTimeMillis, endTimeMillis, dataSourceId) -> dict:
98
103
  try:
99
- return service.users().dataset().aggregate(userId="me", body={
100
- "aggregateBy": [{
101
- "dataTypeName": "com.google.step_count.delta",
102
- "dataSourceId": dataSourceId
103
- }],
104
- "bucketByTime": {"durationMillis": 86400000},
105
- "startTimeMillis": startTimeMillis,
106
- "endTimeMillis": endTimeMillis
107
- }).execute()
104
+ return (
105
+ service.users()
106
+ .dataset()
107
+ .aggregate(
108
+ userId="me",
109
+ body={
110
+ "aggregateBy": [{"dataTypeName": "com.google.step_count.delta", "dataSourceId": dataSourceId}],
111
+ "bucketByTime": {"durationMillis": 86400000},
112
+ "startTimeMillis": startTimeMillis,
113
+ "endTimeMillis": endTimeMillis,
114
+ },
115
+ )
116
+ .execute()
117
+ )
108
118
  except HttpError:
109
119
  raise HttpError
110
120
 
@@ -112,7 +122,7 @@ class GoogleFitHandler(APIHandler):
112
122
  """Receive raw query and act upon it somehow.
113
123
  Args:
114
124
  query (Any): query in native format (str for sql databases,
115
- dict for mongo, api's json etc)
125
+ api's json etc)
116
126
  Returns:
117
127
  HandlerResponse
118
128
  """
@@ -121,20 +131,26 @@ class GoogleFitHandler(APIHandler):
121
131
 
122
132
  def get_steps(self, start_time_millis, end_time_millis) -> pd.DataFrame:
123
133
  steps = {}
124
- steps_data = self.retrieve_data(self.api, start_time_millis, end_time_millis, "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps")
125
- for daily_step_data in steps_data['bucket']:
126
- local_date = datetime.fromtimestamp(int(daily_step_data['startTimeMillis']) / 1000,
127
- tz=pytz.timezone(str(get_localzone())))
134
+ steps_data = self.retrieve_data(
135
+ self.api,
136
+ start_time_millis,
137
+ end_time_millis,
138
+ "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps",
139
+ )
140
+ for daily_step_data in steps_data["bucket"]:
141
+ local_date = datetime.fromtimestamp(
142
+ int(daily_step_data["startTimeMillis"]) / 1000, tz=pytz.timezone(str(get_localzone()))
143
+ )
128
144
  local_date_str = local_date.strftime(DATE_FORMAT)
129
145
 
130
- data_point = daily_step_data['dataset'][0]['point']
146
+ data_point = daily_step_data["dataset"][0]["point"]
131
147
  if data_point:
132
- count = data_point[0]['value'][0]['intVal']
133
- data_source_id = data_point[0]['originDataSourceId']
134
- steps[local_date_str] = {'steps': count, 'originDataSourceId': data_source_id}
148
+ count = data_point[0]["value"][0]["intVal"]
149
+ data_source_id = data_point[0]["originDataSourceId"]
150
+ steps[local_date_str] = {"steps": count, "originDataSourceId": data_source_id}
135
151
  ret = pd.DataFrame.from_dict(steps)
136
152
  ret = ret.T
137
- ret = ret.drop('originDataSourceId', axis=1)
153
+ ret = ret.drop("originDataSourceId", axis=1)
138
154
  ret = ret.reset_index(drop=False)
139
155
  return ret
140
156
 
@@ -147,7 +163,7 @@ class GoogleFitHandler(APIHandler):
147
163
  DataFrame
148
164
  """
149
165
  self.connect()
150
- if method_name == 'get_steps':
151
- val = self.get_steps(params['start_time'], params['end_time'])
166
+ if method_name == "get_steps":
167
+ val = self.get_steps(params["start_time"], params["end_time"])
152
168
  return val
153
- raise NotImplementedError('Method name {} not supported by Google Fit Handler'.format(method_name))
169
+ raise NotImplementedError("Method name {} not supported by Google Fit Handler".format(method_name))