universal-mcp-applications 0.1.33__py3-none-any.whl → 0.1.39rc16__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 universal-mcp-applications might be problematic. Click here for more details.

Files changed (119) hide show
  1. universal_mcp/applications/BEST_PRACTICES.md +1 -1
  2. universal_mcp/applications/ahrefs/app.py +92 -238
  3. universal_mcp/applications/airtable/app.py +36 -135
  4. universal_mcp/applications/apollo/app.py +124 -477
  5. universal_mcp/applications/asana/app.py +605 -1755
  6. universal_mcp/applications/aws_s3/app.py +63 -119
  7. universal_mcp/applications/bill/app.py +644 -2055
  8. universal_mcp/applications/box/app.py +1246 -4159
  9. universal_mcp/applications/braze/app.py +410 -1476
  10. universal_mcp/applications/browser_use/README.md +15 -1
  11. universal_mcp/applications/browser_use/__init__.py +1 -0
  12. universal_mcp/applications/browser_use/app.py +91 -26
  13. universal_mcp/applications/cal_com_v2/app.py +207 -625
  14. universal_mcp/applications/calendly/app.py +103 -242
  15. universal_mcp/applications/canva/app.py +75 -140
  16. universal_mcp/applications/clickup/app.py +331 -798
  17. universal_mcp/applications/coda/app.py +240 -520
  18. universal_mcp/applications/confluence/app.py +497 -1285
  19. universal_mcp/applications/contentful/app.py +40 -155
  20. universal_mcp/applications/crustdata/app.py +44 -123
  21. universal_mcp/applications/dialpad/app.py +451 -924
  22. universal_mcp/applications/digitalocean/app.py +2071 -6082
  23. universal_mcp/applications/domain_checker/app.py +3 -54
  24. universal_mcp/applications/e2b/app.py +17 -68
  25. universal_mcp/applications/elevenlabs/README.md +27 -3
  26. universal_mcp/applications/elevenlabs/app.py +741 -74
  27. universal_mcp/applications/exa/README.md +8 -4
  28. universal_mcp/applications/exa/app.py +415 -186
  29. universal_mcp/applications/falai/README.md +5 -7
  30. universal_mcp/applications/falai/app.py +156 -232
  31. universal_mcp/applications/figma/app.py +91 -175
  32. universal_mcp/applications/file_system/app.py +2 -13
  33. universal_mcp/applications/firecrawl/app.py +198 -176
  34. universal_mcp/applications/fireflies/app.py +59 -281
  35. universal_mcp/applications/fpl/app.py +92 -529
  36. universal_mcp/applications/fpl/utils/fixtures.py +15 -49
  37. universal_mcp/applications/fpl/utils/helper.py +25 -89
  38. universal_mcp/applications/fpl/utils/league_utils.py +20 -64
  39. universal_mcp/applications/ghost_content/app.py +70 -179
  40. universal_mcp/applications/github/app.py +30 -67
  41. universal_mcp/applications/gong/app.py +142 -302
  42. universal_mcp/applications/google_calendar/app.py +26 -78
  43. universal_mcp/applications/google_docs/README.md +15 -14
  44. universal_mcp/applications/google_docs/app.py +103 -206
  45. universal_mcp/applications/google_drive/app.py +194 -793
  46. universal_mcp/applications/google_gemini/app.py +68 -59
  47. universal_mcp/applications/google_mail/README.md +1 -0
  48. universal_mcp/applications/google_mail/app.py +93 -214
  49. universal_mcp/applications/google_searchconsole/app.py +25 -58
  50. universal_mcp/applications/google_sheet/README.md +2 -1
  51. universal_mcp/applications/google_sheet/app.py +226 -624
  52. universal_mcp/applications/google_sheet/helper.py +26 -53
  53. universal_mcp/applications/hashnode/app.py +57 -269
  54. universal_mcp/applications/heygen/README.md +10 -32
  55. universal_mcp/applications/heygen/app.py +339 -811
  56. universal_mcp/applications/http_tools/app.py +10 -32
  57. universal_mcp/applications/hubspot/README.md +1 -1
  58. universal_mcp/applications/hubspot/app.py +7508 -99
  59. universal_mcp/applications/jira/app.py +2419 -8334
  60. universal_mcp/applications/klaviyo/app.py +739 -1621
  61. universal_mcp/applications/linkedin/README.md +18 -1
  62. universal_mcp/applications/linkedin/app.py +729 -251
  63. universal_mcp/applications/mailchimp/app.py +696 -1851
  64. universal_mcp/applications/markitdown/app.py +8 -20
  65. universal_mcp/applications/miro/app.py +333 -815
  66. universal_mcp/applications/ms_teams/app.py +420 -1407
  67. universal_mcp/applications/neon/app.py +144 -250
  68. universal_mcp/applications/notion/app.py +38 -53
  69. universal_mcp/applications/onedrive/app.py +26 -48
  70. universal_mcp/applications/openai/app.py +43 -166
  71. universal_mcp/applications/outlook/README.md +22 -9
  72. universal_mcp/applications/outlook/app.py +403 -141
  73. universal_mcp/applications/perplexity/README.md +2 -1
  74. universal_mcp/applications/perplexity/app.py +161 -20
  75. universal_mcp/applications/pipedrive/app.py +1021 -3331
  76. universal_mcp/applications/posthog/app.py +272 -541
  77. universal_mcp/applications/reddit/app.py +65 -164
  78. universal_mcp/applications/resend/app.py +72 -139
  79. universal_mcp/applications/retell/app.py +23 -50
  80. universal_mcp/applications/rocketlane/app.py +252 -965
  81. universal_mcp/applications/scraper/app.py +114 -142
  82. universal_mcp/applications/semanticscholar/app.py +36 -78
  83. universal_mcp/applications/semrush/app.py +44 -78
  84. universal_mcp/applications/sendgrid/app.py +826 -1576
  85. universal_mcp/applications/sentry/app.py +444 -1079
  86. universal_mcp/applications/serpapi/app.py +44 -146
  87. universal_mcp/applications/sharepoint/app.py +27 -49
  88. universal_mcp/applications/shopify/app.py +1748 -4486
  89. universal_mcp/applications/shortcut/app.py +275 -536
  90. universal_mcp/applications/slack/app.py +43 -125
  91. universal_mcp/applications/spotify/app.py +206 -405
  92. universal_mcp/applications/supabase/app.py +174 -283
  93. universal_mcp/applications/tavily/app.py +2 -2
  94. universal_mcp/applications/trello/app.py +853 -2816
  95. universal_mcp/applications/twilio/app.py +27 -62
  96. universal_mcp/applications/twitter/api_segments/compliance_api.py +4 -14
  97. universal_mcp/applications/twitter/api_segments/dm_conversations_api.py +6 -18
  98. universal_mcp/applications/twitter/api_segments/likes_api.py +1 -3
  99. universal_mcp/applications/twitter/api_segments/lists_api.py +5 -15
  100. universal_mcp/applications/twitter/api_segments/trends_api.py +1 -3
  101. universal_mcp/applications/twitter/api_segments/tweets_api.py +9 -31
  102. universal_mcp/applications/twitter/api_segments/usage_api.py +1 -5
  103. universal_mcp/applications/twitter/api_segments/users_api.py +14 -42
  104. universal_mcp/applications/whatsapp/app.py +35 -186
  105. universal_mcp/applications/whatsapp/audio.py +2 -6
  106. universal_mcp/applications/whatsapp/whatsapp.py +17 -51
  107. universal_mcp/applications/whatsapp_business/app.py +86 -299
  108. universal_mcp/applications/wrike/app.py +80 -153
  109. universal_mcp/applications/yahoo_finance/app.py +19 -65
  110. universal_mcp/applications/youtube/app.py +120 -306
  111. universal_mcp/applications/zenquotes/app.py +3 -3
  112. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/METADATA +4 -2
  113. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/RECORD +115 -119
  114. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/WHEEL +1 -1
  115. universal_mcp/applications/hubspot/api_segments/__init__.py +0 -0
  116. universal_mcp/applications/hubspot/api_segments/api_segment_base.py +0 -54
  117. universal_mcp/applications/hubspot/api_segments/crm_api.py +0 -7337
  118. universal_mcp/applications/hubspot/api_segments/marketing_api.py +0 -1467
  119. {universal_mcp_applications-0.1.33.dist-info → universal_mcp_applications-0.1.39rc16.dist-info}/licenses/LICENSE +0 -0
