MindsDB 25.9.2.0a1__py3-none-any.whl → 25.9.3rc1__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 (116) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/__main__.py +39 -20
  3. mindsdb/api/a2a/agent.py +7 -9
  4. mindsdb/api/a2a/common/server/server.py +3 -3
  5. mindsdb/api/a2a/common/server/task_manager.py +4 -4
  6. mindsdb/api/a2a/task_manager.py +15 -17
  7. mindsdb/api/common/middleware.py +9 -11
  8. mindsdb/api/executor/command_executor.py +2 -4
  9. mindsdb/api/executor/datahub/datanodes/datanode.py +2 -2
  10. mindsdb/api/executor/datahub/datanodes/integration_datanode.py +100 -48
  11. mindsdb/api/executor/datahub/datanodes/project_datanode.py +8 -4
  12. mindsdb/api/executor/datahub/datanodes/system_tables.py +1 -1
  13. mindsdb/api/executor/exceptions.py +29 -10
  14. mindsdb/api/executor/planner/plan_join.py +17 -3
  15. mindsdb/api/executor/sql_query/sql_query.py +74 -74
  16. mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +1 -2
  17. mindsdb/api/executor/sql_query/steps/subselect_step.py +0 -1
  18. mindsdb/api/executor/utilities/functions.py +6 -6
  19. mindsdb/api/executor/utilities/sql.py +32 -16
  20. mindsdb/api/http/gui.py +5 -11
  21. mindsdb/api/http/initialize.py +8 -10
  22. mindsdb/api/http/namespaces/agents.py +10 -12
  23. mindsdb/api/http/namespaces/analysis.py +13 -20
  24. mindsdb/api/http/namespaces/auth.py +1 -1
  25. mindsdb/api/http/namespaces/config.py +15 -11
  26. mindsdb/api/http/namespaces/databases.py +140 -201
  27. mindsdb/api/http/namespaces/file.py +15 -4
  28. mindsdb/api/http/namespaces/handlers.py +7 -2
  29. mindsdb/api/http/namespaces/knowledge_bases.py +8 -7
  30. mindsdb/api/http/namespaces/models.py +94 -126
  31. mindsdb/api/http/namespaces/projects.py +13 -22
  32. mindsdb/api/http/namespaces/sql.py +33 -25
  33. mindsdb/api/http/namespaces/tab.py +27 -37
  34. mindsdb/api/http/namespaces/views.py +1 -1
  35. mindsdb/api/http/start.py +14 -8
  36. mindsdb/api/mcp/__init__.py +2 -1
  37. mindsdb/api/mysql/mysql_proxy/executor/mysql_executor.py +15 -20
  38. mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +26 -50
  39. mindsdb/api/mysql/mysql_proxy/utilities/__init__.py +0 -1
  40. mindsdb/api/postgres/postgres_proxy/executor/executor.py +6 -13
  41. mindsdb/api/postgres/postgres_proxy/postgres_packets/postgres_packets.py +40 -28
  42. mindsdb/integrations/handlers/byom_handler/byom_handler.py +168 -185
  43. mindsdb/integrations/handlers/file_handler/file_handler.py +7 -0
  44. mindsdb/integrations/handlers/lightwood_handler/functions.py +45 -79
  45. mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +13 -1
  46. mindsdb/integrations/handlers/shopify_handler/shopify_handler.py +25 -12
  47. mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +2 -1
  48. mindsdb/integrations/handlers/statsforecast_handler/requirements.txt +1 -0
  49. mindsdb/integrations/handlers/statsforecast_handler/requirements_extra.txt +1 -0
  50. mindsdb/integrations/handlers/web_handler/urlcrawl_helpers.py +4 -4
  51. mindsdb/integrations/libs/api_handler.py +10 -10
  52. mindsdb/integrations/libs/base.py +4 -4
  53. mindsdb/integrations/libs/llm/utils.py +2 -2
  54. mindsdb/integrations/libs/ml_handler_process/create_engine_process.py +4 -7
  55. mindsdb/integrations/libs/ml_handler_process/func_call_process.py +2 -7
  56. mindsdb/integrations/libs/ml_handler_process/learn_process.py +37 -47
  57. mindsdb/integrations/libs/ml_handler_process/update_engine_process.py +4 -7
  58. mindsdb/integrations/libs/ml_handler_process/update_process.py +2 -7
  59. mindsdb/integrations/libs/process_cache.py +132 -140
  60. mindsdb/integrations/libs/response.py +18 -12
  61. mindsdb/integrations/libs/vectordatabase_handler.py +26 -0
  62. mindsdb/integrations/utilities/files/file_reader.py +6 -7
  63. mindsdb/integrations/utilities/rag/config_loader.py +37 -26
  64. mindsdb/integrations/utilities/rag/rerankers/base_reranker.py +59 -9
  65. mindsdb/integrations/utilities/rag/rerankers/reranker_compressor.py +4 -4
  66. mindsdb/integrations/utilities/rag/retrievers/sql_retriever.py +55 -133
  67. mindsdb/integrations/utilities/rag/settings.py +58 -133
  68. mindsdb/integrations/utilities/rag/splitters/file_splitter.py +5 -15
  69. mindsdb/interfaces/agents/agents_controller.py +2 -1
  70. mindsdb/interfaces/agents/constants.py +0 -2
  71. mindsdb/interfaces/agents/litellm_server.py +34 -58
  72. mindsdb/interfaces/agents/mcp_client_agent.py +10 -10
  73. mindsdb/interfaces/agents/mindsdb_database_agent.py +5 -5
  74. mindsdb/interfaces/agents/run_mcp_agent.py +12 -21
  75. mindsdb/interfaces/chatbot/chatbot_task.py +20 -23
  76. mindsdb/interfaces/chatbot/polling.py +30 -18
  77. mindsdb/interfaces/data_catalog/data_catalog_loader.py +10 -10
  78. mindsdb/interfaces/database/integrations.py +19 -2
  79. mindsdb/interfaces/file/file_controller.py +6 -6
  80. mindsdb/interfaces/functions/controller.py +1 -1
  81. mindsdb/interfaces/functions/to_markdown.py +2 -2
  82. mindsdb/interfaces/jobs/jobs_controller.py +5 -5
  83. mindsdb/interfaces/jobs/scheduler.py +3 -8
  84. mindsdb/interfaces/knowledge_base/controller.py +50 -23
  85. mindsdb/interfaces/knowledge_base/preprocessing/json_chunker.py +40 -61
  86. mindsdb/interfaces/model/model_controller.py +170 -166
  87. mindsdb/interfaces/query_context/context_controller.py +14 -2
  88. mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +6 -4
  89. mindsdb/interfaces/skills/retrieval_tool.py +43 -50
  90. mindsdb/interfaces/skills/skill_tool.py +2 -2
  91. mindsdb/interfaces/skills/sql_agent.py +25 -19
  92. mindsdb/interfaces/storage/fs.py +114 -169
  93. mindsdb/interfaces/storage/json.py +19 -18
  94. mindsdb/interfaces/tabs/tabs_controller.py +49 -72
  95. mindsdb/interfaces/tasks/task_monitor.py +3 -9
  96. mindsdb/interfaces/tasks/task_thread.py +7 -9
  97. mindsdb/interfaces/triggers/trigger_task.py +7 -13
  98. mindsdb/interfaces/triggers/triggers_controller.py +47 -50
  99. mindsdb/migrations/migrate.py +16 -16
  100. mindsdb/utilities/api_status.py +58 -0
  101. mindsdb/utilities/config.py +49 -0
  102. mindsdb/utilities/exception.py +40 -1
  103. mindsdb/utilities/fs.py +0 -1
  104. mindsdb/utilities/hooks/profiling.py +17 -14
  105. mindsdb/utilities/langfuse.py +40 -45
  106. mindsdb/utilities/log.py +272 -0
  107. mindsdb/utilities/ml_task_queue/consumer.py +52 -58
  108. mindsdb/utilities/ml_task_queue/producer.py +26 -30
  109. mindsdb/utilities/render/sqlalchemy_render.py +7 -6
  110. mindsdb/utilities/utils.py +2 -2
  111. {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.9.3rc1.dist-info}/METADATA +269 -264
  112. {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.9.3rc1.dist-info}/RECORD +115 -115
  113. mindsdb/api/mysql/mysql_proxy/utilities/exceptions.py +0 -14
  114. {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.9.3rc1.dist-info}/WHEEL +0 -0
  115. {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.9.3rc1.dist-info}/licenses/LICENSE +0 -0
  116. {mindsdb-25.9.2.0a1.dist-info → mindsdb-25.9.3rc1.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@ from http import HTTPStatus
3
3
  from flask import request
4
4
  from flask_restx import Resource
5
5
  from langchain_text_splitters import MarkdownHeaderTextSplitter
6
+ from mindsdb_sql_parser.ast import Identifier
6
7
 
7
8
  from mindsdb.api.http.namespaces.configs.projects import ns_conf
8
9
  from mindsdb.api.executor.controllers.session_controller import SessionController
@@ -24,12 +25,10 @@ from mindsdb.metrics.metrics import api_endpoint_metrics
24
25
  from mindsdb.interfaces.database.projects import ProjectController
25
26
  from mindsdb.interfaces.knowledge_base.controller import KnowledgeBaseTable
26
27
  from mindsdb.utilities import log
27
- from mindsdb.utilities.exception import EntityNotExistsError
28
+ from mindsdb.utilities.exception import EntityNotExistsError, EntityExistsError
28
29
  from mindsdb.integrations.utilities.rag.settings import DEFAULT_LLM_MODEL, DEFAULT_RAG_PROMPT_TEMPLATE
29
30
 
30
31
 
31
- from mindsdb_sql_parser.ast import Identifier
32
-
33
32
  logger = log.getLogger(__name__)
34
33
 
35
34
 
@@ -133,6 +132,8 @@ class KnowledgeBasesResource(Resource):
133
132
  )
