marqetive-lib 0.1.22__tar.gz → 0.2.2__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.1.22 → marqetive_lib-0.2.2}/PKG-INFO +1 -1
  2. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/pyproject.toml +1 -1
  3. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/__init__.py +3 -1
  4. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/core/base.py +4 -0
  5. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/core/exceptions.py +46 -0
  6. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/twitter/client.py +14 -0
  7. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/README.md +0 -0
  8. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/core/__init__.py +0 -0
  9. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/core/client.py +0 -0
  10. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/core/models.py +0 -0
  11. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/factory.py +0 -0
  12. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/__init__.py +0 -0
  13. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/instagram/__init__.py +0 -0
  14. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/instagram/client.py +0 -0
  15. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/instagram/exceptions.py +0 -0
  16. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/instagram/media.py +0 -0
  17. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/instagram/models.py +0 -0
  18. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/linkedin/__init__.py +0 -0
  19. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/linkedin/client.py +0 -0
  20. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/linkedin/exceptions.py +0 -0
  21. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/linkedin/media.py +0 -0
  22. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/linkedin/models.py +0 -0
  23. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/tiktok/__init__.py +0 -0
  24. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/tiktok/client.py +0 -0
  25. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/tiktok/exceptions.py +0 -0
  26. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/tiktok/media.py +0 -0
  27. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/tiktok/models.py +0 -0
  28. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/twitter/__init__.py +0 -0
  29. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/twitter/exceptions.py +0 -0
  30. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/twitter/media.py +0 -0
  31. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/platforms/twitter/models.py +0 -0
  32. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/py.typed +0 -0
  33. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/utils/__init__.py +0 -0
  34. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/utils/file_handlers.py +0 -0
  35. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/utils/helpers.py +0 -0
  36. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/utils/media.py +0 -0
  37. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/src/marqetive/utils/oauth.py +0 -0
  38. {marqetive_lib-0.1.22 → marqetive_lib-0.2.2}/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.1.22
3
+ Version: 0.2.2
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.22"
7
+ version = "0.2.2"
8
8
  description = "Modern Python utilities for web APIs"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -47,6 +47,7 @@ from marqetive.core.exceptions import (
47
47
  PlatformError,
48
48
  PostNotFoundError,
49
49
  RateLimitError,
50
+ ThreadCancelledException,
50
51
  ValidationError,
51
52
  )
52
53
 
@@ -79,7 +80,7 @@ from marqetive.utils.helpers import format_response
79
80
  # Retry utilities
80
81
  from marqetive.utils.retry import STANDARD_BACKOFF, BackoffConfig, retry_async
81
82
 
82
- __version__ = "0.2.0"
83
+ __version__ = "0.2.2"
83
84
 
