tgdata 0.0.0__tar.gz → 0.0.1__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 (33) hide show
  1. {tgdata-0.0.0 → tgdata-0.0.1}/PKG-INFO +88 -137
  2. tgdata-0.0.1/README.md +234 -0
  3. {tgdata-0.0.0 → tgdata-0.0.1}/setup.py +1 -1
  4. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/connection_engine.py +20 -4
  5. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/message_engine.py +78 -45
  6. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/test_00_connection.py +1 -1
  7. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/test_01_list_group_chats.py +1 -1
  8. tgdata-0.0.1/tgdata/smoke_tests/test_05_with_progress_feature.py +330 -0
  9. tgdata-0.0.1/tgdata/smoke_tests/test_06_polling_simple.py +124 -0
  10. tgdata-0.0.1/tgdata/smoke_tests/test_07_on_new_message_simple.py +159 -0
  11. tgdata-0.0.1/tgdata/smoke_tests/test_07_real_time_event_handler.py +433 -0
  12. tgdata-0.0.1/tgdata/smoke_tests/test_08_batch_callback.py +351 -0
  13. tgdata-0.0.0/tgdata/smoke_tests/test_10_polling.py → tgdata-0.0.1/tgdata/smoke_tests/test_08_polling.py +25 -22
  14. tgdata-0.0.1/tgdata/smoke_tests/test_debug_min_id.py +91 -0
  15. tgdata-0.0.1/tgdata/smoke_tests/test_polling_debug.py +190 -0
  16. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/tgdata.py +84 -31
  17. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata.egg-info/PKG-INFO +88 -137
  18. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata.egg-info/SOURCES.txt +9 -2
  19. tgdata-0.0.0/README.md +0 -283
  20. {tgdata-0.0.0 → tgdata-0.0.1}/setup.cfg +0 -0
  21. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/__init__.py +0 -0
  22. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/models.py +0 -0
  23. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/progress.py +0 -0
  24. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/__init__.py +0 -0
  25. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/my_test.py +0 -0
  26. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/test_02_get_message_count.py +0 -0
  27. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/test_03_get_all_messages.py +0 -0
  28. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/smoke_tests/test_04_get_all_messages_in_batches.py +0 -0
  29. /tgdata-0.0.0/tgdata/smoke_tests/test_06_advanced_features.py → /tgdata-0.0.1/tgdata/smoke_tests/test_10_advanced_features.py +0 -0
  30. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata/utils.py +0 -0
  31. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata.egg-info/dependency_links.txt +0 -0
  32. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata.egg-info/requires.txt +0 -0
  33. {tgdata-0.0.0 → tgdata-0.0.1}/tgdata.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tgdata
3
- Version: 0.0.0
3
+ Version: 0.0.1
4
4
  Summary: A production-grade Python library for extracting and processing Telegram group and channel messages
5
5
  Author: enes kuzucu
6
6
  Classifier: Development Status :: 3 - Alpha
@@ -46,20 +46,72 @@ A production-grade Python library for extracting and processing Telegram group a
46
46
  pip install tgdata
47
47
  ```
48
48
 
49
+
50
+ ## Authentication
51
+
52
+ tgdata supports 1 authentication at the moment.
53
+
54
+ (2 other are being implemented)
55
+
56
+ 1. get telegram development credentials in telegram API Development Tools from [https://my.telegram.org/apps](https://my.telegram.org/apps)
57
+
58
+ 2. Create a `config.ini` file with your Telegram API credentials like this:
59
+
60
+ ```ini
61
+ [Telegram]
62
+
63
+ # you can get telegram development credentials in telegram API Development Tools
64
+ api_id = 1234566
65
+ api_hash = a24adjfakjdfakjshdflkajsbdflk
66
+ phone = +905064004949 # use full phone number including + and country code
67
+ username = 'powerpuffdude'
68
+
69
+ ```
70
+
71
+
49
72
  ## Quick Start
50
73
 
74
+ ### List All Group Chats
75
+
76
+ This is required for finding chat id for the chat of interest.
77
+
51
78
  ```python
52
79
  from tgdata import TgData
53
80
  import asyncio
54
81
 
55
82
  async def main():
56
83
  # Initialize the client
57
- tg = TgData()
84
+ tg = TgData("config.ini")
58
85
 
59
86
  # List available groups and channels
60
87
  groups = await tg.list_groups()