134
133
  except ValueError as e:
135
134
  return http_error(HTTPStatus.BAD_REQUEST, "Invalid preprocessing configuration", str(e))
135
+ except EntityExistsError as e:
136
+ return http_error(HTTPStatus.BAD_REQUEST, "Knowledge base already exists", str(e))
136
137
 
137
138
  return new_kb.as_dict(session.show_secrets), HTTPStatus.CREATED
138
139
 
@@ -241,17 +242,17 @@ class KnowledgeBaseResource(Resource):
241
242
  table.insert_query_result(kb_data["query"], project_name)
242
243
 
243
244
  except ExecutorException as e:
244
- logger.error(f"Error during preprocessing and insertion: {str(e)}")
245
+ logger.exception("Error during preprocessing and insertion:")
245
246
  return http_error(
246
247
  HTTPStatus.BAD_REQUEST,
247
248
  "Invalid SELECT query",
248
- f'Executing "query" failed. Needs to be a valid SELECT statement that returns data: {str(e)}',
249
+ f'Executing "query" failed. Needs to be a valid SELECT statement that returns data: {e}',
249
250
  )
250
251
 
251
252
  except Exception as e:
252
- logger.error(f"Error during preprocessing and insertion: {str(e)}")
253
+ logger.exception("Error during preprocessing and insertion:")
253
254
  return http_error(
254
- HTTPStatus.BAD_REQUEST, "Preprocessing Error", f"Error during preprocessing and insertion: {str(e)}"
255
+ HTTPStatus.BAD_REQUEST, "Preprocessing Error", f"Error during preprocessing and insertion: {e}"
255
256
  )
