MindsDB 25.8.2.0__py3-none-any.whl → 25.9.1.0__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 (101) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/__main__.py +5 -45
  3. mindsdb/api/a2a/__init__.py +52 -0
  4. mindsdb/api/a2a/agent.py +17 -28
  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/common/types.py +3 -4
  8. mindsdb/api/a2a/task_manager.py +43 -55
  9. mindsdb/api/a2a/utils.py +63 -0
  10. mindsdb/api/common/middleware.py +106 -0
  11. mindsdb/api/http/initialize.py +13 -15
  12. mindsdb/api/http/namespaces/agents.py +6 -7
  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/start.py +25 -44
  17. mindsdb/api/litellm/start.py +11 -10
  18. mindsdb/api/mcp/__init__.py +165 -0
  19. mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +33 -64
  20. mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +86 -85
  21. mindsdb/integrations/handlers/crate_handler/crate_handler.py +3 -7
  22. mindsdb/integrations/handlers/derby_handler/derby_handler.py +32 -34
  23. mindsdb/integrations/handlers/documentdb_handler/requirements.txt +1 -0
  24. mindsdb/integrations/handlers/dummy_data_handler/dummy_data_handler.py +12 -13
  25. mindsdb/integrations/handlers/google_books_handler/google_books_handler.py +45 -44
  26. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_handler.py +101 -95
  27. mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_handler.py +129 -129
  28. mindsdb/integrations/handlers/google_fit_handler/google_fit_handler.py +59 -43
  29. mindsdb/integrations/handlers/google_search_handler/google_search_handler.py +38 -39
  30. mindsdb/integrations/handlers/informix_handler/informix_handler.py +5 -18
  31. mindsdb/integrations/handlers/maxdb_handler/maxdb_handler.py +22 -28
  32. mindsdb/integrations/handlers/monetdb_handler/monetdb_handler.py +3 -7
  33. mindsdb/integrations/handlers/mongodb_handler/mongodb_handler.py +53 -67
  34. mindsdb/integrations/handlers/mongodb_handler/requirements.txt +1 -0
  35. mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_ast.py +43 -68
  36. mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_parser.py +17 -25
  37. mindsdb/{api/mongo/utilities → integrations/handlers/mongodb_handler/utils}/mongodb_query.py +10 -16
  38. mindsdb/integrations/handlers/mongodb_handler/utils/mongodb_render.py +43 -69
  39. mindsdb/integrations/libs/base.py +1 -1
  40. mindsdb/interfaces/agents/constants.py +17 -2
  41. mindsdb/interfaces/agents/langchain_agent.py +83 -18
  42. mindsdb/interfaces/knowledge_base/controller.py +3 -1
  43. mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +7 -1
  44. mindsdb/interfaces/skills/skill_tool.py +7 -1
  45. mindsdb/interfaces/skills/sql_agent.py +6 -2
  46. mindsdb/utilities/config.py +3 -155
  47. mindsdb/utilities/fs.py +10 -4
  48. mindsdb/utilities/log.py +0 -25
  49. mindsdb/utilities/starters.py +0 -39
  50. {mindsdb-25.8.2.0.dist-info → mindsdb-25.9.1.0.dist-info}/METADATA +265 -263
  51. {mindsdb-25.8.2.0.dist-info → mindsdb-25.9.1.0.dist-info}/RECORD +54 -98
  52. mindsdb/api/a2a/__main__.py +0 -144
  53. mindsdb/api/a2a/run_a2a.py +0 -86
  54. mindsdb/api/common/check_auth.py +0 -42
  55. mindsdb/api/http/gunicorn_wrapper.py +0 -17
  56. mindsdb/api/mcp/start.py +0 -205
  57. mindsdb/api/mongo/__init__.py +0 -0
  58. mindsdb/api/mongo/classes/__init__.py +0 -5
  59. mindsdb/api/mongo/classes/query_sql.py +0 -19
  60. mindsdb/api/mongo/classes/responder.py +0 -45
  61. mindsdb/api/mongo/classes/responder_collection.py +0 -34
  62. mindsdb/api/mongo/classes/scram.py +0 -86
  63. mindsdb/api/mongo/classes/session.py +0 -23
  64. mindsdb/api/mongo/functions/__init__.py +0 -19
  65. mindsdb/api/mongo/responders/__init__.py +0 -73
  66. mindsdb/api/mongo/responders/add_shard.py +0 -13
  67. mindsdb/api/mongo/responders/aggregate.py +0 -90
  68. mindsdb/api/mongo/responders/buildinfo.py +0 -17
  69. mindsdb/api/mongo/responders/coll_stats.py +0 -63
  70. mindsdb/api/mongo/responders/company_id.py +0 -25
  71. mindsdb/api/mongo/responders/connection_status.py +0 -22
  72. mindsdb/api/mongo/responders/count.py +0 -21
  73. mindsdb/api/mongo/responders/db_stats.py +0 -32
  74. mindsdb/api/mongo/responders/delete.py +0 -105
  75. mindsdb/api/mongo/responders/describe.py +0 -23
  76. mindsdb/api/mongo/responders/end_sessions.py +0 -13
  77. mindsdb/api/mongo/responders/find.py +0 -175
  78. mindsdb/api/mongo/responders/get_cmd_line_opts.py +0 -18
  79. mindsdb/api/mongo/responders/get_free_monitoring_status.py +0 -14
  80. mindsdb/api/mongo/responders/get_parameter.py +0 -23
  81. mindsdb/api/mongo/responders/getlog.py +0 -14
  82. mindsdb/api/mongo/responders/host_info.py +0 -28
  83. mindsdb/api/mongo/responders/insert.py +0 -270
  84. mindsdb/api/mongo/responders/is_master.py +0 -20
  85. mindsdb/api/mongo/responders/is_master_lower.py +0 -13
  86. mindsdb/api/mongo/responders/list_collections.py +0 -55
  87. mindsdb/api/mongo/responders/list_databases.py +0 -37
  88. mindsdb/api/mongo/responders/list_indexes.py +0 -22
  89. mindsdb/api/mongo/responders/ping.py +0 -13
  90. mindsdb/api/mongo/responders/recv_chunk_start.py +0 -13
  91. mindsdb/api/mongo/responders/replsetgetstatus.py +0 -13
  92. mindsdb/api/mongo/responders/sasl_continue.py +0 -34
  93. mindsdb/api/mongo/responders/sasl_start.py +0 -33
  94. mindsdb/api/mongo/responders/update_range_deletions.py +0 -12
  95. mindsdb/api/mongo/responders/whatsmyuri.py +0 -18
  96. mindsdb/api/mongo/server.py +0 -388
  97. mindsdb/api/mongo/start.py +0 -15
  98. mindsdb/api/mongo/utilities/__init__.py +0 -0
  99. {mindsdb-25.8.2.0.dist-info → mindsdb-25.9.1.0.dist-info}/WHEEL +0 -0
  100. {mindsdb-25.8.2.0.dist-info → mindsdb-25.9.1.0.dist-info}/licenses/LICENSE +0 -0
  101. {mindsdb-25.8.2.0.dist-info → mindsdb-25.9.1.0.dist-info}/top_level.txt +0 -0
