marqetive-lib 0.1.3__py3-none-any.whl → 0.1.5__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.
- marqetive/__init__.py +54 -56
- marqetive/core/__init__.py +50 -1
- marqetive/{platforms → core}/base.py +35 -2
- marqetive/factory.py +380 -0
- marqetive/platforms/__init__.py +3 -3
- marqetive/platforms/instagram/__init__.py +1 -3
- marqetive/platforms/instagram/client.py +11 -7
- marqetive/platforms/instagram/exceptions.py +1 -1
- marqetive/platforms/instagram/media.py +1 -1
- marqetive/platforms/linkedin/__init__.py +1 -3
- marqetive/platforms/linkedin/client.py +8 -4
- marqetive/platforms/linkedin/exceptions.py +1 -1
- marqetive/platforms/linkedin/media.py +1 -1
- marqetive/platforms/tiktok/__init__.py +1 -3
- marqetive/platforms/tiktok/client.py +18 -9
- marqetive/platforms/tiktok/exceptions.py +1 -1
- marqetive/platforms/tiktok/media.py +2 -4
- marqetive/platforms/twitter/__init__.py +1 -3
- marqetive/platforms/twitter/client.py +7 -3
- marqetive/platforms/twitter/exceptions.py +1 -1
- marqetive/platforms/twitter/media.py +1 -1
- marqetive/utils/oauth.py +2 -2
- marqetive/utils/token_validator.py +1 -1
- {marqetive_lib-0.1.3.dist-info → marqetive_lib-0.1.5.dist-info}/METADATA +1 -1
- marqetive_lib-0.1.5.dist-info/RECORD +35 -0
- marqetive/core/account_factory.py +0 -212
- marqetive/core/base_manager.py +0 -303
- marqetive/core/progress.py +0 -291
- marqetive/core/registry.py +0 -257
- marqetive/platforms/instagram/factory.py +0 -106
- marqetive/platforms/instagram/manager.py +0 -112
- marqetive/platforms/linkedin/factory.py +0 -130
- marqetive/platforms/linkedin/manager.py +0 -119
- marqetive/platforms/tiktok/factory.py +0 -188
- marqetive/platforms/tiktok/manager.py +0 -115
- marqetive/platforms/twitter/factory.py +0 -150
- marqetive/platforms/twitter/manager.py +0 -121
- marqetive/registry_init.py +0 -68
- marqetive_lib-0.1.3.dist-info/RECORD +0 -47
- /marqetive/{platforms → core}/exceptions.py +0 -0
- /marqetive/{platforms → core}/models.py +0 -0
- {marqetive_lib-0.1.3.dist-info → marqetive_lib-0.1.5.dist-info}/WHEEL +0 -0
marqetive/core/base_manager.py
DELETED
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
"""Base manager for platform post operations.
|
|
2
|
-
|
|
3
|
-
This module provides an abstract base class for managing post operations
|
|
4
|
-
across different social media platforms with consistent patterns for
|
|
5
|
-
progress tracking, error handling, and state management.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import asyncio
|
|
9
|
-
import logging
|
|
10
|
-
from abc import ABC, abstractmethod
|
|
11
|
-
from typing import Any
|
|
12
|
-
|
|
13
|
-
from marqetive.core.account_factory import BaseAccountFactory
|
|
14
|
-
from marqetive.core.progress import ProgressCallback, ProgressTracker
|
|
15
|
-
from marqetive.platforms.exceptions import PlatformError
|
|
16
|
-
from marqetive.platforms.models import AuthCredentials, Post, PostCreateRequest
|
|
17
|
-
|
|
18
|
-
logger = logging.getLogger(__name__)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class BasePostManager(ABC):
|
|
22
|
-
"""Abstract base class for platform post managers.
|
|
23
|
-
|
|
24
|
-
Managers coordinate the posting process including:
|
|
25
|
-
- Creating authenticated clients via account factories
|
|
26
|
-
- Tracking operation progress
|
|
27
|
-
- Handling errors consistently
|
|
28
|
-
- Supporting cancellation
|
|
29
|
-
|
|
30
|
-
Subclasses must implement:
|
|
31
|
-
- _execute_post_impl(): Platform-specific posting logic
|
|
32
|
-
- platform_name: Property returning the platform name
|
|
33
|
-
|
|
34
|
-
Example:
|
|
35
|
-
>>> class TwitterPostManager(BasePostManager):
|
|
36
|
-
... @property
|
|
37
|
-
... def platform_name(self) -> str:
|
|
38
|
-
... return "twitter"
|
|
39
|
-
...
|
|
40
|
-
... async def _execute_post_impl(self, client, request):
|
|
41
|
-
... return await client.create_post(request)
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
def __init__(
|
|
45
|
-
self,
|
|
46
|
-
account_factory: BaseAccountFactory | None = None,
|
|
47
|
-
) -> None:
|
|
48
|
-
"""Initialize the post manager.
|
|
49
|
-
|
|
50
|
-
Args:
|
|
51
|
-
account_factory: Account factory for creating clients.
|
|
52
|
-
If None, subclass must provide default.
|
|
53
|
-
"""
|
|
54
|
-
self._account_factory = account_factory
|
|
55
|
-
self._progress_tracker = ProgressTracker()
|
|
56
|
-
self._cancel_event = asyncio.Event()
|
|
57
|
-
|
|
58
|
-
@property
|
|
59
|
-
@abstractmethod
|
|
60
|
-
def platform_name(self) -> str:
|
|
61
|
-
"""Get the name of the platform this manager handles.
|
|
62
|
-
|
|
63
|
-
Returns:
|
|
64
|
-
Platform name (e.g., "twitter", "linkedin").
|
|
65
|
-
"""
|
|
66
|
-
pass
|
|
67
|
-
|
|
68
|
-
@property
|
|
69
|
-
def account_factory(self) -> BaseAccountFactory:
|
|
70
|
-
"""Get the account factory.
|
|
71
|
-
|
|
72
|
-
Returns:
|
|
73
|
-
Account factory instance.
|
|
74
|
-
|
|
75
|
-
Raises:
|
|
76
|
-
RuntimeError: If account factory not set.
|
|
77
|
-
"""
|
|
78
|
-
if self._account_factory is None:
|
|
79
|
-
raise RuntimeError(
|
|
80
|
-
f"{self.__class__.__name__} requires an account_factory. "
|
|
81
|
-
"Either pass it to __init__ or override this property."
|
|
82
|
-
)
|
|
83
|
-
return self._account_factory
|
|
84
|
-
|
|
85
|
-
def add_progress_callback(self, callback: ProgressCallback) -> None:
|
|
86
|
-
"""Add a callback to receive progress updates.
|
|
87
|
-
|
|
88
|
-
Args:
|
|
89
|
-
callback: Function that receives ProgressEvent objects.
|
|
90
|
-
|
|
91
|
-
Example:
|
|
92
|
-
>>> def my_callback(event):
|
|
93
|
-
... print(f"{event.operation}: {event.percentage}%")
|
|
94
|
-
>>>
|
|
95
|
-
>>> manager.add_progress_callback(my_callback)
|
|
96
|
-
"""
|
|
97
|
-
self._progress_tracker.add_callback(callback)
|
|
98
|
-
|
|
99
|
-
def remove_progress_callback(self, callback: ProgressCallback) -> None:
|
|
100
|
-
"""Remove a progress callback.
|
|
101
|
-
|
|
102
|
-
Args:
|
|
103
|
-
callback: Callback to remove.
|
|
104
|
-
"""
|
|
105
|
-
self._progress_tracker.remove_callback(callback)
|
|
106
|
-
|
|
107
|
-
def clear_progress_callbacks(self) -> None:
|
|
108
|
-
"""Remove all progress callbacks."""
|
|
109
|
-
self._progress_tracker.clear_callbacks()
|
|
110
|
-
|
|
111
|
-
async def execute_post(
|
|
112
|
-
self,
|
|
113
|
-
credentials: AuthCredentials,
|
|
114
|
-
request: PostCreateRequest,
|
|
115
|
-
) -> Post:
|
|
116
|
-
"""Execute post creation with progress tracking and error handling.
|
|
117
|
-
|
|
118
|
-
This is the main entry point for creating posts. It handles:
|
|
119
|
-
- Client creation via account factory
|
|
120
|
-
- Progress tracking
|
|
121
|
-
- Cancellation support
|
|
122
|
-
- Consistent error handling
|
|
123
|
-
|
|
124
|
-
Args:
|
|
125
|
-
credentials: Platform credentials.
|
|
126
|
-
request: Post creation request.
|
|
127
|
-
|
|
128
|
-
Returns:
|
|
129
|
-
Created Post object.
|
|
130
|
-
|
|
131
|
-
Raises:
|
|
132
|
-
PlatformError: If post creation fails.
|
|
133
|
-
asyncio.CancelledError: If operation is cancelled.
|
|
134
|
-
|
|
135
|
-
Example:
|
|
136
|
-
>>> credentials = AuthCredentials(platform="twitter", ...)
|
|
137
|
-
>>> request = PostCreateRequest(content="Hello world!")
|
|
138
|
-
>>> post = await manager.execute_post(credentials, request)
|
|
139
|
-
>>> print(f"Posted: {post.post_id}")
|
|
140
|
-
"""
|
|
141
|
-
# Reset cancel event
|
|
142
|
-
self._cancel_event.clear()
|
|
143
|
-
|
|
144
|
-
try:
|
|
145
|
-
# Emit start event
|
|
146
|
-
self._progress_tracker.emit_start(
|
|
147
|
-
"execute_post",
|
|
148
|
-
message=f"Starting post to {self.platform_name}",
|
|
149
|
-
platform=self.platform_name,
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
# Check for cancellation
|
|
153
|
-
if self._cancel_event.is_set():
|
|
154
|
-
self._progress_tracker.emit_cancelled("execute_post")
|
|
155
|
-
raise asyncio.CancelledError("Post execution was cancelled")
|
|
156
|
-
|
|
157
|
-
# Create authenticated client
|
|
158
|
-
logger.info(f"Creating {self.platform_name} client...")
|
|
159
|
-
client = await self.account_factory.create_authenticated_client(credentials)
|
|
160
|
-
|
|
161
|
-
# Check for cancellation
|
|
162
|
-
if self._cancel_event.is_set():
|
|
163
|
-
self._progress_tracker.emit_cancelled("execute_post")
|
|
164
|
-
raise asyncio.CancelledError("Post execution was cancelled")
|
|
165
|
-
|
|
166
|
-
# Execute platform-specific posting logic
|
|
167
|
-
logger.info(f"Creating post on {self.platform_name}...")
|
|
168
|
-
post = await self._execute_post_impl(client, request, credentials)
|
|
169
|
-
|
|
170
|
-
# Emit completion event
|
|
171
|
-
self._progress_tracker.emit_complete(
|
|
172
|
-
"execute_post",
|
|
173
|
-
message=f"Post created successfully on {self.platform_name}",
|
|
174
|
-
post_id=post.post_id,
|
|
175
|
-
platform=self.platform_name,
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
logger.info(
|
|
179
|
-
f"Successfully created post {post.post_id} on {self.platform_name}"
|
|
180
|
-
)
|
|
181
|
-
return post
|
|
182
|
-
|
|
183
|
-
except asyncio.CancelledError:
|
|
184
|
-
self._progress_tracker.emit_cancelled(
|
|
185
|
-
"execute_post",
|
|
186
|
-
message=f"Post creation cancelled on {self.platform_name}",
|
|
187
|
-
)
|
|
188
|
-
raise
|
|
189
|
-
|
|
190
|
-
except Exception as e:
|
|
191
|
-
error_msg = f"Failed to create post on {self.platform_name}: {str(e)}"
|
|
192
|
-
logger.error(error_msg)
|
|
193
|
-
self._progress_tracker.emit_failed("execute_post", e)
|
|
194
|
-
|
|
195
|
-
# Wrap in PlatformError if not already
|
|
196
|
-
if not isinstance(e, PlatformError):
|
|
197
|
-
raise PlatformError(error_msg, platform=self.platform_name) from e
|
|
198
|
-
raise
|
|
199
|
-
|
|
200
|
-
@abstractmethod
|
|
201
|
-
async def _execute_post_impl(
|
|
202
|
-
self,
|
|
203
|
-
client: Any,
|
|
204
|
-
request: PostCreateRequest,
|
|
205
|
-
credentials: AuthCredentials,
|
|
206
|
-
) -> Post:
|
|
207
|
-
"""Platform-specific post creation implementation.
|
|
208
|
-
|
|
209
|
-
Subclasses must implement this to handle the actual post creation
|
|
210
|
-
logic for their specific platform.
|
|
211
|
-
|
|
212
|
-
Args:
|
|
213
|
-
client: Platform-specific authenticated client.
|
|
214
|
-
request: Post creation request.
|
|
215
|
-
credentials: Platform credentials (for context).
|
|
216
|
-
|
|
217
|
-
Returns:
|
|
218
|
-
Created Post object.
|
|
219
|
-
|
|
220
|
-
Raises:
|
|
221
|
-
PlatformError: If post creation fails.
|
|
222
|
-
"""
|
|
223
|
-
pass
|
|
224
|
-
|
|
225
|
-
def cancel_post(self) -> None:
|
|
226
|
-
"""Cancel the current post operation.
|
|
227
|
-
|
|
228
|
-
Sets a cancellation flag that is checked at key points during
|
|
229
|
-
post execution. The operation may not stop immediately.
|
|
230
|
-
|
|
231
|
-
Example:
|
|
232
|
-
>>> task = asyncio.create_task(manager.execute_post(...))
|
|
233
|
-
>>> # Later...
|
|
234
|
-
>>> manager.cancel_post()
|
|
235
|
-
>>> try:
|
|
236
|
-
... await task
|
|
237
|
-
... except asyncio.CancelledError:
|
|
238
|
-
... print("Operation was cancelled")
|
|
239
|
-
"""
|
|
240
|
-
self._cancel_event.set()
|
|
241
|
-
logger.info(f"Cancellation requested for {self.platform_name} post")
|
|
242
|
-
|
|
243
|
-
def is_cancelled(self) -> bool:
|
|
244
|
-
"""Check if cancellation has been requested.
|
|
245
|
-
|
|
246
|
-
Returns:
|
|
247
|
-
True if cancel_post() was called, False otherwise.
|
|
248
|
-
"""
|
|
249
|
-
return self._cancel_event.is_set()
|
|
250
|
-
|
|
251
|
-
async def get_post_status(
|
|
252
|
-
self,
|
|
253
|
-
credentials: AuthCredentials,
|
|
254
|
-
post_id: str,
|
|
255
|
-
) -> Post:
|
|
256
|
-
"""Get the current status of a post.
|
|
257
|
-
|
|
258
|
-
Args:
|
|
259
|
-
credentials: Platform credentials.
|
|
260
|
-
post_id: Platform-specific post ID.
|
|
261
|
-
|
|
262
|
-
Returns:
|
|
263
|
-
Post object with current status.
|
|
264
|
-
|
|
265
|
-
Raises:
|
|
266
|
-
PlatformError: If fetching post fails.
|
|
267
|
-
"""
|
|
268
|
-
try:
|
|
269
|
-
client = await self.account_factory.create_authenticated_client(credentials)
|
|
270
|
-
return await client.get_post(post_id)
|
|
271
|
-
except Exception as e:
|
|
272
|
-
error_msg = f"Failed to get post status from {self.platform_name}: {str(e)}"
|
|
273
|
-
logger.error(error_msg)
|
|
274
|
-
if not isinstance(e, PlatformError):
|
|
275
|
-
raise PlatformError(error_msg, platform=self.platform_name) from e
|
|
276
|
-
raise
|
|
277
|
-
|
|
278
|
-
async def delete_post(
|
|
279
|
-
self,
|
|
280
|
-
credentials: AuthCredentials,
|
|
281
|
-
post_id: str,
|
|
282
|
-
) -> bool:
|
|
283
|
-
"""Delete a post.
|
|
284
|
-
|
|
285
|
-
Args:
|
|
286
|
-
credentials: Platform credentials.
|
|
287
|
-
post_id: Platform-specific post ID.
|
|
288
|
-
|
|
289
|
-
Returns:
|
|
290
|
-
True if deletion was successful.
|
|
291
|
-
|
|
292
|
-
Raises:
|
|
293
|
-
PlatformError: If deletion fails.
|
|
294
|
-
"""
|
|
295
|
-
try:
|
|
296
|
-
client = await self.account_factory.create_authenticated_client(credentials)
|
|
297
|
-
return await client.delete_post(post_id)
|
|
298
|
-
except Exception as e:
|
|
299
|
-
error_msg = f"Failed to delete post from {self.platform_name}: {str(e)}"
|
|
300
|
-
logger.error(error_msg)
|
|
301
|
-
if not isinstance(e, PlatformError):
|
|
302
|
-
raise PlatformError(error_msg, platform=self.platform_name) from e
|
|
303
|
-
raise
|
marqetive/core/progress.py
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
"""Progress tracking system for long-running operations.
|
|
2
|
-
|
|
3
|
-
This module provides models and utilities for tracking progress of operations
|
|
4
|
-
like media uploads, post creation, and other long-running tasks.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from collections.abc import Callable
|
|
8
|
-
from datetime import datetime
|
|
9
|
-
from enum import Enum
|
|
10
|
-
from typing import Any
|
|
11
|
-
|
|
12
|
-
from pydantic import BaseModel, Field
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class ProgressStatus(str, Enum):
|
|
16
|
-
"""Status of a progress event."""
|
|
17
|
-
|
|
18
|
-
STARTED = "started"
|
|
19
|
-
IN_PROGRESS = "in_progress"
|
|
20
|
-
COMPLETED = "completed"
|
|
21
|
-
FAILED = "failed"
|
|
22
|
-
CANCELLED = "cancelled"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class ProgressEvent(BaseModel):
|
|
26
|
-
"""Represents a progress event for an operation.
|
|
27
|
-
|
|
28
|
-
Attributes:
|
|
29
|
-
operation: Name of the operation (e.g., "upload_media", "create_post").
|
|
30
|
-
progress: Current progress value (e.g., bytes uploaded).
|
|
31
|
-
total: Total expected value (e.g., total bytes).
|
|
32
|
-
status: Current status of the operation.
|
|
33
|
-
message: Optional human-readable message.
|
|
34
|
-
metadata: Additional operation-specific data.
|
|
35
|
-
timestamp: When this event occurred.
|
|
36
|
-
|
|
37
|
-
Example:
|
|
38
|
-
>>> event = ProgressEvent(
|
|
39
|
-
... operation="upload_media",
|
|
40
|
-
... progress=500,
|
|
41
|
-
... total=1000,
|
|
42
|
-
... status=ProgressStatus.IN_PROGRESS,
|
|
43
|
-
... message="Uploading image..."
|
|
44
|
-
... )
|
|
45
|
-
>>> print(f"Progress: {event.percentage}%")
|
|
46
|
-
Progress: 50.0%
|
|
47
|
-
"""
|
|
48
|
-
|
|
49
|
-
operation: str
|
|
50
|
-
progress: int | float
|
|
51
|
-
total: int | float | None = None
|
|
52
|
-
status: ProgressStatus
|
|
53
|
-
message: str | None = None
|
|
54
|
-
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
55
|
-
timestamp: datetime = Field(default_factory=datetime.now)
|
|
56
|
-
|
|
57
|
-
@property
|
|
58
|
-
def percentage(self) -> float:
|
|
59
|
-
"""Calculate progress as a percentage.
|
|
60
|
-
|
|
61
|
-
Returns:
|
|
62
|
-
Progress percentage (0-100), or 0 if total is None.
|
|
63
|
-
"""
|
|
64
|
-
if self.total is None or self.total == 0:
|
|
65
|
-
return 0.0
|
|
66
|
-
return (self.progress / self.total) * 100
|
|
67
|
-
|
|
68
|
-
def is_complete(self) -> bool:
|
|
69
|
-
"""Check if operation is complete.
|
|
70
|
-
|
|
71
|
-
Returns:
|
|
72
|
-
True if status is COMPLETED, False otherwise.
|
|
73
|
-
"""
|
|
74
|
-
return self.status == ProgressStatus.COMPLETED
|
|
75
|
-
|
|
76
|
-
def is_failed(self) -> bool:
|
|
77
|
-
"""Check if operation failed.
|
|
78
|
-
|
|
79
|
-
Returns:
|
|
80
|
-
True if status is FAILED, False otherwise.
|
|
81
|
-
"""
|
|
82
|
-
return self.status == ProgressStatus.FAILED
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
# Type alias for progress callback functions
|
|
86
|
-
ProgressCallback = Callable[[ProgressEvent], None]
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
class ProgressTracker:
|
|
90
|
-
"""Tracks and emits progress events for operations.
|
|
91
|
-
|
|
92
|
-
Manages multiple progress callbacks and provides utilities for
|
|
93
|
-
emitting progress events with consistent formatting.
|
|
94
|
-
|
|
95
|
-
Example:
|
|
96
|
-
>>> tracker = ProgressTracker()
|
|
97
|
-
>>> tracker.add_callback(lambda e: print(f"{e.operation}: {e.percentage}%"))
|
|
98
|
-
>>>
|
|
99
|
-
>>> tracker.emit_start("upload_media")
|
|
100
|
-
>>> tracker.emit_progress("upload_media", 500, 1000, "Uploading...")
|
|
101
|
-
>>> tracker.emit_complete("upload_media", "Upload complete")
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
def __init__(self) -> None:
|
|
105
|
-
"""Initialize progress tracker."""
|
|
106
|
-
self._callbacks: list[ProgressCallback] = []
|
|
107
|
-
|
|
108
|
-
def add_callback(self, callback: ProgressCallback) -> None:
|
|
109
|
-
"""Add a progress callback.
|
|
110
|
-
|
|
111
|
-
Args:
|
|
112
|
-
callback: Function to call when progress events occur.
|
|
113
|
-
|
|
114
|
-
Example:
|
|
115
|
-
>>> def my_callback(event: ProgressEvent) -> None:
|
|
116
|
-
... print(f"{event.operation}: {event.percentage}%")
|
|
117
|
-
>>>
|
|
118
|
-
>>> tracker.add_callback(my_callback)
|
|
119
|
-
"""
|
|
120
|
-
self._callbacks.append(callback)
|
|
121
|
-
|
|
122
|
-
def remove_callback(self, callback: ProgressCallback) -> None:
|
|
123
|
-
"""Remove a progress callback.
|
|
124
|
-
|
|
125
|
-
Args:
|
|
126
|
-
callback: Callback to remove.
|
|
127
|
-
"""
|
|
128
|
-
if callback in self._callbacks:
|
|
129
|
-
self._callbacks.remove(callback)
|
|
130
|
-
|
|
131
|
-
def clear_callbacks(self) -> None:
|
|
132
|
-
"""Remove all callbacks."""
|
|
133
|
-
self._callbacks.clear()
|
|
134
|
-
|
|
135
|
-
def emit(self, event: ProgressEvent) -> None:
|
|
136
|
-
"""Emit a progress event to all callbacks.
|
|
137
|
-
|
|
138
|
-
Args:
|
|
139
|
-
event: Progress event to emit.
|
|
140
|
-
"""
|
|
141
|
-
import contextlib
|
|
142
|
-
|
|
143
|
-
for callback in self._callbacks:
|
|
144
|
-
with contextlib.suppress(Exception):
|
|
145
|
-
# Silently ignore callback errors to prevent disrupting operations
|
|
146
|
-
callback(event)
|
|
147
|
-
|
|
148
|
-
def emit_start(
|
|
149
|
-
self,
|
|
150
|
-
operation: str,
|
|
151
|
-
total: int | float | None = None,
|
|
152
|
-
message: str | None = None,
|
|
153
|
-
**metadata: Any,
|
|
154
|
-
) -> None:
|
|
155
|
-
"""Emit an operation start event.
|
|
156
|
-
|
|
157
|
-
Args:
|
|
158
|
-
operation: Name of the operation.
|
|
159
|
-
total: Total expected value (optional).
|
|
160
|
-
message: Optional message.
|
|
161
|
-
**metadata: Additional metadata.
|
|
162
|
-
|
|
163
|
-
Example:
|
|
164
|
-
>>> tracker.emit_start("upload_media", total=1024000,
|
|
165
|
-
... message="Starting upload...")
|
|
166
|
-
"""
|
|
167
|
-
event = ProgressEvent(
|
|
168
|
-
operation=operation,
|
|
169
|
-
progress=0,
|
|
170
|
-
total=total,
|
|
171
|
-
status=ProgressStatus.STARTED,
|
|
172
|
-
message=message or f"Starting {operation}",
|
|
173
|
-
metadata=metadata,
|
|
174
|
-
)
|
|
175
|
-
self.emit(event)
|
|
176
|
-
|
|
177
|
-
def emit_progress(
|
|
178
|
-
self,
|
|
179
|
-
operation: str,
|
|
180
|
-
progress: int | float,
|
|
181
|
-
total: int | float | None = None,
|
|
182
|
-
message: str | None = None,
|
|
183
|
-
**metadata: Any,
|
|
184
|
-
) -> None:
|
|
185
|
-
"""Emit a progress update event.
|
|
186
|
-
|
|
187
|
-
Args:
|
|
188
|
-
operation: Name of the operation.
|
|
189
|
-
progress: Current progress value.
|
|
190
|
-
total: Total expected value (optional).
|
|
191
|
-
message: Optional message.
|
|
192
|
-
**metadata: Additional metadata.
|
|
193
|
-
|
|
194
|
-
Example:
|
|
195
|
-
>>> tracker.emit_progress("upload_media", 512000, 1024000,
|
|
196
|
-
... message="Uploading...")
|
|
197
|
-
"""
|
|
198
|
-
event = ProgressEvent(
|
|
199
|
-
operation=operation,
|
|
200
|
-
progress=progress,
|
|
201
|
-
total=total,
|
|
202
|
-
status=ProgressStatus.IN_PROGRESS,
|
|
203
|
-
message=message,
|
|
204
|
-
metadata=metadata,
|
|
205
|
-
)
|
|
206
|
-
self.emit(event)
|
|
207
|
-
|
|
208
|
-
def emit_complete(
|
|
209
|
-
self,
|
|
210
|
-
operation: str,
|
|
211
|
-
message: str | None = None,
|
|
212
|
-
**metadata: Any,
|
|
213
|
-
) -> None:
|
|
214
|
-
"""Emit an operation complete event.
|
|
215
|
-
|
|
216
|
-
Args:
|
|
217
|
-
operation: Name of the operation.
|
|
218
|
-
message: Optional message.
|
|
219
|
-
**metadata: Additional metadata.
|
|
220
|
-
|
|
221
|
-
Example:
|
|
222
|
-
>>> tracker.emit_complete("upload_media",
|
|
223
|
-
... message="Upload successful!")
|
|
224
|
-
"""
|
|
225
|
-
event = ProgressEvent(
|
|
226
|
-
operation=operation,
|
|
227
|
-
progress=100,
|
|
228
|
-
total=100,
|
|
229
|
-
status=ProgressStatus.COMPLETED,
|
|
230
|
-
message=message or f"{operation} completed",
|
|
231
|
-
metadata=metadata,
|
|
232
|
-
)
|
|
233
|
-
self.emit(event)
|
|
234
|
-
|
|
235
|
-
def emit_failed(
|
|
236
|
-
self,
|
|
237
|
-
operation: str,
|
|
238
|
-
error: str | Exception,
|
|
239
|
-
**metadata: Any,
|
|
240
|
-
) -> None:
|
|
241
|
-
"""Emit an operation failed event.
|
|
242
|
-
|
|
243
|
-
Args:
|
|
244
|
-
operation: Name of the operation.
|
|
245
|
-
error: Error message or exception.
|
|
246
|
-
**metadata: Additional metadata.
|
|
247
|
-
|
|
248
|
-
Example:
|
|
249
|
-
>>> try:
|
|
250
|
-
... # Some operation
|
|
251
|
-
... pass
|
|
252
|
-
... except Exception as e:
|
|
253
|
-
... tracker.emit_failed("upload_media", e)
|
|
254
|
-
"""
|
|
255
|
-
message = str(error) if isinstance(error, Exception) else error
|
|
256
|
-
event = ProgressEvent(
|
|
257
|
-
operation=operation,
|
|
258
|
-
progress=0,
|
|
259
|
-
total=100,
|
|
260
|
-
status=ProgressStatus.FAILED,
|
|
261
|
-
message=message,
|
|
262
|
-
metadata=metadata,
|
|
263
|
-
)
|
|
264
|
-
self.emit(event)
|
|
265
|
-
|
|
266
|
-
def emit_cancelled(
|
|
267
|
-
self,
|
|
268
|
-
operation: str,
|
|
269
|
-
message: str | None = None,
|
|
270
|
-
**metadata: Any,
|
|
271
|
-
) -> None:
|
|
272
|
-
"""Emit an operation cancelled event.
|
|
273
|
-
|
|
274
|
-
Args:
|
|
275
|
-
operation: Name of the operation.
|
|
276
|
-
message: Optional message.
|
|
277
|
-
**metadata: Additional metadata.
|
|
278
|
-
|
|
279
|
-
Example:
|
|
280
|
-
>>> tracker.emit_cancelled("upload_media",
|
|
281
|
-
... message="Upload cancelled by user")
|
|
282
|
-
"""
|
|
283
|
-
event = ProgressEvent(
|
|
284
|
-
operation=operation,
|
|
285
|
-
progress=0,
|
|
286
|
-
total=100,
|
|
287
|
-
status=ProgressStatus.CANCELLED,
|
|
288
|
-
message=message or f"{operation} cancelled",
|
|
289
|
-
metadata=metadata,
|
|
290
|
-
)
|
|
291
|
-
self.emit(event)
|