@@ -1,17 +1,13 @@
1
1
  from collections.abc import Callable
2
2
  from datetime import datetime
3
3
  from typing import Any
4
-
5
4
  from loguru import logger
6
5
 
7
6
  try:
8
7
  from twilio.rest import Client as TwilioClient
9
8
  except ImportError:
10
9
  TwilioClient = None
11
- logger.error(
12
- "Twilio SDK is not installed. Please install 'twilio' to use TwilioApp."
13
- )
14
-
10
+ logger.error("Twilio SDK is not installed. Please install 'twilio' to use TwilioApp.")
15
11
  from universal_mcp.applications.application import APIApplication
16
12
  from universal_mcp.exceptions import NotAuthorizedError, ToolError
17
13
  from universal_mcp.integrations import Integration
@@ -29,12 +25,9 @@ class TwilioApp(APIApplication):
29
25
  self._account_sid: str | None = None
30
26
  self._auth_token: str | None = None
31
27
  if TwilioClient is None:
32
- logger.warning(
33
- "Twilio SDK is not available. Twilio tools will not function."
34
- )
28
+ logger.warning("Twilio SDK is not available. Twilio tools will not function.")
35
29
 
36
- @property
37
- def account_sid(self) -> str:
30
+ async def account_sid(self) -> str:
38
31
  """
39
32
  Retrieves and caches the Twilio Account SID from the integration credentials.
40
33
  """
@@ -42,24 +35,16 @@ class TwilioApp(APIApplication):
42
35
  if not self.integration:
43
36
  raise NotAuthorizedError("Integration not configured for Twilio App.")
44
37
  try:
45
- credentials = self.integration.get_credentials()
38
+ credentials = await self.integration.get_credentials_async()
46
39
  except Exception as e:
47
40
  raise NotAuthorizedError(f"Failed to get Twilio credentials: {e}")