@@ -19,9 +19,10 @@ logger = log.getLogger(__name__)
19
19
 
20
20
  class GoogleSearchConsoleHandler(APIHandler):
21
21
  """
22
- A class for handling connections and interactions with the Google Search Console API.
22
+ A class for handling connections and interactions with the Google Search Console API.
23
23
  """
24
- name = 'google_search'
24
+
25
+ name = "google_search"
25
26
 
26
27
  def __init__(self, name: str, **kwargs):
27
28
  """
@@ -33,19 +34,21 @@ class GoogleSearchConsoleHandler(APIHandler):
33
34
  super().__init__(name)
34
35
  self.token = None
35
36
  self.service = None
36
- self.connection_data = kwargs.get('connection_data', {})
37
- self.fs_storage = kwargs['file_storage']
38
- self.credentials_file = self.connection_data.get('credentials', 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)
39
40
  self.credentials = None
40
- self.scopes = ['https://www.googleapis.com/auth/webmasters.readonly',
41
- 'https://www.googleapis.com/auth/webmasters']
41
+ self.scopes = [
42
+ "https://www.googleapis.com/auth/webmasters.readonly",
43
+ "https://www.googleapis.com/auth/webmasters",
44
+ ]
42
45
  self.is_connected = False
43
46
  analytics = SearchAnalyticsTable(self)
44
47
  self.analytics = analytics
45
- self._register_table('Analytics', analytics)
48
+ self._register_table("Analytics", analytics)
46
49
  sitemaps = SiteMapsTable(self)
47
50
  self.sitemaps = sitemaps
48
- self._register_table('Sitemaps', sitemaps)
51
+ self._register_table("Sitemaps", sitemaps)
49
52
 
50
53
  def connect(self):
51
54
  """
@@ -59,7 +62,7 @@ class GoogleSearchConsoleHandler(APIHandler):
59
62
  return self.service
60
63
  if self.credentials_file:
61
64
  try:
62
- json_str_bytes = self.fs_storage.file_get('token_search.json')
65
+ json_str_bytes = self.fs_storage.file_get("token_search.json")
63
66
  json_str = json_str_bytes.decode()
64
67
  self.credentials = Credentials.from_authorized_user_info(info=json.loads(json_str), scopes=self.scopes)
65
68
  except Exception:
@@ -69,13 +72,12 @@ class GoogleSearchConsoleHandler(APIHandler):
69
72
  if self.credentials and self.credentials.expired and self.credentials.refresh_token:
70
73
  self.credentials.refresh(Request())
