Name | pyrsolace JSON |
Version |
0.3.2
JSON |
| download |
home_page | None |
Summary | Python bindings for rsolace |
upload_time | 2025-07-13 07:04:20 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.7 |
license | None |
keywords |
solace
python
rsolace
rust
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# pyrsolace
[](https://www.gnu.org/licenses/gpl-3.0)
[](https://www.python.org)
[](https://pypi.org/project/pyrsolace/)
Python bindings for rsolace with **full async/await support** and proper GIL release.
## ✨ Key Features
- 🐍 **Full asyncio Support**: Native async/await patterns with asyncio
- 🔓 **GIL Release**: Properly releases GIL during blocking operations
- 🔄 **Sync + Async**: Choose the best pattern for your use case
- 📦 **Complete API**: Pub/Sub, Request/Reply, Message Caching, Events
- ⚡ **High Performance**: Zero-copy message handling from Rust
- 🛡️ **Type Safe**: Complete type hints with `.pyi` files
## 🚀 Installation
```bash
# Using pip
pip install pyrsolace
# Using uv (recommended)
uv add pyrsolace
```
## 🔥 Quick Start
### Async Example (NEW!)
```python
import asyncio
import pyrsolace
async def main():
# Initialize client
client = pyrsolace.Client()
# Connect to Solace broker
connected = client.connect(
host="tcp://localhost:55555",
vpn="default",
username="admin",
password="admin",
compression_level=5
)
if not connected:
print("Failed to connect")
return
# Subscribe to topics
client.subscribe_ext("test/topic/*", pyrsolace.SubscribeFlag.RequestConfirm)
# Get async receivers
async_msg_receiver = client.get_async_msg_receiver()
async_event_receiver = client.get_async_event_receiver()
# Handle messages asynchronously
async def message_handler():
while True:
try:
msg = await async_msg_receiver.recv()
print(f"Async received: {msg.topic} - {msg.data}")
except Exception as e:
print(f"Message handler error: {e}")
break
# Handle events asynchronously
async def event_handler():
while True:
try:
event = await async_event_receiver.recv()
print(f"Event: {event.session_event}")
except Exception as e:
print(f"Event handler error: {e}")
break
# Start async handlers
msg_task = asyncio.create_task(message_handler())
event_task = asyncio.create_task(event_handler())
# Send some test messages
for i in range(5):
msg = pyrsolace.Msg(
topic="test/topic/async",
data=f"Async message {i}".encode()
)
client.send_msg(msg)
await asyncio.sleep(1)
# Send async request (true async, no blocking!)
try:
request_msg = pyrsolace.Msg(
topic="test/request",
data=b"Hello async world!",
corr_id="req123"
)
response = await client.send_request_async(request_msg)
print(f"Async response: {response.data}")
except Exception as e:
print(f"Async request failed: {e}")
# Cleanup
await asyncio.sleep(2)
msg_task.cancel()
event_task.cancel()
client.disconnect()
if __name__ == "__main__":
asyncio.run(main())
```
### Sync Example (Enhanced with GIL Release)
```python
import pyrsolace
import threading
import time
def message_handler(receiver, name):
"""Handle messages synchronously with proper GIL release."""
while True:
try:
# This properly releases GIL, allowing other threads to run
msg = receiver.recv()
print(f"{name} received: {msg.topic} - {msg.data}")
except Exception as e:
print(f"{name} handler error: {e}")
break
def main():
client = pyrsolace.Client()
# Connect
connected = client.connect(
host="tcp://localhost:55555",
vpn="default",
username="admin",
password="admin"
)
if not connected:
print("Failed to connect")
return
# Subscribe
client.subscribe("test/topic/*")
# Get receivers
msg_receiver = client.get_msg_receiver()
event_receiver = client.get_event_receiver()
# Start background threads (GIL is properly released)
msg_thread = threading.Thread(
target=message_handler,
args=(msg_receiver, "Messages")
)
event_thread = threading.Thread(
target=message_handler,
args=(event_receiver, "Events")
)
msg_thread.start()
event_thread.start()
# Send messages
for i in range(5):
msg = pyrsolace.Msg(
topic="test/topic/sync",
data=f"Sync message {i}".encode()
)
client.send_msg(msg)
time.sleep(1)
client.disconnect()
if __name__ == "__main__":
main()
```
### Callback-based Example
```python
import pyrsolace
import time
def on_message(msg):
"""Message callback function."""
print(f"Callback received: {msg.topic} - {msg.data}")
def on_event(event):
"""Event callback function."""
print(f"Event: {event.session_event} - {event.info}")
def main():
client = pyrsolace.Client()
# Set callbacks
client.set_msg_callback(on_message)
client.set_event_callback(on_event)
# Connect and subscribe
client.connect(
host="tcp://localhost:55555",
vpn="default",
username="admin",
password="admin"
)
client.subscribe("test/topic/*")
# Send messages
for i in range(5):
msg = pyrsolace.Msg(
topic="test/topic/callback",
data=f"Callback message {i}".encode()
)
client.send_msg(msg)
time.sleep(1)
client.disconnect()
if __name__ == "__main__":
main()
```
## 🔄 Sync vs Async
| Pattern | Best For | Usage | GIL Behavior |
|---------|----------|-------|--------------|
| **Callbacks** | Simple event handling | `client.set_msg_callback(fn)` | Released during callback |
| **Sync Receivers** | Threading, blocking I/O | `receiver.recv()` | Released during recv |
| **Async Receivers** | High concurrency | `await async_receiver.recv()` | N/A (async) |
### Migration from Sync to Async
```python
# Before: Sync only
receiver = client.get_msg_receiver()
msg = receiver.recv() # Blocks thread (but releases GIL)
# After: True async
async_receiver = client.get_async_msg_receiver()
msg = await async_receiver.recv() # Non-blocking, async
# Mixed: Use both in same application
sync_receiver = client.get_msg_receiver() # For background threads
async_receiver = client.get_async_msg_receiver() # For async tasks
```
## 📋 API Reference
### Client Class
```python
class Client:
def connect(self, host: str, vpn: str, username: str, password: str, ...) -> bool
def disconnect(self) -> None
def subscribe(self, topic: str) -> ReturnCode
def subscribe_ext(self, topic: str, flag: SubscribeFlag) -> ReturnCode
# Message sending
def send_msg(self, msg: Msg) -> ReturnCode
def send_reply(self, rx_msg: Msg, reply_msg: Msg) -> ReturnCode
# Sync receivers (with GIL release)
def get_msg_receiver(self) -> MsgReceiver
def get_request_receiver(self) -> MsgReceiver
def get_p2p_receiver(self) -> MsgReceiver
def get_event_receiver(self) -> EventReceiver
# Async receivers (NEW!)
def get_async_msg_receiver(self) -> AsyncMsgReceiver
def get_async_request_receiver(self) -> AsyncMsgReceiver
def get_async_p2p_receiver(self) -> AsyncMsgReceiver
def get_async_event_receiver(self) -> AsyncEventReceiver
# Request/Reply
def send_request(self, msg: Msg, timeout: int) -> MsgReceiver
async def send_request_async(self, msg: Msg) -> Msg # NEW!
# Callbacks
def set_msg_callback(self, callback: Callable[[Msg], None]) -> None
def set_event_callback(self, callback: Callable[[Event], None]) -> None
```
### Message Class
```python
class Msg:
def __init__(self, topic: str = None, data: bytes = None, ...) -> None
# Properties
topic: str
data: bytes
corr_id: str
reply_topic: str
delivery_mode: DeliveryMode
# Methods
def set_user_prop(self, key: str, value: str) -> None
def get_user_prop(self, key: str) -> str
def dump(self) -> str
```
### Receiver Classes
```python
class MsgReceiver:
def recv(self) -> Msg # Releases GIL
class AsyncMsgReceiver:
async def recv(self) -> Msg # True async
class EventReceiver:
def recv(self) -> Event # Releases GIL
class AsyncEventReceiver:
async def recv(self) -> Event # True async
```
## 🛠️ Development
### Building from Source
```bash
# Clone repository
git clone https://github.com/Yvictor/rsolace.git
cd rsolace/pyrsolace
# Using uv (recommended)
uv build
uv pip install -e .
# Using maturin
pip install maturin
maturin develop --release
```
### Running Tests
```bash
# Run tests
uv run pytest tests/
# Run specific tests
uv run pytest tests/test_msg.py -v
```
## 🔧 Configuration
### Connection Parameters
```python
client.connect(
host="tcp://broker:55555", # Broker URL
vpn="vpn_name", # VPN name
username="user", # Username
password="pass", # Password
client_name="my_client", # Client identifier
compression_level=5, # 1-9 (higher = more compression)
connect_timeout_ms=30000, # Connection timeout
connect_retries=3, # Retry attempts
reconnect_retries=10, # Auto-reconnect attempts
keep_alive_ms=3000, # Keep-alive interval
reapply_subscriptions=True, # Restore subs on reconnect
generate_sender_id=True, # Add sender ID to messages
generate_timestamps=True, # Add timestamps
)
```
### Message Properties
```python
msg = pyrsolace.Msg(
topic="my/topic",
data=b"payload",
corr_id="request-123",
reply_topic="reply/topic",
delivery_mode=pyrsolace.DeliveryMode.Persistent
)
# User properties
msg.set_user_prop("priority", "high")
msg.set_user_prop("version", "1.0")
```
## 🎯 Advanced Examples
### Async Producer-Consumer Pattern
```python
import asyncio
from asyncio import Queue
async def producer(client, queue):
"""Produce messages to queue."""
for i in range(100):
msg = pyrsolace.Msg(
topic=f"data/stream/{i % 10}",
data=f"Data packet {i}".encode()
)
await queue.put(msg)
await asyncio.sleep(0.1)
async def consumer(client, queue):
"""Consume messages from queue."""
while True:
msg = await queue.get()
client.send_msg(msg)
queue.task_done()
async def message_processor(client):
"""Process incoming messages."""
receiver = client.get_async_msg_receiver()
while True:
msg = await receiver.recv()
# Process message asynchronously
await process_message(msg)
async def main():
client = pyrsolace.Client()
client.connect(...)
queue = Queue(maxsize=100)
# Start producer, consumer, and processor
await asyncio.gather(
producer(client, queue),
consumer(client, queue),
message_processor(client)
)
```
### Request/Reply Service
```python
async def request_handler(client):
"""Handle incoming requests asynchronously."""
receiver = client.get_async_request_receiver()
while True:
request = await receiver.recv()
# Process request
response_data = await process_request(request.data)
# Send reply
reply = pyrsolace.Msg(
topic=request.reply_topic,
data=response_data,
corr_id=request.corr_id
)
client.send_reply(request, reply)
```
## 🚀 Performance Tips
### Async Best Practices
1. **Use Semaphores**: Limit concurrent operations
```python
semaphore = asyncio.Semaphore(10)
async with semaphore:
await process_message(msg)
```
2. **Batch Operations**: Group related operations
```python
messages = []
async for msg in message_stream():
messages.append(msg)
if len(messages) >= 100:
await process_batch(messages)
messages.clear()
```
3. **Graceful Shutdown**: Cancel tasks properly
```python
try:
await main_task
except asyncio.CancelledError:
await cleanup()
```
## 📚 Documentation
- **Main Project**: See [root README](../README.md) for complete documentation
- **Rust Library**: Check [rsolace](../rsolace/README.md) for Rust-specific features
- **Type Hints**: Complete API in [`pyrsolace.pyi`](pyrsolace.pyi)
- **Examples**: More examples in [`tests/`](tests/) directory
## 🤝 Contributing
1. Fork the repository
2. Create a feature branch
3. Add tests for new functionality
4. Run tests: `uv run pytest`
5. Submit a pull request
## 📄 License
GPL-3.0-only License - see [LICENSE](../LICENSE) for details.
---
**Powered by rsolace** ⚡ - High-performance Rust Solace bindings
Raw data
{
"_id": null,
"home_page": null,
"name": "pyrsolace",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "solace, python, rsolace, rust",
"author": null,
"author_email": "yvictor <yvictor3141@gmail.com>",
"download_url": null,
"platform": null,
"description": "# pyrsolace\n\n[](https://www.gnu.org/licenses/gpl-3.0)\n[](https://www.python.org)\n[](https://pypi.org/project/pyrsolace/)\n\nPython bindings for rsolace with **full async/await support** and proper GIL release.\n\n## \u2728 Key Features\n\n- \ud83d\udc0d **Full asyncio Support**: Native async/await patterns with asyncio\n- \ud83d\udd13 **GIL Release**: Properly releases GIL during blocking operations\n- \ud83d\udd04 **Sync + Async**: Choose the best pattern for your use case\n- \ud83d\udce6 **Complete API**: Pub/Sub, Request/Reply, Message Caching, Events\n- \u26a1 **High Performance**: Zero-copy message handling from Rust\n- \ud83d\udee1\ufe0f **Type Safe**: Complete type hints with `.pyi` files\n\n## \ud83d\ude80 Installation\n\n```bash\n# Using pip\npip install pyrsolace\n\n# Using uv (recommended)\nuv add pyrsolace\n```\n\n## \ud83d\udd25 Quick Start\n\n### Async Example (NEW!)\n\n```python\nimport asyncio\nimport pyrsolace\n\nasync def main():\n # Initialize client\n client = pyrsolace.Client()\n \n # Connect to Solace broker\n connected = client.connect(\n host=\"tcp://localhost:55555\",\n vpn=\"default\",\n username=\"admin\",\n password=\"admin\",\n compression_level=5\n )\n \n if not connected:\n print(\"Failed to connect\")\n return\n \n # Subscribe to topics\n client.subscribe_ext(\"test/topic/*\", pyrsolace.SubscribeFlag.RequestConfirm)\n \n # Get async receivers\n async_msg_receiver = client.get_async_msg_receiver()\n async_event_receiver = client.get_async_event_receiver()\n \n # Handle messages asynchronously\n async def message_handler():\n while True:\n try:\n msg = await async_msg_receiver.recv()\n print(f\"Async received: {msg.topic} - {msg.data}\")\n except Exception as e:\n print(f\"Message handler error: {e}\")\n break\n \n # Handle events asynchronously\n async def event_handler():\n while True:\n try:\n event = await async_event_receiver.recv()\n print(f\"Event: {event.session_event}\")\n except Exception as e:\n print(f\"Event handler error: {e}\")\n break\n \n # Start async handlers\n msg_task = asyncio.create_task(message_handler())\n event_task = asyncio.create_task(event_handler())\n \n # Send some test messages\n for i in range(5):\n msg = pyrsolace.Msg(\n topic=\"test/topic/async\",\n data=f\"Async message {i}\".encode()\n )\n client.send_msg(msg)\n await asyncio.sleep(1)\n \n # Send async request (true async, no blocking!)\n try:\n request_msg = pyrsolace.Msg(\n topic=\"test/request\", \n data=b\"Hello async world!\", \n corr_id=\"req123\"\n )\n \n response = await client.send_request_async(request_msg)\n print(f\"Async response: {response.data}\")\n except Exception as e:\n print(f\"Async request failed: {e}\")\n \n # Cleanup\n await asyncio.sleep(2)\n msg_task.cancel()\n event_task.cancel()\n client.disconnect()\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n### Sync Example (Enhanced with GIL Release)\n\n```python\nimport pyrsolace\nimport threading\nimport time\n\ndef message_handler(receiver, name):\n \"\"\"Handle messages synchronously with proper GIL release.\"\"\"\n while True:\n try:\n # This properly releases GIL, allowing other threads to run\n msg = receiver.recv()\n print(f\"{name} received: {msg.topic} - {msg.data}\")\n except Exception as e:\n print(f\"{name} handler error: {e}\")\n break\n\ndef main():\n client = pyrsolace.Client()\n \n # Connect\n connected = client.connect(\n host=\"tcp://localhost:55555\",\n vpn=\"default\",\n username=\"admin\", \n password=\"admin\"\n )\n \n if not connected:\n print(\"Failed to connect\")\n return\n \n # Subscribe\n client.subscribe(\"test/topic/*\")\n \n # Get receivers\n msg_receiver = client.get_msg_receiver()\n event_receiver = client.get_event_receiver()\n \n # Start background threads (GIL is properly released)\n msg_thread = threading.Thread(\n target=message_handler, \n args=(msg_receiver, \"Messages\")\n )\n event_thread = threading.Thread(\n target=message_handler, \n args=(event_receiver, \"Events\")\n )\n \n msg_thread.start()\n event_thread.start()\n \n # Send messages\n for i in range(5):\n msg = pyrsolace.Msg(\n topic=\"test/topic/sync\",\n data=f\"Sync message {i}\".encode()\n )\n client.send_msg(msg)\n time.sleep(1)\n \n client.disconnect()\n\nif __name__ == \"__main__\":\n main()\n```\n\n### Callback-based Example\n\n```python\nimport pyrsolace\nimport time\n\ndef on_message(msg):\n \"\"\"Message callback function.\"\"\"\n print(f\"Callback received: {msg.topic} - {msg.data}\")\n\ndef on_event(event):\n \"\"\"Event callback function.\"\"\"\n print(f\"Event: {event.session_event} - {event.info}\")\n\ndef main():\n client = pyrsolace.Client()\n \n # Set callbacks\n client.set_msg_callback(on_message)\n client.set_event_callback(on_event)\n \n # Connect and subscribe\n client.connect(\n host=\"tcp://localhost:55555\",\n vpn=\"default\",\n username=\"admin\",\n password=\"admin\"\n )\n \n client.subscribe(\"test/topic/*\")\n \n # Send messages\n for i in range(5):\n msg = pyrsolace.Msg(\n topic=\"test/topic/callback\",\n data=f\"Callback message {i}\".encode()\n )\n client.send_msg(msg)\n time.sleep(1)\n \n client.disconnect()\n\nif __name__ == \"__main__\":\n main()\n```\n\n## \ud83d\udd04 Sync vs Async\n\n| Pattern | Best For | Usage | GIL Behavior |\n|---------|----------|-------|--------------|\n| **Callbacks** | Simple event handling | `client.set_msg_callback(fn)` | Released during callback |\n| **Sync Receivers** | Threading, blocking I/O | `receiver.recv()` | Released during recv |\n| **Async Receivers** | High concurrency | `await async_receiver.recv()` | N/A (async) |\n\n### Migration from Sync to Async\n\n```python\n# Before: Sync only\nreceiver = client.get_msg_receiver()\nmsg = receiver.recv() # Blocks thread (but releases GIL)\n\n# After: True async\nasync_receiver = client.get_async_msg_receiver()\nmsg = await async_receiver.recv() # Non-blocking, async\n\n# Mixed: Use both in same application\nsync_receiver = client.get_msg_receiver() # For background threads\nasync_receiver = client.get_async_msg_receiver() # For async tasks\n```\n\n## \ud83d\udccb API Reference\n\n### Client Class\n\n```python\nclass Client:\n def connect(self, host: str, vpn: str, username: str, password: str, ...) -> bool\n def disconnect(self) -> None\n def subscribe(self, topic: str) -> ReturnCode\n def subscribe_ext(self, topic: str, flag: SubscribeFlag) -> ReturnCode\n \n # Message sending\n def send_msg(self, msg: Msg) -> ReturnCode\n def send_reply(self, rx_msg: Msg, reply_msg: Msg) -> ReturnCode\n \n # Sync receivers (with GIL release)\n def get_msg_receiver(self) -> MsgReceiver\n def get_request_receiver(self) -> MsgReceiver\n def get_p2p_receiver(self) -> MsgReceiver\n def get_event_receiver(self) -> EventReceiver\n \n # Async receivers (NEW!)\n def get_async_msg_receiver(self) -> AsyncMsgReceiver\n def get_async_request_receiver(self) -> AsyncMsgReceiver\n def get_async_p2p_receiver(self) -> AsyncMsgReceiver\n def get_async_event_receiver(self) -> AsyncEventReceiver\n \n # Request/Reply\n def send_request(self, msg: Msg, timeout: int) -> MsgReceiver\n async def send_request_async(self, msg: Msg) -> Msg # NEW!\n \n # Callbacks\n def set_msg_callback(self, callback: Callable[[Msg], None]) -> None\n def set_event_callback(self, callback: Callable[[Event], None]) -> None\n```\n\n### Message Class\n\n```python\nclass Msg:\n def __init__(self, topic: str = None, data: bytes = None, ...) -> None\n \n # Properties\n topic: str\n data: bytes\n corr_id: str\n reply_topic: str\n delivery_mode: DeliveryMode\n \n # Methods\n def set_user_prop(self, key: str, value: str) -> None\n def get_user_prop(self, key: str) -> str\n def dump(self) -> str\n```\n\n### Receiver Classes\n\n```python\nclass MsgReceiver:\n def recv(self) -> Msg # Releases GIL\n\nclass AsyncMsgReceiver:\n async def recv(self) -> Msg # True async\n\nclass EventReceiver:\n def recv(self) -> Event # Releases GIL\n\nclass AsyncEventReceiver:\n async def recv(self) -> Event # True async\n```\n\n## \ud83d\udee0\ufe0f Development\n\n### Building from Source\n\n```bash\n# Clone repository\ngit clone https://github.com/Yvictor/rsolace.git\ncd rsolace/pyrsolace\n\n# Using uv (recommended)\nuv build\nuv pip install -e .\n\n# Using maturin\npip install maturin\nmaturin develop --release\n```\n\n### Running Tests\n\n```bash\n# Run tests\nuv run pytest tests/\n\n# Run specific tests\nuv run pytest tests/test_msg.py -v\n```\n\n## \ud83d\udd27 Configuration\n\n### Connection Parameters\n\n```python\nclient.connect(\n host=\"tcp://broker:55555\", # Broker URL\n vpn=\"vpn_name\", # VPN name\n username=\"user\", # Username\n password=\"pass\", # Password\n client_name=\"my_client\", # Client identifier\n compression_level=5, # 1-9 (higher = more compression)\n connect_timeout_ms=30000, # Connection timeout\n connect_retries=3, # Retry attempts\n reconnect_retries=10, # Auto-reconnect attempts\n keep_alive_ms=3000, # Keep-alive interval\n reapply_subscriptions=True, # Restore subs on reconnect\n generate_sender_id=True, # Add sender ID to messages\n generate_timestamps=True, # Add timestamps\n)\n```\n\n### Message Properties\n\n```python\nmsg = pyrsolace.Msg(\n topic=\"my/topic\",\n data=b\"payload\",\n corr_id=\"request-123\",\n reply_topic=\"reply/topic\",\n delivery_mode=pyrsolace.DeliveryMode.Persistent\n)\n\n# User properties\nmsg.set_user_prop(\"priority\", \"high\")\nmsg.set_user_prop(\"version\", \"1.0\")\n```\n\n## \ud83c\udfaf Advanced Examples\n\n### Async Producer-Consumer Pattern\n\n```python\nimport asyncio\nfrom asyncio import Queue\n\nasync def producer(client, queue):\n \"\"\"Produce messages to queue.\"\"\"\n for i in range(100):\n msg = pyrsolace.Msg(\n topic=f\"data/stream/{i % 10}\",\n data=f\"Data packet {i}\".encode()\n )\n await queue.put(msg)\n await asyncio.sleep(0.1)\n\nasync def consumer(client, queue):\n \"\"\"Consume messages from queue.\"\"\"\n while True:\n msg = await queue.get()\n client.send_msg(msg)\n queue.task_done()\n\nasync def message_processor(client):\n \"\"\"Process incoming messages.\"\"\"\n receiver = client.get_async_msg_receiver()\n while True:\n msg = await receiver.recv()\n # Process message asynchronously\n await process_message(msg)\n\nasync def main():\n client = pyrsolace.Client()\n client.connect(...)\n \n queue = Queue(maxsize=100)\n \n # Start producer, consumer, and processor\n await asyncio.gather(\n producer(client, queue),\n consumer(client, queue),\n message_processor(client)\n )\n```\n\n### Request/Reply Service\n\n```python\nasync def request_handler(client):\n \"\"\"Handle incoming requests asynchronously.\"\"\"\n receiver = client.get_async_request_receiver()\n \n while True:\n request = await receiver.recv()\n \n # Process request\n response_data = await process_request(request.data)\n \n # Send reply\n reply = pyrsolace.Msg(\n topic=request.reply_topic,\n data=response_data,\n corr_id=request.corr_id\n )\n client.send_reply(request, reply)\n```\n\n## \ud83d\ude80 Performance Tips\n\n### Async Best Practices\n\n1. **Use Semaphores**: Limit concurrent operations\n```python\nsemaphore = asyncio.Semaphore(10)\nasync with semaphore:\n await process_message(msg)\n```\n\n2. **Batch Operations**: Group related operations\n```python\nmessages = []\nasync for msg in message_stream():\n messages.append(msg)\n if len(messages) >= 100:\n await process_batch(messages)\n messages.clear()\n```\n\n3. **Graceful Shutdown**: Cancel tasks properly\n```python\ntry:\n await main_task\nexcept asyncio.CancelledError:\n await cleanup()\n```\n\n## \ud83d\udcda Documentation\n\n- **Main Project**: See [root README](../README.md) for complete documentation\n- **Rust Library**: Check [rsolace](../rsolace/README.md) for Rust-specific features\n- **Type Hints**: Complete API in [`pyrsolace.pyi`](pyrsolace.pyi)\n- **Examples**: More examples in [`tests/`](tests/) directory\n\n## \ud83e\udd1d Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Add tests for new functionality\n4. Run tests: `uv run pytest`\n5. Submit a pull request\n\n## \ud83d\udcc4 License\n\nGPL-3.0-only License - see [LICENSE](../LICENSE) for details.\n\n---\n\n**Powered by rsolace** \u26a1 - High-performance Rust Solace bindings\n\n",
"bugtrack_url": null,
"license": null,
"summary": "Python bindings for rsolace",
"version": "0.3.2",
"project_urls": null,
"split_keywords": [
"solace",
" python",
" rsolace",
" rust"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "4dabff30597a7de4de7a0816499245f8128132af7b0e51aa20a72b09801749bc",
"md5": "472661ef6dc97017bc887af5ee89863d",
"sha256": "1f52435c5a2fbfa71572f2343e352b1168912cdbf1b68fc045a083f1dd674238"
},
"downloads": -1,
"filename": "pyrsolace-0.3.2-cp37-abi3-macosx_10_12_x86_64.whl",
"has_sig": false,
"md5_digest": "472661ef6dc97017bc887af5ee89863d",
"packagetype": "bdist_wheel",
"python_version": "cp37",
"requires_python": ">=3.7",
"size": 2146057,
"upload_time": "2025-07-13T07:04:20",
"upload_time_iso_8601": "2025-07-13T07:04:20.252004Z",
"url": "https://files.pythonhosted.org/packages/4d/ab/ff30597a7de4de7a0816499245f8128132af7b0e51aa20a72b09801749bc/pyrsolace-0.3.2-cp37-abi3-macosx_10_12_x86_64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "bdc5a4bcc0188aba1fa0b6267cc1101d5e7be3f9fb6daf6e9390ce552dd42413",
"md5": "0ce9412e9071c100ce7030c3d014c955",
"sha256": "db495600567a35f93275b4b136fb2ffa0ea928cc87e53fbddfa42d947d74d950"
},
"downloads": -1,
"filename": "pyrsolace-0.3.2-cp37-abi3-macosx_11_0_arm64.whl",
"has_sig": false,
"md5_digest": "0ce9412e9071c100ce7030c3d014c955",
"packagetype": "bdist_wheel",
"python_version": "cp37",
"requires_python": ">=3.7",
"size": 1986064,
"upload_time": "2025-07-13T07:04:21",
"upload_time_iso_8601": "2025-07-13T07:04:21.649790Z",
"url": "https://files.pythonhosted.org/packages/bd/c5/a4bcc0188aba1fa0b6267cc1101d5e7be3f9fb6daf6e9390ce552dd42413/pyrsolace-0.3.2-cp37-abi3-macosx_11_0_arm64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "8830194e797f34c5ec7b8660e8d20c94a5ceb28dba528b8f269fd1a3f8d4e667",
"md5": "7364cd8a1f4a8c6c51309cb2a870bf0b",
"sha256": "21a634c7564ef6f6cb53a0118790d2071e76e1f9a7c48c73809746c25bcd7e62"
},
"downloads": -1,
"filename": "pyrsolace-0.3.2-cp37-abi3-manylinux_2_34_aarch64.whl",
"has_sig": false,
"md5_digest": "7364cd8a1f4a8c6c51309cb2a870bf0b",
"packagetype": "bdist_wheel",
"python_version": "cp37",
"requires_python": ">=3.7",
"size": 1305551,
"upload_time": "2025-07-13T07:04:23",
"upload_time_iso_8601": "2025-07-13T07:04:23.286509Z",
"url": "https://files.pythonhosted.org/packages/88/30/194e797f34c5ec7b8660e8d20c94a5ceb28dba528b8f269fd1a3f8d4e667/pyrsolace-0.3.2-cp37-abi3-manylinux_2_34_aarch64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "b5b89e1f6f076b0a189b728b166ac430db98b2aa5e5b728557ad7a337d2cb229",
"md5": "4f3ce87eecd830a515c8169423e22d06",
"sha256": "34be8a672c0063b8750aa6de4e084c5208278d42e95796848978d2405a66a38e"
},
"downloads": -1,
"filename": "pyrsolace-0.3.2-cp37-abi3-manylinux_2_34_x86_64.whl",
"has_sig": false,
"md5_digest": "4f3ce87eecd830a515c8169423e22d06",
"packagetype": "bdist_wheel",
"python_version": "cp37",
"requires_python": ">=3.7",
"size": 1308533,
"upload_time": "2025-07-13T07:04:24",
"upload_time_iso_8601": "2025-07-13T07:04:24.888337Z",
"url": "https://files.pythonhosted.org/packages/b5/b8/9e1f6f076b0a189b728b166ac430db98b2aa5e5b728557ad7a337d2cb229/pyrsolace-0.3.2-cp37-abi3-manylinux_2_34_x86_64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "e46fa3422244ceb5743f4efee24fd0be832d6a2bf41397dc26b8b1afb97eca4a",
"md5": "d12e48200d73ed9ab239441c26c6e546",
"sha256": "736c62dded8357ee434f0d785f73cca6ce11d5ff29e19dd4a89d587903d4e171"
},
"downloads": -1,
"filename": "pyrsolace-0.3.2-cp37-abi3-win32.whl",
"has_sig": false,
"md5_digest": "d12e48200d73ed9ab239441c26c6e546",
"packagetype": "bdist_wheel",
"python_version": "cp37",
"requires_python": ">=3.7",
"size": 1662678,
"upload_time": "2025-07-13T07:04:26",
"upload_time_iso_8601": "2025-07-13T07:04:26.424683Z",
"url": "https://files.pythonhosted.org/packages/e4/6f/a3422244ceb5743f4efee24fd0be832d6a2bf41397dc26b8b1afb97eca4a/pyrsolace-0.3.2-cp37-abi3-win32.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "39d551453c90e59fb77eaa9eccc34b2b873af69de33d55290fe112ca010b8edc",
"md5": "5a0c8119d07132ef04449e406a86e17e",
"sha256": "71a53fc39a1803bc1c111ba64da1fcf37630acb45bb05c4dcb4fe85879990b5c"
},
"downloads": -1,
"filename": "pyrsolace-0.3.2-cp37-abi3-win_amd64.whl",
"has_sig": false,
"md5_digest": "5a0c8119d07132ef04449e406a86e17e",
"packagetype": "bdist_wheel",
"python_version": "cp37",
"requires_python": ">=3.7",
"size": 1955175,
"upload_time": "2025-07-13T07:04:27",
"upload_time_iso_8601": "2025-07-13T07:04:27.855590Z",
"url": "https://files.pythonhosted.org/packages/39/d5/51453c90e59fb77eaa9eccc34b2b873af69de33d55290fe112ca010b8edc/pyrsolace-0.3.2-cp37-abi3-win_amd64.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-13 07:04:20",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "pyrsolace"
}