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.
- mindsdb/__about__.py +1 -1
- mindsdb/__main__.py +3 -45
- mindsdb/api/a2a/__init__.py +52 -0
- mindsdb/api/a2a/agent.py +11 -12
- mindsdb/api/a2a/common/server/server.py +17 -36
- mindsdb/api/a2a/common/server/task_manager.py +14 -28
- mindsdb/api/a2a/task_manager.py +20 -21
- mindsdb/api/a2a/utils.py +1 -1
- mindsdb/api/common/middleware.py +106 -0
- mindsdb/api/executor/utilities/mysql_to_duckdb_functions.py +466 -18
- mindsdb/api/executor/utilities/sql.py +9 -31
- mindsdb/api/http/initialize.py +34 -43
- mindsdb/api/http/namespaces/auth.py +6 -14
- mindsdb/api/http/namespaces/config.py +0 -2
- mindsdb/api/http/namespaces/default.py +74 -106
- mindsdb/api/http/namespaces/file.py +9 -3
- mindsdb/api/http/namespaces/handlers.py +77 -87
- mindsdb/api/http/start.py +29 -47
- mindsdb/api/litellm/start.py +11 -10
- mindsdb/api/mcp/__init__.py +165 -0
- mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +33 -64
- mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +86 -85
- mindsdb/integrations/handlers/autogluon_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/autosklearn_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/crate_handler/crate_handler.py +3 -7
- mindsdb/integrations/handlers/derby_handler/derby_handler.py +32 -34
- mindsdb/integrations/handlers/documentdb_handler/requirements.txt +1 -0
- mindsdb/integrations/handlers/dummy_data_handler/dummy_data_handler.py +12 -13
- mindsdb/integrations/handlers/flaml_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/google_books_handler/google_books_handler.py +45 -44
- mindsdb/integrations/handlers/google_calendar_handler/google_calendar_handler.py +101 -95
- mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_handler.py +129 -129
- mindsdb/integrations/handlers/google_fit_handler/google_fit_handler.py +59 -43
- mindsdb/integrations/handlers/google_search_handler/google_search_handler.py +38 -39
- mindsdb/integrations/handlers/informix_handler/informix_handler.py +5 -18
- mindsdb/integrations/handlers/lightfm_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/lightwood_handler/requirements.txt +4 -4
- mindsdb/integrations/handlers/maxdb_handler/maxdb_handler.py +22 -28
- mindsdb/integrations/handlers/monetdb_handler/monetdb_handler.py +3 -7
- mindsdb/integrations/handlers/mongodb_handler/mongodb_handler.py +53 -67
- mindsdb/integrations/handlers/mongodb_handler/requirements.txt +1 -0
- mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_ast.py +43 -68
- mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_parser.py +17 -25
- mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_query.py +10 -16
- mindsdb/integrations/handlers/mongodb_handler/utils/mongodb_render.py +43 -69
- mindsdb/integrations/handlers/tpot_handler/requirements.txt +1 -1
- mindsdb/integrations/libs/base.py +1 -1
- mindsdb/integrations/libs/llm/config.py +15 -0
- mindsdb/integrations/libs/llm/utils.py +15 -0
- mindsdb/interfaces/agents/constants.py +1 -0
- mindsdb/interfaces/agents/langchain_agent.py +4 -0
- mindsdb/interfaces/agents/providers.py +20 -0
- mindsdb/interfaces/knowledge_base/controller.py +25 -7
- mindsdb/utilities/config.py +15 -158
- mindsdb/utilities/log.py +0 -25
- mindsdb/utilities/render/sqlalchemy_render.py +7 -1
- mindsdb/utilities/starters.py +0 -39
- {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.1.dist-info}/METADATA +269 -267
- {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.1.dist-info}/RECORD +62 -105
- mindsdb/api/a2a/__main__.py +0 -144
- mindsdb/api/a2a/run_a2a.py +0 -86
- mindsdb/api/common/check_auth.py +0 -42
- mindsdb/api/http/gunicorn_wrapper.py +0 -17
- mindsdb/api/mcp/start.py +0 -205
- mindsdb/api/mongo/__init__.py +0 -0
- mindsdb/api/mongo/classes/__init__.py +0 -5
- mindsdb/api/mongo/classes/query_sql.py +0 -19
- mindsdb/api/mongo/classes/responder.py +0 -45
- mindsdb/api/mongo/classes/responder_collection.py +0 -34
- mindsdb/api/mongo/classes/scram.py +0 -86
- mindsdb/api/mongo/classes/session.py +0 -23
- mindsdb/api/mongo/functions/__init__.py +0 -19
- mindsdb/api/mongo/responders/__init__.py +0 -73
- mindsdb/api/mongo/responders/add_shard.py +0 -13
- mindsdb/api/mongo/responders/aggregate.py +0 -90
- mindsdb/api/mongo/responders/buildinfo.py +0 -17
- mindsdb/api/mongo/responders/coll_stats.py +0 -63
- mindsdb/api/mongo/responders/company_id.py +0 -25
- mindsdb/api/mongo/responders/connection_status.py +0 -22
- mindsdb/api/mongo/responders/count.py +0 -21
- mindsdb/api/mongo/responders/db_stats.py +0 -32
- mindsdb/api/mongo/responders/delete.py +0 -105
- mindsdb/api/mongo/responders/describe.py +0 -23
- mindsdb/api/mongo/responders/end_sessions.py +0 -13
- mindsdb/api/mongo/responders/find.py +0 -175
- mindsdb/api/mongo/responders/get_cmd_line_opts.py +0 -18
- mindsdb/api/mongo/responders/get_free_monitoring_status.py +0 -14
- mindsdb/api/mongo/responders/get_parameter.py +0 -23
- mindsdb/api/mongo/responders/getlog.py +0 -14
- mindsdb/api/mongo/responders/host_info.py +0 -28
- mindsdb/api/mongo/responders/insert.py +0 -270
- mindsdb/api/mongo/responders/is_master.py +0 -20
- mindsdb/api/mongo/responders/is_master_lower.py +0 -13
- mindsdb/api/mongo/responders/list_collections.py +0 -55
- mindsdb/api/mongo/responders/list_databases.py +0 -37
- mindsdb/api/mongo/responders/list_indexes.py +0 -22
- mindsdb/api/mongo/responders/ping.py +0 -13
- mindsdb/api/mongo/responders/recv_chunk_start.py +0 -13
- mindsdb/api/mongo/responders/replsetgetstatus.py +0 -13
- mindsdb/api/mongo/responders/sasl_continue.py +0 -34
- mindsdb/api/mongo/responders/sasl_start.py +0 -33
- mindsdb/api/mongo/responders/update_range_deletions.py +0 -12
- mindsdb/api/mongo/responders/whatsmyuri.py +0 -18
- mindsdb/api/mongo/server.py +0 -388
- mindsdb/api/mongo/start.py +0 -15
- mindsdb/api/mongo/utilities/__init__.py +0 -0
- {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.1.dist-info}/WHEEL +0 -0
- {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.1.dist-info}/licenses/LICENSE +0 -0
- {mindsdb-25.8.3.0.dist-info → mindsdb-25.9.1.1.dist-info}/top_level.txt +0 -0
mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_handler.py
CHANGED
|
@@ -20,9 +20,10 @@ logger = log.getLogger(__name__)
|
|
|
20
20
|
|
|
21
21
|
class GoogleContentShoppingHandler(APIHandler):
|
|
22
22
|
"""
|
|
23
|
-
|
|
23
|
+
A class for handling connections and interactions with the Google Content API for Shopping.
|
|
24
24
|
"""
|
|
25
|
-
|
|
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(
|
|
38
|
-
self.fs_storage = kwargs[
|
|
39
|
-
self.credentials_file = self.connection_data.get(
|
|
40
|
-
self.merchant_id = self.connection_data.get(
|
|
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 = [
|
|
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(
|
|
47
|
+
self._register_table("Accounts", accounts)
|
|
47
48
|
orders = OrdersTable(self)
|
|
48
49
|
self.orders = orders
|
|
49
|
-
self._register_table(
|
|
50
|
+
self._register_table("Orders", orders)
|
|
50
51
|
products = ProductsTable(self)
|
|
51
52
|
self.products = products
|
|
52
|
-
self._register_table(
|
|
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(
|
|
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(
|
|
80
|
-
self.service = build(
|
|
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
|
|
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
|
-
|
|
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[
|
|
131
|
-
result = service.accounts().get(merchantId=self.merchant_id, accountId=params[
|
|
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[
|
|
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(
|
|
138
|
+
page_token = result.get("nextPageToken")
|
|
141
139
|
if not page_token:
|
|
142
140
|
break
|
|
143
141
|
|
|
144
|
-
if params[
|
|
145
|
-
start_id = int(params[
|
|
146
|
-
end_id = int(params[
|
|
147
|
-
elif params[
|
|
148
|
-
start_id = int(params[
|
|
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[
|
|
151
|
-
end_id = int(params[
|
|
148
|
+
elif params["endId"]:
|
|
149
|
+
end_id = int(params["endId"])
|
|
152
150
|
start_id = end_id - 10
|
|
153
151
|
else:
|
|
154
|
-
raise Exception(
|
|
152
|
+
raise Exception("startId or endId must be specified")
|
|
155
153
|
|
|
156
|
-
accounts = accounts.drop(accounts[(accounts[
|
|
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[
|
|
171
|
-
args = {
|
|
172
|
-
if params[
|
|
173
|
-
result =
|
|
174
|
-
|
|
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=[
|
|
178
|
-
if not params[
|
|
179
|
-
start_id = int(params[
|
|
180
|
-
elif not params[
|
|
181
|
-
end_id = int(params[
|
|
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[
|
|
184
|
-
end_id = int(params[
|
|
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([{
|
|
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
|
|
204
|
-
|
|
205
|
-
|
|
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[
|
|
212
|
-
result = service.orders().get(merchantId=self.merchant_id, orderId=params[
|
|
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[
|
|
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(
|
|
216
|
+
page_token = result.get("nextPageToken")
|
|
222
217
|
if not page_token:
|
|
223
218
|
break
|
|
224
219
|
|
|
225
|
-
if params[
|
|
226
|
-
start_id = int(params[
|
|
227
|
-
end_id = int(params[
|
|
228
|
-
elif params[
|
|
229
|
-
start_id = int(params[
|
|
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[
|
|
232
|
-
end_id = int(params[
|
|
226
|
+
elif params["endId"]:
|
|
227
|
+
end_id = int(params["endId"])
|
|
233
228
|
start_id = end_id - 10
|
|
234
229
|
else:
|
|
235
|
-
raise Exception(
|
|
230
|
+
raise Exception("startId or endId must be specified")
|
|
236
231
|
|
|
237
|
-
orders = orders.drop(orders[(orders[
|
|
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[
|
|
251
|
-
result = service.orders().delete(merchantId=self.merchant_id, orderId=params[
|
|
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=[
|
|
255
|
-
if not params[
|
|
256
|
-
start_id = int(params[
|
|
257
|
-
elif not params[
|
|
258
|
-
end_id = int(params[
|
|
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[
|
|
261
|
-
end_id = int(params[
|
|
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([{
|
|
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[
|
|
280
|
-
result = service.products().get(merchantId=self.merchant_id, productId=params[
|
|
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[
|
|
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(
|
|
283
|
+
page_token = result.get("nextPageToken")
|
|
290
284
|
if not page_token:
|
|
291
285
|
break
|
|
292
286
|
|
|
293
|
-
if params[
|
|
294
|
-
start_id = int(params[
|
|
295
|
-
end_id = int(params[
|
|
296
|
-
elif params[
|
|
297
|
-
start_id = int(params[
|
|
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[
|
|
300
|
-
end_id = int(params[
|
|
293
|
+
elif params["endId"]:
|
|
294
|
+
end_id = int(params["endId"])
|
|
301
295
|
start_id = end_id - 10
|
|
302
296
|
else:
|
|
303
|
-
raise Exception(
|
|
297
|
+
raise Exception("startId or endId must be specified")
|
|
304
298
|
|
|
305
|
-
products = products.drop(products[(products[
|
|
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[
|
|
322
|
-
result =
|
|
323
|
-
|
|
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=[
|
|
328
|
-
if not params[
|
|
329
|
-
start_id = int(params[
|
|
330
|
-
elif not params[
|
|
331
|
-
end_id = int(params[
|
|
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[
|
|
334
|
-
end_id = int(params[
|
|
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(
|
|
338
|
-
|
|
339
|
-
|
|
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
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
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=[
|
|
360
|
-
if not params[
|
|
361
|
-
start_id = int(params[
|
|
362
|
-
elif not params[
|
|
363
|
-
end_id = int(params[
|
|
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[
|
|
366
|
-
end_id = int(params[
|
|
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([{
|
|
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 ==
|
|
382
|
+
if method_name == "get_accounts":
|
|
383
383
|
return self.get_accounts(params)
|
|
384
|
-
elif method_name ==
|
|
384
|
+
elif method_name == "delete_accounts":
|
|
385
385
|
return self.delete_accounts(params)
|
|
386
|
-
elif method_name ==
|
|
386
|
+
elif method_name == "get_orders":
|
|
387
387
|
return self.get_orders(params)
|
|
388
|
-
elif method_name ==
|
|
388
|
+
elif method_name == "delete_orders":
|
|
389
389
|
return self.delete_orders(params)
|
|
390
|
-
elif method_name ==
|
|
390
|
+
elif method_name == "get_products":
|
|
391
391
|
return self.get_products(params)
|
|
392
|
-
elif method_name ==
|
|
392
|
+
elif method_name == "update_products":
|
|
393
393
|
return self.update_products(params)
|
|
394
|
-
elif method_name ==
|
|
394
|
+
elif method_name == "delete_products":
|
|
395
395
|
return self.delete_products(params)
|
|
396
396
|
else:
|
|
397
|
-
raise NotImplementedError(f
|
|
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 = [
|
|
25
|
-
DATE_FORMAT =
|
|
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(
|
|
33
|
+
args = kwargs.get("connection_data", {})
|
|
35
34
|
self.connection_args = {}
|
|
36
35
|
self.credentials_path = None
|
|
37
|
-
if
|
|
38
|
-
if os.path.isfile(args[
|
|
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[
|
|
41
|
-
elif
|
|
42
|
-
self.connection_args = args[
|
|
43
|
-
if
|
|
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[
|
|
46
|
-
self.credentials_path =
|
|
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(
|
|
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(
|
|
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(
|
|
68
|
-
creds = Credentials.from_authorized_user_file(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
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(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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[
|
|
146
|
+
data_point = daily_step_data["dataset"][0]["point"]
|
|
131
147
|
if data_point:
|
|
132
|
-
count = data_point[0][
|
|
133
|
-
data_source_id = data_point[0][
|
|
134
|
-
steps[local_date_str] = {
|
|
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(
|
|
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 ==
|
|
151
|
-
val = self.get_steps(params[
|
|
166
|
+
if method_name == "get_steps":
|
|
167
|
+
val = self.get_steps(params["start_time"], params["end_time"])
|
|
152
168
|
return val
|
|
153
|
-
raise NotImplementedError(
|
|
169
|
+
raise NotImplementedError("Method name {} not supported by Google Fit Handler".format(method_name))
|