71
74
  else:
72
- self.credentials = Credentials.from_authorized_user_file(
73
- self.credentials_file, scopes=self.scopes)
75
+ self.credentials = Credentials.from_authorized_user_file(self.credentials_file, scopes=self.scopes)
74
76
  # Save the credentials for the next run
75
77
  json_str = self.credentials.to_json()
76
- self.fs_storage.file_set('token_search.json', json_str.encode())
78
+ self.fs_storage.file_set("token_search.json", json_str.encode())
77
79
 
78
- self.service = build('webmasters', 'v3', credentials=self.credentials)
80
+ self.service = build("webmasters", "v3", credentials=self.credentials)
79
81
  return self.service
80
82
 
81
83
  def check_connection(self) -> StatusResponse:
@@ -90,7 +92,7 @@ class GoogleSearchConsoleHandler(APIHandler):
90
92
  self.connect()
91
93
  response.success = True
92
94
  except Exception as e:
93
- logger.error(f'Error connecting to Google Search Console API: {e}!')
95
+ logger.error(f"Error connecting to Google Search Console API: {e}!")
94
96
  response.error_message = e
95
97
 
96
98
  self.is_connected = response.success
@@ -101,7 +103,7 @@ class GoogleSearchConsoleHandler(APIHandler):
101
103
  Receive raw query and act upon it somehow.
102
104
  Args:
103
105
  query (Any): query in native format (str for sql databases,
104
- dict for mongo, api's json etc)
106
+ api's json etc)
105
107
  Returns:
106
108
  HandlerResponse
107
109
  """
@@ -109,10 +111,7 @@ class GoogleSearchConsoleHandler(APIHandler):
109
111
 
110
112
  df = self.call_application_api(method_name, params)
111
113
 
112
- return Response(
113
- RESPONSE_TYPE.TABLE,
114
- data_frame=df
115
- )
114
+ return Response(RESPONSE_TYPE.TABLE, data_frame=df)
116
115
 
117
116
  def get_traffic_data(self, params: dict = None) -> DataFrame:
118
117
  """
@@ -123,14 +122,14 @@ class GoogleSearchConsoleHandler(APIHandler):
123
122
  DataFrame
124
123
  """
125
124
  service = self.connect()
126
- accepted_params = ['start_date', 'end_date', 'dimensions', 'row_limit', 'aggregation_type']
125
+ accepted_params = ["start_date", "end_date", "dimensions", "row_limit", "aggregation_type"]
127
126
  search_analytics_query_request = {
128
127
  key: value for key, value in params.items() if key in accepted_params and value is not None
129
128
  }
130
- response = service.searchanalytics(). \
131
- query(siteUrl=params['siteUrl'], body=search_analytics_query_request). \
132
- execute()
133
- df = pd.DataFrame(response['rows'], columns=self.analytics.get_columns())
129
+ response = (
130
+ service.searchanalytics().query(siteUrl=params["siteUrl"], body=search_analytics_query_request).execute()
131
+ )
132
+ df = pd.DataFrame(response["rows"], columns=self.analytics.get_columns())
134
133
  return df
135
134
 
136
135
  def get_sitemaps(self, params: dict = None) -> DataFrame:
@@ -142,18 +141,18 @@ class GoogleSearchConsoleHandler(APIHandler):
142
141
  DataFrame
143
142
  """
144
143
  service = self.connect()
145
- if params['sitemapIndex']:
146
- response = service.sitemaps().list(siteUrl=params['siteUrl'], sitemapIndex=params['sitemapIndex']).execute()
144
+ if params["sitemapIndex"]:
145
+ response = service.sitemaps().list(siteUrl=params["siteUrl"], sitemapIndex=params["sitemapIndex"]).execute()
147
146
  else:
148
- response = service.sitemaps().list(siteUrl=params['siteUrl']).execute()
149
- df = pd.DataFrame(response['sitemap'], columns=self.sitemaps.get_columns())
147
+ response = service.sitemaps().list(siteUrl=params["siteUrl"]).execute()
148
+ df = pd.DataFrame(response["sitemap"], columns=self.sitemaps.get_columns())
150
149
 
151
150
  # Get as many sitemaps as indicated by the row_limit parameter
152
- if params['row_limit']:
153
- if params['row_limit'] > len(df):
151
+ if params["row_limit"]:
152
+ if params["row_limit"] > len(df):
154
153
  row_limit = len(df)
155
154
  else:
156
- row_limit = params['row_limit']
155
+ row_limit = params["row_limit"]
157
156
 
158
157
  df = df[:row_limit]
159
158
 
@@ -168,7 +167,7 @@ class GoogleSearchConsoleHandler(APIHandler):
168
167
  DataFrame
169
168
  """
170
169
  service = self.connect()
171
- response = service.sitemaps().submit(siteUrl=params['siteUrl'], feedpath=params['feedpath']).execute()
170
+ response = service.sitemaps().submit(siteUrl=params["siteUrl"], feedpath=params["feedpath"]).execute()
172
171
  df = pd.DataFrame(response, columns=self.sitemaps.get_columns())
173
172
  return df
174
173
 
@@ -181,7 +180,7 @@ class GoogleSearchConsoleHandler(APIHandler):
181
180
  DataFrame
182
181
  """
183
182
  service = self.connect()
184
- response = service.sitemaps().delete(siteUrl=params['siteUrl'], feedpath=params['feedpath']).execute()
183
+ response = service.sitemaps().delete(siteUrl=params["siteUrl"], feedpath=params["feedpath"]).execute()
185
184
  df = pd.DataFrame(response, columns=self.sitemaps.get_columns())
186
185
  return df
187
186
 
@@ -194,13 +193,13 @@ class GoogleSearchConsoleHandler(APIHandler):
194
193
  Returns:
195
194
  DataFrame
196
195
  """
197
- if method_name == 'get_traffic_data':
196
+ if method_name == "get_traffic_data":
198
197
  return self.get_traffic_data(params)
199
- elif method_name == 'get_sitemaps':
198
+ elif method_name == "get_sitemaps":
200
199
  return self.get_sitemaps(params)
201
- elif method_name == 'submit_sitemap':
200
+ elif method_name == "submit_sitemap":
202
201
  return self.submit_sitemap(params)
203
- elif method_name == 'delete_sitemap':
202
+ elif method_name == "delete_sitemap":
204
203
  return self.delete_sitemap(params)
205
204
  else:
206
- raise NotImplementedError(f'Unknown method {method_name}')
205
+ raise NotImplementedError(f"Unknown method {method_name}")
@@ -21,7 +21,6 @@ logger = log.getLogger(__name__)
21
21
 
22
22
 
23
23
  class InformixHandler(DatabaseHandler):
24
-
25
24
  name = "informix"
26
25
 
27
26
  def __init__(self, name: str, connection_data: Optional[dict], **kwargs):
@@ -35,11 +34,7 @@ class InformixHandler(DatabaseHandler):
35
34
 
36
35
  self.kwargs = kwargs
37
36
  self.parser = parse_sql
38
- self.loging_enabled = (
39
- connection_data["loging_enabled"]
40
- if "loging_enabled" in connection_data
41
- else True
42
- )
37
+ self.loging_enabled = connection_data["loging_enabled"] if "loging_enabled" in connection_data else True
43
38
  self.server = connection_data["server"]
44
39
  self.database = connection_data["database"]
45
40
  self.user = connection_data["user"]
@@ -47,9 +42,7 @@ class InformixHandler(DatabaseHandler):
47
42
  self.schemaName = connection_data["schema_name"]
48
43
  self.host = connection_data["host"]
49
44
  self.port = connection_data["port"]
50
- self.connString = (
51
- "SERVER={0};" "DATABASE={1};" "HOST={2};" "PORT={3};" "UID={4};" "PWD={5};"
52
- ).format(
45
+ self.connString = ("SERVER={0};DATABASE={1};HOST={2};PORT={3};UID={4};PWD={5};").format(
53
46
  self.server, self.database, self.host, self.port, self.user, self.password
54
47
  )
55
48
 
@@ -115,7 +108,7 @@ class InformixHandler(DatabaseHandler):
115
108
  """Receive raw query and act upon it somehow.
116
109
  Args:
117
110
  query (Any): query in native format (str for sql databases,
118
- dict for mongo, etc)
111
+ etc)
119
112
  Returns:
120
113
  HandlerResponse
121
114
  """
@@ -129,9 +122,7 @@ class InformixHandler(DatabaseHandler):
129
122
  result = cur.fetchall()
130
123
  response = Response(
131
124
  RESPONSE_TYPE.TABLE,
132
- data_frame=pd.DataFrame(
133
- result, columns=[x[0] for x in cur.description]
134
- ),
125
+ data_frame=pd.DataFrame(result, columns=[x[0] for x in cur.description]),
135
126
  )
136
127
  else:
137
128
  response = Response(RESPONSE_TYPE.OK)
@@ -179,11 +170,7 @@ class InformixHandler(DatabaseHandler):
179
170
  response = Response(
180
171
  RESPONSE_TYPE.TABLE,
181
172
  data_frame=pd.DataFrame(
182
- [
183
- x["TABLE_NAME"]
184
- for x in result
185
- if x["TABLE_SCHEM"] == self.schemaName
186
- ],
173
+ [x["TABLE_NAME"] for x in result if x["TABLE_SCHEM"] == self.schemaName],
187
174
  columns=["TABLE_NAME"],
188
175
  ),
189
176
  )
@@ -9,7 +9,8 @@ from mindsdb.utilities import log
9
9
  from mindsdb.integrations.libs.response import (
10
10
  HandlerStatusResponse as StatusResponse,
11
11
  HandlerResponse as Response,
12
- RESPONSE_TYPE, HandlerResponse
12
+ RESPONSE_TYPE,
13
+ HandlerResponse,
13
14
  )
14
15
  import pandas as pd
15
16
  import jaydebeapi as jd
@@ -19,13 +20,13 @@ logger = log.getLogger(__name__)
19
20
 
20
21
  class MaxDBHandler(DatabaseHandler):
21
22
  """
