marqetive-lib 0.1.12__tar.gz → 0.1.14__tar.gz

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.
Files changed (39) hide show
  1. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/PKG-INFO +1 -1
  2. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/pyproject.toml +1 -1
  3. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/twitter/client.py +21 -18
  4. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/utils/oauth.py +41 -6
  5. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/README.md +0 -0
  6. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/__init__.py +0 -0
  7. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/core/__init__.py +0 -0
  8. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/core/base.py +0 -0
  9. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/core/client.py +0 -0
  10. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/core/exceptions.py +0 -0
  11. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/core/models.py +0 -0
  12. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/factory.py +0 -0
  13. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/__init__.py +0 -0
  14. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/instagram/__init__.py +0 -0
  15. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/instagram/client.py +0 -0
  16. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/instagram/exceptions.py +0 -0
  17. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/instagram/media.py +0 -0
  18. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/instagram/models.py +0 -0
  19. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/linkedin/__init__.py +0 -0
  20. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/linkedin/client.py +0 -0
  21. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/linkedin/exceptions.py +0 -0
  22. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/linkedin/media.py +0 -0
  23. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/linkedin/models.py +0 -0
  24. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/tiktok/__init__.py +0 -0
  25. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/tiktok/client.py +0 -0
  26. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/tiktok/exceptions.py +0 -0
  27. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/tiktok/media.py +0 -0
  28. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/tiktok/models.py +0 -0
  29. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/twitter/__init__.py +0 -0
  30. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/twitter/exceptions.py +0 -0
  31. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/twitter/media.py +0 -0
  32. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/platforms/twitter/models.py +0 -0
  33. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/py.typed +0 -0
  34. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/utils/__init__.py +0 -0
  35. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/utils/file_handlers.py +0 -0
  36. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/utils/helpers.py +0 -0
  37. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/utils/media.py +0 -0
  38. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/utils/retry.py +0 -0
  39. {marqetive_lib-0.1.12 → marqetive_lib-0.1.14}/src/marqetive/utils/token_validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: marqetive-lib
3
- Version: 0.1.12
3
+ Version: 0.1.14
4
4
  Summary: Modern Python utilities for web APIs
5
5
  Keywords: api,utilities,web,http,marqetive
6
6
  Requires-Python: >=3.12
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "marqetive-lib"
7
- version = "0.1.12"
7
+ version = "0.1.14"
8
8
  description = "Modern Python utilities for web APIs"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -207,14 +207,6 @@ class TwitterClient(SocialMediaPlatform):
207
207
  platform=self.platform_name,
208
208
  )
209
209
 
210
- # Validate tweet length (280 characters)
211
- if request.content and len(request.content) > 280:
212
- raise ValidationError(
213
- f"Tweet exceeds 280 characters ({len(request.content)} characters)",
214
- platform=self.platform_name,
215
- field="content",
216
- )
217
-
218
210
  try:
219
211
  media_ids = []
220
212
 
@@ -234,11 +226,17 @@ class TwitterClient(SocialMediaPlatform):
234
226
  if media_ids:
235
227
  tweet_params["media_ids"] = media_ids
236
228
 
237
- response = self._tweepy_client.create_tweet(**tweet_params)
229
+ response = self._tweepy_client.create_tweet(**tweet_params, user_auth=False)
238
230
  tweet_id = response.data["id"] # type: ignore[index]
239
231
 
240
- # Fetch full tweet details
241
- return await self.get_post(tweet_id)
232
+ # Return minimal Post object without fetching details
233
+ return Post(
234
+ post_id=tweet_id,
235
+ platform=self.platform_name,
236
+ content=request.content or "",
237
+ status=PostStatus.PUBLISHED,
238
+ created_at=datetime.now(),
239
+ )
242
240
 
243
241
  except tweepy.TweepyException as e:
244
242
  if "429" in str(e):
@@ -278,6 +276,7 @@ class TwitterClient(SocialMediaPlatform):
278
276
  ],
279
277
  expansions=["attachments.media_keys"],
280
278
  media_fields=["url", "type", "width", "height"],
279
+ user_auth=False,
281
280
  )
282
281
 
283
282
  if not response.data: # type: ignore[attr-defined]
