MindsDB 25.7.2.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.
- mindsdb/__about__.py +1 -1
- mindsdb/__main__.py +1 -1
- mindsdb/api/a2a/common/server/server.py +16 -6
- mindsdb/api/executor/command_executor.py +213 -137
- mindsdb/api/executor/datahub/datanodes/integration_datanode.py +5 -1
- mindsdb/api/executor/datahub/datanodes/project_datanode.py +14 -3
- mindsdb/api/executor/planner/plan_join.py +3 -0
- mindsdb/api/executor/planner/plan_join_ts.py +117 -100
- mindsdb/api/executor/planner/query_planner.py +1 -0
- mindsdb/api/executor/sql_query/steps/apply_predictor_step.py +54 -85
- mindsdb/api/http/initialize.py +16 -43
- mindsdb/api/http/namespaces/agents.py +24 -21
- mindsdb/api/http/namespaces/chatbots.py +83 -120
- mindsdb/api/http/namespaces/file.py +1 -1
- mindsdb/api/http/namespaces/jobs.py +38 -60
- mindsdb/api/http/namespaces/tree.py +69 -61
- mindsdb/api/mcp/start.py +2 -0
- mindsdb/api/mysql/mysql_proxy/utilities/dump.py +3 -2
- mindsdb/integrations/handlers/autogluon_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/autosklearn_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/bigquery_handler/bigquery_handler.py +25 -5
- mindsdb/integrations/handlers/chromadb_handler/chromadb_handler.py +3 -3
- mindsdb/integrations/handlers/flaml_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/google_calendar_handler/google_calendar_tables.py +82 -73
- mindsdb/integrations/handlers/hubspot_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/langchain_handler/langchain_handler.py +83 -76
- mindsdb/integrations/handlers/lightwood_handler/requirements.txt +4 -4
- mindsdb/integrations/handlers/litellm_handler/litellm_handler.py +16 -3
- mindsdb/integrations/handlers/litellm_handler/settings.py +2 -1
- mindsdb/integrations/handlers/llama_index_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/pgvector_handler/pgvector_handler.py +106 -90
- mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +41 -39
- mindsdb/integrations/handlers/s3_handler/s3_handler.py +72 -70
- mindsdb/integrations/handlers/salesforce_handler/constants.py +208 -0
- mindsdb/integrations/handlers/salesforce_handler/salesforce_handler.py +142 -81
- mindsdb/integrations/handlers/salesforce_handler/salesforce_tables.py +12 -4
- mindsdb/integrations/handlers/slack_handler/slack_tables.py +141 -161
- mindsdb/integrations/handlers/tpot_handler/requirements.txt +1 -1
- mindsdb/integrations/handlers/web_handler/urlcrawl_helpers.py +32 -17
- mindsdb/integrations/handlers/web_handler/web_handler.py +19 -22
- mindsdb/integrations/handlers/youtube_handler/youtube_tables.py +183 -55
- mindsdb/integrations/libs/vectordatabase_handler.py +10 -1
- mindsdb/integrations/utilities/handler_utils.py +32 -12
- mindsdb/interfaces/agents/agents_controller.py +169 -110
- mindsdb/interfaces/agents/langchain_agent.py +10 -3
- mindsdb/interfaces/data_catalog/data_catalog_loader.py +22 -8
- mindsdb/interfaces/database/database.py +38 -13
- mindsdb/interfaces/database/integrations.py +20 -5
- mindsdb/interfaces/database/projects.py +63 -16
- mindsdb/interfaces/database/views.py +86 -60
- mindsdb/interfaces/jobs/jobs_controller.py +103 -110
- mindsdb/interfaces/knowledge_base/controller.py +33 -5
- mindsdb/interfaces/knowledge_base/evaluate.py +53 -9
- mindsdb/interfaces/knowledge_base/executor.py +24 -0
- mindsdb/interfaces/knowledge_base/llm_client.py +3 -3
- mindsdb/interfaces/knowledge_base/preprocessing/document_preprocessor.py +21 -13
- mindsdb/interfaces/query_context/context_controller.py +100 -133
- mindsdb/interfaces/skills/skills_controller.py +18 -6
- mindsdb/interfaces/storage/db.py +40 -6
- mindsdb/interfaces/variables/variables_controller.py +8 -15
- mindsdb/utilities/config.py +3 -3
- mindsdb/utilities/functions.py +72 -60
- mindsdb/utilities/log.py +38 -6
- mindsdb/utilities/ps.py +7 -7
- {mindsdb-25.7.2.0.dist-info → mindsdb-25.7.4.0.dist-info}/METADATA +262 -263
- {mindsdb-25.7.2.0.dist-info → mindsdb-25.7.4.0.dist-info}/RECORD +69 -68
- {mindsdb-25.7.2.0.dist-info → mindsdb-25.7.4.0.dist-info}/WHEEL +0 -0
- {mindsdb-25.7.2.0.dist-info → mindsdb-25.7.4.0.dist-info}/licenses/LICENSE +0 -0
- {mindsdb-25.7.2.0.dist-info → mindsdb-25.7.4.0.dist-info}/top_level.txt +0 -0
|
@@ -6,7 +6,12 @@ import pandas as pd
|
|
|
6
6
|
from slack_sdk.errors import SlackApiError
|
|
7
7
|
|
|
8
8
|
from mindsdb.integrations.libs.api_handler import APIResource
|
|
9
|
-
from mindsdb.integrations.utilities.sql_utils import
|
|
9
|
+
from mindsdb.integrations.utilities.sql_utils import (
|
|
10
|
+
extract_comparison_conditions,
|
|
11
|
+
FilterCondition,
|
|
12
|
+
FilterOperator,
|
|
13
|
+
SortColumn,
|
|
14
|
+
)
|
|
10
15
|
from mindsdb.utilities import log
|
|
11
16
|
|
|
12
17
|
logger = log.getLogger(__name__)
|
|
@@ -17,12 +22,7 @@ class SlackConversationsTable(APIResource):
|
|
|
17
22
|
This is the table abstraction for interacting with conversations via the Slack API.
|
|
18
23
|
"""
|
|
19
24
|
|
|
20
|
-
def list(
|
|
21
|
-
self,
|
|
22
|
-
conditions: List[FilterCondition] = None,
|
|
23
|
-
limit: int = None,
|
|
24
|
-
**kwargs: Any
|
|
25
|
-
) -> pd.DataFrame:
|
|
25
|
+
def list(self, conditions: List[FilterCondition] = None, limit: int = None, **kwargs: Any) -> pd.DataFrame:
|
|
26
26
|
"""
|
|
27
27
|
Retrieves a list of Slack conversations based on the specified conditions.
|
|
28
28
|
If no channel ID(s) are provided, all channels are retrieved as follows:
|
|
@@ -53,7 +53,7 @@ class SlackConversationsTable(APIResource):
|
|
|
53
53
|
op = condition.op
|
|
54
54
|
|
|
55
55
|
# Handle the column 'id'.
|
|
56
|
-
if condition.column ==
|
|
56
|
+
if condition.column == "id":
|
|
57
57
|
if op not in [FilterOperator.EQUAL, FilterOperator.IN]:
|
|
58
58
|
raise ValueError(f"Unsupported operator '{op}' for column 'id'")
|
|
59
59
|
|
|
@@ -66,9 +66,7 @@ class SlackConversationsTable(APIResource):
|
|
|
66
66
|
|
|
67
67
|
if op == FilterOperator.IN:
|
|
68
68
|
try:
|
|
69
|
-
channels = self._get_channels(
|
|
70
|
-
value if isinstance(value, list) else [value]
|
|
71
|
-
)
|
|
69
|
+
channels = self._get_channels(value if isinstance(value, list) else [value])
|
|
72
70
|
condition.applied = True
|
|
73
71
|
except ValueError:
|
|
74
72
|
raise
|
|
@@ -78,8 +76,8 @@ class SlackConversationsTable(APIResource):
|
|
|
78
76
|
channels = self._get_all_channels(limit)
|
|
79
77
|
|
|
80
78
|
for channel in channels:
|
|
81
|
-
channel[
|
|
82
|
-
channel[
|
|
79
|
+
channel["created_at"] = dt.datetime.fromtimestamp(channel["created"])
|
|
80
|
+
channel["updated_at"] = dt.datetime.fromtimestamp(channel["updated"] / 1000)
|
|
83
81
|
|
|
84
82
|
return pd.DataFrame(channels, columns=self.get_columns())
|
|
85
83
|
|
|
@@ -104,7 +102,7 @@ class SlackConversationsTable(APIResource):
|
|
|
104
102
|
logger.error(f"Error getting channel '{channel_id}': {slack_error.response['error']}")
|
|
105
103
|
raise ValueError(f"Channel '{channel_id}' not found")
|
|
106
104
|
|
|
107
|
-
return response[
|
|
105
|
+
return response["channel"]
|
|
108
106
|
|
|
109
107
|
def _get_channels(self, channel_ids: List[Text]) -> List[Dict]:
|
|
110
108
|
"""
|
|
@@ -148,12 +146,12 @@ class SlackConversationsTable(APIResource):
|
|
|
148
146
|
# If the limit is greater than 1000, paginate the results until the limit is reached.
|
|
149
147
|
if limit and limit > 1000:
|
|
150
148
|
response = client.conversations_list()
|
|
151
|
-
channels = response[
|
|
149
|
+
channels = response["channels"]
|
|
152
150
|
|
|
153
151
|
# Paginate the results until the limit is reached.
|
|
154
|
-
while response[
|
|
155
|
-
response = client.conversations_list(cursor=response[
|
|
156
|
-
channels.extend(response[
|
|
152
|
+
while response["response_metadata"]["next_cursor"]:
|
|
153
|
+
response = client.conversations_list(cursor=response["response_metadata"]["next_cursor"])
|
|
154
|
+
channels.extend(response["channels"])
|
|
157
155
|
if len(channels) >= limit:
|
|
158
156
|
break
|
|
159
157
|
|
|
@@ -161,7 +159,7 @@ class SlackConversationsTable(APIResource):
|
|
|
161
159
|
# Otherwise, use the provided limit or a default limit of 1000.
|
|
162
160
|
else:
|
|
163
161
|
response = client.conversations_list(limit=limit if limit else 1000)
|
|
164
|
-
channels = response[
|
|
162
|
+
channels = response["channels"]
|
|
165
163
|
except SlackApiError as slack_error:
|
|
166
164
|
logger.error(f"Error getting channels: {slack_error.response['error']}")
|
|
167
165
|
raise
|
|
@@ -176,21 +174,21 @@ class SlackConversationsTable(APIResource):
|
|
|
176
174
|
List[str]: The list of columns.
|
|
177
175
|
"""
|
|
178
176
|
return [
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
177
|
+
"id",
|
|
178
|
+
"name",
|
|
179
|
+
"is_channel",
|
|
180
|
+
"is_group",
|
|
181
|
+
"is_im",
|
|
182
|
+
"is_mpim",
|
|
183
|
+
"is_private",
|
|
184
|
+
"is_archived",
|
|
185
|
+
"is_general",
|
|
186
|
+
"is_shared",
|
|
187
|
+
"is_ext_shared",
|
|
188
|
+
"is_org_shared",
|
|
189
|
+
"creator",
|
|
190
|
+
"created_at",
|
|
191
|
+
"updated_at",
|
|
194
192
|
]
|
|
195
193
|
|
|
196
194
|
|
|
@@ -200,11 +198,7 @@ class SlackMessagesTable(APIResource):
|
|
|
200
198
|
"""
|
|
201
199
|
|
|
202
200
|
def list(
|
|
203
|
-
self,
|
|
204
|
-
conditions: List[FilterCondition] = None,
|
|
205
|
-
limit: int = None,
|
|
206
|
-
sort: List[SortColumn] = None,
|
|
207
|
-
**kwargs: Any
|
|
201
|
+
self, conditions: List[FilterCondition] = None, limit: int = None, sort: List[SortColumn] = None, **kwargs: Any
|
|
208
202
|
) -> pd.DataFrame:
|
|
209
203
|
"""
|
|
210
204
|
Retrieves a list of messages from Slack conversations based on the specified conditions.
|
|
@@ -245,76 +239,75 @@ class SlackMessagesTable(APIResource):
|
|
|
245
239
|
op = condition.op
|
|
246
240
|
|
|
247
241
|
# Handle the column 'channel_id'.
|
|
248
|
-
if condition.column ==
|
|
242
|
+
if condition.column == "channel_id":
|
|
249
243
|
if op != FilterOperator.EQUAL:
|
|
250
244
|
raise ValueError(f"Unsupported operator '{op}' for column 'channel_id'")
|
|
251
245
|
|
|
252
246
|
# Check if the provided channel exists.
|
|
253
247
|
try:
|
|
254
248
|
channel = SlackConversationsTable(self.handler).get_channel(value)
|
|
255
|
-
params[
|
|
249
|
+
params["channel"] = value
|
|
256
250
|
condition.applied = True
|
|
257
251
|
except SlackApiError:
|
|
258
252
|
raise ValueError(f"Channel '{value}' not found")
|
|
259
253
|
|
|
260
254
|
# Handle the column 'created_at'.
|
|
261
|
-
elif condition.column ==
|
|
255
|
+
elif condition.column == "created_at" and value is not None:
|
|
262
256
|
date = dt.datetime.fromisoformat(value).replace(tzinfo=dt.timezone.utc)
|
|
263
257
|
if op == FilterOperator.GREATER_THAN:
|
|
264
|
-
params[
|
|
258
|
+
params["oldest"] = date.timestamp() + 1
|
|
265
259
|
elif op == FilterOperator.GREATER_THAN_OR_EQUAL:
|
|
266
|
-
params[
|
|
260
|
+
params["oldest"] = date.timestamp()
|
|
267
261
|
elif op == FilterOperator.LESS_THAN_OR_EQUAL:
|
|
268
|
-
params[
|
|
262
|
+
params["latest"] = date.timestamp()
|
|
269
263
|
else:
|
|
270
264
|
continue
|
|
271
265
|
condition.applied = True
|
|
272
266
|
|
|
273
|
-
if
|
|
267
|
+
if "channel" not in params:
|
|
274
268
|
raise ValueError("To retrieve data from Slack, you need to provide the 'channel_id' parameter.")
|
|
275
269
|
|
|
276
270
|
# Retrieve the messages from the Slack API.
|
|
277
271
|
try:
|
|
278
272
|
# If the limit is greater than 999, paginate the results until the limit is reached.
|
|
279
273
|
if limit and limit > 999:
|
|
274
|
+
params["limit"] = 999
|
|
280
275
|
response = client.conversations_history(**params)
|
|
281
|
-
messages = response[
|
|
282
|
-
|
|
283
|
-
# Paginate the results until the limit is reached.
|
|
284
|
-
while response
|
|
285
|
-
response = client.conversations_history(
|
|
286
|
-
|
|
276
|
+
messages = response["messages"]
|
|
277
|
+
|
|
278
|
+
# Paginate the results until the limit is reached. response_metadata may be None.
|
|
279
|
+
while response.get("response_metadata", {}).get("next_cursor"):
|
|
280
|
+
response = client.conversations_history(
|
|
281
|
+
cursor=response["response_metadata"]["next_cursor"], **params
|
|
282
|
+
)
|
|
283
|
+
messages.extend(response["messages"])
|
|
287
284
|
if len(messages) >= limit:
|
|
288
285
|
break
|
|
289
286
|
|
|
290
|
-
|
|
287
|
+
messages = messages[:limit]
|
|
291
288
|
# Otherwise, use the provided limit or a default limit of 999.
|
|
292
289
|
else:
|
|
293
|
-
params[
|
|
290
|
+
params["limit"] = limit if limit else 999
|
|
294
291
|
response = client.conversations_history(**params)
|
|
295
|
-
messages = response[
|
|
292
|
+
messages = response["messages"]
|
|
296
293
|
except SlackApiError as slack_error:
|
|
297
294
|
logger.error(f"Error getting messages: {slack_error.response['error']}")
|
|
298
295
|
raise
|
|
299
296
|
|
|
300
297
|
result = pd.DataFrame(messages, columns=self.get_columns())
|
|
301
298
|
|
|
302
|
-
result = result[result[
|
|
299
|
+
result = result[result["text"].notnull()]
|
|
303
300
|
|
|
304
301
|
# Add the channel ID and name to the result.
|
|
305
|
-
result[
|
|
306
|
-
result[
|
|
302
|
+
result["channel_id"] = params["channel"]
|
|
303
|
+
result["channel_name"] = channel["name"] if "name" in channel else None
|
|
307
304
|
|
|
308
305
|
# Translate the time stamp into a 'created_at' field.
|
|
309
|
-
result[
|
|
306
|
+
result["created_at"] = pd.to_datetime(result["ts"].astype(float), unit="s").dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
310
307
|
|
|
311
308
|
# Sort the messages by the specified columns.
|
|
312
309
|
if sort:
|
|
313
|
-
result.sort_values(
|
|
314
|
-
by=[col.column for col in sort],
|
|
315
|
-
ascending=[col.ascending for col in sort],
|
|
316
|
-
inplace=True
|
|
317
|
-
)
|
|
310
|
+
result.sort_values(by=[col.column for col in sort], ascending=[col.ascending for col in sort], inplace=True)
|
|
318
311
|
|
|
319
312
|
return result
|
|
320
313
|
|
|
@@ -337,16 +330,17 @@ class SlackMessagesTable(APIResource):
|
|
|
337
330
|
params = dict(zip(columns, row))
|
|
338
331
|
|
|
339
332
|
# Check if required parameters are provided.
|
|
340
|
-
if
|
|
341
|
-
raise ValueError(
|
|
333
|
+
if "channel_id" not in params or "text" not in params:
|
|
334
|
+
raise ValueError(
|
|
335
|
+
"To insert data into Slack, you need to provide the 'channel_id' and 'text' parameters."
|
|
336
|
+
)
|
|
342
337
|
|
|
343
338
|
try:
|
|
344
|
-
client.chat_postMessage(
|
|
345
|
-
channel=params['channel_id'],
|
|
346
|
-
text=params['text']
|
|
347
|
-
)
|
|
339
|
+
client.chat_postMessage(channel=params["channel_id"], text=params["text"])
|
|
348
340
|
except SlackApiError as slack_error:
|
|
349
|
-
logger.error(
|
|
341
|
+
logger.error(
|
|
342
|
+
f"Error posting message to Slack channel '{params['channel_id']}': {slack_error.response['error']}"
|
|
343
|
+
)
|
|
350
344
|
raise
|
|
351
345
|
|
|
352
346
|
def update(self, query: Update):
|
|
@@ -373,18 +367,18 @@ class SlackMessagesTable(APIResource):
|
|
|
373
367
|
# Extract the parameters from the conditions.
|
|
374
368
|
for op, arg1, arg2 in conditions:
|
|
375
369
|
# Handle the column 'channel_id'.
|
|
376
|
-
if arg1 ==
|
|
370
|
+
if arg1 == "channel_id":
|
|
377
371
|
# Check if the provided channel exists.
|
|
378
372
|
try:
|
|
379
373
|
SlackConversationsTable(self.handler).get_channel(arg2)
|
|
380
|
-
params[
|
|
374
|
+
params["channel"] = arg2
|
|
381
375
|
except SlackApiError as slack_error:
|
|
382
376
|
logger.error(f"Error getting channel '{arg2}': {slack_error.response['error']}")
|
|
383
377
|
raise ValueError(f"Channel '{arg2}' not found")
|
|
384
378
|
|
|
385
379
|
# Handle the column'ts'.
|
|
386
|
-
elif arg1 ==
|
|
387
|
-
if op ==
|
|
380
|
+
elif arg1 == "ts":
|
|
381
|
+
if op == "=":
|
|
388
382
|
params[arg1] = str(arg2)
|
|
389
383
|
else:
|
|
390
384
|
raise ValueError(f"Unsupported operator '{op}' for column '{arg1}'")
|
|
@@ -394,23 +388,23 @@ class SlackMessagesTable(APIResource):
|
|
|
394
388
|
|
|
395
389
|
# Extract the update columns and values.
|
|
396
390
|
for col, val in query.update_columns.items():
|
|
397
|
-
if col ==
|
|
391
|
+
if col == "text":
|
|
398
392
|
params[col] = str(val).strip("'")
|
|
399
393
|
else:
|
|
400
394
|
raise ValueError(f"Unsupported column '{col}'")
|
|
401
395
|
|
|
402
396
|
# Check if required parameters are provided.
|
|
403
|
-
if
|
|
404
|
-
raise ValueError(
|
|
397
|
+
if "channel" not in params or "ts" not in params or "text" not in params:
|
|
398
|
+
raise ValueError(
|
|
399
|
+
"To update a message in Slack, you need to provide the 'channel', 'ts', and 'text' parameters."
|
|
400
|
+
)
|
|
405
401
|
|
|
406
402
|
try:
|
|
407
|
-
client.chat_update(
|
|
408
|
-
channel=params['channel'],
|
|
409
|
-
ts=params['ts'],
|
|
410
|
-
text=params['text'].strip()
|
|
411
|
-
)
|
|
403
|
+
client.chat_update(channel=params["channel"], ts=params["ts"], text=params["text"].strip())
|
|
412
404
|
except SlackApiError as slack_error:
|
|
413
|
-
logger.error(
|
|
405
|
+
logger.error(
|
|
406
|
+
f"Error updating message in Slack channel '{params['channel']}' with timestamp '{params['ts']}': {slack_error.response['error']}"
|
|
407
|
+
)
|
|
414
408
|
raise
|
|
415
409
|
|
|
416
410
|
def delete(self, query: Delete):
|
|
@@ -436,37 +430,36 @@ class SlackMessagesTable(APIResource):
|
|
|
436
430
|
params = {}
|
|
437
431
|
for op, arg1, arg2 in conditions:
|
|
438
432
|
# Handle the column 'channel_id'.
|
|
439
|
-
if arg1 ==
|
|
433
|
+
if arg1 == "channel_id":
|
|
440
434
|
# Check if the provided channel exists.
|
|
441
435
|
try:
|
|
442
436
|
SlackConversationsTable(self.handler).get_channel(arg2)
|
|
443
|
-
params[
|
|
437
|
+
params["channel"] = arg2
|
|
444
438
|
except SlackApiError as slack_error:
|
|
445
439
|
logger.error(f"Error getting channel '{arg2}': {slack_error.response['error']}")
|
|
446
440
|
raise ValueError(f"Channel '{arg2}' not found")
|
|
447
441
|
|
|
448
442
|
# Handle the columns 'ts'.
|
|
449
|
-
elif arg1 ==
|
|
450
|
-
if op ==
|
|
451
|
-
params[
|
|
443
|
+
elif arg1 == "ts":
|
|
444
|
+
if op == "=":
|
|
445
|
+
params["ts"] = float(arg2)
|
|
452
446
|
else:
|
|
453
|
-
raise NotImplementedError(f
|
|
447
|
+
raise NotImplementedError(f"Unknown op: {op}")
|
|
454
448
|
|
|
455
449
|
else:
|
|
456
450
|
raise ValueError(f"Unsupported column '{arg1}'")
|
|
457
451
|
|
|
458
452
|
# Check if required parameters are provided.
|
|
459
|
-
if
|
|
453
|
+
if "channel" not in params or "ts" not in params:
|
|
460
454
|
raise ValueError("To delete a message from Slack, you need to provide the 'channel' and 'ts' parameters.")
|
|
461
455
|
|
|
462
456
|
try:
|
|
463
|
-
client.chat_delete(
|
|
464
|
-
channel=params['channel'],
|
|
465
|
-
ts=params['ts']
|
|
466
|
-
)
|
|
457
|
+
client.chat_delete(channel=params["channel"], ts=params["ts"])
|
|
467
458
|
|
|
468
459
|
except SlackApiError as slack_error:
|
|
469
|
-
logger.error(
|
|
460
|
+
logger.error(
|
|
461
|
+
f"Error deleting message in Slack channel '{params['channel']}' with timestamp '{params['ts']}': {slack_error.response['error']}"
|
|
462
|
+
)
|
|
470
463
|
raise
|
|
471
464
|
|
|
472
465
|
def get_columns(self) -> List[Text]:
|
|
@@ -477,23 +470,23 @@ class SlackMessagesTable(APIResource):
|
|
|
477
470
|
List[str]: The list of columns.
|
|
478
471
|
"""
|
|
479
472
|
return [
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
473
|
+
"channel_id",
|
|
474
|
+
"channel",
|
|
475
|
+
"client_msg_id",
|
|
476
|
+
"type",
|
|
477
|
+
"subtype",
|
|
478
|
+
"ts",
|
|
479
|
+
"created_at",
|
|
480
|
+
"user",
|
|
481
|
+
"text",
|
|
482
|
+
"attachments",
|
|
483
|
+
"files",
|
|
484
|
+
"reactions",
|
|
485
|
+
"thread_ts",
|
|
486
|
+
"reply_count",
|
|
487
|
+
"reply_users_count",
|
|
488
|
+
"latest_reply",
|
|
489
|
+
"reply_users",
|
|
497
490
|
]
|
|
498
491
|
|
|
499
492
|
|
|
@@ -503,11 +496,7 @@ class SlackThreadsTable(APIResource):
|
|
|
503
496
|
"""
|
|
504
497
|
|
|
505
498
|
def list(
|
|
506
|
-
self,
|
|
507
|
-
conditions: List[FilterCondition] = None,
|
|
508
|
-
limit: int = None,
|
|
509
|
-
sort: List[SortColumn] = None,
|
|
510
|
-
**kwargs: Any
|
|
499
|
+
self, conditions: List[FilterCondition] = None, limit: int = None, sort: List[SortColumn] = None, **kwargs: Any
|
|
511
500
|
) -> pd.DataFrame:
|
|
512
501
|
"""
|
|
513
502
|
Retrieves a list of messages in a thread based on the specified conditions.
|
|
@@ -548,68 +537,66 @@ class SlackThreadsTable(APIResource):
|
|
|
548
537
|
op = condition.op
|
|
549
538
|
|
|
550
539
|
# Handle the column 'channel_id'.
|
|
551
|
-
if condition.column ==
|
|
540
|
+
if condition.column == "channel_id":
|
|
552
541
|
if op != FilterOperator.EQUAL:
|
|
553
542
|
raise ValueError(f"Unsupported operator '{op}' for column 'channel_id'")
|
|
554
543
|
|
|
555
544
|
# Check if the provided channel exists.
|
|
556
545
|
try:
|
|
557
546
|
channel = SlackConversationsTable(self.handler).get_channel(value)
|
|
558
|
-
params[
|
|
547
|
+
params["channel"] = value
|
|
559
548
|
condition.applied = True
|
|
560
549
|
except SlackApiError as slack_error:
|
|
561
550
|
logger.error(f"Error getting channel '{value}': {slack_error.response['error']}")
|
|
562
551
|
raise ValueError(f"Channel '{value}' not found")
|
|
563
552
|
|
|
564
553
|
# Handle the column 'thread_ts'.
|
|
565
|
-
elif condition.column ==
|
|
554
|
+
elif condition.column == "thread_ts":
|
|
566
555
|
if op != FilterOperator.EQUAL:
|
|
567
556
|
raise ValueError(f"Unsupported operator '{op}' for column 'thread_ts'")
|
|
568
557
|
|
|
569
|
-
params[
|
|
558
|
+
params["ts"] = value
|
|
570
559
|
|
|
571
|
-
if
|
|
572
|
-
raise ValueError(
|
|
560
|
+
if "channel" not in params or "ts" not in params:
|
|
561
|
+
raise ValueError(
|
|
562
|
+
"To retrieve data from Slack, you need to provide the 'channel_id' and 'thread_ts' parameters."
|
|
563
|
+
)
|
|
573
564
|
|
|
574
565
|
# Retrieve the messages from the Slack API.
|
|
575
566
|
try:
|
|
576
567
|
# If the limit is greater than 1000, paginate the results until the limit is reached.
|
|
577
568
|
if limit and limit > 1000:
|
|
578
569
|
response = client.conversations_replies(**params)
|
|
579
|
-
messages = response[
|
|
570
|
+
messages = response["messages"]
|
|
580
571
|
|
|
581
572
|
# Paginate the results until the limit is reached.
|
|
582
|
-
while response[
|
|
583
|
-
response = client.conversations_replies(cursor=response[
|
|
584
|
-
messages.extend(response[
|
|
573
|
+
while response["response_metadata"]["next_cursor"]:
|
|
574
|
+
response = client.conversations_replies(cursor=response["response_metadata"]["next_cursor"])
|
|
575
|
+
messages.extend(response["messages"])
|
|
585
576
|
if len(messages) >= limit:
|
|
586
577
|
break
|
|
587
578
|
|
|
588
579
|
messages = messages[:limit]
|
|
589
580
|
# Otherwise, use the provided limit or a default limit of 1000.
|
|
590
581
|
else:
|
|
591
|
-
params[
|
|
582
|
+
params["limit"] = limit if limit else 1000
|
|
592
583
|
response = client.conversations_replies(**params)
|
|
593
|
-
messages = response[
|
|
584
|
+
messages = response["messages"]
|
|
594
585
|
except SlackApiError as slack_error:
|
|
595
586
|
logger.error(f"Error getting messages: {slack_error.response['error']}")
|
|
596
587
|
raise
|
|
597
588
|
|
|
598
589
|
result = pd.DataFrame(messages, columns=self.get_columns())
|
|
599
590
|
|
|
600
|
-
result = result[result[
|
|
591
|
+
result = result[result["text"].notnull()]
|
|
601
592
|
|
|
602
593
|
# Add the channel ID and name to the result.
|
|
603
|
-
result[
|
|
604
|
-
result[
|
|
594
|
+
result["channel_id"] = params["channel"]
|
|
595
|
+
result["channel_name"] = channel["name"] if "name" in channel else None
|
|
605
596
|
|
|
606
597
|
# Sort the messages by the specified columns.
|
|
607
598
|
if sort:
|
|
608
|
-
result.sort_values(
|
|
609
|
-
by=[col.column for col in sort],
|
|
610
|
-
ascending=[col.ascending for col in sort],
|
|
611
|
-
inplace=True
|
|
612
|
-
)
|
|
599
|
+
result.sort_values(by=[col.column for col in sort], ascending=[col.ascending for col in sort], inplace=True)
|
|
613
600
|
|
|
614
601
|
return result
|
|
615
602
|
|
|
@@ -631,17 +618,19 @@ class SlackThreadsTable(APIResource):
|
|
|
631
618
|
params = dict(zip(columns, row))
|
|
632
619
|
|
|
633
620
|
# Check if required parameters are provided.
|
|
634
|
-
if
|
|
635
|
-
raise ValueError(
|
|
621
|
+
if "channel_id" not in params or "text" not in params or "thread_ts" not in params:
|
|
622
|
+
raise ValueError(
|
|
623
|
+
"To insert data into Slack, you need to provide the 'channel_id', 'text', and 'thread_ts' parameters."
|
|
624
|
+
)
|
|
636
625
|
|
|
637
626
|
try:
|
|
638
627
|
client.chat_postMessage(
|
|
639
|
-
channel=params[
|
|
640
|
-
text=params['text'],
|
|
641
|
-
thread_ts=params['thread_ts']
|
|
628
|
+
channel=params["channel_id"], text=params["text"], thread_ts=params["thread_ts"]
|
|
642
629
|
)
|
|
643
630
|
except SlackApiError as slack_error:
|
|
644
|
-
logger.error(
|
|
631
|
+
logger.error(
|
|
632
|
+
f"Error posting message to Slack channel '{params['channel_id']}': {slack_error.response['error']}"
|
|
633
|
+
)
|
|
645
634
|
raise
|
|
646
635
|
|
|
647
636
|
def get_columns(self) -> List[Text]:
|
|
@@ -664,7 +653,7 @@ class SlackThreadsTable(APIResource):
|
|
|
664
653
|
"reply_count",
|
|
665
654
|
"reply_users_count",
|
|
666
655
|
"latest_reply",
|
|
667
|
-
"reply_users"
|
|
656
|
+
"reply_users",
|
|
668
657
|
]
|
|
669
658
|
|
|
670
659
|
|
|
@@ -673,12 +662,7 @@ class SlackUsersTable(APIResource):
|
|
|
673
662
|
This is the table abstraction for interacting with users in Slack.
|
|
674
663
|
"""
|
|
675
664
|
|
|
676
|
-
def list(
|
|
677
|
-
self,
|
|
678
|
-
conditions: List[FilterCondition] = None,
|
|
679
|
-
limit: int = None,
|
|
680
|
-
**kwargs: Any
|
|
681
|
-
) -> pd.DataFrame:
|
|
665
|
+
def list(self, conditions: List[FilterCondition] = None, limit: int = None, **kwargs: Any) -> pd.DataFrame:
|
|
682
666
|
"""
|
|
683
667
|
Retrieves a list of users based on the specified conditions.
|
|
684
668
|
Users are retrieved as follows:
|
|
@@ -704,12 +688,12 @@ class SlackUsersTable(APIResource):
|
|
|
704
688
|
# If the limit is greater than 1000, paginate the results until the limit is reached.
|
|
705
689
|
if limit and limit > 1000:
|
|
706
690
|
response = client.users_list()
|
|
707
|
-
users = response[
|
|
691
|
+
users = response["members"]
|
|
708
692
|
|
|
709
693
|
# Paginate the results until the limit is reached.
|
|
710
|
-
while response[
|
|
711
|
-
response = client.users_list(cursor=response[
|
|
712
|
-
users.extend(response[
|
|
694
|
+
while response["response_metadata"]["next_cursor"]:
|
|
695
|
+
response = client.users_list(cursor=response["response_metadata"]["next_cursor"])
|
|
696
|
+
users.extend(response["members"])
|
|
713
697
|
if len(users) >= limit:
|
|
714
698
|
break
|
|
715
699
|
|
|
@@ -717,7 +701,7 @@ class SlackUsersTable(APIResource):
|
|
|
717
701
|
# Otherwise, use the provided limit or a default limit of 1000.
|
|
718
702
|
else:
|
|
719
703
|
response = client.users_list(limit=limit if limit else 1000)
|
|
720
|
-
users = response[
|
|
704
|
+
users = response["members"]
|
|
721
705
|
except SlackApiError as slack_error:
|
|
722
706
|
logger.error(f"Error getting users: {slack_error.response['error']}")
|
|
723
707
|
raise
|
|
@@ -731,8 +715,4 @@ class SlackUsersTable(APIResource):
|
|
|
731
715
|
Returns:
|
|
732
716
|
List[Text]: The list of columns.
|
|
733
717
|
"""
|
|
734
|
-
return [
|
|
735
|
-
'id',
|
|
736
|
-
'name',
|
|
737
|
-
'real_name'
|
|
738
|
-
]
|
|
718
|
+
return ["id", "name", "real_name"]
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
tpot<=0.11.7
|
|
2
|
-
type_infer==0.0.
|
|
2
|
+
type_infer==0.0.23
|