22
- This handler handles connection and execution of the SAP MaxDB statements.
23
- """
23
+ This handler handles connection and execution of the SAP MaxDB statements.
24
+ """
24
25
 
25
- name = 'maxdb'
26
+ name = "maxdb"
26
27
 
27
28
  def __init__(self, name: str, connection_data: Optional[dict], **kwargs):
28
- """ Initialize the handler
29
+ """Initialize the handler
29
30
  Args:
30
31
  name (str): name of particular handler instance
31
32
  connection_data (dict): parameters for connecting to the database
@@ -35,12 +36,12 @@ class MaxDBHandler(DatabaseHandler):
35
36
  self.kwargs = kwargs
36
37
  self.parser = parse_sql
37
38
  self.connection_config = connection_data
38
- self.database = connection_data['database']
39
- self.host = connection_data['host']
40
- self.port = connection_data['port']
41
- self.user = connection_data['user']
42
- self.password = connection_data['password']
43
- self.jdbc_location = connection_data['jdbc_location']
39
+ self.database = connection_data["database"]
40
+ self.host = connection_data["host"]
41
+ self.port = connection_data["port"]
42
+ self.user = connection_data["user"]
43
+ self.password = connection_data["password"]
44
+ self.jdbc_location = connection_data["jdbc_location"]
44
45
  self.connection = None
45
46
  self.is_connected = False
46
47
 
@@ -61,14 +62,14 @@ class MaxDBHandler(DatabaseHandler):
61
62
  return self.connection
62
63
 
63
64
  jdbc_url = f"jdbc:sapdb://{self.host}:{self.port}/{self.database}"
64
- jdbc_class = 'com.sap.dbtech.jdbc.DriverSapDB'
65
+ jdbc_class = "com.sap.dbtech.jdbc.DriverSapDB"
65
66
 
66
67
  self.connection = jd.connect(jdbc_class, jdbc_url, [self.user, self.password], self.jdbc_location)
67
68
  self.is_connected = True
68
69
  return self.connection
69
70
 
70
71
  def disconnect(self):
71
- """ Close any existing connections
72
+ """Close any existing connections
72
73
  Should switch self.is_connected.
73
74
  """
74
75
  if self.is_connected is False:
@@ -82,7 +83,7 @@ class MaxDBHandler(DatabaseHandler):
82
83
  return
83
84
 
84
85
  def check_connection(self) -> StatusResponse:
85
- """ Check connection to the handler
86
+ """Check connection to the handler
86
87
  Returns:
87
88
  HandlerStatusResponse
88
89
  """
@@ -93,7 +94,7 @@ class MaxDBHandler(DatabaseHandler):
93
94
  self.connect()
94
95
  response.success = True
95
96
  except Exception as e:
96
- logger.error(f'Error connecting to database {self.database}, {e}!')
97
+ logger.error(f"Error connecting to database {self.database}, {e}!")
97
98
  response.error_message = str(e)
98
99
  finally:
99
100
  if response.success is True and need_to_close:
@@ -107,7 +108,7 @@ class MaxDBHandler(DatabaseHandler):
107
108
  """Receive raw query and act upon it somehow.
108
109
  Args:
109
110
  query (Any): query in native format (str for sql databases,
110
- dict for mongo, etc)
111
+ etc)
111
112
  Returns:
112
113
  HandlerResponse
113
114
  """
@@ -119,21 +120,14 @@ class MaxDBHandler(DatabaseHandler):
119
120
  if cur.description:
120
121
  result = cur.fetchall()
121
122
  response = Response(
122
- RESPONSE_TYPE.TABLE,
123
- data_frame=pd.DataFrame(
124
- result,
125
- columns=[x[0] for x in cur.description]
126
- )
123
+ RESPONSE_TYPE.TABLE, data_frame=pd.DataFrame(result, columns=[x[0] for x in cur.description])
127
124
  )
128
125
  else:
129
126
  response = Response(RESPONSE_TYPE.OK)
130
127
  self.connection.commit()
131
128
  except Exception as e:
132
- logger.error(f'Error running query: {query} on {self.database}!')
133
- response = Response(
134
- RESPONSE_TYPE.ERROR,
135
- error_message=str(e)
136
- )
129
+ logger.error(f"Error running query: {query} on {self.database}!")
130
+ response = Response(RESPONSE_TYPE.ERROR, error_message=str(e))
137
131
  self.connection.rollback()
138
132
 