84
85
  __all__ = [
85
86
  # Core
@@ -119,6 +120,7 @@ __all__ = [
119
120
  "MediaUploadError",
120
121
  "ValidationError",
121
122
  "InvalidFileTypeError",
123
+ "ThreadCancelledException",
122
124
  # Types
123
125
  "ProgressCallback",
124
126
  # Utilities
@@ -389,6 +389,7 @@ class SocialMediaPlatform(ABC):
389
389
  async def create_thread(
390
390
  self,
391
391
  posts: list[PostCreateRequest],
392
+ cancellation_check: Callable[[], Awaitable[bool]] | None = None,
392
393
  ) -> list[Post]:
393
394
  """Create a thread of connected posts.
394
395
 
@@ -400,6 +401,8 @@ class SocialMediaPlatform(ABC):
400
401
  posts: List of post requests to create as a thread.
401
402
  Each post can have its own content, media, etc.
402
403
  First post is the head of the thread.
404
+ cancellation_check: Optional async callback that returns True if the
405
+ thread creation should be cancelled. Called before each post.
403
406
 
404
407
  Returns:
405
408
  List of Post objects for each post in the thread.
@@ -408,6 +411,7 @@ class SocialMediaPlatform(ABC):
408
411
  NotImplementedError: If platform doesn't support threads.
409
412
  ValidationError: If posts list is empty.
410
413
  PlatformAuthError: If not authenticated.
414
+ ThreadCancelledException: If cancelled mid-thread (includes posted items).
411
415
 
412
416
  Example:
413
417
  >>> # Twitter thread example
@@ -4,6 +4,13 @@ This module defines platform-specific exceptions for handling errors
4
4
  that may occur during API interactions with various social media platforms.
5
5
  """
6
6
 
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from marqetive.core.models import Post
13
+
7
14
 
8
15
  class PlatformError(Exception):
9
16
  """Base exception for all platform-related errors.
@@ -266,3 +273,42 @@ class InvalidFileTypeError(PlatformError):
266
273
  if self.file_type:
267
274
  return f"{base_message} | File type: {self.file_type}"
268
275
  return base_message
276
+
277
+
278
+ class ThreadCancelledException(PlatformError):
279
+ """Raised when a thread is cancelled mid-posting.
280
+
281
+ This exception is raised when:
282
+ - A cancellation callback returns True during thread creation
283
+ - Thread posting is interrupted before completion
284
+
285
+ The exception includes the list of posts that were successfully
286
+ created before cancellation, allowing the caller to handle rollback.
287
+
288
+ Args:
289
+ message: Human-readable error message
290
+ platform: Name of the platform where cancellation occurred
291
+ posted_tweets: List of Post objects that were created before cancellation
292
+
293
+ Example:
294
+ >>> try:
295
+ ... await client.create_thread(tweets, cancellation_check=check_cancel)
296
+ ... except ThreadCancelledException as e:
297
+ ... for post in e.posted_tweets:
298
+ ... await client.delete_post(post.post_id)
299
+ """
300
+
301
+ def __init__(
302
+ self,
303
+ message: str,
304
+ platform: str | None = None,
305
+ posted_tweets: list[Post] | None = None,
306
+ ) -> None:
307
+ self.posted_tweets = posted_tweets or []
308
+ super().__init__(message, platform)
309
+
310
+ def _format_message(self) -> str:
311
+ """Format the error message with posted tweet count."""
312
+ base_message = super()._format_message()
313
+ count = len(self.posted_tweets)
314
+ return f"{base_message} | Posted tweets: {count}"
@@ -6,6 +6,7 @@ ABC for Twitter (X), using the Twitter API v2 via tweepy.
6
6
  API Documentation: https://developer.x.com/en/docs/twitter-api
7
7
  """
8
8
 
9
+ from collections.abc import Awaitable, Callable
9
10
  from datetime import datetime
10
11
  from typing import Any
11
12
 
@@ -20,6 +21,7 @@ from marqetive.core.exceptions import (
20
21
  PlatformError,
21
22
  PostNotFoundError,
22
23
  RateLimitError,
24
+ ThreadCancelledException,
23
25
  ValidationError,
24
26
  )
25
27
  from marqetive.core.models import (
@@ -681,6 +683,7 @@ class TwitterClient(SocialMediaPlatform):
681
683
  async def create_thread(
682
684
  self,
683
685
  posts: list[PostCreateRequest],
686
+ cancellation_check: Callable[[], Awaitable[bool]] | None = None,
684
687
  ) -> list[Post]:
685
688
  """Create a Twitter thread (multiple linked tweets).
686
689
 
@@ -691,6 +694,8 @@ class TwitterClient(SocialMediaPlatform):
691
694
  posts: List of PostCreateRequest objects to create as a thread.
692
695
  First tweet is the head of the thread.
693
696
  Use TwitterPostRequest for Twitter-specific features.
697
+ cancellation_check: Optional async callback that returns True if the
698
+ thread creation should be cancelled. Called before each tweet.
694
699
 
695
700
  Returns:
696
701
  List of Post objects for each tweet in the thread.
@@ -699,6 +704,7 @@ class TwitterClient(SocialMediaPlatform):
699
704
  ValidationError: If posts list is empty.
700
705
  PlatformAuthError: If not authenticated.
701
706
  MediaUploadError: If media upload fails.
707
+ ThreadCancelledException: If cancelled mid-thread (includes posted tweets).
702
708
  RuntimeError: If client not used as context manager.
703
709
 
704
710
  Example:
@@ -723,6 +729,14 @@ class TwitterClient(SocialMediaPlatform):
723
729
  reply_to_id: str | None = None
724
730
 
725
731
  for idx, post_request in enumerate(posts):
732
+ # Check cancellation BEFORE posting each tweet
733
+ if cancellation_check is not None and await cancellation_check():
734
+ raise ThreadCancelledException(
735
+ f"Thread cancelled after {len(created_posts)} of {len(posts)} tweets",
736
+ platform=self.platform_name,
737
+ posted_tweets=created_posts,
738
+ )
739
+
726
740
  # Convert to TwitterPostRequest if needed and set reply chain
727
741
  if isinstance(post_request, TwitterPostRequest):
728
742
  if reply_to_id is not None:
File without changes