marqetive-lib 0.1.3__py3-none-any.whl → 0.1.4__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.
@@ -1,150 +0,0 @@
1
- """Twitter account factory for managing credentials and client creation."""
2
-
3
- import logging
4
- import os
5
- from collections.abc import Callable
6
-
7
- from marqetive.core.account_factory import BaseAccountFactory
8
- from marqetive.platforms.exceptions import PlatformAuthError
9
- from marqetive.platforms.models import AccountStatus, AuthCredentials
10
- from marqetive.platforms.twitter.client import TwitterClient
11
- from marqetive.utils.oauth import refresh_twitter_token
12
-
13
- logger = logging.getLogger(__name__)
14
-
15
-
16
- class TwitterAccountFactory(BaseAccountFactory):
17
- """Factory for creating and managing Twitter/X accounts and clients.
18
-
19
- Example:
20
- >>> factory = TwitterAccountFactory(
21
- ... client_id="your_client_id",
22
- ... client_secret="your_client_secret"
23
- ... )
24
- >>> credentials = AuthCredentials(
25
- ... platform="twitter",
26
- ... access_token="token",
27
- ... refresh_token="refresh"
28
- ... )
29
- >>> client = await factory.create_authenticated_client(credentials)
30
- >>> async with client:
31
- ... tweet = await client.create_post(request)
32
- """
33
-
34
- def __init__(
35
- self,
36
- client_id: str | None = None,
37
- client_secret: str | None = None,
38
- on_status_update: Callable[[str, AccountStatus], None] | None = None,
39
- ) -> None:
40
- """Initialize Twitter account factory.
41
-
42
- Args:
43
- client_id: Twitter OAuth client ID (uses TWITTER_CLIENT_ID env if None).
44
- client_secret: Twitter OAuth client secret (uses TWITTER_CLIENT_SECRET env if None).
45
- on_status_update: Optional callback when account status changes.
46
- """
47
- super().__init__(on_status_update=on_status_update)
48
- self.client_id = client_id or os.getenv("TWITTER_CLIENT_ID")
49
- self.client_secret = client_secret or os.getenv("TWITTER_CLIENT_SECRET")
50
-
51
- if not self.client_id or not self.client_secret:
52
- logger.warning(
53
- "Twitter client_id/client_secret not provided. "
54
- "Token refresh will not work."
55
- )
56
-
57
- @property
58
- def platform_name(self) -> str:
59
- """Get platform name."""
60
- return "twitter"
61
-
62
- async def refresh_token(self, credentials: AuthCredentials) -> AuthCredentials:
63
- """Refresh Twitter OAuth2 access token.
64
-
65
- Args:
66
- credentials: Current credentials with refresh token.
67
-
68
- Returns:
69
- Updated credentials with new access token.
70
-
71
- Raises:
72
- PlatformAuthError: If refresh fails or credentials missing.
73
- """
74
- if not self.client_id or not self.client_secret:
75
- raise PlatformAuthError(
76
- "Twitter client_id and client_secret are required for token refresh",
77
- platform=self.platform_name,
78
- )
79
-
80
- if not credentials.refresh_token:
81
- raise PlatformAuthError(
82
- "No refresh token available",
83
- platform=self.platform_name,
84
- )
85
-
86
- logger.info("Refreshing Twitter access token...")
87
- return await refresh_twitter_token(
88
- credentials,
89
- self.client_id,
90
- self.client_secret,
91
- )
92
-
93
- async def create_client(self, credentials: AuthCredentials) -> TwitterClient:
94
- """Create Twitter API client.
95
-
96
- Args:
97
- credentials: Valid Twitter credentials.
98
-
99
- Returns:
100
- TwitterClient instance.
101
-
102
- Raises:
103
- PlatformAuthError: If credentials are invalid.
104
- """
105
- if not credentials.access_token:
106
- raise PlatformAuthError(
107
- "Access token is required",
108
- platform=self.platform_name,
109
- )
110
-
111
- # Get additional data for Twitter
112
- additional_data = credentials.additional_data or {}
113
-
114
- # Twitter needs API key/secret for some operations
115
- api_key = additional_data.get("api_key") or os.getenv("TWITTER_API_KEY")
116
- api_secret = additional_data.get("api_secret") or os.getenv(
117
- "TWITTER_API_SECRET"
118
- )
119
-
120
- # Update additional_data if we have env values
121
- if api_key:
122
- additional_data["api_key"] = api_key
123
- if api_secret:
124
- additional_data["api_secret"] = api_secret
125
-
126
- credentials.additional_data = additional_data
127
-
128
- return TwitterClient(credentials=credentials)
129
-
130
- async def validate_credentials(self, credentials: AuthCredentials) -> bool:
131
- """Validate Twitter credentials by making a test API call.
132
-
133
- Args:
134
- credentials: Credentials to validate.
135
-
136
- Returns:
137
- True if credentials are valid, False otherwise.
138
- """
139
- try:
140
- client = await self.create_client(credentials)
141
- async with client:
142
- # Try to verify credentials by getting current user
143
- # This is a lightweight call to test authentication
144
- if client._tweepy_client:
145
- me = client._tweepy_client.get_me()
146
- return me is not None
147
- return False
148
- except Exception as e:
149
- logger.error(f"Error validating Twitter credentials: {e}")
150
- return False
@@ -1,121 +0,0 @@
1
- """Twitter post manager for handling post operations."""
2
-
3
- import logging
4
- from typing import Any
5
-
6
- from marqetive.core.base_manager import BasePostManager
7
- from marqetive.platforms.models import AuthCredentials, Post, PostCreateRequest
8
- from marqetive.platforms.twitter.client import TwitterClient
9
- from marqetive.platforms.twitter.factory import TwitterAccountFactory
10
-
11
- logger = logging.getLogger(__name__)
12
-
13
-
14
- class TwitterPostManager(BasePostManager):
15
- """Manager for Twitter/X post operations.
16
-
17
- Coordinates post creation, media uploads, and progress tracking for Twitter.
18
-
19
- Example:
20
- >>> manager = TwitterPostManager()
21
- >>> credentials = AuthCredentials(
22
- ... platform="twitter",
23
- ... access_token="token",
24
- ... refresh_token="refresh"
25
- ... )
26
- >>> request = PostCreateRequest(content="Hello Twitter!")
27
- >>> post = await manager.execute_post(credentials, request)
28
- >>> print(f"Tweet ID: {post.post_id}")
29
- """
30
-
31
- def __init__(
32
- self,
33
- account_factory: TwitterAccountFactory | None = None,
34
- client_id: str | None = None,
35
- client_secret: str | None = None,
36
- ) -> None:
37
- """Initialize Twitter post manager.
38
-
39
- Args:
40
- account_factory: Twitter account factory (creates default if None).
41
- client_id: Twitter OAuth client ID (for default factory).
42
- client_secret: Twitter OAuth client secret (for default factory).
43
- """
44
- if account_factory is None:
45
- account_factory = TwitterAccountFactory(
46
- client_id=client_id,
47
- client_secret=client_secret,
48
- )
49
-
50
- super().__init__(account_factory=account_factory)
51
-
52
- @property
53
- def platform_name(self) -> str:
54
- """Get platform name."""
55
- return "twitter"
56
-
57
- async def _execute_post_impl(
58
- self,
59
- client: Any,
60
- request: PostCreateRequest,
61
- credentials: AuthCredentials, # noqa: ARG002
62
- ) -> Post:
63
- """Execute Twitter post creation.
64
-
65
- Args:
66
- client: TwitterClient instance.
67
- request: Post creation request.
68
- credentials: Twitter credentials.
69
-
70
- Returns:
71
- Created Post object.
72
- """
73
- if not isinstance(client, TwitterClient):
74
- raise TypeError(f"Expected TwitterClient, got {type(client)}")
75
-
76
- # Handle media uploads with progress tracking
77
- media_ids: list[str] = []
78
- if request.media_urls:
79
- self._progress_tracker.emit_start(
80
- "upload_media",
81
- total=len(request.media_urls),
82
- message=f"Uploading {len(request.media_urls)} media files...",
83
- )
84
-
85
- for idx, media_url in enumerate(request.media_urls):
86
- if self.is_cancelled():
87
- raise InterruptedError("Post creation was cancelled")
88
-
89
- self._progress_tracker.emit_progress(
90
- "upload_media",
91
- progress=idx,
92
- total=len(request.media_urls),
93
- message=f"Uploading media {idx + 1}/{len(request.media_urls)}...",
94
- )
95
-
96
- # Twitter media upload is simplified in the client
97
- # In production, this would use tweepy's media upload
98
- media_attachment = await client.upload_media(
99
- media_url=media_url,
100
- media_type="image", # Default to image
101
- alt_text=None,
102
- )
103
- media_ids.append(media_attachment.media_id)
104
-
105
- self._progress_tracker.emit_complete(
106
- "upload_media",
107
- message="All media uploaded successfully",
108
- )
109
-
110
- # Create post with progress tracking
111
- self._progress_tracker.emit_progress(
112
- "execute_post",
113
- progress=50,
114
- total=100,
115
- message="Creating tweet...",
116
- )
117
-
118
- # Use the client to create the post
119
- post = await client.create_post(request)
120
-
121
- return post
@@ -1,68 +0,0 @@
1
- """Registry initialization for platform managers.
2
-
3
- This module provides the initialization function that registers all available
4
- platform managers with the global registry.
5
- """
6
-
7
- import logging
8
-
9
- from marqetive.core.registry import register_platform
10
- from marqetive.platforms.instagram.manager import InstagramPostManager
11
- from marqetive.platforms.linkedin.manager import LinkedInPostManager
12
- from marqetive.platforms.tiktok.manager import TikTokPostManager
13
- from marqetive.platforms.twitter.manager import TwitterPostManager
14
-
15
- logger = logging.getLogger(__name__)
16
-
17
- _initialized = False
18
-
19
-
20
- def initialize_platform_registry() -> None:
21
- """Initialize the platform registry with all available platforms.
22
-
23
- This function registers all platform managers (Twitter, LinkedIn, Instagram, TikTok)
24
- with the global registry. It should be called once at application startup.
25
-
26
- This function is idempotent - calling it multiple times is safe.
27
-
28
- Example:
29
- >>> from marqetive import initialize_platform_registry
30
- >>> initialize_platform_registry()
31
- >>> # Now you can use get_manager_for_platform()
32
- >>> from marqetive import get_manager_for_platform
33
- >>> manager = get_manager_for_platform("twitter")
34
- """
35
- global _initialized
36
-
37
- if _initialized:
38
- logger.debug("Platform registry already initialized")
39
- return
40
-
41
- logger.info("Initializing platform registry...")
42
-
43
- # Register all platform managers
44
- register_platform("twitter", TwitterPostManager)
45
- register_platform("linkedin", LinkedInPostManager)
46
- register_platform("instagram", InstagramPostManager)
47
- register_platform("tiktok", TikTokPostManager)
48
-
49
- _initialized = True
50
- logger.info("Platform registry initialized with 4 platforms")
51
-
52
-
53
- def is_registry_initialized() -> bool:
54
- """Check if registry has been initialized.
55
-
56
- Returns:
57
- True if initialized, False otherwise.
58
- """
59
- return _initialized
60
-
61
-
62
- def reset_registry() -> None:
63
- """Reset the initialization flag.
64
-
65
- This is mainly useful for testing. It allows re-initialization of the registry.
66
- """
67
- global _initialized
68
- _initialized = False
@@ -1,47 +0,0 @@
1
- marqetive/__init__.py,sha256=HqOJ0c2W_U31NelSR0-5CfzS8blJofRteSTudgr1Qwg,3090
2
- marqetive/core/__init__.py,sha256=qOC6JhGjWOpj9_7umtc6VGH16ZJZE6iNDhA6iDZm8kg,113
3
- marqetive/core/account_factory.py,sha256=3PrkWPdeUS8K8yaMufCsc-mhNN8k_9oDUo_ltnkMSPY,7145
4
- marqetive/core/base_manager.py,sha256=tbuwO2QQaSup_UXMCtmETcNutzCFV0omvroUM7yHFKA,10031
5
- marqetive/core/client.py,sha256=2_FoNpqaRglsWg10i5RTbyDg_kRQKhgWjYs6iDdFxLg,3210
6
- marqetive/core/progress.py,sha256=5Vyksf8YfQUVRudwDEuegcxoc0js5qbHM2SFZ6VLxHM,8593
7
- marqetive/core/registry.py,sha256=oqf32OJr9FDwmL5d5-UbDSV_-ICTI7vTYSrjagGp2r4,8072
8
- marqetive/platforms/__init__.py,sha256=jMzSg8fI5nCO20aTNaoF6cQ6RIZoxzVhEDvq3ZpAbXc,1327
9
- marqetive/platforms/base.py,sha256=y37RkSb3AGHtU-JmjxlUgbwlqG2MmF7w4MI3FATHoG4,11945
10
- marqetive/platforms/exceptions.py,sha256=Xyj0bzNiZm5VTErmzXgVW8T6IQnOpF92-HJiKPKjIio,7076
11
- marqetive/platforms/instagram/__init__.py,sha256=dFrDIyKGdw8AsRRYb_AjW1R8PWkxqytM-nrjuAvbw0A,331
12
- marqetive/platforms/instagram/client.py,sha256=XuvWl0aRHdAFScjOf4x4reQWkfZXdtGKmh1lIWcj4Lc,24939
13
- marqetive/platforms/instagram/exceptions.py,sha256=zwTc90VbG8uz_6O5bKw68Pp53SoevLQUqPiXj4ZgThU,8983
14
- marqetive/platforms/instagram/factory.py,sha256=qo7kLk7IoVWGjB0hJbkQqesOveN4gidw0kUh_7SzvaM,3533
15
- marqetive/platforms/instagram/manager.py,sha256=ZCqdlz5DgOhKUb1n2WOviLsr4NQxfBT4KiycSRv3Q-4,3714
16
- marqetive/platforms/instagram/media.py,sha256=JDRFB66UlhSjAf0PFR3raGqYxtNTSd5yIZ_2xTGmZRk,21166
17
- marqetive/platforms/linkedin/__init__.py,sha256=r-1p9yaJO4n8wYWNtN32Quwar6eAWkF5EtFN-v2AdPg,321
18
- marqetive/platforms/linkedin/client.py,sha256=ddcKmVN2d0ow2abfnaNSeswRsoYREdxj-J9w711zsy0,23558
19
- marqetive/platforms/linkedin/exceptions.py,sha256=WHjMZ-XJnKgT6uzzi7LXqFt4lD7nSCjzMzaqtOQA3hM,9767
20
- marqetive/platforms/linkedin/factory.py,sha256=N8POv4vMSg1L8PYnV9-JpHgYlaa33AfeWUhh6UPkViI,4516
21
- marqetive/platforms/linkedin/manager.py,sha256=K_X74qenJyd5HIL3KtsKpHjQOz48uENFJabZdsXwE-Y,3984
22
- marqetive/platforms/linkedin/media.py,sha256=360OT1sdBuJRjuL3wJ-T1irAX5gHmcf4AwAU__cvwwA,16901
23
- marqetive/platforms/models.py,sha256=W_yOuRWItWSn82n8vXRNN_ScdNkzY1De2qqXaVN2RGU,10974
24
- marqetive/platforms/tiktok/__init__.py,sha256=3S9ItK1Md7Qts21iNJQ5nvvkz7vHeu3ZUR2ZouoWz64,301
25
- marqetive/platforms/tiktok/client.py,sha256=lLTkUsQ-KEOyrBQXPeA3cK_enNqJVIgffZ99WHz9QJg,16783
26
- marqetive/platforms/tiktok/exceptions.py,sha256=yOjkZgHyo_t9Chrhws_2n-2sbiDDkCUBv5fdW2nfiHI,10129
27
- marqetive/platforms/tiktok/factory.py,sha256=U9myKTyPD1HEy3UShDeb1irP0PDZEMamLcbtHxjVtvQ,6744
28
- marqetive/platforms/tiktok/manager.py,sha256=HMem8to9WsKlQQBm6tiAmcJhoAeM6nwq7YAIvcfKnuY,4113
29
- marqetive/platforms/tiktok/media.py,sha256=3XjBrHQ7ahB6jVISNmYLgBR3p9N2RKiQRRdqCu_Dh2U,23785
30
- marqetive/platforms/twitter/__init__.py,sha256=zDEslH3Y6zCnFlYaoW77bkO7j75OmABjqMf1BGh8P5M,313
31
- marqetive/platforms/twitter/client.py,sha256=1jZz_ft77R0LqJbS6Po0HUErhGF_vRBGsoz7ExOb4L0,19379
32
- marqetive/platforms/twitter/exceptions.py,sha256=aKrjUZL07KWQ8hatj5-U7UfnSTl-n8DnTgGGigYCrIY,8931
33
- marqetive/platforms/twitter/factory.py,sha256=EZneqxoGg0TO952C4AHjv_HjyZ1ZQPR_jWPYYtQjF8E,5221
34
- marqetive/platforms/twitter/manager.py,sha256=QlPrVniPbJdlt39iMi_hmDGpaMkPT7pNjjIYUre2byY,4092
35
- marqetive/platforms/twitter/media.py,sha256=16atvKwSukvK_YC_gIm2qsl3pmidWEBAwIfJBPG9HQo,24968
36
- marqetive/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
- marqetive/registry_init.py,sha256=TFzkqd7ArW-pqp9GYGDRfNDQkvs3YUbUwakvX95IDKw,2151
38
- marqetive/utils/__init__.py,sha256=bSrNajbxYBSKQayrPviLz8JeGjplnyK8y_NGDtgb7yQ,977
39
- marqetive/utils/file_handlers.py,sha256=4TP5kmWofNTSZmlS683CM1UYP83WvRd_NubMbqtXv-g,12568
40
- marqetive/utils/helpers.py,sha256=8-ljhL47SremKcQO2GF8DIHOPODEv1rSioVNuSPCbec,2634
41
- marqetive/utils/media.py,sha256=Rvxw9XKU65n-z4G1bEihG3wXZBmjSDZUqClfjGFrg6k,12013
42
- marqetive/utils/oauth.py,sha256=NjHh3o5iKlXMJmzSFJHq-pn5yn82DvmpB7DMTJT0ht8,12105
43
- marqetive/utils/retry.py,sha256=lAniJLMNWp9XsHrvU0XBNifpNEjfde4MGfd5hlFTPfA,7636
44
- marqetive/utils/token_validator.py,sha256=pNimFr_FNJLcYGV5oADhoBjflKfEbLQ3Epwnwg_nTbg,6703
45
- marqetive_lib-0.1.3.dist-info/METADATA,sha256=9tmxgEtndJ5VUnX0hjAuLAqbAO8Wx0RhdI8joy4pbSY,7798
46
- marqetive_lib-0.1.3.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
47
- marqetive_lib-0.1.3.dist-info/RECORD,,