139
133
  if need_to_close is True:
@@ -165,7 +159,7 @@ class MaxDBHandler(DatabaseHandler):
165
159
  query = f"SELECT TABLENAME FROM DOMAIN.TABLES WHERE TYPE = 'TABLE' AND SCHEMANAME = '{self.user}'"
166
160
  result = self.native_query(query)
167
161
  df = result.data_frame
168
- result.data_frame = df.rename(columns={df.columns[0]: 'table_name'})
162
+ result.data_frame = df.rename(columns={df.columns[0]: "table_name"})
169
163
  return result
170
164
 
171
165
  def get_columns(self, table_name: str) -> Response:
@@ -182,5 +176,5 @@ class MaxDBHandler(DatabaseHandler):
182
176
  query = f"SELECT COLUMNNAME,DATATYPE FROM DOMAIN.COLUMNS WHERE TABLENAME ='{table_name}'"
183
177
  result = self.native_query(query)
184
178
  df = result.data_frame
185
- result.data_frame = df.rename(columns={'name': 'column_name', 'type': 'data_type'})
179
+ result.data_frame = df.rename(columns={"name": "column_name", "type": "data_type"})
186
180
  return self.native_query(query)
@@ -35,9 +35,7 @@ class MonetDBHandler(DatabaseHandler):
35
35
  self.database = connection_data["database"]
36
36
  self.user = connection_data["user"]
37
37
  self.password = connection_data["password"]
38
- self.schemaName = (
39
- connection_data["schema_name"] if "schema_name" in connection_data else None
40
- )
38
+ self.schemaName = connection_data["schema_name"] if "schema_name" in connection_data else None
41
39
  self.host = connection_data["host"]
42
40
  self.port = connection_data["port"]
43
41
 
@@ -109,7 +107,7 @@ class MonetDBHandler(DatabaseHandler):
109
107
  """Receive raw query and act upon it somehow.
110
108
  Args:
111
109
  query (Any): query in native format (str for sql databases,
112
- dict for mongo, etc)
110
+ etc)
113
111
  Returns:
114
112
  HandlerResponse
115
113
  """
@@ -123,9 +121,7 @@ class MonetDBHandler(DatabaseHandler):
123
121
  result = cur.fetchall()
124
122
  response = Response(
125
123
  RESPONSE_TYPE.TABLE,
126
- data_frame=pd.DataFrame(
127
- result, columns=[x[0] for x in cur.description]
128
- ),
124
+ data_frame=pd.DataFrame(result, columns=[x[0] for x in cur.description]),
129
125
  )
130
126
  else:
131
127
  response = Response(RESPONSE_TYPE.OK)
@@ -10,13 +10,13 @@ from pymongo import MongoClient
10
10
  from pymongo.errors import ServerSelectionTimeoutError, OperationFailure, ConfigurationError, InvalidURI
11
11
  from typing import Text, List, Dict, Any, Union
12
12
 
13
- from mindsdb.api.mongo.utilities.mongodb_query import MongoQuery
14
- from mindsdb.api.mongo.utilities.mongodb_parser import MongodbParser
13
+ from mindsdb.integrations.handlers.mongodb_handler.utils.mongodb_query import MongoQuery
14
+ from mindsdb.integrations.handlers.mongodb_handler.utils.mongodb_parser import MongodbParser
15
15
  from mindsdb.integrations.libs.base import DatabaseHandler
16
16
  from mindsdb.integrations.libs.response import (
17
17
  HandlerStatusResponse as StatusResponse,
18
18
  HandlerResponse as Response,
19
- RESPONSE_TYPE
19
+ RESPONSE_TYPE,
20
20
  )
21
21
  from mindsdb.utilities import log
22
22
  from .utils.mongodb_render import MongodbRender
@@ -31,7 +31,7 @@ class MongoDBHandler(DatabaseHandler):
31
31
  """
32
32
 
33
33
  _SUBSCRIBE_SLEEP_INTERVAL = 0.5
34
- name = 'mongodb'
34
+ name = "mongodb"
35
35
 
36
36
  def __init__(self, name: Text, **kwargs: Any) -> None:
37
37
  """
@@ -42,13 +42,13 @@ class MongoDBHandler(DatabaseHandler):
42
42
  kwargs: Arbitrary keyword arguments including the connection data.
43
43
  """
44
44
  super().__init__(name)
45
- connection_data = kwargs['connection_data']
45
+ connection_data = kwargs["connection_data"]
46
46
  self.host = connection_data.get("host")
47
47
  self.port = int(connection_data.get("port") or 27017)
48
48
  self.user = connection_data.get("username")
49
49
  self.password = connection_data.get("password")
50
- self.database = connection_data.get('database')
51
- self.flatten_level = connection_data.get('flatten_level', 0)
50
+ self.database = connection_data.get("database")
51
+ self.flatten_level = connection_data.get("flatten_level", 0)
52
52
 
53
53
  self.connection = None
54
54
  self.is_connected = False
@@ -72,31 +72,27 @@ class MongoDBHandler(DatabaseHandler):
72
72
  """
