MindsDB 25.7.3.0__py3-none-any.whl → 25.7.4.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 (61) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/api/a2a/common/server/server.py +16 -6
  3. mindsdb/api/executor/command_executor.py +206 -135
  4. mindsdb/api/executor/datahub/datanodes/project_datanode.py +14 -3
  5. mindsdb/api/executor/planner/plan_join.py +3 -0
  6. mindsdb/api/executor/planner/plan_join_ts.py +117 -100
  7. mindsdb/api/executor/planner/query_planner.py +1 -0
  8. mindsdb/api/executor/sql_query/steps/apply_predictor_step.py +54 -85
  9. mindsdb/api/http/initialize.py +16 -43
  10. mindsdb/api/http/namespaces/agents.py +23 -20
  11. mindsdb/api/http/namespaces/chatbots.py +83 -120
  12. mindsdb/api/http/namespaces/file.py +1 -1
  13. mindsdb/api/http/namespaces/jobs.py +38 -60
  14. mindsdb/api/http/namespaces/tree.py +69 -61
  15. mindsdb/api/mcp/start.py +2 -0
  16. mindsdb/api/mysql/mysql_proxy/utilities/dump.py +3 -2
  17. mindsdb/integrations/handlers/autogluon_handler/requirements.txt +1 -1
  18. mindsdb/integrations/handlers/autosklearn_handler/requirements.txt +1 -1
  19. mindsdb/integrations/handlers/bigquery_handler/bigquery_handler.py +25 -5
  20. mindsdb/integrations/handlers/chromadb_handler/chromadb_handler.py +3 -3
  21. mindsdb/integrations/handlers/flaml_handler/requirements.txt +1 -1
  22. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_tables.py +82 -73
  23. mindsdb/integrations/handlers/hubspot_handler/requirements.txt +1 -1
  24. mindsdb/integrations/handlers/langchain_handler/langchain_handler.py +83 -76
  25. mindsdb/integrations/handlers/lightwood_handler/requirements.txt +4 -4
  26. mindsdb/integrations/handlers/litellm_handler/litellm_handler.py +5 -2
  27. mindsdb/integrations/handlers/litellm_handler/settings.py +2 -1
  28. mindsdb/integrations/handlers/pgvector_handler/pgvector_handler.py +106 -90
  29. mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +41 -39
  30. mindsdb/integrations/handlers/salesforce_handler/constants.py +208 -0
  31. mindsdb/integrations/handlers/salesforce_handler/salesforce_handler.py +141 -80
  32. mindsdb/integrations/handlers/salesforce_handler/salesforce_tables.py +0 -1
  33. mindsdb/integrations/handlers/tpot_handler/requirements.txt +1 -1
  34. mindsdb/integrations/handlers/web_handler/urlcrawl_helpers.py +32 -17
  35. mindsdb/integrations/handlers/web_handler/web_handler.py +19 -22
  36. mindsdb/integrations/libs/vectordatabase_handler.py +10 -1
  37. mindsdb/integrations/utilities/handler_utils.py +32 -12
  38. mindsdb/interfaces/agents/agents_controller.py +167 -108
  39. mindsdb/interfaces/agents/langchain_agent.py +10 -3
  40. mindsdb/interfaces/data_catalog/data_catalog_loader.py +4 -4
  41. mindsdb/interfaces/database/database.py +38 -13
  42. mindsdb/interfaces/database/integrations.py +20 -5
  43. mindsdb/interfaces/database/projects.py +63 -16
  44. mindsdb/interfaces/database/views.py +86 -60
  45. mindsdb/interfaces/jobs/jobs_controller.py +103 -110
  46. mindsdb/interfaces/knowledge_base/controller.py +26 -5
  47. mindsdb/interfaces/knowledge_base/evaluate.py +2 -1
  48. mindsdb/interfaces/knowledge_base/executor.py +24 -0
  49. mindsdb/interfaces/query_context/context_controller.py +100 -133
  50. mindsdb/interfaces/skills/skills_controller.py +18 -6
  51. mindsdb/interfaces/storage/db.py +40 -6
  52. mindsdb/interfaces/variables/variables_controller.py +8 -15
  53. mindsdb/utilities/config.py +3 -3
  54. mindsdb/utilities/functions.py +72 -60
  55. mindsdb/utilities/log.py +38 -6
  56. mindsdb/utilities/ps.py +7 -7
  57. {mindsdb-25.7.3.0.dist-info → mindsdb-25.7.4.0.dist-info}/METADATA +246 -247
  58. {mindsdb-25.7.3.0.dist-info → mindsdb-25.7.4.0.dist-info}/RECORD +61 -60
  59. {mindsdb-25.7.3.0.dist-info → mindsdb-25.7.4.0.dist-info}/WHEEL +0 -0
  60. {mindsdb-25.7.3.0.dist-info → mindsdb-25.7.4.0.dist-info}/licenses/LICENSE +0 -0
  61. {mindsdb-25.7.3.0.dist-info → mindsdb-25.7.4.0.dist-info}/top_level.txt +0 -0