256
257
 
257
258
  return "", HTTPStatus.OK
@@ -4,7 +4,6 @@ import json
4
4
 
5
5
  from flask import request
6
6
  from flask_restx import Resource
7
- from sqlalchemy.exc import NoResultFound
8
7
  import pandas as pd
9
8
 
10
9
  from mindsdb.api.http.namespaces.configs.projects import ns_conf
@@ -15,71 +14,65 @@ from mindsdb.interfaces.model.functions import PredictorRecordNotFound
15
14
  from mindsdb.interfaces.storage.db import Predictor
16
15
  from mindsdb_sql_parser import parse_sql
17
16
  from mindsdb_sql_parser.ast.mindsdb import CreatePredictor
17
+ from mindsdb.utilities.exception import EntityNotExistsError
18
+ from mindsdb.utilities import log
18
19
 
20
+ logger = log.getLogger(__name__)
19
21
 
20
- @ns_conf.route('/<project_name>/models')
22
+
23
+ @ns_conf.route("/<project_name>/models")
21
24
  class ModelsList(Resource):
22
- @ns_conf.doc('list_models')
23
- @api_endpoint_metrics('GET', '/models')
25
+ @ns_conf.doc("list_models")
26
+ @api_endpoint_metrics("GET", "/models")
24
27
  def get(self, project_name):
25
- ''' List all models '''
28
+ """List all models"""
26
29
  session = SessionController()
27
30
 
28
31
  try:
29
32
  session.database_controller.get_project(project_name)
30
- except NoResultFound:
31
- return http_error(
32
- HTTPStatus.NOT_FOUND,
33
- 'Project not found',
34
- f'Project name {project_name} does not exist')
33
+ except EntityNotExistsError:
34
+ return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
35
35
 
36
36
  return session.model_controller.get_models(with_versions=True, project_name=project_name)
37
37
 
38
- @ns_conf.doc('train_model')
39
- @api_endpoint_metrics('POST', '/models')
38
+ @ns_conf.doc("train_model")
39
+ @api_endpoint_metrics("POST", "/models")
40
40
  def post(self, project_name):
