rabbitmq-easy 1.0.0__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.
@@ -0,0 +1,128 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ pip-wheel-metadata/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ *.manifest
32
+ *.spec
33
+
34
+ # Installer logs
35
+ pip-log.txt
36
+ pip-delete-this-directory.txt
37
+
38
+ # Unit test / coverage reports
39
+ htmlcov/
40
+ .tox/
41
+ .nox/
42
+ .coverage
43
+ .coverage.*
44
+ .cache
45
+ nosetests.xml
46
+ coverage.xml
47
+ *.cover
48
+ *.py,cover
49
+ .hypothesis/
50
+ .pytest_cache/
51
+
52
+ # Translations
53
+ *.mo
54
+ *.pot
55
+
56
+ # Django stuff:
57
+ *.log
58
+ local_settings.py
59
+ db.sqlite3
60
+ db.sqlite3-journal
61
+
62
+ # Flask stuff:
63
+ instance/
64
+ .webassets-cache
65
+
66
+ # Scrapy stuff:
67
+ .scrapy
68
+
69
+ # Sphinx documentation
70
+ docs/_build/
71
+
72
+ # PyBuilder
73
+ target/
74
+
75
+ # Jupyter Notebook
76
+ .ipynb_checkpoints
77
+
78
+ # IPython
79
+ profile_default/
80
+ ipython_config.py
81
+
82
+ # pyenv
83
+ .python-version
84
+
85
+ # pipenv
86
+ Pipfile.lock
87
+
88
+ # PEP 582
89
+ __pypackages__/
90
+
91
+ # Celery stuff
92
+ celerybeat-schedule
93
+ celerybeat.pid
94
+
95
+ # SageMath parsed files
96
+ *.sage.py
97
+
98
+ # Environments
99
+ .env
100
+ .venv
101
+ env/
102
+ venv/
103
+ ENV/
104
+ env.bak/
105
+ venv.bak/
106
+
107
+ # Spyder project settings
108
+ .spyderproject
109
+ .spyproject
110
+
111
+ # Rope project settings
112
+ .ropeproject
113
+
114
+ # mkdocs documentation
115
+ /site
116
+
117
+ # mypy
118
+ .mypy_cache/
119
+ .dmypy.json
120
+ dmypy.json
121
+
122
+ # Pyre type checker
123
+ .pyre/
124
+
125
+ # Custom
126
+ rabbitmq_manager.log
127
+ *.log
128
+ .DS_Store
@@ -0,0 +1,24 @@
1
+ # Changelog
2
+
3
+ ## [1.0.0] - 2025-06-10
4
+
5
+ ### Added
6
+ - Initial release of RabbitMQ Easy
7
+ - Automatic connection management with retry logic
8
+ - Dead letter queue support
9
+ - Environment variable configuration
10
+ - Comprehensive logging with emoji indicators
11
+ - Context manager support
12
+ - Health check functionality
13
+ - Queue information retrieval
14
+ - Batch queue setup
15
+ - Custom exceptions for better error handling
16
+ - Complete test suite
17
+ - Documentation and examples
18
+
19
+ ### Features
20
+ - Idempotent queue and exchange creation
21
+ - Automatic reconnection on connection loss
22
+ - Configurable retry logic
23
+ - Support for both file and console logging
24
+ - Production-ready error handling
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Your Name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ include README.md
2
+ include LICENSE
3
+ include CHANGELOG.md
4
+ include requirements.txt
5
+ include requirements-dev.txt
6
+ recursive-include examples *.py
7
+ recursive-include tests *.py
@@ -0,0 +1,435 @@
1
+ Metadata-Version: 2.4
2
+ Name: rabbitmq-easy
3
+ Version: 1.0.0
4
+ Summary: A simple, robust RabbitMQ manager for Python applications
5
+ Home-page: https://github.com/yourusername/rabbitmq-easy
6
+ Author: Your Name
7
+ Author-email: Your Name <your.email@example.com>
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/yourusername/rabbitmq-easy
10
+ Project-URL: Bug Reports, https://github.com/yourusername/rabbitmq-easy/issues
11
+ Project-URL: Source, https://github.com/yourusername/rabbitmq-easy
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.7
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Requires-Python: >=3.7
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: pika>=1.2.0
26
+ Requires-Dist: python-dotenv>=0.19.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=6.0; extra == "dev"
29
+ Requires-Dist: pytest-cov; extra == "dev"
30
+ Requires-Dist: black; extra == "dev"
31
+ Requires-Dist: flake8; extra == "dev"
32
+ Requires-Dist: mypy; extra == "dev"
33
+ Requires-Dist: twine; extra == "dev"
34
+ Requires-Dist: wheel; extra == "dev"
35
+ Dynamic: author
36
+ Dynamic: home-page
37
+ Dynamic: license-file
38
+ Dynamic: requires-python
39
+
40
+ # RabbitMQ Easy
41
+
42
+ [![PyPI version](https://badge.fury.io/py/rabbitmq-easy.svg)](https://badge.fury.io/py/rabbitmq-easy)
43
+ [![Python Support](https://img.shields.io/pypi/pyversions/rabbitmq-easy.svg)](https://pypi.org/project/rabbitmq-easy/)
44
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
45
+
46
+ A simple, robust RabbitMQ manager for Python applications with built-in connection management, retry logic, and dead letter queue support.
47
+
48
+ ## 🚀 Features
49
+
50
+ - **🔄 Automatic Connection Management**: Built-in retry logic and connection recovery
51
+ - **🛡️ Dead Letter Queue Support**: Automatic setup of dead letter exchanges and queues
52
+ - **📊 Comprehensive Logging**: Both file and console logging with emoji indicators
53
+ - **🔧 Environment Variable Support**: Easy configuration through environment variables
54
+ - **🧪 Idempotent Operations**: Safe to run multiple times without errors
55
+ - **📦 Context Manager Support**: Proper resource cleanup
56
+ - **⚡ Production Ready**: Used in production environments
57
+ - **🗑️ Resource Management**: Built-in cleanup and deletion functions
58
+
59
+ ## 📦 Installation
60
+
61
+ ```bash
62
+ pip install rabbitmq-easy
63
+ ```
64
+
65
+ ## 🏃‍♂️ Quick Start
66
+
67
+ ### Basic Usage
68
+
69
+ ```python
70
+ from rabbitmq_easy import RabbitMQManager
71
+
72
+ # Simple setup
73
+ manager = RabbitMQManager(
74
+ host='localhost',
75
+ port=5672,
76
+ username='admin',
77
+ password='password',
78
+ queues=['queue1', 'queue2'],
79
+ routing_keys=['queue1.*', 'queue2.*'],
80
+ exchange='my_exchange'
81
+ )
82
+
83
+ # Publish a message
84
+ manager.publish_message('my_exchange', 'queue1.new', '{"order_id": 123}')
85
+
86
+ # Use as context manager
87
+ with RabbitMQManager() as manager: # Uses environment variables
88
+ manager.publish_message('my_exchange', 'queue1.new', '{"order_id": 123}')
89
+ ```
90
+
91
+ ### Environment Variables Setup
92
+
93
+ Create a `.env` file:
94
+
95
+ ```bash
96
+ RABBITMQ_HOST=localhost
97
+ RABBITMQ_PORT=5672
98
+ RABBITMQ_USERNAME=admin
99
+ RABBITMQ_PASSWORD=password
100
+ RABBITMQ_EXCHANGE=my_exchange
101
+ RABBITMQ_QUEUES=queue1,queue2
102
+ RABBITMQ_ROUTING_KEYS=queue1.*,queue2.*.*
103
+ ```
104
+
105
+ Then use:
106
+
107
+ ```python
108
+ from rabbitmq_easy import create_rabbitmq_manager
109
+
110
+ # Auto-loads from environment variables
111
+ manager = create_rabbitmq_manager()
112
+ ```
113
+
114
+ ## 🔧 Advanced Usage
115
+
116
+ ### Custom Configuration
117
+
118
+ ```python
119
+ from rabbitmq_easy import RabbitMQManager
120
+
121
+ # Advanced configuration
122
+ manager = RabbitMQManager(
123
+ host='rabbitmq.example.com',
124
+ port=5672,
125
+ username='user',
126
+ password='pass',
127
+ queues=['high_priority', 'low_priority'],
128
+ routing_keys=['urgent.*', 'normal.*'],
129
+ exchange='task_exchange',
130
+ dead_letter_exchange='failed_tasks',
131
+ dead_letter_routing_key='failed',
132
+ max_retries=3,
133
+ retry_delay=5,
134
+ enable_console_logging=True,
135
+ log_level='INFO'
136
+ )
137
+
138
+ # Setup additional queues dynamically
139
+ manager.setup_queue(
140
+ queue_name='special_queue',
141
+ exchange='task_exchange',
142
+ routing_key='special.*'
143
+ )
144
+
145
+ # Get queue information
146
+ info = manager.get_queue_info('high_priority')
147
+ print(f"Messages in queue: {info['message_count']}")
148
+
149
+ # Health check
150
+ health = manager.health_check()
151
+ print(f"Status: {health['status']}")
152
+ ```
153
+
154
+ ### Consumer Example
155
+
156
+ ```python
157
+ import json
158
+ from rabbitmq_easy import RabbitMQManager
159
+
160
+ def process_message(ch, method, properties, body):
161
+ """Process incoming message"""
162
+ try:
163
+ data = json.loads(body)
164
+ print(f"Processing: {data}")
165
+
166
+ # Your business logic here
167
+
168
+ # Acknowledge message
169
+ ch.basic_ack(delivery_tag=method.delivery_tag)
170
+ except Exception as e:
171
+ print(f"Error processing message: {e}")
172
+ # Reject message (will go to dead letter queue if configured)
173
+ ch.basic_nack(delivery_tag=method.delivery_tag, requeue=False)
174
+
175
+ # Setup consumer
176
+ with RabbitMQManager() as manager:
177
+ manager.start_consuming('queue1', process_message)
178
+ ```
179
+
180
+ ### Dead Letter Queue Handling
181
+
182
+ ```python
183
+ def handle_failed_messages(ch, method, properties, body):
184
+ """Handle messages that failed processing"""
185
+ try:
186
+ # Get failure information
187
+ headers = properties.headers or {}
188
+ death_info = headers.get('x-death', [])
189
+
190
+ if death_info:
191
+ failure_reason = death_info[0].get('reason')
192
+ failure_count = death_info[0].get('count')
193
+ print(f"Message failed {failure_count} times. Reason: {failure_reason}")
194
+
195
+ # Reprocess or log the failure
196
+ data = json.loads(body)
197
+ print(f"Dead letter message: {data}")
198
+
199
+ # Acknowledge to remove from DLQ
200
+ ch.basic_ack(delivery_tag=method.delivery_tag)
201
+
202
+ except Exception as e:
203
+ print(f"Error handling dead letter: {e}")
204
+ # Acknowledge to prevent infinite loops
205
+ ch.basic_ack(delivery_tag=method.delivery_tag)
206
+
207
+ # Monitor failed messages
208
+ manager.start_consuming('failed_messages', handle_failed_messages)
209
+ ```
210
+
211
+ ## ⚙️ Configuration Options
212
+
213
+ | Parameter | Environment Variable | Default | Description |
214
+ |-----------|---------------------|---------|-------------|
215
+ | `host` | `RABBITMQ_HOST` | `localhost` | RabbitMQ server host |
216
+ | `port` | `RABBITMQ_PORT` | `5672` | RabbitMQ server port |
217
+ | `username` | `RABBITMQ_USERNAME` | `guest` | Username for authentication |
218
+ | `password` | `RABBITMQ_PASSWORD` | `guest` | Password for authentication |
219
+ | `queues` | `RABBITMQ_QUEUES` | `[]` | Comma-separated list of queues |
220
+ | `routing_keys` | `RABBITMQ_ROUTING_KEYS` | `[]` | Comma-separated list of routing keys |
221
+ | `exchange` | `RABBITMQ_EXCHANGE` | `''` | Exchange name |
222
+ | `dead_letter_exchange` | `RABBITMQ_DEAD_LETTER_EXCHANGE` | `{exchange}_dlx` | Dead letter exchange name |
223
+ | `dead_letter_routing_key` | `RABBITMQ_DEAD_LETTER_ROUTING_KEY` | `dead_letter` | Dead letter routing key |
224
+ | `max_retries` | `RABBITMQ_MAX_RETRIES` | `5` | Maximum connection retry attempts |
225
+ | `retry_delay` | `RABBITMQ_RETRY_DELAY` | `5` | Delay between retry attempts |
226
+ | `heartbeat` | `RABBITMQ_HEARTBEAT` | `60` | Connection heartbeat interval |
227
+ | `enable_console_logging` | `RABBITMQ_CONSOLE_LOGGING` | `True` | Enable console logging |
228
+ | `log_level` | `RABBITMQ_LOG_LEVEL` | `INFO` | Logging level |
229
+
230
+ ## 🛠️ Resource Management
231
+
232
+ ### Queue and Exchange Operations
233
+
234
+ ```python
235
+ # Delete specific resources
236
+ manager.delete_queue("old_queue")
237
+ manager.delete_exchange("old_exchange")
238
+
239
+ # Delete only if empty/unused
240
+ manager.delete_queue("queue_name", if_empty=True)
241
+ manager.delete_exchange("exchange_name", if_unused=True)
242
+
243
+ # Purge messages without deleting queue
244
+ message_count = manager.purge_queue("queue_name")
245
+ print(f"Purged {message_count} messages")
246
+
247
+ # Clean up dead letter infrastructure
248
+ manager.cleanup_dead_letter_setup()
249
+
250
+ # Delete all resources created by this manager
251
+ results = manager.delete_all_setup_resources(confirm=True)
252
+
253
+ # Complete reset
254
+ manager.reset_manager(confirm=True)
255
+ ```
256
+
257
+ ## ❌ Error Handling
258
+
259
+ The package includes custom exceptions for better error handling:
260
+
261
+ ```python
262
+ from rabbitmq_easy import RabbitMQConnectionError, RabbitMQConfigurationError
263
+
264
+ try:
265
+ manager = RabbitMQManager(
266
+ host='invalid-host',
267
+ queues=['queue1', 'queue2'],
268
+ routing_keys=['key1'] # Mismatch with queues count
269
+ )
270
+ except RabbitMQConfigurationError as e:
271
+ print(f"Configuration error: {e}")
272
+ except RabbitMQConnectionError as e:
273
+ print(f"Connection error: {e}")
274
+ ```
275
+
276
+ ## 🏗️ What Gets Created Automatically
277
+
278
+ When you initialize with:
279
+
280
+ ```python
281
+ manager = RabbitMQManager(
282
+ exchange='queue1',
283
+ queues=['new_queue1', 'pending_queue1'],
284
+ routing_keys=['queue1.new', 'queue1.pending']
285
+ )
286
+ ```
287
+
288
+ RabbitMQ Easy automatically creates:
289
+
290
+ 1. **`queue1`** exchange (main exchange)
291
+ 2. **`queue1_dlx`** exchange (dead letter exchange)
292
+ 3. **`new_queue1`** queue → bound to `queue1` exchange with `queue1.new` routing key
293
+ 4. **`pending_queue1`** queue → bound to `queue1` exchange with `queue1.pending` routing key
294
+ 5. **`failed_messages`** queue → bound to `queue1_dlx` exchange for error handling
295
+
296
+ All queues are configured with dead letter routing to capture failed messages automatically.
297
+
298
+ ## 📋 Best Practices
299
+
300
+ 1. **Use Environment Variables**: Store sensitive information like passwords in environment variables
301
+ 2. **Context Managers**: Use `with` statements for automatic cleanup
302
+ 3. **Dead Letter Queues**: Always configure dead letter queues for production
303
+ 4. **Health Checks**: Implement health checks in your applications
304
+ 5. **Logging**: Monitor logs for connection issues and errors
305
+ 6. **Error Handling**: Always handle exceptions in your consumers
306
+ 7. **Resource Cleanup**: Use the provided cleanup functions during development
307
+
308
+ ## ⚠️ Important Notes
309
+
310
+ ### Queue and Routing Key Validation
311
+
312
+ The number of queues must match the number of routing keys:
313
+
314
+ ```python
315
+ # ✅ Correct
316
+ manager = RabbitMQManager(
317
+ queues=['queue1', 'queue2'],
318
+ routing_keys=['key1', 'key2'] # Same count
319
+ )
320
+
321
+ # ❌ Will raise RabbitMQConfigurationError
322
+ manager = RabbitMQManager(
323
+ queues=['queue1', 'queue2'],
324
+ routing_keys=['key1'] # Mismatch!
325
+ )
326
+ ```
327
+
328
+ ### Dead Letter Configuration
329
+
330
+ Don't configure dead letter queues to point to themselves:
331
+
332
+ ```python
333
+ # ❌ Don't do this - creates infinite loop
334
+ manager.setup_queue(
335
+ 'my_dlq',
336
+ dead_letter_exchange='same_exchange'
337
+ )
338
+
339
+ # ✅ Do this instead
340
+ manager.setup_queue('my_dlq', dead_letter_exchange=None)
341
+ ```
342
+
343
+ ## 🔍 Monitoring and Health Checks
344
+
345
+ ```python
346
+ # Check connection health
347
+ health = manager.health_check()
348
+ if health['status'] == 'healthy':
349
+ print("✅ RabbitMQ connection is healthy")
350
+ else:
351
+ print(f"❌ RabbitMQ connection issues: {health['error']}")
352
+
353
+ # Get detailed queue information
354
+ info = manager.get_queue_info('queue1')
355
+ print(f"Queue: {info['queue']}")
356
+ print(f"Messages: {info['message_count']}")
357
+ print(f"Consumers: {info['consumer_count']}")
358
+ ```
359
+
360
+ ## 🚀 Production Deployment
361
+
362
+ ### Docker Compose Example
363
+
364
+ ```yaml
365
+ version: '3.8'
366
+ services:
367
+ app:
368
+ build: .
369
+ environment:
370
+ RABBITMQ_HOST: rabbitmq
371
+ RABBITMQ_USERNAME: admin
372
+ RABBITMQ_PASSWORD: ${RABBITMQ_PASSWORD}
373
+ RABBITMQ_EXCHANGE: production
374
+ RABBITMQ_QUEUES: queue1,queue2
375
+ RABBITMQ_ROUTING_KEYS: queue1.*,queue2.*.*
376
+ depends_on:
377
+ - rabbitmq
378
+
379
+ rabbitmq:
380
+ image: rabbitmq:3-management
381
+ environment:
382
+ RABBITMQ_DEFAULT_USER: admin
383
+ RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD}
384
+ ```
385
+
386
+ ### Kubernetes ConfigMap
387
+
388
+ ```yaml
389
+ apiVersion: v1
390
+ kind: ConfigMap
391
+ metadata:
392
+ name: rabbitmq-config
393
+ data:
394
+ RABBITMQ_HOST: "rabbitmq-service"
395
+ RABBITMQ_PORT: "5672"
396
+ RABBITMQ_EXCHANGE: "production"
397
+ RABBITMQ_QUEUES: "queue1,queue2"
398
+ RABBITMQ_ROUTING_KEYS: "queue1.*,queue2.*.*"
399
+ ```
400
+
401
+ ## 🤝 Contributing
402
+
403
+ Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
404
+
405
+ 1. Fork the repository
406
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
407
+ 3. Make your changes
408
+ 4. Add tests for your changes
409
+ 5. Run the test suite (`pytest`)
410
+ 6. Commit your changes (`git commit -m 'Add amazing feature'`)
411
+ 7. Push to the branch (`git push origin feature/amazing-feature`)
412
+ 8. Open a Pull Request
413
+
414
+ ## 📝 License
415
+
416
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
417
+
418
+ ## 🐛 Support
419
+
420
+ - Create an issue on [GitHub](https://github.com/mount-isaac/rabbitmq-easy/issues)
421
+ - Check the [documentation](https://github.com/mount-isaac/rabbitmq-easy#readme)
422
+
423
+ ## 📚 Changelog
424
+
425
+ See [CHANGELOG.md](CHANGELOG.md) for a detailed list of changes and version history.
426
+
427
+ ## 🙏 Acknowledgments
428
+
429
+ - Built on top of the excellent [pika](https://github.com/pika/pika) library
430
+ - Inspired by the need for simpler RabbitMQ management in Python applications
431
+ - Thanks to the RabbitMQ team for creating an amazing message broker
432
+
433
+ ---
434
+
435
+ **Made with ❤️ for the Python community**