73
73
  kwargs = {}
74
74
  if isinstance(self.user, str) and len(self.user) > 0:
75
- kwargs['username'] = self.user
75
+ kwargs["username"] = self.user
76
76
 
77
77
  if isinstance(self.password, str) and len(self.password) > 0:
78
- kwargs['password'] = self.password
78
+ kwargs["password"] = self.password
79
79
 
80
- if re.match(r'/?.*tls=true', self.host.lower()):
81
- kwargs['tls'] = True
80
+ if re.match(r"/?.*tls=true", self.host.lower()):
81
+ kwargs["tls"] = True
82
82
 
83
- if re.match(r'/?.*tls=false', self.host.lower()):
84
- kwargs['tls'] = False
83
+ if re.match(r"/?.*tls=false", self.host.lower()):
84
+ kwargs["tls"] = False
85
85
 
86
86
  try:
87
- connection = MongoClient(
88
- self.host,
89
- port=self.port,
90
- **kwargs
91
- )
87
+ connection = MongoClient(self.host, port=self.port, **kwargs)
92
88
  except InvalidURI as invalid_uri_error:
93
- logger.error(f'Invalid URI provided for MongoDB connection: {invalid_uri_error}!')
89
+ logger.error(f"Invalid URI provided for MongoDB connection: {invalid_uri_error}!")
94
90
  raise
95
91
  except ConfigurationError as config_error:
96
- logger.error(f'Configuration error connecting to MongoDB: {config_error}!')
92
+ logger.error(f"Configuration error connecting to MongoDB: {config_error}!")
97
93
  raise
98
94
  except Exception as unknown_error:
99
- logger.error(f'Unknown error connecting to MongoDB: {unknown_error}!')
95
+ logger.error(f"Unknown error connecting to MongoDB: {unknown_error}!")
100
96
  raise
101
97
 
102
98
  # Get the database name from the connection if it's not provided.
@@ -107,7 +103,9 @@ class MongoDBHandler(DatabaseHandler):
107
103
  self.connection = connection
108
104
  return self.connection
109
105
 
110
- def subscribe(self, stop_event: threading.Event, callback: callable, table_name: Text, columns: List = None, **kwargs: Any) -> None:
106
+ def subscribe(
107
+ self, stop_event: threading.Event, callback: callable, table_name: Text, columns: List = None, **kwargs: Any
108
+ ) -> None:
111
109
  """
112
110
  Subscribes to changes in a MongoDB collection and calls the provided callback function when changes occur.
113
111
 
@@ -131,26 +129,26 @@ class MongoDBHandler(DatabaseHandler):
131
129
  time.sleep(self._SUBSCRIBE_SLEEP_INTERVAL)
132
130
  continue
133
131
 
134
- _id = res['documentKey']['_id']
135
- if res['operationType'] == 'insert':
132
+ _id = res["documentKey"]["_id"]
133
+ if res["operationType"] == "insert":
136
134
  if columns is not None:
137
- updated_columns = set(res['fullDocument'].keys())
135
+ updated_columns = set(res["fullDocument"].keys())
138
136
  if not set(columns) & set(updated_columns):
139
137
  # Do nothing.
140
138
  continue
141
139
 
142
- callback(row=res['fullDocument'], key={'_id': _id})
140
+ callback(row=res["fullDocument"], key={"_id": _id})
143
141
 
144
- if res['operationType'] == 'update':
142
+ if res["operationType"] == "update":
145
143
  if columns is not None:
146
- updated_columns = set(res['updateDescription']['updatedFields'].keys())
144
+ updated_columns = set(res["updateDescription"]["updatedFields"].keys())
147
145
  if not set(columns) & set(updated_columns):
148
146
  # Do nothing.
149
147
  continue
150
148
 
151
149
  # Get the full document.
152
- full_doc = con[self.database][table_name].find_one(res['documentKey'])
153
- callback(row=full_doc, key={'_id': _id})
150
+ full_doc = con[self.database][table_name].find_one(res["documentKey"])
151
+ callback(row=full_doc, key={"_id": _id})
154
152
 
155
153
  def disconnect(self) -> None:
156
154
  """
@@ -178,14 +176,20 @@ class MongoDBHandler(DatabaseHandler):
178
176
 
179
177
  # Check if the database exists.
180
178
  if self.database not in con.list_database_names():
181
- raise ValueError(f'Database {self.database} not found!')
179
+ raise ValueError(f"Database {self.database} not found!")
182
180
 
183
181
  response.success = True
