marqetive-lib 0.2.2__tar.gz → 0.2.4__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 (38) hide show
  1. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/PKG-INFO +1 -1
  2. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/pyproject.toml +1 -1
  3. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/linkedin/client.py +14 -0
  4. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/twitter/__init__.py +2 -0
  5. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/twitter/client.py +46 -0
  6. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/twitter/exceptions.py +35 -0
  7. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/twitter/media.py +22 -0
  8. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/README.md +0 -0
  9. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/__init__.py +0 -0
  10. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/core/__init__.py +0 -0
  11. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/core/base.py +0 -0
  12. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/core/client.py +0 -0
  13. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/core/exceptions.py +0 -0
  14. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/core/models.py +0 -0
  15. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/factory.py +0 -0
  16. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/__init__.py +0 -0
  17. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/instagram/__init__.py +0 -0
  18. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/instagram/client.py +0 -0
  19. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/instagram/exceptions.py +0 -0
  20. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/instagram/media.py +0 -0
  21. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/instagram/models.py +0 -0
  22. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/linkedin/__init__.py +0 -0
  23. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/linkedin/exceptions.py +0 -0
  24. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/linkedin/media.py +0 -0
  25. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/linkedin/models.py +0 -0
  26. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/tiktok/__init__.py +0 -0
  27. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/tiktok/client.py +0 -0
  28. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/tiktok/exceptions.py +0 -0
  29. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/tiktok/media.py +0 -0
  30. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/tiktok/models.py +0 -0
  31. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/platforms/twitter/models.py +0 -0
  32. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/py.typed +0 -0
  33. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/utils/__init__.py +0 -0
  34. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/utils/file_handlers.py +0 -0
  35. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/utils/helpers.py +0 -0
  36. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/utils/media.py +0 -0
  37. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/utils/oauth.py +0 -0
  38. {marqetive_lib-0.2.2 → marqetive_lib-0.2.4}/src/marqetive/utils/retry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: marqetive-lib
3
- Version: 0.2.2
3
+ Version: 0.2.4
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.2.2"
7
+ version = "0.2.4"
8
8
  description = "Modern Python utilities for web APIs"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -612,6 +612,20 @@ class LinkedInClient(SocialMediaPlatform):
612
612
  raw_data=response.data,
613
613
  )
614
614
 
615
+ except httpx.HTTPStatusError as e:
616
+ # Extract error details from LinkedIn's response body
617
+ error_details = ""
618
+ try:
619
+ error_body = e.response.json()
620
+ error_details = f" | Details: {error_body}"
621
+ except Exception:
622
+ if e.response.text:
623
+ error_details = f" | Response: {e.response.text[:500]}"
624
+
625
+ raise PlatformError(
626
+ f"Failed to create LinkedIn post: {e}{error_details}",
627
+ platform=self.platform_name,
628
+ ) from e
615
629
  except httpx.HTTPError as e:
616
630
  raise PlatformError(
617
631
  f"Failed to create LinkedIn post: {e}",
@@ -1,6 +1,7 @@
1
1
  """Twitter/X platform integration."""
2
2
 
3
3
  from marqetive.platforms.twitter.client import TwitterClient
4
+ from marqetive.platforms.twitter.exceptions import TwitterUnauthorizedError
4
5
  from marqetive.platforms.twitter.models import (
5
6
  TwitterDMRequest,
6
7
  TwitterGroupDMRequest,
@@ -12,4 +13,5 @@ __all__ = [
12
13
  "TwitterPostRequest",
13
14
  "TwitterDMRequest",
14
15
  "TwitterGroupDMRequest",
16
+ "TwitterUnauthorizedError",
15
17
  ]
@@ -40,6 +40,7 @@ from marqetive.core.models import (
40
40
  PostUpdateRequest,
41
41
  ProgressStatus,
42
42
  )
43
+ from marqetive.platforms.twitter.exceptions import TwitterUnauthorizedError
43
44
  from marqetive.platforms.twitter.media import MediaCategory, TwitterMediaManager
44
45
  from marqetive.platforms.twitter.models import TwitterDMRequest, TwitterPostRequest
45
46
 
@@ -312,6 +313,11 @@ class TwitterClient(SocialMediaPlatform):
312
313
  platform=self.platform_name,
313
314
  status_code=429,
314
315
  ) from e
316
+ if "401" in str(e):
317
+ raise TwitterUnauthorizedError(
318
+ "Unauthorized: Invalid or expired access token",
319
+ error_code=89,
320
+ ) from e
315
321
  raise PlatformError(
316
322
  f"Failed to create tweet: {e}",
317
323
  platform=self.platform_name,
@@ -362,6 +368,11 @@ class TwitterClient(SocialMediaPlatform):
362
368
  status_code=404,
363
369
  ) from e
364
370
  except tweepy.TweepyException as e:
371
+ if "401" in str(e):
372
+ raise TwitterUnauthorizedError(
373
+ "Unauthorized: Invalid or expired access token",
374
+ error_code=89,
375
+ ) from e
365
376
  raise PlatformError(
366
377
  f"Failed to fetch tweet: {e}",
367
378
  platform=self.platform_name,
@@ -415,6 +426,11 @@ class TwitterClient(SocialMediaPlatform):
415
426
  status_code=404,
416
427
  ) from e
417
428
  except tweepy.TweepyException as e:
429
+ if "401" in str(e):
430
+ raise TwitterUnauthorizedError(
431
+ "Unauthorized: Invalid or expired access token",
432
+ error_code=89,
433
+ ) from e
418
434
  raise PlatformError(
419
435
  f"Failed to delete tweet: {e}",
420
436
  platform=self.platform_name,
@@ -458,6 +474,16 @@ class TwitterClient(SocialMediaPlatform):
458
474
 
459
475
  return comments
460
476
 
477
+ except httpx.HTTPStatusError as e:
478
+ if e.response.status_code == 401:
479
+ raise TwitterUnauthorizedError(
480
+ "Unauthorized: Invalid or expired access token",
481
+ error_code=89,
482
+ ) from e
483
+ raise PlatformError(
484
+ f"Failed to fetch replies: {e}",
485
+ platform=self.platform_name,
486
+ ) from e
461
487
  except httpx.HTTPError as e:
462
488
  raise PlatformError(
463
489
  f"Failed to fetch replies: {e}",
@@ -515,6 +541,11 @@ class TwitterClient(SocialMediaPlatform):
515
541
  )
516
542
 
517
543
  except tweepy.TweepyException as e:
544
+ if "401" in str(e):
545
+ raise TwitterUnauthorizedError(
546
+ "Unauthorized: Invalid or expired access token",
547
+ error_code=89,
548
+ ) from e
518
549
  raise PlatformError(
519
550
  f"Failed to create reply: {e}",
520
551
  platform=self.platform_name,
@@ -633,6 +664,11 @@ class TwitterClient(SocialMediaPlatform):
633
664
  platform=self.platform_name,
634
665
  status_code=429,
635
666
  ) from e
667
+ if "401" in str(e):
668
+ raise TwitterUnauthorizedError(
669
+ "Unauthorized: Invalid or expired access token",
670
+ error_code=89,
671
+ ) from e
636
672
  raise PlatformError(
637
673
  f"Failed to retweet: {e}",
638
674
  platform=self.platform_name,
@@ -673,6 +709,11 @@ class TwitterClient(SocialMediaPlatform):
673
709
  platform=self.platform_name,
674
710
  status_code=429,
675
711
  ) from e
712
+ if "401" in str(e):
713
+ raise TwitterUnauthorizedError(
714
+ "Unauthorized: Invalid or expired access token",
715
+ error_code=89,
716
+ ) from e
676
717
  raise PlatformError(
677
718
  f"Failed to unretweet: {e}",
678
719
  platform=self.platform_name,
@@ -1108,6 +1149,11 @@ class TwitterClient(SocialMediaPlatform):
1108
1149
  platform=self.platform_name,
1109
1150
  status_code=429,
1110
1151
  ) from e
1152
+ if "401" in str(e):
1153
+ raise TwitterUnauthorizedError(
1154
+ "Unauthorized: Invalid or expired access token",
1155
+ error_code=89,
1156
+ ) from e
1111
1157
  raise PlatformError(
1112
1158
  f"Failed to create group conversation: {e}",
1113
1159
  platform=self.platform_name,
@@ -270,6 +270,41 @@ def get_retry_delay(
270
270
  return 5.0
271
271
 
272
272
 
273
+ class TwitterUnauthorizedError(PlatformAuthError):
274
+ """Raised when Twitter API returns 401 Unauthorized.
275
+
276
+ Common causes:
277
+ - Invalid or expired access token
278
+ - Revoked app permissions
279
+ - Invalid bearer token
280
+
281
+ Attributes:
282
+ error_code: Twitter-specific error code (e.g., 89 for invalid token).
283
+ """
284
+
285
+ def __init__(
286
+ self,
287
+ message: str,
288
+ *,
289
+ status_code: int = 401,
290
+ error_code: int | None = None,
291
+ ) -> None:
292
+ """Initialize Twitter unauthorized error.
293
+
294
+ Args:
295
+ message: Error message.
296
+ status_code: HTTP status code (default 401).
297
+ error_code: Twitter-specific error code.
298
+ """
299
+ super().__init__(
300
+ message,
301
+ platform="twitter",
302
+ status_code=status_code,
303
+ requires_reconnection=True,
304
+ )
305
+ self.error_code = error_code
306
+
307
+
273
308
  class TwitterAPIError(PlatformError):
274
309
  """Twitter API specific error with detailed information.
275
310
 
@@ -25,6 +25,7 @@ from marqetive.core.exceptions import (
25
25
  MediaUploadError,
26
26
  )
27
27
  from marqetive.core.models import ProgressEvent, ProgressStatus
28
+ from marqetive.platforms.twitter.exceptions import TwitterUnauthorizedError
28
29
  from marqetive.utils.file_handlers import download_file
29
30
  from marqetive.utils.media import (
30
31
  detect_mime_type,
@@ -399,6 +400,17 @@ class TwitterMediaManager:
399
400
 
400
401
  try:
401
402
  return await _do_upload()
403
+ except httpx.HTTPStatusError as e:
404
+ if e.response.status_code == 401:
405
+ raise TwitterUnauthorizedError(
406
+ "Unauthorized: Invalid or expired access token",
407
+ error_code=89,
408
+ ) from e
409
+ raise MediaUploadError(
410
+ f"Simple upload failed: {e}",
411
+ platform="twitter",
412
+ media_type=detect_mime_type(file_path),
413
+ ) from e
402
414
  except httpx.HTTPError as e:
403
415
  raise MediaUploadError(
404
416
  f"Simple upload failed: {e}",
@@ -701,6 +713,16 @@ class TwitterMediaManager:
701
713
  response.raise_for_status()
702
714
  logger.info(f"Added alt text to media: {media_id}")
703
715
 
716
+ except httpx.HTTPStatusError as e:
717
+ if e.response.status_code == 401:
718
+ raise TwitterUnauthorizedError(
719
+ "Unauthorized: Invalid or expired access token",
720
+ error_code=89,
721
+ ) from e
722
+ raise MediaUploadError(
723
+ f"Failed to add alt text: {e}",
724
+ platform="twitter",
725
+ ) from e
704
726
  except httpx.HTTPError as e:
705
727
  raise MediaUploadError(
706
728
  f"Failed to add alt text: {e}",
File without changes