48
-
49
- sid = (
50
- credentials.get("account_sid")
51
- or credentials.get("ACCOUNT_SID")
52
- or credentials.get("TWILIO_ACCOUNT_SID")
53
- )
41
+ sid = credentials.get("account_sid") or credentials.get("ACCOUNT_SID") or credentials.get("TWILIO_ACCOUNT_SID")
54
42
  if not sid:
55
- raise NotAuthorizedError(
56
- "Twilio Account SID is missing. Please set it in the integration."
57
- )
43
+ raise NotAuthorizedError("Twilio Account SID is missing. Please set it in the integration.")
58
44
  self._account_sid = sid
59
45
  return self._account_sid
60
46
 
61
- @property
62
- def auth_token(self) -> str:
47
+ async def auth_token(self) -> str:
63
48
  """
64
49
  Retrieves and caches the Twilio Auth Token from the integration credentials.
65
50
  """
@@ -67,34 +52,26 @@ class TwilioApp(APIApplication):
67
52
  if not self.integration:
68
53
  raise NotAuthorizedError("Integration not configured for Twilio App.")
69
54
  try:
70
- credentials = self.integration.get_credentials()
55
+ credentials = await self.integration.get_credentials_async()
71
56
  except Exception as e:
72
57
  raise NotAuthorizedError(f"Failed to get Twilio credentials: {e}")
73
-
74
- token = (
75
- credentials.get("auth_token")
76
- or credentials.get("AUTH_TOKEN")
77
- or credentials.get("TWILIO_AUTH_TOKEN")
78
- )
58
+ token = credentials.get("auth_token") or credentials.get("AUTH_TOKEN") or credentials.get("TWILIO_AUTH_TOKEN")
79
59
  if not token:
80
- raise NotAuthorizedError(
81
- "Twilio Auth Token is missing. Please set it in the integration."
82
- )
60
+ raise NotAuthorizedError("Twilio Auth Token is missing. Please set it in the integration.")
83
61
  self._auth_token = token
84
62
  return self._auth_token
85
63
 
86
- @property
87
- def twilio_client(self) -> Any:
64
+ async def twilio_client(self) -> Any:
88
65
  """
89
66
  Returns a cached Twilio Client instance.
90
67
  """
91
68
  if self._twilio_client is None:
92
69
  if TwilioClient is None:
93
70
  raise ToolError("Twilio SDK is not installed.")
94
- self._twilio_client = TwilioClient(self.account_sid, self.auth_token)
71
+ self._twilio_client = TwilioClient(await self.account_sid, await self.auth_token)
95
72
  return self._twilio_client
96
73
 
97
- def create_message(self, from_: str, to: str, body: str) -> dict[str, Any]:
74
+ async def create_message(self, from_: str, to: str, body: str) -> dict[str, Any]:
98
75
  """
99
76
  Sends a new SMS or MMS message using Twilio.
100
77
 
@@ -114,12 +91,8 @@ class TwilioApp(APIApplication):
114
91
  create, message, sms, mms, send, twilio, api, important
115
92
  """
116
93
  try:
117
- message = self.twilio_client.messages.create(
118
- from_=from_,
119
- to=to,
120
- body=body,
121
- )
122
- # Convert the Twilio MessageInstance to a dict
94
+ client = await self.twilio_client()
95
+ message = await client.messages.create(from_=from_, to=to, body=body)
123
96
  return {
124
97
  "sid": message.sid,
125
98
  "status": message.status,
@@ -137,7 +110,7 @@ class TwilioApp(APIApplication):
137
110
  raise NotAuthorizedError(f"Twilio authentication failed: {e}")
138
111
  raise ToolError(f"Failed to send message: {e}")
139
112
 
140
- def fetch_message(self, message_sid: str) -> dict[str, Any]:
113
+ async def fetch_message(self, message_sid: str) -> dict[str, Any]:
141
114
  """
142
115
  Fetches the details of a specific message by its SID.
143
116
 
@@ -155,7 +128,8 @@ class TwilioApp(APIApplication):
155
128
  fetch, message, sms, mms, read, twilio, api, important
156
129
  """
157
130
  try:
158
- message = self.twilio_client.messages(message_sid).fetch()
131
+ client = await self.twilio_client()
132
+ message = await client.messages(message_sid).fetch()
159
133
  return {
160
134
  "sid": message.sid,
161
135
  "status": message.status,
@@ -173,11 +147,8 @@ class TwilioApp(APIApplication):
173
147
  raise NotAuthorizedError(f"Twilio authentication failed: {e}")
174
148
  raise ToolError(f"Failed to fetch message: {e}")
175
149
 
176
- def list_messages(
177
- self,
178
- limit: int = 20,
179
- date_sent_before: datetime | None = None,
180
- date_sent_after: datetime | None = None,
150
+ async def list_messages(
151
+ self, limit: int = 20, date_sent_before: datetime | None = None, date_sent_after: datetime | None = None
181
152
  ) -> list[dict[str, Any]]:
182
153
  """
183
154
  Lists messages from your Twilio account, optionally filtered by date.
@@ -198,15 +169,13 @@ class TwilioApp(APIApplication):
198
169
  list, message, sms, mms, read, twilio, api, important
199
170
  """
200
171
  try:
201
- params = {
202
- "limit": limit,
203
- }
172
+ params = {"limit": limit}
204
173
  if date_sent_before:
205
174
  params["date_sent_before"] = date_sent_before
206
175
  if date_sent_after:
207
176
  params["date_sent_after"] = date_sent_after
208
-
209
- messages = self.twilio_client.messages.list(**params)
177
+ client = await self.twilio_client()
178
+ messages = await client.messages.list(**params)
210
179
  result = []
211
180
  for msg in messages:
212
181
  result.append(
@@ -229,7 +198,7 @@ class TwilioApp(APIApplication):
229
198
  raise NotAuthorizedError(f"Twilio authentication failed: {e}")
230
199
  raise ToolError(f"Failed to list messages: {e}")
231
200
 
232
- def delete_message(self, message_sid: str) -> bool:
201
+ async def delete_message(self, message_sid: str) -> bool:
233
202
  """
234
203
  Deletes a specific message from your Twilio account.
235
204
 
@@ -247,7 +216,8 @@ class TwilioApp(APIApplication):
247
216
  delete, message, sms, mms, remove, twilio, api, important
248
217
  """
249
218
  try:
250
- result = self.twilio_client.messages(message_sid).delete()
219
+ client = await self.twilio_client()
220
+ result = await client.messages(message_sid).delete()
251
221
  return bool(result)
252
222
  except Exception as e:
253
223
  if "Authenticate" in str(e) or "401" in str(e):
@@ -261,9 +231,4 @@ class TwilioApp(APIApplication):
261
231
  Returns:
262
232
  A list of callable tool methods.
263
233
  """
264
- return [
265
- self.create_message,
266
- self.fetch_message,
267
- self.list_messages,
268
- self.delete_message,
269
- ]
234
+ return [self.create_message, self.fetch_message, self.list_messages, self.delete_message]
@@ -7,9 +7,7 @@ class ComplianceApi(APISegmentBase):
7
7
  def __init__(self, main_app_client: Any):
8
8
  super().__init__(main_app_client)
9
9
 
10
- def list_batch_compliance_jobs(
11
- self, type, status=None, compliance_job_fields=None
12
- ) -> dict[str, Any]:
10
+ def list_batch_compliance_jobs(self, type, status=None, compliance_job_fields=None) -> dict[str, Any]:
13
11
  """
14
12
  Retrieves a list of compliance jobs, requiring a job `type` ('tweets' or 'users') and allowing optional filtering by `status`. This function fetches multiple jobs, distinguishing it from `get_batch_compliance_job` which retrieves a single job by its unique ID.
15
13
 
@@ -42,9 +40,7 @@ class ComplianceApi(APISegmentBase):
42
40
  response.raise_for_status()
43
41
  return response.json()
44
42
 
45
- def create_batch_compliance_job(
46
- self, type, name=None, resumable=None
47
- ) -> dict[str, Any]:
43
+ def create_batch_compliance_job(self, type, name=None, resumable=None) -> dict[str, Any]:
48
44
  """
49
45
  Creates a new batch compliance job for a specified type ('tweets' or 'users'). A custom name can be provided, and resumable uploads can be enabled. This initiates the job creation process, differing from functions that list or retrieve existing jobs.
50
46
 
@@ -65,9 +61,7 @@ class ComplianceApi(APISegmentBase):
65
61
  """
66
62
  request_body_data = None
67
63
  request_body_data = {"name": name, "resumable": resumable, "type": type}
68
- request_body_data = {
69
- k: v for k, v in request_body_data.items() if v is not None
70
- }
64
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
71
65
  url = f"{self.main_app_client.base_url}/2/compliance/jobs"
72
66
  query_params = {}
73
67
  response = self._post(
@@ -100,11 +94,7 @@ class ComplianceApi(APISegmentBase):
100
94
  if id is None:
101
95
  raise ValueError("Missing required parameter 'id'.")
102
96
  url = f"{self.main_app_client.base_url}/2/compliance/jobs/{id}"
103
- query_params = {
104
- k: v
105
- for k, v in [("compliance_job.fields", compliance_job_fields)]
106
- if v is not None
107
- }
97
+ query_params = {k: v for k, v in [("compliance_job.fields", compliance_job_fields)] if v is not None}
108
98
  response = self._get(url, params=query_params)
109
99
  response.raise_for_status()
110
100
  return response.json()
@@ -7,9 +7,7 @@ class DmConversationsApi(APISegmentBase):
7
7
  def __init__(self, main_app_client: Any):
8
8
  super().__init__(main_app_client)
9
9
 
10
- def create_dm_conversation(
11
- self, conversation_type=None, message=None, participant_ids=None
12
- ) -> dict[str, Any]:
10
+ def create_dm_conversation(self, conversation_type=None, message=None, participant_ids=None) -> dict[str, Any]:
13
11
  """
14
12
  Creates a new group Direct Message conversation with specified participants and sends an initial message. This function specifically handles the creation of new multi-participant conversations, distinct from other methods in this class that add messages to existing one-to-one or group DMs.
15
13
 
@@ -34,9 +32,7 @@ class DmConversationsApi(APISegmentBase):
34
32
  "message": message,
35
33
  "participant_ids": participant_ids,
36
34
  }
37
- request_body_data = {
38
- k: v for k, v in request_body_data.items() if v is not None
39
- }
35
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
40
36
  url = f"{self.main_app_client.base_url}/2/dm_conversations"
41
37
  query_params = {}
42
38
  response = self._post(
@@ -105,9 +101,7 @@ class DmConversationsApi(APISegmentBase):
105
101
  response.raise_for_status()
106
102
  return response.json()
107
103
 
108
- def send_dm_by_participant_id(
109
- self, participant_id, attachments=None, text=None
110
- ) -> dict[str, Any]:
104
+ def send_dm_by_participant_id(self, participant_id, attachments=None, text=None) -> dict[str, Any]:
111
105
  """
112
106
  Sends a direct message to a user specified by their participant ID. It creates a new one-on-one conversation or appends the message to an existing one. Unlike other functions, this method identifies the conversation using the participant's ID rather than a pre-existing conversation ID.
113
107
 
@@ -130,9 +124,7 @@ class DmConversationsApi(APISegmentBase):
130
124
  raise ValueError("Missing required parameter 'participant_id'.")
131
125
  request_body_data = None
132
126
  request_body_data = {"attachments": attachments, "text": text}
133
- request_body_data = {
134
- k: v for k, v in request_body_data.items() if v is not None
135
- }
127
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
136
128
  url = f"{self.main_app_client.base_url}/2/dm_conversations/with/{participant_id}/messages"
137
129
  query_params = {}
138
130
  response = self._post(
@@ -144,9 +136,7 @@ class DmConversationsApi(APISegmentBase):
144
136
  response.raise_for_status()
145
137
  return response.json()
146
138
 
147
- def add_message_to_dm_conversation(
148
- self, dm_conversation_id, attachments=None, text=None
149
- ) -> dict[str, Any]:
139
+ def add_message_to_dm_conversation(self, dm_conversation_id, attachments=None, text=None) -> dict[str, Any]:
150
140
  """
151
141
  Sends a new message with optional text and attachments to an existing Direct Message conversation. The target conversation is specified by its `dm_conversation_id`, distinguishing it from functions that create new conversations or send one-to-one messages using a participant ID.
152
142
 
@@ -169,9 +159,7 @@ class DmConversationsApi(APISegmentBase):
169
159
  raise ValueError("Missing required parameter 'dm_conversation_id'.")
170
160
  request_body_data = None
171
161
  request_body_data = {"attachments": attachments, "text": text}
172
- request_body_data = {
173
- k: v for k, v in request_body_data.items() if v is not None
174
- }
162
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
175
163
  url = f"{self.main_app_client.base_url}/2/dm_conversations/{dm_conversation_id}/messages"
176
164
  query_params = {}
177
165
  response = self._post(
@@ -7,9 +7,7 @@ class LikesApi(APISegmentBase):
7
7
  def __init__(self, main_app_client: Any):
8
8
  super().__init__(main_app_client)
9
9
 
10
- def get_likes_compliance_stream(
11
- self, backfill_minutes=None, start_time=None, end_time=None
12
- ) -> Any:
10
+ def get_likes_compliance_stream(self, backfill_minutes=None, start_time=None, end_time=None) -> Any:
13
11
  """
14
12
  Streams compliance-related data for 'like' events, such as un-likes, with optional time and backfill filters. This endpoint is for compliance monitoring, differing from the firehose and sample streams which provide real-time like creation events.
15
13
 
@@ -32,9 +32,7 @@ class ListsApi(APISegmentBase):
32
32
  "name": name,
33
33
  "private": private,
34
34
  }
35
- request_body_data = {
36
- k: v for k, v in request_body_data.items() if v is not None
37
- }
35
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
38
36
  url = f"{self.main_app_client.base_url}/2/lists"
39
37
  query_params = {}
40
38
  response = self._post(
@@ -71,9 +69,7 @@ class ListsApi(APISegmentBase):
71
69
  response.raise_for_status()
72
70
  return response.json()
73
71
 
74
- def get_list_by_id(
75
- self, id, list_fields=None, expansions=None, user_fields=None
76
- ) -> dict[str, Any]:
72
+ def get_list_by_id(self, id, list_fields=None, expansions=None, user_fields=None) -> dict[str, Any]:
77
73
  """
78
74
  Retrieves detailed information for a specific list by its ID. This function allows for response customization by specifying which list and user fields to return and supports expansions to include related objects like the owner's user data.
79
75
 
@@ -109,9 +105,7 @@ class ListsApi(APISegmentBase):
109
105
  response.raise_for_status()
110
106
  return response.json()
111
107
 
112
- def update_list(
113
- self, id, description=None, name=None, private=None
114
- ) -> dict[str, Any]:
108
+ def update_list(self, id, description=None, name=None, private=None) -> dict[str, Any]:
115
109
  """
116
110
  Modifies an existing Twitter list identified by its unique ID. This function updates the list's name, description, or privacy status by sending a PUT request to the API and returns the updated list data upon success.
117
111
 
@@ -139,9 +133,7 @@ class ListsApi(APISegmentBase):
139
133
  "name": name,
140
134
  "private": private,
141
135
  }
142
- request_body_data = {
143
- k: v for k, v in request_body_data.items() if v is not None
144
- }
136
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
145
137
  url = f"{self.main_app_client.base_url}/2/lists/{id}"
146
138
  query_params = {}
147
139
  response = self._put(
@@ -271,9 +263,7 @@ class ListsApi(APISegmentBase):
271
263
  raise ValueError("Missing required parameter 'id'.")
272
264
  request_body_data = None
273
265
  request_body_data = {"user_id": user_id}
274
- request_body_data = {
275
- k: v for k, v in request_body_data.items() if v is not None
276
- }
266
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
277
267
  url = f"{self.main_app_client.base_url}/2/lists/{id}/members"
278
268
  query_params = {}
279
269
  response = self._post(
@@ -28,9 +28,7 @@ class TrendsApi(APISegmentBase):
28
28
  if woeid is None:
29
29
  raise ValueError("Missing required parameter 'woeid'.")
30
30
  url = f"{self.main_app_client.base_url}/2/trends/by/woeid/{woeid}"
31
- query_params = {
32
- k: v for k, v in [("trend.fields", trend_fields)] if v is not None
33
- }
31
+ query_params = {k: v for k, v in [("trend.fields", trend_fields)] if v is not None}
34
32
  response = self._get(url, params=query_params)
35
33
  response.raise_for_status()
36
34
  return response.json()
@@ -111,9 +111,7 @@ class TweetsApi(APISegmentBase):
111
111
  "reply_settings": reply_settings,
112
112
  "text": text,
113
113
  }
114
- request_body_data = {
115
- k: v for k, v in request_body_data.items() if v is not None
116
- }
114
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
117
115
  url = f"{self.main_app_client.base_url}/2/tweets"
118
116
  query_params = {}
119
117
  response = self._post(
@@ -125,9 +123,7 @@ class TweetsApi(APISegmentBase):
125
123
  response.raise_for_status()
126
124
  return response.json()
127
125
 
128
- def get_tweets_compliance_stream(
129
- self, partition, backfill_minutes=None, start_time=None, end_time=None
130
- ) -> Any:
126
+ def get_tweets_compliance_stream(self, partition, backfill_minutes=None, start_time=None, end_time=None) -> Any:
131
127
  """
132
128
  Streams real-time compliance events for tweets, such as deletions and user updates, from a specified partition. Unlike other stream functions that return tweet content, this provides metadata about content and user status changes, supporting optional time-based filtering and backfilling.
133
129
 
@@ -569,9 +565,7 @@ class TweetsApi(APISegmentBase):
569
565
  response.raise_for_status()
570
566
  return response.json()
571
567
 
572
- def stream_labeled_tweets(
573
- self, backfill_minutes=None, start_time=None, end_time=None
574
- ) -> Any:
568
+ def stream_labeled_tweets(self, backfill_minutes=None, start_time=None, end_time=None) -> Any:
575
569
  """
576
570
  Streams real-time Tweet objects labeled for compliance reasons, such as withheld content. Unlike `get_tweets_compliance_stream`, which provides events, this returns the actual tweets. Supports filtering by a time window and backfilling missed data upon reconnection.
577
571
 
@@ -917,9 +911,7 @@ class TweetsApi(APISegmentBase):
917
911
  response.raise_for_status()
918
912
  return response.json()
919
913
 
920
- def get_filtered_stream_rules(
921
- self, ids=None, max_results=None, pagination_token=None
922
- ) -> dict[str, Any]:
914
+ def get_filtered_stream_rules(self, ids=None, max_results=None, pagination_token=None) -> dict[str, Any]:
923
915
  """
924
916
  Retrieves the active filtering rules for a Twitter API v2 filtered stream. It can fetch all rules or a subset specified by rule IDs, with support for pagination to manage large rule sets, complementing the `add_or_delete_rules` and `search_stream` functions.
925
917
 
@@ -952,9 +944,7 @@ class TweetsApi(APISegmentBase):
952
944
  response.raise_for_status()
953
945
  return response.json()
954
946
 
955
- def update_stream_rules(
956
- self, dry_run=None, delete_all=None, add=None, delete=None
957
- ) -> dict[str, Any]:
947
+ def update_stream_rules(self, dry_run=None, delete_all=None, add=None, delete=None) -> dict[str, Any]:
958
948
  """
959
949
  Adds or removes filtering rules for a tweet stream. Supports a dry-run mode to validate rule syntax without application and an option to delete all existing rules. This function directly modifies the active rule set used by the `search_stream` function.
960
950
 
@@ -976,15 +966,9 @@ class TweetsApi(APISegmentBase):
976
966
  """
977
967
  request_body_data = None
978
968
  request_body_data = {"add": add, "delete": delete}
979
- request_body_data = {
980
- k: v for k, v in request_body_data.items() if v is not None
981
- }
969
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
982
970
  url = f"{self.main_app_client.base_url}/2/tweets/search/stream/rules"
983
- query_params = {
984
- k: v
985
- for k, v in [("dry_run", dry_run), ("delete_all", delete_all)]
986
- if v is not None
987
- }
971
+ query_params = {k: v for k, v in [("dry_run", dry_run), ("delete_all", delete_all)] if v is not None}
988
972
  response = self._post(
989
973
  url,
990
974
  data=request_body_data,
@@ -1012,11 +996,7 @@ class TweetsApi(APISegmentBase):
1012
996
  General
1013
997
  """
1014
998
  url = f"{self.main_app_client.base_url}/2/tweets/search/stream/rules/counts"
1015
- query_params = {
1016
- k: v
1017
- for k, v in [("rules_count.fields", rules_count_fields)]
1018
- if v is not None
1019
- }
999
+ query_params = {k: v for k, v in [("rules_count.fields", rules_count_fields)] if v is not None}
1020
1000
  response = self._get(url, params=query_params)
1021
1001
  response.raise_for_status()
1022
1002
  return response.json()
@@ -1332,9 +1312,7 @@ class TweetsApi(APISegmentBase):
1332
1312
  raise ValueError("Missing required parameter 'tweet_id'.")
1333
1313
  request_body_data = None
1334
1314
  request_body_data = {"hidden": hidden}
1335
- request_body_data = {
1336
- k: v for k, v in request_body_data.items() if v is not None
1337
- }
1315
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
1338
1316
  url = f"{self.main_app_client.base_url}/2/tweets/{tweet_id}/hidden"
1339
1317
  query_params = {}
1340
1318
  response = self._put(
@@ -26,11 +26,7 @@ class UsageApi(APISegmentBase):
26
26
  Usage
27
27
  """
28
28
  url = f"{self.main_app_client.base_url}/2/usage/tweets"
29
- query_params = {
30
- k: v
31
- for k, v in [("days", days), ("usage.fields", usage_fields)]
32
- if v is not None
33
- }
29
+ query_params = {k: v for k, v in [("days", days), ("usage.fields", usage_fields)] if v is not None}
34
30
  response = self._get(url, params=query_params)
35
31
  response.raise_for_status()
36
32
  return response.json()
@@ -7,9 +7,7 @@ class UsersApi(APISegmentBase):
7
7
  def __init__(self, main_app_client: Any):
8
8
  super().__init__(main_app_client)
9
9
 
10
- def get_users_by_ids(
11
- self, ids, user_fields=None, expansions=None, tweet_fields=None
12
- ) -> dict[str, Any]:
10
+ def get_users_by_ids(self, ids, user_fields=None, expansions=None, tweet_fields=None) -> dict[str, Any]:
13
11
  """
14
12
  Retrieves detailed information for multiple users in a single API request, specified by a list of their unique IDs. Unlike `find_user_by_id`, which fetches a single user, this function performs a bulk lookup and allows for response customization with optional fields and expansions.
15
13
 
@@ -44,9 +42,7 @@ class UsersApi(APISegmentBase):
44
42
  response.raise_for_status()
45
43
  return response.json()
46
44
 
47
- def get_users_by_usernames(
48
- self, usernames, user_fields=None, expansions=None, tweet_fields=None
49
- ) -> dict[str, Any]:
45
+ def get_users_by_usernames(self, usernames, user_fields=None, expansions=None, tweet_fields=None) -> dict[str, Any]:
50
46
  """
51
47
  Fetches public data for a batch of users specified by their usernames. This function supports retrieving multiple users in a single request, unlike `find_user_by_username`. It allows for data customization through optional fields and expansions.
52
48
 
@@ -81,9 +77,7 @@ class UsersApi(APISegmentBase):
81
77
  response.raise_for_status()
82
78
  return response.json()
83
79
 
84
- def find_user_by_username(
85
- self, username, user_fields=None, expansions=None, tweet_fields=None
86
- ) -> dict[str, Any]:
80
+ def find_user_by_username(self, username, user_fields=None, expansions=None, tweet_fields=None) -> dict[str, Any]:
87
81
  """
88
82
  Retrieves detailed information for a single user specified by their username, with options to include additional user, tweet, and expansion fields. This differs from `find_users_by_username`, which fetches data for multiple users in a single request.
89
83
 
@@ -119,9 +113,7 @@ class UsersApi(APISegmentBase):
119
113
  response.raise_for_status()
120
114
  return response.json()
121
115
 
122
- def get_users_compliance_stream(
123
- self, partition, backfill_minutes=None, start_time=None, end_time=None
124
- ) -> Any:
116
+ def get_users_compliance_stream(self, partition, backfill_minutes=None, start_time=None, end_time=None) -> Any:
125
117
  """
126
118
  Streams real-time user compliance events, such as account deletions or suspensions, from a specified data partition. Allows for backfilling missed data after a disconnection and filtering the event stream by a specific time range for targeted data retrieval.
127
119
 
@@ -156,9 +148,7 @@ class UsersApi(APISegmentBase):
156
148
  response.raise_for_status()
157
149
  return response.json()
158
150
 
159
- def get_authenticated_user(
160
- self, user_fields=None, expansions=None, tweet_fields=None
161
- ) -> dict[str, Any]:
151
+ def get_authenticated_user(self, user_fields=None, expansions=None, tweet_fields=None) -> dict[str, Any]:
162
152
  """
163
153
  Retrieves detailed information about the authenticated user making the request. Optional parameters allow for customizing the returned user and tweet data fields and including expanded objects. This differs from other 'find' functions as it requires no ID or username.
164
154
 
@@ -238,9 +228,7 @@ class UsersApi(APISegmentBase):
238
228
  response.raise_for_status()
239
229
  return response.json()
240
230
 
241
- def find_user_by_id(
242
- self, id, user_fields=None, expansions=None, tweet_fields=None
243
- ) -> dict[str, Any]:
231
+ def find_user_by_id(self, id, user_fields=None, expansions=None, tweet_fields=None) -> dict[str, Any]:
244
232
  """
245
233
  Retrieves detailed information for a single user specified by their unique ID. This function allows for response customization using optional fields and expansions. It differs from `find_users_by_id`, which fetches data for multiple users in a single request.
246
234
 
@@ -403,9 +391,7 @@ class UsersApi(APISegmentBase):
403
391
  raise ValueError("Missing required parameter 'id'.")
404
392
  request_body_data = None
405
393
  request_body_data = {"tweet_id": tweet_id}
406
- request_body_data = {
407
- k: v for k, v in request_body_data.items() if v is not None
408
- }
394
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
409
395
  url = f"{self.main_app_client.base_url}/2/users/{id}/bookmarks"
410
396
  query_params = {}
411
397
  response = self._post(
@@ -515,9 +501,7 @@ class UsersApi(APISegmentBase):
515
501
  raise ValueError("Missing required parameter 'id'.")
516
502
  request_body_data = None
517
503
  request_body_data = {"list_id": list_id}
518
- request_body_data = {
519
- k: v for k, v in request_body_data.items() if v is not None
520
- }
504
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
521
505
  url = f"{self.main_app_client.base_url}/2/users/{id}/followed_lists"
522
506
  query_params = {}
523
507
  response = self._post(
@@ -675,9 +659,7 @@ class UsersApi(APISegmentBase):
675
659
  raise ValueError("Missing required parameter 'id'.")
676
660
  request_body_data = None
677
661
  request_body_data = {"target_user_id": target_user_id}
678
- request_body_data = {
679
- k: v for k, v in request_body_data.items() if v is not None
680
- }
662
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
681
663
  url = f"{self.main_app_client.base_url}/2/users/{id}/following"
682
664
  query_params = {}
683
665
  response = self._post(
@@ -768,9 +750,7 @@ class UsersApi(APISegmentBase):
768
750
  raise ValueError("Missing required parameter 'id'.")
769
751
  request_body_data = None
770
752
  request_body_data = {"tweet_id": tweet_id}
771
- request_body_data = {
772
- k: v for k, v in request_body_data.items() if v is not None
773
- }
753
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
774
754
  url = f"{self.main_app_client.base_url}/2/users/{id}/likes"
775
755
  query_params = {}
776
756
  response = self._post(
@@ -997,9 +977,7 @@ class UsersApi(APISegmentBase):
997
977
  raise ValueError("Missing required parameter 'id'.")
998
978
  request_body_data = None
999
979
  request_body_data = {"target_user_id": target_user_id}
1000
- request_body_data = {
1001
- k: v for k, v in request_body_data.items() if v is not None
1002
- }
980
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
1003
981
  url = f"{self.main_app_client.base_url}/2/users/{id}/muting"
1004
982
  query_params = {}
1005
983
  response = self._post(
@@ -1059,9 +1037,7 @@ class UsersApi(APISegmentBase):
1059
1037
  response.raise_for_status()
1060
1038
  return response.json()
1061
1039
 
1062
- def get_user_pinned_lists(
1063
- self, id, list_fields=None, expansions=None, user_fields=None
1064
- ) -> dict[str, Any]:
1040
+ def get_user_pinned_lists(self, id, list_fields=None, expansions=None, user_fields=None) -> dict[str, Any]:
1065
1041
  """
1066
1042
  Retrieves the collection of lists pinned by a specific user, identified by their ID. Optional parameters allow for customizing the returned list and user data fields, and including expansions. This is distinct from fetching lists a user follows or owns.
1067
1043
 
@@ -1119,9 +1095,7 @@ class UsersApi(APISegmentBase):
1119
1095
  raise ValueError("Missing required parameter 'id'.")
1120
1096
  request_body_data = None
1121
1097
  request_body_data = {"list_id": list_id}
1122
- request_body_data = {
1123
- k: v for k, v in request_body_data.items() if v is not None
1124
- }
1098
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
1125
1099
  url = f"{self.main_app_client.base_url}/2/users/{id}/pinned_lists"
1126
1100
  query_params = {}
1127
1101
  response = self._post(
@@ -1183,9 +1157,7 @@ class UsersApi(APISegmentBase):
1183
1157
  raise ValueError("Missing required parameter 'id'.")
1184
1158
  request_body_data = None
1185
1159
  request_body_data = {"tweet_id": tweet_id}
1186
- request_body_data = {
1187
- k: v for k, v in request_body_data.items() if v is not None
1188
- }
1160
+ request_body_data = {k: v for k, v in request_body_data.items() if v is not None}
1189
1161
  url = f"{self.main_app_client.base_url}/2/users/{id}/retweets"
1190
1162
  query_params = {}
1191
1163
  response = self._post(