41
- '''Creates a new model and trains it'''
41
+ """Creates a new model and trains it"""
42
42
  session = SessionController()
43
43
 
44
- if 'query' not in request.json:
45
- return http_error(
46
- HTTPStatus.BAD_REQUEST,
47
- 'Query required',
48
- 'Missing "query" SQL statement')
49
- query = request.json['query']
44
+ if "query" not in request.json:
45
+ return http_error(HTTPStatus.BAD_REQUEST, "Query required", 'Missing "query" SQL statement')
46
+ query = request.json["query"]
50
47
 
51
48
  project_datanode = session.datahub.get(project_name)
52
49
  if project_datanode is None:
53
- return http_error(
54
- HTTPStatus.NOT_FOUND,
55
- 'Project not found',
56
- f'Project name {project_name} does not exist')
50
+ return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
57
51
 
58
52
  try:
59
53
  create_statement = parse_sql(query)
60
54
  except Exception:
61
55
  return http_error(
62
- HTTPStatus.BAD_REQUEST,
63
- 'Invalid query string',
64
- f'SQL CREATE statement is invalid: {query}')
56
+ HTTPStatus.BAD_REQUEST, "Invalid query string", f"SQL CREATE statement is invalid: {query}"
57
+ )
65
58
 
66
59
  if type(create_statement) is not CreatePredictor:
67
60
  return http_error(
68
61
  HTTPStatus.BAD_REQUEST,
69
- 'Invalid CREATE SQL statement',
70
- f'SQL statement is not a CREATE model statement: {query}')
62
+ "Invalid CREATE SQL statement",
63
+ f"SQL statement is not a CREATE model statement: {query}",
64
+ )
71
65
 
72
66
  model_name = create_statement.name.parts[1].lower()
73
67
  try:
74
68
  session.model_controller.get_model(model_name, project_name=project_name)
75
69
  return http_error(
76
- HTTPStatus.CONFLICT,
77
- 'Model already exists',
78
- f'Model with name {model_name} already exists')
70
+ HTTPStatus.CONFLICT, "Model already exists", f"Model with name {model_name} already exists"
71
+ )
79
72
  except PredictorRecordNotFound:
80
73
  pass
81
74
 
82
- ml_integration = 'lightwood'
75
+ ml_integration = "lightwood"
83
76
  if create_statement.using is not None:
84
77
  # Convert using to lowercase
85
78
  create_statement.using = {k.lower(): v for k, v in create_statement.using.items()}
@@ -89,60 +82,55 @@ class ModelsList(Resource):
89
82
  ml_handler = session.integration_controller.get_ml_handler(ml_integration)
90
83
  except Exception:
91
84
  return http_error(
92
- HTTPStatus.NOT_FOUND,
93
- 'ML handler not found',
94
- f'Cannot find ML handler with name {ml_integration}')
85
+ HTTPStatus.NOT_FOUND, "ML handler not found", f"Cannot find ML handler with name {ml_integration}"
86
+ )
95
87
 
96
88
  try:
97
89
  model_df = session.model_controller.create_model(create_statement, ml_handler)
98
90
  # Consistent format with GET /projects/<project_name>/models/<model_name>
99
91
  return {
100
- 'name': model_df.at[0, 'NAME'],
101
- 'accuracy': None,
102
- 'active': model_df.at[0, 'ACTIVE'],
103
- 'version': model_df.at[0, 'VERSION'],
104
- 'status': model_df.at[0, 'STATUS'],
105
- 'predict': model_df.at[0, 'PREDICT'],
106
- 'mindsdb_version': model_df.at[0, 'MINDSDB_VERSION'],
107
- 'error': model_df.at[0, 'ERROR'],
108
- 'fetch_data_query': model_df.at[0, 'SELECT_DATA_QUERY'],
109
- 'problem_definition': model_df.at[0, 'TRAINING_OPTIONS']
92
+ "name": model_df.at[0, "NAME"],
93
+ "accuracy": None,
94
+ "active": model_df.at[0, "ACTIVE"],
95
+ "version": model_df.at[0, "VERSION"],
96
+ "status": model_df.at[0, "STATUS"],
97
+ "predict": model_df.at[0, "PREDICT"],
98
+ "mindsdb_version": model_df.at[0, "MINDSDB_VERSION"],
99
+ "error": model_df.at[0, "ERROR"],
100
+ "fetch_data_query": model_df.at[0, "SELECT_DATA_QUERY"],
101
+ "problem_definition": model_df.at[0, "TRAINING_OPTIONS"],
110
102
  }, HTTPStatus.CREATED
111
103
  except Exception as e:
104
+ logger.exception("Something went wrong while creating and training model")
112
105
  return http_error(
113
106
  HTTPStatus.INTERNAL_SERVER_ERROR,
114
- 'Unable to train model',
115
- f'Something went wrong while creating and training model {model_name}: {e}')
107
+ "Unable to train model",
108
+ f"Something went wrong while creating and training model {model_name}: {e}",
109
+ )
116
110
 
117
111
 
118
- @ns_conf.route('/<project_name>/models/<model_name>')
119
- @ns_conf.param('project_name', 'Name of the project')
120
- @ns_conf.param('model_name', 'Name of the model')
112
+ @ns_conf.route("/<project_name>/models/<model_name>")
113
+ @ns_conf.param("project_name", "Name of the project")
114
+ @ns_conf.param("model_name", "Name of the model")
121
115
  class ModelResource(Resource):
122
- @ns_conf.doc('get_model')
123
- @api_endpoint_metrics('GET', '/models/model')
116
+ @ns_conf.doc("get_model")
117
+ @api_endpoint_metrics("GET", "/models/model")
124
118
  def get(self, project_name, model_name):
125
- '''Get a model by name and version'''
119
+ """Get a model by name and version"""
126
120
  session = SessionController()
127
121
 
128
122
  project_datanode = session.datahub.get(project_name)
129
123
  if project_datanode is None:
130
- return http_error(
131
- HTTPStatus.NOT_FOUND,
132
- 'Project not found',
133
- f'Project name {project_name} does not exist')
124
+ return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
134
125
 
135
126
  name_no_version, version = Predictor.get_name_and_version(model_name)
136
127
  try:
137
128
  return session.model_controller.get_model(name_no_version, version=version, project_name=project_name)
138
129
  except PredictorRecordNotFound:
139
- return http_error(
140
- HTTPStatus.NOT_FOUND,
141
- 'Model not found',
142
- f'Model with name {model_name} not found')
130
+ return http_error(HTTPStatus.NOT_FOUND, "Model not found", f"Model with name {model_name} not found")
143
131
 
144
- @ns_conf.doc('update_model')
145
- @api_endpoint_metrics('PUT', '/models/model')
132
+ @ns_conf.doc("update_model")
133
+ @api_endpoint_metrics("PUT", "/models/model")
146
134
  def put(self, project_name, model_name):
147
135
  """Update model"""
148
136
 
@@ -150,18 +138,14 @@ class ModelResource(Resource):
150
138
 
151
139
  project_datanode = session.datahub.get(project_name)
152
140
  if project_datanode is None:
153
- return http_error(
154
- HTTPStatus.NOT_FOUND,
155
- 'Project not found',
156
- f'Project name {project_name} does not exist')
141
+ return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
157
142
 
158
- if 'problem_definition' not in request.json:
143
+ if "problem_definition" not in request.json:
159
144
  return http_error(
160
- HTTPStatus.BAD_REQUEST,
161
- 'problem_definition required',
162
- 'Missing "problem_definition" field')
145
+ HTTPStatus.BAD_REQUEST, "problem_definition required", 'Missing "problem_definition" field'
146
+ )
163
147
 
164
- problem_definition = request.json['problem_definition']
148
+ problem_definition = request.json["problem_definition"]
165
149
 
166
150
  model_name, version = Predictor.get_name_and_version(model_name)
167
151
 
@@ -174,48 +158,44 @@ class ModelResource(Resource):
174
158
  )
175
159
  return session.model_controller.get_model(model_name, version=version, project_name=project_name)
176
160
 
177
- @ns_conf.doc('delete_model')
178
- @api_endpoint_metrics('DELETE', '/models/model')
161
+ @ns_conf.doc("delete_model")
162
+ @api_endpoint_metrics("DELETE", "/models/model")
179
163
  def delete(self, project_name, model_name):
180
- '''Deletes a model by name'''
164
+ """Deletes a model by name"""
181
165
 
182
166
  session = SessionController()
183
167
 
184
168
  project_datanode = session.datahub.get(project_name)
185
169
  if project_datanode is None:
186
- return http_error(
187
- HTTPStatus.NOT_FOUND,
188
- 'Project not found',
189
- f'Project name {project_name} does not exist')
170
+ return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
190
171
 
191
172
  name_no_version, version = Predictor.get_name_and_version(model_name)
192
173
  try:
193
174
  session.model_controller.get_model(name_no_version, version=version, project_name=project_name)
194
175
  except PredictorRecordNotFound:
195
- return http_error(
196
- HTTPStatus.NOT_FOUND,
197
- 'Model not found',
198
- f'Model with name {model_name} not found')
176
+ return http_error(HTTPStatus.NOT_FOUND, "Model not found", f"Model with name {model_name} not found")
199
177
 
200
178
  try:
201
179
  session.model_controller.delete_model(name_no_version, project_name, version=version)
202
180
  except Exception as e:
181
+ logger.exception(f"Something went wrong while deleting model '{model_name}'")
203
182
  return http_error(
204
183
  HTTPStatus.INTERNAL_SERVER_ERROR,
205
- 'Error deleting model',
206
- f'Something went wrong while deleting {model_name}: {e}')
184
+ "Error deleting model",
185
+ f"Something went wrong while deleting {model_name}: {e}",
186
+ )
207
187
 
208
- return '', HTTPStatus.NO_CONTENT
188
+ return "", HTTPStatus.NO_CONTENT
209
189
 
210
190
 
211
- @ns_conf.route('/<project_name>/models/<model_name>/predict')
212
- @ns_conf.param('project_name', 'Name of the project')
213
- @ns_conf.param('model_name', 'Name of the model')
191
+ @ns_conf.route("/<project_name>/models/<model_name>/predict")
192
+ @ns_conf.param("project_name", "Name of the project")
193
+ @ns_conf.param("model_name", "Name of the model")
214
194
  class ModelPredict(Resource):
215
- @ns_conf.doc('post_model_predict')
216
- @api_endpoint_metrics('POST', '/models/model/predict')
195
+ @ns_conf.doc("post_model_predict")
196
+ @api_endpoint_metrics("POST", "/models/model/predict")
217
197
  def post(self, project_name, model_name):
218
- '''Call prediction'''
198
+ """Call prediction"""
219
199
 
220
200
  name_no_version, version = Predictor.get_name_and_version(model_name)
221
201
 
@@ -223,23 +203,19 @@ class ModelPredict(Resource):
223
203
  project_datanode = session.datahub.get(project_name)
224
204
  if project_datanode is None:
225
205
  return http_error(
226
- HTTPStatus.NOT_FOUND,
227
- 'Project not found',
228
- f'Project with name {project_name} does not exist')
206
+ HTTPStatus.NOT_FOUND, "Project not found", f"Project with name {project_name} does not exist"
207
+ )
229
208
 
230
209
  try:
231
210
  session.model_controller.get_model(name_no_version, version=version, project_name=project_name)
232
211
  except PredictorRecordNotFound:
233
- return http_error(
234
- HTTPStatus.NOT_FOUND,
235
- 'Model not found',
236
- f'Model with name {model_name} not found')
212
+ return http_error(HTTPStatus.NOT_FOUND, "Model not found", f"Model with name {model_name} not found")
237
213
 
238
- data = request.json['data']
214
+ data = request.json["data"]
239
215
  if isinstance(data, str):
240
216
  # Support object or serialized object.
241
217
  data = json.loads(data)
242
- params = request.json.get('params')
218
+ params = request.json.get("params")
243
219
 
244
220
  predictions = project_datanode.predict(
245
221
  model_name=name_no_version,
@@ -248,50 +224,42 @@ class ModelPredict(Resource):
248
224
  params=params,
249
225
  )
250
226
 
251
- return predictions.to_dict('records')
227
+ return predictions.to_dict("records")
252
228
 
253
229
 
254
- @ns_conf.route('/<project_name>/models/<model_name>/describe')
255
- @ns_conf.param('project_name', 'Name of the project')
256
- @ns_conf.param('model_name', 'Name of the model')
230
+ @ns_conf.route("/<project_name>/models/<model_name>/describe")
231
+ @ns_conf.param("project_name", "Name of the project")
232
+ @ns_conf.param("model_name", "Name of the model")
257
233
  class ModelDescribe(Resource):
258
- @ns_conf.doc('describe_model')
259
- @api_endpoint_metrics('GET', '/models/model/describe')
234
+ @ns_conf.doc("describe_model")
235
+ @api_endpoint_metrics("GET", "/models/model/describe")
260
236
  def get(self, project_name, model_name):
261
- '''Describes a model'''
237
+ """Describes a model"""
262
238
  session = SessionController()
263
239
 
264
240
  project_datanode = session.datahub.get(project_name)
265
241
  if project_datanode is None:
266
- return http_error(
267
- HTTPStatus.NOT_FOUND,
268
- 'Project not found',
269
- f'Project name {project_name} does not exist')
242
+ return http_error(HTTPStatus.NOT_FOUND, "Project not found", f"Project name {project_name} does not exist")
270
243
 
271
244
  name_no_version, version = Predictor.get_name_and_version(model_name)