@@ -339,7 +338,7 @@ class TwitterClient(SocialMediaPlatform):
339
338
  raise RuntimeError("Client must be used as async context manager")
340
339
 
341
340
  try:
342
- self._tweepy_client.delete_tweet(post_id)
341
+ self._tweepy_client.delete_tweet(post_id, user_auth=False)
343
342
  return True
344
343
 
345
344
  except tweepy.errors.NotFound as e: # type: ignore[attr-defined]
@@ -432,18 +431,22 @@ class TwitterClient(SocialMediaPlatform):
432
431
  response = self._tweepy_client.create_tweet(
433
432
  text=content,
434
433
  in_reply_to_tweet_id=post_id,
434
+ user_auth=False,
435
435
  )
436
436
 
437
437
  reply_id = response.data["id"] # type: ignore[index]
438
438
 
439
- # Fetch full reply details
440
- reply_response = self._tweepy_client.get_tweet(
441
- reply_id,
442
- tweet_fields=["created_at", "author_id", "public_metrics"],
439
+ # Return minimal Comment object without fetching details
440
+ return Comment(
441
+ comment_id=reply_id,
442
+ post_id=post_id,
443
+ platform=self.platform_name,
444
+ content=content,
445
+ author_id="",
446
+ created_at=datetime.now(),
447
+ status=CommentStatus.VISIBLE,
443
448
  )
444
449
 
445
- return self._parse_reply(reply_response.data, post_id) # type: ignore[attr-defined]
446
-
447
450
  except tweepy.TweepyException as e:
448
451
  raise PlatformError(
449
452
  f"Failed to create reply: {e}",
@@ -120,6 +120,9 @@ async def refresh_twitter_token(
120
120
  ) -> AuthCredentials:
121
121
  """Refresh Twitter OAuth2 access token.
122
122
 
123
+ Twitter requires HTTP Basic Authentication with client credentials
124
+ in the Authorization header, not in the request body.
125
+
123
126
  Args:
124
127
  credentials: Current credentials with refresh token.
125
128
  client_id: Twitter OAuth client ID.
@@ -144,6 +147,8 @@ async def refresh_twitter_token(
144
147
  ... os.getenv("TWITTER_CLIENT_SECRET")
145
148
  ... )
146
149
  """
150
+ import base64
151
+
147
152
  if not credentials.refresh_token:
148
153
  raise PlatformAuthError(
149
154
  "No refresh token available",
@@ -152,12 +157,42 @@ async def refresh_twitter_token(
152
157
 
153
158
  token_url = "https://api.x.com/2/oauth2/token"
154
159
 
155
- token_data = await refresh_oauth2_token(
156
- refresh_token=credentials.refresh_token,
157
- client_id=client_id,
158
- client_secret=client_secret,
159
- token_url=token_url,
160
- )
160
+ # Twitter requires Basic Auth header for confidential clients
161
+ basic_auth = base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()
162
+
163
+ params = {
164
+ "grant_type": "refresh_token",
165
+ "refresh_token": credentials.refresh_token,
166
+ }
167
+
168
+ try:
169
+ async with httpx.AsyncClient() as client:
170
+ response = await client.post(
171
+ token_url,
172
+ data=params,
173
+ headers={
174
+ "Content-Type": "application/x-www-form-urlencoded",
175
+ "Authorization": f"Basic {basic_auth}",
176
+ },
177
+ timeout=30.0,
178
+ )
179
+ response.raise_for_status()
180
+ token_data = response.json()
181
+
182
+ except httpx.HTTPStatusError as e:
183
+ logger.error(f"HTTP error refreshing Twitter token: {e.response.status_code}")
184
+ raise PlatformAuthError(
185
+ f"Failed to refresh token: {_sanitize_response_text(e.response.text)}",
186
+ platform="twitter",
187
+ status_code=e.response.status_code,
188
+ ) from e
189
+
190
+ except httpx.HTTPError as e:
191
+ logger.error(f"Network error refreshing Twitter token: {e}")
192
+ raise PlatformAuthError(
193
+ f"Network error refreshing token: {e}",
194
+ platform="twitter",
195
+ ) from e
161
196
 
162
197
  # Update credentials
163
198
  credentials.access_token = token_data["access_token"]
File without changes