184
- except (InvalidURI, ServerSelectionTimeoutError, OperationFailure, ConfigurationError, ValueError) as known_error:
185
- logger.error(f'Error connecting to MongoDB {self.database}, {known_error}!')
182
+ except (
183
+ InvalidURI,
184
+ ServerSelectionTimeoutError,
185
+ OperationFailure,
186
+ ConfigurationError,
187
+ ValueError,
188
+ ) as known_error:
189
+ logger.error(f"Error connecting to MongoDB {self.database}, {known_error}!")
186
190
  response.error_message = str(known_error)
187
191
  except Exception as unknown_error:
188
- logger.error(f'Unknown error connecting to MongoDB {self.database}, {unknown_error}!')
192
+ logger.error(f"Unknown error connecting to MongoDB {self.database}, {unknown_error}!")
189
193
  response.error_message = str(unknown_error)
190
194
 
191
195
  if response.success and need_to_close:
@@ -211,13 +215,10 @@ class MongoDBHandler(DatabaseHandler):
211
215
 
212
216
  if isinstance(query, dict):
213
217
  # Fallback for the previous API.
214
- mquery = MongoQuery(query['collection'])
218
+ mquery = MongoQuery(query["collection"])
215
219
 
216
- for c in query['call']:
217
- mquery.add_step({
218
- 'method': c['method'],
219
- 'args': c['args']
220
- })
220
+ for c in query["call"]:
221
+ mquery.add_step({"method": c["method"], "args": c["args"]})
221
222
 
222
223
  query = mquery
223
224
 
@@ -229,16 +230,15 @@ class MongoDBHandler(DatabaseHandler):
229
230
  # Check if the collection exists.
230
231
  if collection not in con[database].list_collection_names():
231
232
  return Response(
232
- RESPONSE_TYPE.ERROR,
233
- error_message=f'Collection {collection} not found in database {database}!'
233
+ RESPONSE_TYPE.ERROR, error_message=f"Collection {collection} not found in database {database}!"
234
234
  )
235
235
 
236
236
  try:
237
237
  cursor = con[database][collection]
238
238
 
239
239
  for step in query.pipeline:
240
- fnc = getattr(cursor, step['method'])
241
- cursor = fnc(*step['args'])
240
+ fnc = getattr(cursor, step["method"])
241
+ cursor = fnc(*step["args"])
242
242
 
243
243
  result = []
244
244
  if not isinstance(cursor, pymongo.results.UpdateResult):
@@ -254,16 +254,10 @@ class MongoDBHandler(DatabaseHandler):
254
254
  columns = list(self.get_columns(collection).data_frame.Field)
255
255
  df = pd.DataFrame([], columns=columns)
256
256
 
257
- response = Response(
258
- RESPONSE_TYPE.TABLE,
259
- df
260
- )
257
+ response = Response(RESPONSE_TYPE.TABLE, df)
261
258
  except Exception as e:
262
- logger.error(f'Error running query: {query} on {self.database}.{collection}!')
263
- response = Response(
264
- RESPONSE_TYPE.ERROR,
265
- error_message=str(e)
266
- )
259
+ logger.error(f"Error running query: {query} on {self.database}.{collection}!")
260
+ response = Response(RESPONSE_TYPE.ERROR, error_message=str(e))
267
261
 
268
262
  return response
269
263
 
@@ -289,7 +283,7 @@ class MongoDBHandler(DatabaseHandler):
289
283
  if level > 0:
290
284
  if isinstance(v, dict):
291
285
  for k2, v2 in self.flatten(v, level=level - 1).items():
292
- add[f'{k}.{k2}'] = v2
286
+ add[f"{k}.{k2}"] = v2
293
287
  del_keys.append(k)
294
288
 
295
289
  if add:
@@ -324,15 +318,10 @@ class MongoDBHandler(DatabaseHandler):
324
318
  """
325
319
  con = self.connect()
326
320
  collections = con[self.database].list_collection_names()
327
- collections_ar = [
328
- [i] for i in collections
329
- ]
330
- df = pd.DataFrame(collections_ar, columns=['table_name'])
321
+ collections_ar = [[i] for i in collections]
322
+ df = pd.DataFrame(collections_ar, columns=["table_name"])
331
323
 
332
- response = Response(
333
- RESPONSE_TYPE.TABLE,
334
- df
335
- )
324
+ response = Response(RESPONSE_TYPE.TABLE, df)
336
325
 
337
326
  return response
338
327
 
@@ -363,10 +352,7 @@ class MongoDBHandler(DatabaseHandler):
363
352
  for k, v in record.items():
364
353
  data.append([k, type(v).__name__])
365
354
 
366
- df = pd.DataFrame(data, columns=['Field', 'Type'])
355
+ df = pd.DataFrame(data, columns=["Field", "Type"])
367
356
 
368
- response = Response(
369
- RESPONSE_TYPE.TABLE,
370
- df
371
- )
357
+ response = Response(RESPONSE_TYPE.TABLE, df)
372
358
  return response
@@ -0,0 +1 @@
1
+ pymongo == 4.8.0