272
245
 
273
246
  try:
274
247
  session.model_controller.get_model(name_no_version, version=version, project_name=project_name)
275
248
  except PredictorRecordNotFound:
276
- return http_error(
277
- HTTPStatus.NOT_FOUND,
278
- 'Model not found',
279
- f'Model with name {model_name} not found')
249
+ return http_error(HTTPStatus.NOT_FOUND, "Model not found", f"Model with name {model_name} not found")
280
250
 
281
251
  attribute = None
282
- if 'attribute' in request.json:
283
- attribute = request.json['attribute']
252
+ if "attribute" in request.json:
253
+ attribute = request.json["attribute"]
284
254
 
285
255
  try:
286
256
  description_df = session.model_controller.describe_model(
287
- session,
288
- project_name,
289
- name_no_version,
290
- attribute,
291
- version=version)
292
- return description_df.to_dict('records')
257
+ session, project_name, name_no_version, attribute, version=version
258
+ )
259
+ return description_df.to_dict("records")
293
260
  except Exception:
294
261
  return http_error(
295
262
  HTTPStatus.BAD_REQUEST,
296
- 'ML handler unsupported',
297
- f'ML handler for {model_name} does not support model description')
263
+ "ML handler unsupported",
264
+ f"ML handler for {model_name} does not support model description",
265
+ )
@@ -1,7 +1,6 @@
1
1
  from http import HTTPStatus
2
2
 
3
3
  from flask_restx import Resource
4
- from sqlalchemy.exc import NoResultFound
5
4
 
6
5
  from mindsdb.metrics.metrics import api_endpoint_metrics
7
6
  from mindsdb.api.http.utils import http_error
@@ -10,37 +9,29 @@ from mindsdb.api.executor.controllers.session_controller import SessionControlle
10
9
  from mindsdb.utilities.exception import EntityNotExistsError
11
10
 
12
11
 
13
- @ns_conf.route('/')
12
+ @ns_conf.route("/")
14
13
  class ProjectsList(Resource):
15
- @ns_conf.doc('list_projects')
16
- @api_endpoint_metrics('GET', '/projects')
14
+ @ns_conf.doc("list_projects")
15
+ @api_endpoint_metrics("GET", "/projects")
17
16
  def get(self):
18
- ''' List all projects '''
17
+ """List all projects"""
19
18
  session = SessionController()
20
19
 
21
- projects = [
22
- {'name': i}
23
- for i in session.datahub.get_projects_names()
24
- ]
20
+ projects = [{"name": i} for i in session.datahub.get_projects_names()]
25
21
  return projects
26
22
 
27
23
 
28
- @ns_conf.route('/<project_name>')
24
+ @ns_conf.route("/<project_name>")
29
25
  class ProjectsGet(Resource):
30
- @ns_conf.doc('get_project')
31
- @api_endpoint_metrics('GET', '/projects/project')
26
+ @ns_conf.doc("get_project")
27
+ @api_endpoint_metrics("GET", "/projects/project")
32
28
  def get(self, project_name):
33
- '''Gets a project by name'''
29
+ """Gets a project by name"""
34
30
  session = SessionController()
35
31
 
36
32
  try:
37
33
  project = session.database_controller.get_project(project_name)
38
- except (NoResultFound, EntityNotExistsError):
39
- return http_error(
40
- HTTPStatus.NOT_FOUND, 'Project not exists',
41
- f'Project name {project_name} does not exist'
42
- )
43
-
44
- return {
45
- 'name': project.name
46
- }
34
+ except EntityNotExistsError:
35
+ return http_error(HTTPStatus.NOT_FOUND, "Project not exists", f"Project name {project_name} does not exist")
36
+
37
+ return {"name": project.name}
@@ -1,5 +1,4 @@
1
1
  from http import HTTPStatus
2
- import traceback
3
2
 
4
3
  from flask import request
5
4
  from flask_restx import Resource
@@ -18,6 +17,7 @@ from mindsdb.metrics.metrics import api_endpoint_metrics
18
17
  from mindsdb.utilities import log
19
18
  from mindsdb.utilities.config import Config
20
19
  from mindsdb.utilities.context import context as ctx
20
+ from mindsdb.utilities.exception import QueryError
21
21
 
22
22
  logger = log.getLogger(__name__)
23
23
 
@@ -29,18 +29,14 @@ class Query(Resource):
29
29
  super().__init__(*args, **kwargs)
30
30
 
31
31
  @ns_conf.doc("query")
32
- @api_endpoint_metrics('POST', '/sql/query')
32
+ @api_endpoint_metrics("POST", "/sql/query")
33
33
  def post(self):