61
- print(f"Found {len(groups)} groups/channels")
62
-
88
+
89
+ print(groups)
90
+
91
+ ```
92
+
93
+ Outputs:
94
+
95
+ ```
96
+ Python Devs 10012312313
97
+ ```
98
+
99
+
100
+ ### Get all messages of a chat
101
+
102
+ Once you optain chat id, you can use it to get all messages.
103
+ Upto 2500 messages you will not see limiting from Telegram.
104
+ If group is really active (+20 messages each day for over a year) then it is better to use batch logic.
105
+
106
+
107
+ ```python
108
+ from tgdata import TgData
109
+ import asyncio
110
+
111
+ async def main():
112
+ # Initialize the client
113
+ tg = TgData("config.ini")
114
+
63
115
  # Fetch messages from a specific group
64
116
  messages = await tg.get_messages(
65
117
  group_id=-1001234567890, # Your group ID
@@ -69,40 +121,43 @@ async def main():
69
121
 
70
122
  # Export to CSV
71
123
  tg.export_messages(messages, "messages.csv")
72
-
73
- # Get message statistics
74
- stats = tg.get_statistics(messages)
75
- print(f"Total messages: {stats['total_messages']}")
76
- print(f"Date range: {stats['date_range']['first']} to {stats['date_range']['last']}")
77
124
 
78
125
  asyncio.run(main())
79
126
  ```
80
127
 
81
- ## Configuration
128
+ ### Get message count of a chat
82
129
 
83
- Create a `config.ini` file with your Telegram API credentials:
84
130
 
85
- ```ini
86
- [telegram]
87
- api_id = YOUR_API_ID
88
- api_hash = YOUR_API_HASH
89
- session_file = telegram_session
131
+
132
+ ```python
133
+ from tgdata import TgData
134
+ import asyncio
135
+
136
+ async def main():
137
+ # Initialize the client
138
+ tg = TgData("config.ini")
139
+
140
+ # Fetch messages from a specific group
141
+ message_count = await tg.get_message_count(
142
+ group_id=-1001234567890, # Your group ID
143
+
144
+ )
145
+
146
+ print(message_count)
147
+
148
+ asyncio.run(main())
90
149
  ```
91
150
 
92
- Get your API credentials from [https://my.telegram.org/apps](https://my.telegram.org/apps)
151
+
152
+
93
153
 
94
154
  ## Advanced Usage
95
155
 
96
- ### ETL Pipeline Integration
156
+ ### get_messages with start_date parameter
97
157
 
98
158
  ```python
99
- from tgdata import TgData
100
- from datetime import datetime, timedelta
101
- import asyncio
102
159
 
103
- async def etl_pipeline():
104
- tg = TgData()
105
-
160
+ tg = TgData("config.ini")
106
161
  # Fetch recent messages for ETL processing
107
162
  yesterday = datetime.now() - timedelta(days=1)
108
163
  messages = await tg.get_messages(
@@ -111,21 +166,7 @@ async def etl_pipeline():
111
166
  with_progress=True
112
167
  )
113
168
 
114
- # Filter messages
115
- filtered = tg.filter_messages(
116
- messages,
117
- keyword="important",
118
- start_date=yesterday
119
- )
120
-
121
- # Export for data pipeline
122
- tg.export_messages(filtered, "daily_extract.json", format="json")
123
-
124
- # Get metrics
125
- metrics = await tg.get_metrics()
126
- print(f"Processed {len(filtered)} messages")
127
169
 
128
- asyncio.run(etl_pipeline())
129
170
  ```
130
171
 
131
172
  ### Incremental Message Fetching
@@ -134,9 +175,9 @@ asyncio.run(etl_pipeline())
134
175
  from tgdata import TgData
135
176
 
136
177
  async def incremental_fetch():
137
- tg = TgData()
178
+ tg = TgData("config.ini")
138
179
 
139
- # Get the latest message ID from your storage
180
+ # Get the latest message ID from your storage, or db
140
181
  last_processed_id = load_checkpoint() # Your implementation
141
182
 
142
183
  # Fetch only messages after that ID
@@ -144,15 +185,9 @@ async def incremental_fetch():
144
185
  group_id=-1001234567890,
145
186
  after_id=last_processed_id
146
187
  )
147
-
148
- if not new_messages.empty:
149
- # Process new messages
150
- process_messages(new_messages)
151
-
152
- # Save new checkpoint
153
- save_checkpoint(new_messages['MessageId'].max())
154
-
155
- print(f"New messages: {len(new_messages)}")
188
+
189
+ save_checkpoint(new_messages['MessageId'].max()) # Your implementation
190
+
156
191
 
157
192
  asyncio.run(incremental_fetch())
158
193
  ```
@@ -174,24 +209,10 @@ async def monitor_extraction():
174
209
  )
175
210
  ```
176
211
 
177
- ### Real-time Message Monitoring
212
+ ### Custom callback
213
+
214
+
178
215
 
179
- ```python
180
- async def monitor_real_time():
181
- tg = TgData()
182
-
183
- # Register handler for new messages
184
- @tg.on_new_message(group_id=-1001234567890)
185
- async def handle_message(event):
186
- print(f"New message from {event.sender_id}: {event.message.text}")
187
-
188
- # React to commands
189
- if event.message.text == "!ping":
190
- await event.reply("Pong!")
191
-
192
- # Run event loop
193
- await tg.run_with_event_loop()
194
- ```
195
216
 
196
217
  ### Polling for New Messages
197
218
 
@@ -213,69 +234,9 @@ async def poll_messages():
213
234
  )