@@ -94,14 +94,26 @@ class Project:
94
94
  def drop_model(self, name: str):
95
95
  ModelController().delete_model(name, project_name=self.name)
96
96
 
97
- def drop_view(self, name: str):
98
- ViewController().delete(name, project_name=self.name)
97
+ def drop_view(self, name: str, strict_case: bool = False) -> None:
98
+ """Remove a view with the specified name from the current project.
99
+
100
+ Args:
101
+ name (str): The name of the view to remove.
102
+ strict_case (bool, optional): If True, the view name is case-sensitive. Defaults to False.
103
+
104
+ Raises:
105
+ EntityNotExistsError: If the view does not exist.
106
+
107
+ Returns:
108
+ None
109
+ """
110
+ ViewController().delete(name, project_name=self.name, strict_case=strict_case)
99
111
 
100
112
  def create_view(self, name: str, query: str):
101
113
  ViewController().add(name, query=query, project_name=self.name)
102
114
 
103
- def update_view(self, name: str, query: str):
104
- ViewController().update(name, query=query, project_name=self.name)
115
+ def update_view(self, name: str, query: str, strict_case: bool = False):
116
+ ViewController().update(name, query=query, project_name=self.name, strict_case=strict_case)
105
117
 
106
118
  def delete_view(self, name: str):
107
119
  ViewController().delete(name, project_name=self.name)
@@ -279,18 +291,29 @@ class Project:
279
291
  ]
280
292
  return data
281
293
 