34
34
  query = request.json["query"]
35
35
  context = request.json.get("context", {})
36
36
 
37
37
  if isinstance(query, str) is False or isinstance(context, dict) is False:
38
- return http_error(
39
- HTTPStatus.BAD_REQUEST,
40
- 'Wrong arguments',
41
- 'Please provide "query" with the request.'
42
- )
43
- logger.debug(f'Incoming query: {query}')
38
+ return http_error(HTTPStatus.BAD_REQUEST, "Wrong arguments", 'Please provide "query" with the request.')
39
+ logger.debug(f"Incoming query: {query}")
44
40
 
45
41
  if context.get("profiling") is True:
46
42
  profiler.enable()
@@ -50,9 +46,7 @@ class Query(Resource):
50
46
  error_text = None
51
47
  error_traceback = None
52
48
 
53
- profiler.set_meta(
54
- query=query, api="http", environment=Config().get("environment")
55
- )
49
+ profiler.set_meta(query=query, api="http", environment=Config().get("environment"))
56
50
  with profiler.Context("http_query_processing"):
57
51
  mysql_proxy = FakeMysqlProxy()
58
52
  mysql_proxy.set_context(context)
@@ -67,8 +61,18 @@ class Query(Resource):
67
61
  "error_code": 0,
68
62
  "error_message": str(e),
69
63
  }
70
- logger.error(f"Error query processing: \n{traceback.format_exc()}")
71
-
64
+ logger.warning(f"Error query processing: {e}")
65
+ except QueryError as e:
66
+ error_type = "expected" if e.is_acceptable else "unexpected"
67
+ query_response = {
68
+ "type": SQL_RESPONSE_TYPE.ERROR,
69
+ "error_code": 0,
70
+ "error_message": str(e),
71
+ }
72
+ if e.is_acceptable:
73
+ logger.warning(f"Query failed due to expected reason: {e}")
74
+ else:
75
+ logger.exception("Error query processing:")
72
76
  except UnknownError as e:
73
77
  # unclassified
74
78
  error_type = "unexpected"
@@ -77,7 +81,7 @@ class Query(Resource):
77
81
  "error_code": 0,
78
82
  "error_message": str(e),
79
83
  }
80
- logger.error(f"Error query processing: \n{traceback.format_exc()}")
84
+ logger.exception("Error query processing:")
81
85
 
82
86
  except Exception as e:
83
87
  error_type = "unexpected"
@@ -86,7 +90,7 @@ class Query(Resource):
86
90
  "error_code": 0,
87
91
  "error_message": str(e),
88
92
  }
89
- logger.error(f"Error query processing: \n{traceback.format_exc()}")
93
+ logger.exception("Error query processing:")
90
94
 
91
95
  if query_response.get("type") == SQL_RESPONSE_TYPE.ERROR:
92
96
  error_type = "expected"
@@ -115,7 +119,7 @@ class Query(Resource):
115
119
  @ns_conf.param("list_databases", "lists databases of mindsdb")
116
120
  class ListDatabases(Resource):
117
121
  @ns_conf.doc("list_databases")
118
- @api_endpoint_metrics('GET', '/sql/list_databases')
122
+ @api_endpoint_metrics("GET", "/sql/list_databases")
119
123
  def get(self):
120
124
  listing_query = "SHOW DATABASES"
121
125
  mysql_proxy = FakeMysqlProxy()
@@ -133,17 +137,21 @@ class ListDatabases(Resource):
133
137
  listing_query_response = {"type": "ok"}
134
138
  elif result.type == SQL_RESPONSE_TYPE.TABLE:
135
139
  listing_query_response = {
136
- "data": [{
137
- "name": db_row[0],
138
- "tables": [
139
- table_row[0]
140
- for table_row in mysql_proxy.process_query(
141
- "SHOW TABLES FROM `{}`".format(db_row[0])
142
- ).result_set.to_lists()
143
- ]
144
- } for db_row in result.result_set.to_lists()]
140
+ "data": [
141
+ {
142
+ "name": db_row[0],
143
+ "tables": [
144
+ table_row[0]
145
+ for table_row in mysql_proxy.process_query(
146
+ "SHOW TABLES FROM `{}`".format(db_row[0])
147
+ ).result_set.to_lists()
148
+ ],
149
+ }
150
+ for db_row in result.result_set.to_lists()
151
+ ]
145
152
  }
146
153
  except Exception as e:
154
+ logger.exception("Error while retrieving list of databases")
147
155
  listing_query_response = {
148
156
  "type": "error",
149
157
  "error_code": 0,