214
235
  ```
215
236
 
216
- ## API Reference
217
-
218
- ### TgData
219
-
220
- Main class for interacting with Telegram groups and channels.
221
-
222
- #### Methods
223
-
224
- **Core Methods:**
225
- - `list_groups()` - List all accessible groups and channels
226
- - `get_messages()` - Fetch messages with various filters
227
- - `search_messages()` - Search for specific content
228
- - `filter_messages()` - Filter messages by criteria
229
- - `export_messages()` - Export to CSV or JSON
230
- - `get_statistics()` - Get message statistics
231
- - `get_metrics()` - Get session metrics
232
- - `get_message_count()` - Get total message count without fetching all
233
237
 
234
- **Real-time & Polling:**
235
- - `on_new_message()` - Decorator to register real-time message handlers
236
- - `poll_for_messages()` - Poll for new messages at intervals
237
- - `run_with_event_loop()` - Run client with event loop for real-time events
238
+ ### on_new_message method
238
239
 
239
- ### Checkpoint Management
240
-
241
- For production ETL pipelines, implement your own checkpoint logic:
242
-
243
- ```python
244
- # Save last processed message ID to your database
245
- last_id = messages['MessageId'].max()
246
- await save_to_database(group_id, last_id)
247
-
248
- # On next run, fetch only new messages
249
- last_id = await load_from_database(group_id)
250
- new_messages = await tg.get_messages(group_id=group_id, after_id=last_id)
251
- ```
252
-
253
- ## Production Deployment
254
-
255
- ### Best Practices
256
-
257
- 1. **Use environment variables for credentials**:
258
- ```python
259
- import os
260
- config_path = os.getenv("TELEGRAM_CONFIG", "config.ini")
261
- tg = TgData(config_path=config_path)
262
- ```
263
-
264
- 2. **Implement error handling**:
265
- ```python
266
- try:
267
- messages = await tg.get_messages(group_id=group_id)
268
- except Exception as e:
269
- logger.error(f"Failed to fetch messages: {e}")
270
- # Implement retry logic or alerting
271
- ```
272
-
273
- 3. **Monitor rate limits**:
274
- ```python
275
- health = await tg.health_check()
276
- if not health['primary_connection']:
277
- # Handle connection issues
278
- ```
279
240
 
280
241
  ### Performance Tips
281
242
 
@@ -297,13 +258,3 @@ MIT License - see LICENSE file for details
297
258
  ## Contributing
298
259
 
299
260
  Contributions are welcome! Please feel free to submit a Pull Request.
300
-
301
- ## Support
302
-
303
- - Documentation: [Full documentation](https://github.com/yourusername/tgdata)
304
- - Issues: [GitHub Issues](https://github.com/yourusername/tgdata/issues)
305
- - Examples: See the [examples/](examples/) directory
306
-
307
- ## Disclaimer
308
-
309
- This tool is for legitimate data collection and analysis only. Users must comply with Telegram's Terms of Service and applicable laws. Always respect user privacy and platform rate limits.
tgdata-0.0.1/README.md ADDED
@@ -0,0 +1,234 @@
1
+ # tgdata
2
+
3
+ A production-grade Python library for extracting and processing Telegram group and channel messages. Designed for ETL pipelines, data analysis, and archival purposes.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Production-Ready**: Built for reliability and scale in ETL pipelines
8
+ - 📊 **Efficient Data Extraction**: Fetch messages from groups and channels with rate limit handling
9
+ - 🔄 **Incremental Updates**: Fetch only new messages with `after_id` parameter
10
+ - 📈 **Progress Tracking**: Monitor long-running operations with real-time progress
11
+ - 🔌 **Clean Architecture**: Focused on data extraction with minimal dependencies
12
+ - 🛡️ **Robust Error Handling**: Automatic retries with exponential backoff
13
+ - 📁 **Multiple Export Formats**: Export to CSV, JSON, or integrate with your data pipeline
14
+ - 🔔 **Real-time Updates**: Listen for new messages with event handlers
15
+ - ⏱️ **Polling Support**: Poll for new messages at configurable intervals
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install tgdata
21
+ ```
22
+
23
+
24
+ ## Authentication
25
+
26
+ tgdata supports 1 authentication at the moment.
27
+
28
+ (2 other are being implemented)
29
+
30
+ 1. get telegram development credentials in telegram API Development Tools from [https://my.telegram.org/apps](https://my.telegram.org/apps)
31
+
32
+ 2. Create a `config.ini` file with your Telegram API credentials like this:
33
+
34
+ ```ini
35
+ [Telegram]
36
+
37
+ # you can get telegram development credentials in telegram API Development Tools
38
+ api_id = 1234566
39
+ api_hash = a24adjfakjdfakjshdflkajsbdflk
40
+ phone = +905064004949 # use full phone number including + and country code
41
+ username = 'powerpuffdude'
42
+
43
+ ```
44
+
45
+
46
+ ## Quick Start
47
+
48
+ ### List All Group Chats
49
+
50
+ This is required for finding chat id for the chat of interest.
51
+
52
+ ```python
53
+ from tgdata import TgData
54
+ import asyncio
55
+
56
+ async def main():
57
+ # Initialize the client
58
+ tg = TgData("config.ini")
59
+
60
+ # List available groups and channels
61
+ groups = await tg.list_groups()
62
+
63
+ print(groups)
64
+
65
+ ```
66
+
67
+ Outputs:
68
+
69
+ ```
70
+ Python Devs 10012312313
71
+ ```
72
+
73
+
74
+ ### Get all messages of a chat
75
+
76
+ Once you optain chat id, you can use it to get all messages.
77
+ Upto 2500 messages you will not see limiting from Telegram.
78
+ If group is really active (+20 messages each day for over a year) then it is better to use batch logic.
79
+
80
+
81
+ ```python
82
+ from tgdata import TgData
83
+ import asyncio
84
+
85
+ async def main():
86
+ # Initialize the client
87
+ tg = TgData("config.ini")
88
+
89
+ # Fetch messages from a specific group
90
+ messages = await tg.get_messages(
91
+ group_id=-1001234567890, # Your group ID
92
+ limit=1000,
93
+ with_progress=True
94
+ )
95
+
96
+ # Export to CSV
97
+ tg.export_messages(messages, "messages.csv")
98
+
99
+ asyncio.run(main())
100
+ ```
101
+
102
+ ### Get message count of a chat
103
+
104
+
105
+
106
+ ```python
107
+ from tgdata import TgData
108
+ import asyncio
109
+
110
+ async def main():
111
+ # Initialize the client
112
+ tg = TgData("config.ini")
113
+
114
+ # Fetch messages from a specific group
115
+ message_count = await tg.get_message_count(
116
+ group_id=-1001234567890, # Your group ID
117
+
118
+ )
119
+
120
+ print(message_count)
121
+
122
+ asyncio.run(main())
123
+ ```
124
+
125
+
126
+
127
+
128
+ ## Advanced Usage
129
+
130
+ ### get_messages with start_date parameter
131
+
132
+ ```python
133
+
134
+ tg = TgData("config.ini")
135
+ # Fetch recent messages for ETL processing
136
+ yesterday = datetime.now() - timedelta(days=1)
137
+ messages = await tg.get_messages(
138
+ group_id=-1001234567890,
139
+ start_date=yesterday,
140
+ with_progress=True
141
+ )
142
+
143
+
144
+ ```
145
+
146
+ ### Incremental Message Fetching
147
+
148
+ ```python
149
+ from tgdata import TgData
150
+
151
+ async def incremental_fetch():
152
+ tg = TgData("config.ini")
153
+
154
+ # Get the latest message ID from your storage, or db
155
+ last_processed_id = load_checkpoint() # Your implementation
156
+
157
+ # Fetch only messages after that ID
158
+ new_messages = await tg.get_messages(
159
+ group_id=-1001234567890,
160
+ after_id=last_processed_id
161
+ )
162
+
163
+ save_checkpoint(new_messages['MessageId'].max()) # Your implementation
164
+
165
+
166
+ asyncio.run(incremental_fetch())
167
+ ```
168
+
169
+ ### Progress Monitoring
170
+
171
+ ```python
172
+ async def monitor_extraction():
173
+ tg = TgData()
174
+
175
+ def progress_callback(current, total, rate):
176
+ percent = (current / total * 100) if total else 0
177
+ print(f"Progress: {current}/{total} ({percent:.1f}%) - {rate:.1f} msg/s")
178
+
179
+ messages = await tg.get_messages(
180
+ group_id=-1001234567890,
181
+ limit=10000,
182
+ progress_callback=progress_callback
183
+ )
184
+ ```
185
+
186
+ ### Custom callback
187
+
188
+
189
+
190
+
191
+ ### Polling for New Messages
192
+
193
+ ```python
194
+ async def poll_messages():
195
+ tg = TgData()
196
+
197
+ # Define callback for new messages
198
+ async def process_batch(messages_df):
199
+ print(f"Got {len(messages_df)} new messages")
200
+ # Process messages here
201
+
202
+ # Poll every 30 seconds
203
+ await tg.poll_for_messages(
204
+ group_id=-1001234567890,
205
+ interval=30,
206
+ callback=process_batch,
207
+ max_iterations=10 # Stop after 10 polls
208
+ )
209
+ ```
210
+
211
+
212
+ ### on_new_message method
213
+
214
+
215
+ ### Performance Tips
216
+
217
+ - Use connection pooling for parallel operations
218
+ - Implement checkpoint logic for incremental processing
219
+ - Implement progress callbacks for visibility
220
+ - Export data incrementally for large datasets
221
+
222
+ ## Requirements
223
+
224
+ - Python 3.7+
225
+ - Telegram API credentials (not bot tokens)
226
+ - Group/channel membership
227
+
228
+ ## License
229
+
230
+ MIT License - see LICENSE file for details
231
+
232
+ ## Contributing
233
+
234
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='tgdata', # Package name
5
- version='0.0.0', # Version of your package
5
+ version='0.0.1', # Version of your package
6
6
  author='enes kuzucu', # Your name
7
7
 
8
8
  description='A production-grade Python library for extracting and processing Telegram group and channel messages',
@@ -294,10 +294,26 @@ class ConnectionEngine:
294
294
  logger.error(f"Connection validation failed: {e}")
295
295
  return False
296
296
 
297
- async def handle_rate_limit(self, error: FloodWaitError, client: Optional[TelegramClient] = None):
298
- """Handle rate limit errors"""
299
- wait_time = error.seconds
300
- logger.warning(f"Rate limit hit! Waiting {wait_time} seconds...")
297
+ async def handle_rate_limit(self, error: FloodWaitError, client: Optional[TelegramClient] = None, strategy: str = 'wait'):
298
+ """
299
+ Handle rate limit errors with configurable strategy.
300
+
301
+ Args:
302
+ error: The FloodWaitError from Telegram
303
+ client: The client that hit the rate limit
304
+ strategy: 'wait' (wait exact time) or 'exponential' (exponential backoff)
305
+ """
306
+ base_wait_time = error.seconds
307
+
308
+ if strategy == 'exponential':
309
+ # Add random jitter (0-30% extra) to prevent thundering herd
310
+ import random
311
+ jitter = random.uniform(0, 0.3)
312
+ wait_time = base_wait_time * (1 + jitter)
313
+ logger.warning(f"Rate limit hit! Using exponential backoff: waiting {wait_time:.1f}s (base: {base_wait_time}s)")
314
+ else:
315
+ wait_time = base_wait_time
316
+ logger.warning(f"Rate limit hit! Waiting {wait_time} seconds...")
301
317
 
302
318
  if self._pool and client:
303
319
  self._pool.mark_rate_limited(client, wait_time)