282
- def get_view(self, name):
283
- view_record = (
284
- db.session.query(db.View)
285
- .filter(
286
- db.View.project_id == self.id,
287
- db.View.company_id == ctx.company_id,
288
- sa.func.lower(db.View.name) == name.lower(),
289
- )
290
- .one_or_none()
294
+ def get_view(self, name: str, strict_case: bool = False) -> dict | None:
295
+ """Get a view by name from the current project.
296
+
297
+ Args:
298
+ name (str): The name of the view to retrieve.
299
+ strict_case (bool, optional): If True, the view name is case-sensitive. Defaults to False.
300
+
301
+ Returns:
302
+ dict | None: A dictionary with view information if found, otherwise None.
303
+ """
304
+ query = db.session.query(db.View).filter(
305
+ db.View.project_id == self.id,
306
+ db.View.company_id == ctx.company_id,
291
307
  )
308
+ if strict_case:
309
+ query = query.filter(db.View.name == name)
310
+ else:
311
+ query = query.filter(sa.func.lower(db.View.name) == name.lower())
312
+
313
+ view_record = query.one_or_none()
314
+
292
315
  if view_record is None:
293
- return view_record
316
+ return None
294
317
  return {
295
318
  "name": view_record.name,
296
319
  "query": view_record.query,
@@ -385,8 +408,29 @@ class ProjectController:
385
408
  return [Project.from_record(x) for x in records]
386
409
 
387
410
  def get(
388
- self, id: Optional[int] = None, name: Optional[str] = None, deleted: bool = False, is_default: bool = False
411
+ self,
412
+ id: int | None = None,
413
+ name: str | None = None,
414
+ deleted: bool = False,
415
+ is_default: bool = False,
416
+ strict_case: bool = False,
389
417
  ) -> Project:
418
+ """Get a project by id or name.
419
+
420
+ Args:
421
+ id (int | None, optional): The id of the project to retrieve. Cannot be used with 'name'.
422
+ name (str | None, optional): The name of the project to retrieve. Cannot be used with 'id'.
423
+ deleted (bool, optional): If True, include deleted projects. Defaults to False.
424
+ is_default (bool, optional): If True, only return the default project. Defaults to False.
425
+ strict_case (bool, optional): If True, the project name is case-sensitive. Defaults to False.
426
+
427
+ Raises:
428
+ ValueError: If both 'id' and 'name' are provided.
429
+ EntityNotExistsError: If the project is not found.
430
+
431
+ Returns:
432
+ Project: The project instance matching the given criteria.
433
+ """
390
434
  if id is not None and name is not None:
391
435
  raise ValueError("Both 'id' and 'name' can't be provided at the same time")
392
436
 
@@ -396,7 +440,10 @@ class ProjectController:
396
440
  if id is not None:
397
441
  q = q.filter_by(id=id)
398
442
  elif name is not None:
399
- q = q.filter((sa.func.lower(db.Project.name) == sa.func.lower(name)))
443
+ if strict_case:
444
+ q = q.filter((db.Project.name == name))
445
+ else:
446
+ q = q.filter((sa.func.lower(db.Project.name) == sa.func.lower(name)))
400
447
 
401
448
  if deleted is True:
402
449
  q = q.filter((db.Project.deleted_at != sa.null()))
@@ -12,64 +12,90 @@ class ViewController:
12
12
  from mindsdb.interfaces.database.database import DatabaseController
13
13
 
14
14
  database_controller = DatabaseController()
15
- project_databases_dict = database_controller.get_dict(filter_type='project')
15
+ project_databases_dict = database_controller.get_dict(filter_type="project")
16
16
 
17
17
  if project_name not in project_databases_dict:
18
- raise EntityNotExistsError('Can not find project', project_name)
18
+ raise EntityNotExistsError("Can not find project", project_name)
19
19
 
20
- project_id = project_databases_dict[project_name]['id']
20
+ project_id = project_databases_dict[project_name]["id"]
21
21
  view_record = (
22
22
  db.session.query(db.View.id)
23
23
  .filter(
24
- func.lower(db.View.name) == name,
25
- db.View.company_id == ctx.company_id,
26
- db.View.project_id == project_id
27
- ).first()
24
+ func.lower(db.View.name) == name, db.View.company_id == ctx.company_id, db.View.project_id == project_id
25
+ )
26
+ .first()
28
27
  )
29
28
  if view_record is not None:
30
- raise EntityExistsError('View already exists', name)
29
+ raise EntityExistsError("View already exists", name)
31
30
 
32
- view_record = db.View(
33
- name=name,
34
- company_id=ctx.company_id,
35
- query=query,
36
- project_id=project_id
37
- )
31
+ view_record = db.View(name=name, company_id=ctx.company_id, query=query, project_id=project_id)
38
32
  db.session.add(view_record)
39
33
  db.session.commit()
40
34
 
41
- def update(self, name, query, project_name):
42
- name = name.lower()
35
+ def update(self, name: str, query: str, project_name: str, strict_case: bool = False):
36
+ """Update the SQL query of an existing view in the specified project.
37
+
38
+ Args:
39
+ name (str): The name of the view to update.
40
+ query (str): The new SQL query for the view.
41
+ project_name (str): The name of the project containing the view.
42
+ strict_case (bool, optional): If True, the view name is case-sensitive. If False, the name comparison is case-insensitive. Defaults to False.
43
+
44
+ Raises:
45
+ EntityNotExistsError: If the view with the specified name does not exist in the given project.
46
+
47
+ Returns:
48
+ None
49
+ """
43
50
  project_record = get_project_record(project_name)
44
51
 
45
- rec = db.session.query(db.View).filter(
46
- func.lower(db.View.name) == name,
47
- db.View.company_id == ctx.company_id,
48
- db.View.project_id == project_record.id
49
- ).first()
52
+ q = db.session.query(db.View).filter(
53
+ db.View.company_id == ctx.company_id, db.View.project_id == project_record.id
54
+ )
55
+ if strict_case:
56
+ q = q.filter(db.View.name == name)
57
+ else:
58
+ q = q.filter(func.lower(db.View.name) == func.lower(name))
59
+
60
+ rec = q.first()
50
61
  if rec is None:
51
- raise EntityNotExistsError('View not found', name)
62
+ raise EntityNotExistsError("View not found", name)
52
63
  rec.query = query
53
64
  db.session.commit()
54
65
 
55
- def delete(self, name, project_name):
56
- name = name.lower()
66
+ def delete(self, name: str, project_name: str, strict_case: bool = False) -> None:
67
+ """Remove a view with the specified name from the given project.
68
+
69
+ Args:
70
+ name (str): The name of the view to remove.
71
+ project_name (str): The name of the project containing the view.
72
+ strict_case (bool, optional): If True, the view name is case-sensitive. Defaults to False.
73
+
74
+ Raises:
75
+ EntityNotExistsError: If the view does not exist.
76
+
77
+ Returns:
78
+ None
79
+ """
57
80
  project_record = get_project_record(project_name)
58
81
 
59
- rec = db.session.query(db.View).filter(
60
- func.lower(db.View.name) == name,
61
- db.View.company_id == ctx.company_id,
62
- db.View.project_id == project_record.id
63
- ).first()
64
- if rec is None:
65
- raise EntityNotExistsError('View not found', name)
66
- db.session.delete(rec)
82
+ query = db.session.query(db.View).filter(
83
+ db.View.company_id == ctx.company_id, db.View.project_id == project_record.id
84
+ )
85
+ if strict_case:
86
+ query = query.filter(db.View.name == name)
87
+ else:
88
+ query = query.filter(func.lower(db.View.name) == func.lower(name))
89
+
90
+ record = query.first()
91
+ if record is None:
92
+ raise EntityNotExistsError("View not found", name)
93
+ db.session.delete(record)
67
94
  db.session.commit()
68
95
 
69
- query_context_controller.drop_query_context('view', rec.id)
96
+ query_context_controller.drop_query_context("view", record.id)
70
97
 
71
98
  def list(self, project_name):
72
-
73
99
  project_names = {}
74
100
  for project in get_project_records():
75
101
  if project_name is not None and project.name != project_name:
@@ -77,49 +103,49 @@ class ViewController:
77
103
  project_names[project.id] = project.name
78
104
 
79
105
  query = db.session.query(db.View).filter(
80
- db.View.company_id == ctx.company_id,
81
- db.View.project_id.in_(list(project_names.keys()))
106
+ db.View.company_id == ctx.company_id, db.View.project_id.in_(list(project_names.keys()))
82
107
  )
83
108
 
84
109
  data = []
85
110
 
86
111
  for record in query:
87
-
88
- data.append({
89
- 'id': record.id,
90
- 'name': record.name,
91
- 'project': project_names[record.project_id],
92
- 'query': record.query,
93
- })
112
+ data.append(
113
+ {
114
+ "id": record.id,
115
+ "name": record.name,
116
+ "project": project_names[record.project_id],
117
+ "query": record.query,
118
+ }
119
+ )
94
120
 
95
121
  return data
96
122
 
97
123
  def _get_view_record_data(self, record):
98
- return {
99
- 'id': record.id,
100
- 'name': record.name,
101
- 'query': record.query
102
- }
124
+ return {"id": record.id, "name": record.name, "query": record.query}
103
125
 
104
126
  def get(self, id=None, name=None, project_name=None):
105
127
  project_record = get_project_record(project_name)
106
128
 
107
129
  if id is not None:
108
- records = db.session.query(db.View).filter_by(
109
- id=id,
110
- project_id=project_record.id,
111
- company_id=ctx.company_id
112
- ).all()
130
+ records = (
131
+ db.session.query(db.View)
132
+ .filter_by(id=id, project_id=project_record.id, company_id=ctx.company_id)
133
+ .all()
134
+ )
113
135
  elif name is not None:
114
- records = db.session.query(db.View).filter(
115
- func.lower(db.View.name) == name.lower(),
116
- db.View.project_id == project_record.id,
117
- db.View.company_id == ctx.company_id,
118
- ).all()
136
+ records = (
137
+ db.session.query(db.View)
138
+ .filter(
139
+ func.lower(db.View.name) == name.lower(),
140
+ db.View.project_id == project_record.id,
141
+ db.View.company_id == ctx.company_id,
142
+ )
143
+ .all()
144
+ )
119
145
  if len(records) == 0:
120
146
  if name is None:
121
- name = f'id={id}'
122
- raise EntityNotExistsError("Can't find view", f'{project_name}.{name}')
147
+ name = f"id={id}"
148
+ raise EntityNotExistsError("Can't find view", f"{project_name}.{name}")
123
149
  elif len(records) > 1:
124
150
  raise Exception(f"There are multiple views with name/id: {name}/{id}")
125
151
  record = records[0]