Name | py-udp-rust JSON |
Version |
0.2.0
JSON |
| download |
home_page | None |
Summary | High-performance UDP networking library for Python with Rust backend |
upload_time | 2025-08-04 09:41:47 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.12 |
license | MIT |
keywords |
udp
networking
rust
async
socket
server
client
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# py-udp
High-performance UDP networking library for Python with Rust backend.
## Architecture
This project uses PyO3 to create a Python extension module from Rust code:
1. **Rust Implementation** - Core UDP functionality implemented in Rust using Tokio
2. **PyO3 Bindings** - Python bindings created with PyO3
3. **Python API** - User-friendly Python interface
### Why This Architecture?
- **Performance**: Core networking implemented in Rust for maximum performance
- **Safety**: Rust's memory safety and zero-cost abstractions
- **Integration**: Seamless Python integration through PyO3
- **Modern**: Uses Tokio for efficient async I/O
## Features
- **High Performance**: Core networking implemented in Rust for maximum performance
- **Easy to Use**: Simple Python API for UDP server and client operations
- **Async Support**: Built on Tokio runtime for efficient async I/O
- **Type Safe**: Full type hints and error handling
- **Cross Platform**: Works on Windows, macOS, and Linux
- **Message Handlers**: Flexible callback system for processing incoming messages
- **Thread Safety**: Safe concurrent access with proper synchronization
## Installation
### Prerequisites
- Python 3.12+
- Rust (latest stable version)
- Cargo (comes with Rust)
- uv (recommended package manager)
### Build and Install
1. Clone the repository:
```bash
git clone <repository-url>
cd py-udp
```
2. Build and install the package:
```bash
uv run maturin develop
```
### Alternative: Using the Build Script
```bash
uv run python build.py
```
This script will:
- Check prerequisites
- Install maturin
- Build the Rust extension
- Install the Python package
- Run tests
## Quick Start
### UDP Server
```python
from py_udp import UdpServer, MessageHandler
class MyHandler(MessageHandler):
def __call__(self, data: bytes, source_address: str):
print(f"Received from {source_address}: {data.decode()}")
# Process the message...
# Create and start server
server = UdpServer(host="127.0.0.1", port=8888)
server.bind()
server.set_message_handler(MyHandler())
server.start()
# Keep server running
import time
while server.is_running():
time.sleep(1)
```
### UDP Client
```python
from py_udp import UdpClient
# Create client
client = UdpClient()
client.bind()
# Send message
message = "Hello, UDP!".encode('utf-8')
bytes_sent = client.send_to(message, "127.0.0.1", 8888)
print(f"Sent {bytes_sent} bytes")
# Receive response
data, source = client.recv_from()
print(f"Received from {source}: {data.decode()}")
```
## Examples
### Echo Server
The echo server example demonstrates how to create a UDP server that responds to incoming messages:
```python
#!/usr/bin/env python3
"""
UDP Server Example
This example demonstrates how to create a UDP server that echoes back
received messages with additional information.
"""
import time
from py_udp import UdpServer, MessageHandler
class EchoHandler(MessageHandler):
"""Echo handler that responds to incoming messages."""
def __init__(self, server: UdpServer):
self.server = server
self.message_count = 0
def __call__(self, data, source_address: str) -> None:
"""Handle incoming message and send response."""
# Convert data to bytes if it's a list
if isinstance(data, list):
data = bytes(data)
self.message_count += 1
# Decode message
try:
message = data.decode('utf-8')
except UnicodeDecodeError:
message = f"<binary data: {len(data)} bytes>"
print(f"[{self.message_count}] Received from {source_address}: {message}")
# Create response
response = f"Echo #{self.message_count}: {message}"
response_data = response.encode('utf-8')
# Send response using the server's send_to method
try:
bytes_sent = self.server.send_to(response_data, source_address)
print(f"Sent {bytes_sent} bytes to {source_address}")
except Exception as e:
print(f"Error sending response: {e}")
def main():
"""Run UDP echo server."""
print("Starting UDP Echo Server...")
# Create server
server = UdpServer(host="127.0.0.1", port=8888)
# Bind to address
server.bind()
print(f"Server bound to {server.address}")
# Set message handler
handler = EchoHandler(server)
server.set_message_handler(handler)
# Start server
server.start()
print("Server started. Press Ctrl+C to stop.")
try:
# Keep server running
while server.is_running():
time.sleep(1)
except KeyboardInterrupt:
print("\nStopping server...")
server.stop()
print("Server stopped.")
if __name__ == "__main__":
main()
```
Run the echo server example:
```bash
uv run python examples/server_example.py
```
### Echo Client
The echo client example demonstrates how to create a UDP client that sends messages and receives responses:
```python
#!/usr/bin/env python3
"""
UDP Client Example
This example demonstrates how to create a UDP client that sends messages
to a server and receives responses.
"""
import time
import threading
from py_udp import UdpClient
def receive_messages(client: UdpClient):
"""Receive messages in a separate thread."""
print("Starting message receiver...")
while True:
try:
# Add a small delay to avoid busy waiting
time.sleep(0.1)
data, source = client.recv_from()
# Convert data to bytes if it's a list
if isinstance(data, list):
data = bytes(data)
message = data.decode('utf-8')
print(f"Received from {source}: {message}")
except Exception as e:
# Don't break on timeout errors
if "timeout" not in str(e).lower():
print(f"Error receiving message: {e}")
break
def main():
"""Run UDP client."""
print("Starting UDP Client...")
# Create client
client = UdpClient(host="127.0.0.1", port=0)
# Bind to random port
client.bind()
print(f"Client bound to {client.address}")
# Start receiver thread
receiver_thread = threading.Thread(
target=receive_messages,
args=(client,),
daemon=True
)
receiver_thread.start()
# Server address
server_host = "127.0.0.1"
server_port = 8888
print(f"Connecting to server at {server_host}:{server_port}")
print("Sending messages automatically...")
try:
message_count = 0
while True:
message_count += 1
# Create test message
message = f"Hello, UDP! #{message_count}"
data = message.encode('utf-8')
# Send message
try:
bytes_sent = client.send_to(data, server_host, server_port)
print(f"Sent: {message} ({bytes_sent} bytes)")
except Exception as e:
print(f"Error sending message: {e}")
# Wait before sending next message
time.sleep(2)
except KeyboardInterrupt:
print("\nStopping client...")
print("Client stopped.")
if __name__ == "__main__":
main()
```
In another terminal, run the client:
```bash
uv run python examples/client_example.py
```
The client will automatically send messages every 2 seconds and display received responses.
## Development
### Project Structure
```
py-udp/
├── src/ # Rust source code
│ └── lib.rs # Main Rust implementation
├── py_udp/ # Python package
│ ├── __init__.py # Python API
│ └── ...
├── examples/ # Usage examples
│ ├── server_example.py # Echo server example
│ └── client_example.py # Echo client example
├── tests/ # Python tests
├── Cargo.toml # Rust project config
├── pyproject.toml # Python package config
└── README.md
```
### Working with Rust Code
```bash
# Build Rust extension
uv run maturin develop
# Run Rust tests
cargo test
# Run specific test suites
cargo test --test test_udp # Unit tests
cargo test --test integration_udp # Integration tests
# Run with debug output
RUST_LOG=debug cargo test
# Check code coverage
cargo tarpaulin --skip-clean
```
### Working with Python Package
```bash
# Install in development mode
uv run maturin develop
# Run Python tests
uv run pytest tests/
# Run tests with coverage
uv run pytest tests/ --cov=py_udp --cov-report=term-missing
# Run specific test classes
uv run pytest tests/ -k TestUdpServer
uv run pytest tests/ -k TestUdpClient
# Format code
uv run black .
uv run isort .
```
### Running Tests
#### Rust Tests
```bash
# Run all Rust tests (unit + integration)
cargo test
# Run only unit tests
cargo test --lib
# Run only integration tests
cargo test --test integration_udp
cargo test --test test_udp
# Run with debug output
RUST_LOG=debug cargo test
```
**Rust Test Coverage:**
- **Unit Tests**: 19 tests in `tests/test_udp.rs`
- **Integration Tests**: 10 tests in `tests/integration_udp.rs`
- **Coverage**: 33.08% (44/133 lines covered)
#### Python Tests
```bash
# Run Python tests
uv run pytest tests/
# Run with coverage report
uv run pytest tests/ --cov=py_udp --cov-report=term-missing
# Run with verbose output
uv run pytest tests/ -v
```
**Python Test Coverage:**
- **Total Tests**: 26 tests
- **Coverage**: 91% (83/91 lines covered)
- **Missing Lines**: 15-16, 79, 109, 127-130, 188
#### Test Structure
**Rust Tests (`tests/` directory):**
- `test_udp.rs` - Unit tests for core Rust functionality
- Server/client creation and initialization
- Binding and address validation
- Error handling and edge cases
- Basic UDP operations
- `integration_udp.rs` - Integration tests for UDP communication
- Client-server echo communication
- Invalid address handling
- Multiple message sending
- Server lifecycle management
**Python Tests (`tests/test_udp.py`):**
- `TestMessageHandler` - Message handler base class tests
- `TestUdpServer` - Server functionality tests
- `TestUdpClient` - Client functionality tests
- `TestConvenienceFunctions` - Utility function tests
- `TestUdpCommunication` - End-to-end communication tests
#### Coverage Analysis
**Rust Coverage (33.08%):**
- **Covered**: Basic initialization, binding, error handling
- **Uncovered**: Python GIL-dependent methods, async server logic, PyO3 wrappers
- **Limitations**: Python interpreter not available in Rust-only tests
**Python Coverage (91%):**
- **Covered**: All public API methods, error handling, communication
- **Missing**: Some edge cases and error conditions
- **Strength**: Full integration testing with real UDP communication
#### Coverage Commands
```bash
# Rust coverage with cargo-tarpaulin
cargo install cargo-tarpaulin
cargo tarpaulin --skip-clean
cargo tarpaulin --out Html --output-dir coverage
# Python coverage with pytest-cov
uv run pytest tests/ --cov=py_udp --cov-report=html
uv run pytest tests/ --cov=py_udp --cov-report=term-missing
```
## API Reference
### UdpServer
#### Constructor
```python
UdpServer(host: str = "0.0.0.0", port: int = 0)
```
#### Methods
- `bind(host: Optional[str] = None, port: Optional[int] = None) -> None`
- Bind the server to a specific address and port
- `set_message_handler(handler: Union[MessageHandler, Callable]) -> None`
- Set the message handler for processing incoming messages
- `start() -> None`
- Start the server and begin listening for messages
- `stop() -> None`
- Stop the server and clean up resources
- `is_running() -> bool`
- Check if the server is currently running
- `send_to(data: bytes, address: str) -> int`
- Send data to a specific address (host:port format)
#### Properties
- `address: Tuple[str, int]` - Server address
### UdpClient
#### Constructor
```python
UdpClient(host: str = "0.0.0.0", port: int = 0)
```
#### Methods
- `bind(host: Optional[str] = None, port: Optional[int] = None) -> None`
- Bind the client to a specific address and port
- `send_to(data: bytes, host: str, port: int) -> int`
- Send data to a specific host and port
- `recv_from() -> Tuple[bytes, str]`
- Receive data from any address
#### Properties
- `address: Tuple[str, int]` - Client address
### MessageHandler
Base class for handling incoming UDP messages:
```python
class MyHandler(MessageHandler):
def __call__(self, data: bytes, source_address: str) -> None:
# Handle the message
# data: received data as bytes
# source_address: source address as string (host:port)
pass
```
## Performance
The Rust backend provides significant performance improvements over pure Python implementations:
- **Lower Latency**: Direct system calls without Python GIL overhead
- **Higher Throughput**: Efficient async I/O with Tokio
- **Memory Efficiency**: Zero-copy operations where possible
- **Concurrent Processing**: True parallelism for multiple connections
- **Channel-based Communication**: Non-blocking message passing between Rust and Python
## Troubleshooting
### Common Issues
1. **Import Error**: Make sure the Rust extension is built with `uv run maturin develop`
2. **Permission Denied**: Check if the port is already in use or requires elevated privileges
3. **Build Errors**: Ensure you have the latest Rust toolchain installed
4. **Runtime Errors**: Make sure the server is started before calling `send_to()`
### Debug Mode
Enable debug logging for Rust:
```bash
export RUST_LOG=debug
cargo test
```
### Testing the Installation
Run a simple test to verify everything works:
```bash
uv run python -c "from py_udp import UdpServer, UdpClient; print('✅ Installation successful!')"
```
## License
MIT License - see LICENSE file for details.
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for both Rust and Python
5. Run tests and linting
6. Submit a pull request
### Development Workflow
1. **Rust Changes**: Work in `src/` directory
- Add unit tests in `tests/test_udp.rs`
- Add integration tests in `tests/integration_udp.rs`
- Run `cargo test` to verify changes
- Check coverage with `cargo tarpaulin`
2. **Python Changes**: Work in `py_udp/` directory
- Add tests in `tests/test_udp.py`
- Run `uv run pytest tests/` to verify changes
- Check coverage with `uv run pytest tests/ --cov=py_udp`
3. **Integration**: Test both components work together
- Run both Rust and Python test suites
- Test examples in `examples/` directory
- Verify end-to-end functionality
4. **Documentation**: Update README and docstrings
5. **Examples**: Update examples in `examples/` directory
### Code Style
- **Rust**: Follow Rust formatting guidelines with `cargo fmt`
- **Python**: Use Black for formatting and isort for imports
- **Documentation**: Keep docstrings up to date
- **Tests**: Maintain good test coverage for both Rust and Python
Raw data
{
"_id": null,
"home_page": null,
"name": "py-udp-rust",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.12",
"maintainer_email": "Ravil Shakerov <xellaopromaster@yandex.ru>",
"keywords": "udp, networking, rust, async, socket, server, client",
"author": null,
"author_email": "Ravil Shakerov <xellaopromaster@yandex.ru>",
"download_url": null,
"platform": null,
"description": "# py-udp\r\n\r\nHigh-performance UDP networking library for Python with Rust backend.\r\n\r\n## Architecture\r\n\r\nThis project uses PyO3 to create a Python extension module from Rust code:\r\n\r\n1. **Rust Implementation** - Core UDP functionality implemented in Rust using Tokio\r\n2. **PyO3 Bindings** - Python bindings created with PyO3\r\n3. **Python API** - User-friendly Python interface\r\n\r\n### Why This Architecture?\r\n\r\n- **Performance**: Core networking implemented in Rust for maximum performance\r\n- **Safety**: Rust's memory safety and zero-cost abstractions\r\n- **Integration**: Seamless Python integration through PyO3\r\n- **Modern**: Uses Tokio for efficient async I/O\r\n\r\n## Features\r\n\r\n- **High Performance**: Core networking implemented in Rust for maximum performance\r\n- **Easy to Use**: Simple Python API for UDP server and client operations\r\n- **Async Support**: Built on Tokio runtime for efficient async I/O\r\n- **Type Safe**: Full type hints and error handling\r\n- **Cross Platform**: Works on Windows, macOS, and Linux\r\n- **Message Handlers**: Flexible callback system for processing incoming messages\r\n- **Thread Safety**: Safe concurrent access with proper synchronization\r\n\r\n## Installation\r\n\r\n### Prerequisites\r\n\r\n- Python 3.12+\r\n- Rust (latest stable version)\r\n- Cargo (comes with Rust)\r\n- uv (recommended package manager)\r\n\r\n### Build and Install\r\n\r\n1. Clone the repository:\r\n```bash\r\ngit clone <repository-url>\r\ncd py-udp\r\n```\r\n\r\n2. Build and install the package:\r\n```bash\r\nuv run maturin develop\r\n```\r\n\r\n### Alternative: Using the Build Script\r\n\r\n```bash\r\nuv run python build.py\r\n```\r\n\r\nThis script will:\r\n- Check prerequisites\r\n- Install maturin\r\n- Build the Rust extension\r\n- Install the Python package\r\n- Run tests\r\n\r\n## Quick Start\r\n\r\n### UDP Server\r\n\r\n```python\r\nfrom py_udp import UdpServer, MessageHandler\r\n\r\nclass MyHandler(MessageHandler):\r\n def __call__(self, data: bytes, source_address: str):\r\n print(f\"Received from {source_address}: {data.decode()}\")\r\n # Process the message...\r\n\r\n# Create and start server\r\nserver = UdpServer(host=\"127.0.0.1\", port=8888)\r\nserver.bind()\r\nserver.set_message_handler(MyHandler())\r\nserver.start()\r\n\r\n# Keep server running\r\nimport time\r\nwhile server.is_running():\r\n time.sleep(1)\r\n```\r\n\r\n### UDP Client\r\n\r\n```python\r\nfrom py_udp import UdpClient\r\n\r\n# Create client\r\nclient = UdpClient()\r\nclient.bind()\r\n\r\n# Send message\r\nmessage = \"Hello, UDP!\".encode('utf-8')\r\nbytes_sent = client.send_to(message, \"127.0.0.1\", 8888)\r\nprint(f\"Sent {bytes_sent} bytes\")\r\n\r\n# Receive response\r\ndata, source = client.recv_from()\r\nprint(f\"Received from {source}: {data.decode()}\")\r\n```\r\n\r\n## Examples\r\n\r\n### Echo Server\r\n\r\nThe echo server example demonstrates how to create a UDP server that responds to incoming messages:\r\n\r\n```python\r\n#!/usr/bin/env python3\r\n\"\"\"\r\nUDP Server Example\r\n\r\nThis example demonstrates how to create a UDP server that echoes back\r\nreceived messages with additional information.\r\n\"\"\"\r\n\r\nimport time\r\nfrom py_udp import UdpServer, MessageHandler\r\n\r\n\r\nclass EchoHandler(MessageHandler):\r\n \"\"\"Echo handler that responds to incoming messages.\"\"\"\r\n \r\n def __init__(self, server: UdpServer):\r\n self.server = server\r\n self.message_count = 0\r\n \r\n def __call__(self, data, source_address: str) -> None:\r\n \"\"\"Handle incoming message and send response.\"\"\"\r\n # Convert data to bytes if it's a list\r\n if isinstance(data, list):\r\n data = bytes(data)\r\n \r\n self.message_count += 1\r\n \r\n # Decode message\r\n try:\r\n message = data.decode('utf-8')\r\n except UnicodeDecodeError:\r\n message = f\"<binary data: {len(data)} bytes>\"\r\n \r\n print(f\"[{self.message_count}] Received from {source_address}: {message}\")\r\n \r\n # Create response\r\n response = f\"Echo #{self.message_count}: {message}\"\r\n response_data = response.encode('utf-8')\r\n \r\n # Send response using the server's send_to method\r\n try:\r\n bytes_sent = self.server.send_to(response_data, source_address)\r\n print(f\"Sent {bytes_sent} bytes to {source_address}\")\r\n except Exception as e:\r\n print(f\"Error sending response: {e}\")\r\n\r\n\r\ndef main():\r\n \"\"\"Run UDP echo server.\"\"\"\r\n print(\"Starting UDP Echo Server...\")\r\n \r\n # Create server\r\n server = UdpServer(host=\"127.0.0.1\", port=8888)\r\n \r\n # Bind to address\r\n server.bind()\r\n print(f\"Server bound to {server.address}\")\r\n \r\n # Set message handler\r\n handler = EchoHandler(server)\r\n server.set_message_handler(handler)\r\n \r\n # Start server\r\n server.start()\r\n print(\"Server started. Press Ctrl+C to stop.\")\r\n \r\n try:\r\n # Keep server running\r\n while server.is_running():\r\n time.sleep(1)\r\n except KeyboardInterrupt:\r\n print(\"\\nStopping server...\")\r\n server.stop()\r\n print(\"Server stopped.\")\r\n\r\n\r\nif __name__ == \"__main__\":\r\n main()\r\n```\r\n\r\nRun the echo server example:\r\n\r\n```bash\r\nuv run python examples/server_example.py\r\n```\r\n\r\n### Echo Client\r\n\r\nThe echo client example demonstrates how to create a UDP client that sends messages and receives responses:\r\n\r\n```python\r\n#!/usr/bin/env python3\r\n\"\"\"\r\nUDP Client Example\r\n\r\nThis example demonstrates how to create a UDP client that sends messages\r\nto a server and receives responses.\r\n\"\"\"\r\n\r\nimport time\r\nimport threading\r\nfrom py_udp import UdpClient\r\n\r\n\r\ndef receive_messages(client: UdpClient):\r\n \"\"\"Receive messages in a separate thread.\"\"\"\r\n print(\"Starting message receiver...\")\r\n \r\n while True:\r\n try:\r\n # Add a small delay to avoid busy waiting\r\n time.sleep(0.1)\r\n \r\n data, source = client.recv_from()\r\n # Convert data to bytes if it's a list\r\n if isinstance(data, list):\r\n data = bytes(data)\r\n message = data.decode('utf-8')\r\n print(f\"Received from {source}: {message}\")\r\n except Exception as e:\r\n # Don't break on timeout errors\r\n if \"timeout\" not in str(e).lower():\r\n print(f\"Error receiving message: {e}\")\r\n break\r\n\r\n\r\ndef main():\r\n \"\"\"Run UDP client.\"\"\"\r\n print(\"Starting UDP Client...\")\r\n \r\n # Create client\r\n client = UdpClient(host=\"127.0.0.1\", port=0)\r\n \r\n # Bind to random port\r\n client.bind()\r\n print(f\"Client bound to {client.address}\")\r\n \r\n # Start receiver thread\r\n receiver_thread = threading.Thread(\r\n target=receive_messages, \r\n args=(client,), \r\n daemon=True\r\n )\r\n receiver_thread.start()\r\n \r\n # Server address\r\n server_host = \"127.0.0.1\"\r\n server_port = 8888\r\n \r\n print(f\"Connecting to server at {server_host}:{server_port}\")\r\n print(\"Sending messages automatically...\")\r\n \r\n try:\r\n message_count = 0\r\n while True:\r\n message_count += 1\r\n \r\n # Create test message\r\n message = f\"Hello, UDP! #{message_count}\"\r\n data = message.encode('utf-8')\r\n \r\n # Send message\r\n try:\r\n bytes_sent = client.send_to(data, server_host, server_port)\r\n print(f\"Sent: {message} ({bytes_sent} bytes)\")\r\n except Exception as e:\r\n print(f\"Error sending message: {e}\")\r\n \r\n # Wait before sending next message\r\n time.sleep(2)\r\n \r\n except KeyboardInterrupt:\r\n print(\"\\nStopping client...\")\r\n \r\n print(\"Client stopped.\")\r\n\r\n\r\nif __name__ == \"__main__\":\r\n main()\r\n```\r\n\r\nIn another terminal, run the client:\r\n\r\n```bash\r\nuv run python examples/client_example.py\r\n```\r\n\r\nThe client will automatically send messages every 2 seconds and display received responses.\r\n\r\n## Development\r\n\r\n### Project Structure\r\n\r\n```\r\npy-udp/\r\n\u251c\u2500\u2500 src/ # Rust source code\r\n\u2502 \u2514\u2500\u2500 lib.rs # Main Rust implementation\r\n\u251c\u2500\u2500 py_udp/ # Python package\r\n\u2502 \u251c\u2500\u2500 __init__.py # Python API\r\n\u2502 \u2514\u2500\u2500 ...\r\n\u251c\u2500\u2500 examples/ # Usage examples\r\n\u2502 \u251c\u2500\u2500 server_example.py # Echo server example\r\n\u2502 \u2514\u2500\u2500 client_example.py # Echo client example\r\n\u251c\u2500\u2500 tests/ # Python tests\r\n\u251c\u2500\u2500 Cargo.toml # Rust project config\r\n\u251c\u2500\u2500 pyproject.toml # Python package config\r\n\u2514\u2500\u2500 README.md\r\n```\r\n\r\n### Working with Rust Code\r\n\r\n```bash\r\n# Build Rust extension\r\nuv run maturin develop\r\n\r\n# Run Rust tests\r\ncargo test\r\n\r\n# Run specific test suites\r\ncargo test --test test_udp # Unit tests\r\ncargo test --test integration_udp # Integration tests\r\n\r\n# Run with debug output\r\nRUST_LOG=debug cargo test\r\n\r\n# Check code coverage\r\ncargo tarpaulin --skip-clean\r\n```\r\n\r\n### Working with Python Package\r\n\r\n```bash\r\n# Install in development mode\r\nuv run maturin develop\r\n\r\n# Run Python tests\r\nuv run pytest tests/\r\n\r\n# Run tests with coverage\r\nuv run pytest tests/ --cov=py_udp --cov-report=term-missing\r\n\r\n# Run specific test classes\r\nuv run pytest tests/ -k TestUdpServer\r\nuv run pytest tests/ -k TestUdpClient\r\n\r\n# Format code\r\nuv run black .\r\nuv run isort .\r\n```\r\n\r\n### Running Tests\r\n\r\n#### Rust Tests\r\n\r\n```bash\r\n# Run all Rust tests (unit + integration)\r\ncargo test\r\n\r\n# Run only unit tests\r\ncargo test --lib\r\n\r\n# Run only integration tests\r\ncargo test --test integration_udp\r\ncargo test --test test_udp\r\n\r\n# Run with debug output\r\nRUST_LOG=debug cargo test\r\n```\r\n\r\n**Rust Test Coverage:**\r\n- **Unit Tests**: 19 tests in `tests/test_udp.rs`\r\n- **Integration Tests**: 10 tests in `tests/integration_udp.rs`\r\n- **Coverage**: 33.08% (44/133 lines covered)\r\n\r\n#### Python Tests\r\n\r\n```bash\r\n# Run Python tests\r\nuv run pytest tests/\r\n\r\n# Run with coverage report\r\nuv run pytest tests/ --cov=py_udp --cov-report=term-missing\r\n\r\n# Run with verbose output\r\nuv run pytest tests/ -v\r\n```\r\n\r\n**Python Test Coverage:**\r\n- **Total Tests**: 26 tests\r\n- **Coverage**: 91% (83/91 lines covered)\r\n- **Missing Lines**: 15-16, 79, 109, 127-130, 188\r\n\r\n#### Test Structure\r\n\r\n**Rust Tests (`tests/` directory):**\r\n- `test_udp.rs` - Unit tests for core Rust functionality\r\n - Server/client creation and initialization\r\n - Binding and address validation\r\n - Error handling and edge cases\r\n - Basic UDP operations\r\n- `integration_udp.rs` - Integration tests for UDP communication\r\n - Client-server echo communication\r\n - Invalid address handling\r\n - Multiple message sending\r\n - Server lifecycle management\r\n\r\n**Python Tests (`tests/test_udp.py`):**\r\n- `TestMessageHandler` - Message handler base class tests\r\n- `TestUdpServer` - Server functionality tests\r\n- `TestUdpClient` - Client functionality tests\r\n- `TestConvenienceFunctions` - Utility function tests\r\n- `TestUdpCommunication` - End-to-end communication tests\r\n\r\n#### Coverage Analysis\r\n\r\n**Rust Coverage (33.08%):**\r\n- **Covered**: Basic initialization, binding, error handling\r\n- **Uncovered**: Python GIL-dependent methods, async server logic, PyO3 wrappers\r\n- **Limitations**: Python interpreter not available in Rust-only tests\r\n\r\n**Python Coverage (91%):**\r\n- **Covered**: All public API methods, error handling, communication\r\n- **Missing**: Some edge cases and error conditions\r\n- **Strength**: Full integration testing with real UDP communication\r\n\r\n#### Coverage Commands\r\n\r\n```bash\r\n# Rust coverage with cargo-tarpaulin\r\ncargo install cargo-tarpaulin\r\ncargo tarpaulin --skip-clean\r\ncargo tarpaulin --out Html --output-dir coverage\r\n\r\n# Python coverage with pytest-cov\r\nuv run pytest tests/ --cov=py_udp --cov-report=html\r\nuv run pytest tests/ --cov=py_udp --cov-report=term-missing\r\n```\r\n\r\n## API Reference\r\n\r\n### UdpServer\r\n\r\n#### Constructor\r\n```python\r\nUdpServer(host: str = \"0.0.0.0\", port: int = 0)\r\n```\r\n\r\n#### Methods\r\n- `bind(host: Optional[str] = None, port: Optional[int] = None) -> None`\r\n - Bind the server to a specific address and port\r\n- `set_message_handler(handler: Union[MessageHandler, Callable]) -> None`\r\n - Set the message handler for processing incoming messages\r\n- `start() -> None`\r\n - Start the server and begin listening for messages\r\n- `stop() -> None`\r\n - Stop the server and clean up resources\r\n- `is_running() -> bool`\r\n - Check if the server is currently running\r\n- `send_to(data: bytes, address: str) -> int`\r\n - Send data to a specific address (host:port format)\r\n\r\n#### Properties\r\n- `address: Tuple[str, int]` - Server address\r\n\r\n### UdpClient\r\n\r\n#### Constructor\r\n```python\r\nUdpClient(host: str = \"0.0.0.0\", port: int = 0)\r\n```\r\n\r\n#### Methods\r\n- `bind(host: Optional[str] = None, port: Optional[int] = None) -> None`\r\n - Bind the client to a specific address and port\r\n- `send_to(data: bytes, host: str, port: int) -> int`\r\n - Send data to a specific host and port\r\n- `recv_from() -> Tuple[bytes, str]`\r\n - Receive data from any address\r\n\r\n#### Properties\r\n- `address: Tuple[str, int]` - Client address\r\n\r\n### MessageHandler\r\n\r\nBase class for handling incoming UDP messages:\r\n\r\n```python\r\nclass MyHandler(MessageHandler):\r\n def __call__(self, data: bytes, source_address: str) -> None:\r\n # Handle the message\r\n # data: received data as bytes\r\n # source_address: source address as string (host:port)\r\n pass\r\n```\r\n\r\n## Performance\r\n\r\nThe Rust backend provides significant performance improvements over pure Python implementations:\r\n\r\n- **Lower Latency**: Direct system calls without Python GIL overhead\r\n- **Higher Throughput**: Efficient async I/O with Tokio\r\n- **Memory Efficiency**: Zero-copy operations where possible\r\n- **Concurrent Processing**: True parallelism for multiple connections\r\n- **Channel-based Communication**: Non-blocking message passing between Rust and Python\r\n\r\n## Troubleshooting\r\n\r\n### Common Issues\r\n\r\n1. **Import Error**: Make sure the Rust extension is built with `uv run maturin develop`\r\n2. **Permission Denied**: Check if the port is already in use or requires elevated privileges\r\n3. **Build Errors**: Ensure you have the latest Rust toolchain installed\r\n4. **Runtime Errors**: Make sure the server is started before calling `send_to()`\r\n\r\n### Debug Mode\r\n\r\nEnable debug logging for Rust:\r\n\r\n```bash\r\nexport RUST_LOG=debug\r\ncargo test\r\n```\r\n\r\n### Testing the Installation\r\n\r\nRun a simple test to verify everything works:\r\n\r\n```bash\r\nuv run python -c \"from py_udp import UdpServer, UdpClient; print('\u2705 Installation successful!')\"\r\n```\r\n\r\n## License\r\n\r\nMIT License - see LICENSE file for details.\r\n\r\n## Contributing\r\n\r\n1. Fork the repository\r\n2. Create a feature branch\r\n3. Make your changes\r\n4. Add tests for both Rust and Python\r\n5. Run tests and linting\r\n6. Submit a pull request\r\n\r\n### Development Workflow\r\n\r\n1. **Rust Changes**: Work in `src/` directory\r\n - Add unit tests in `tests/test_udp.rs`\r\n - Add integration tests in `tests/integration_udp.rs`\r\n - Run `cargo test` to verify changes\r\n - Check coverage with `cargo tarpaulin`\r\n\r\n2. **Python Changes**: Work in `py_udp/` directory\r\n - Add tests in `tests/test_udp.py`\r\n - Run `uv run pytest tests/` to verify changes\r\n - Check coverage with `uv run pytest tests/ --cov=py_udp`\r\n\r\n3. **Integration**: Test both components work together\r\n - Run both Rust and Python test suites\r\n - Test examples in `examples/` directory\r\n - Verify end-to-end functionality\r\n\r\n4. **Documentation**: Update README and docstrings\r\n5. **Examples**: Update examples in `examples/` directory\r\n\r\n### Code Style\r\n\r\n- **Rust**: Follow Rust formatting guidelines with `cargo fmt`\r\n- **Python**: Use Black for formatting and isort for imports\r\n- **Documentation**: Keep docstrings up to date\r\n- **Tests**: Maintain good test coverage for both Rust and Python \n",
"bugtrack_url": null,
"license": "MIT",
"summary": "High-performance UDP networking library for Python with Rust backend",
"version": "0.2.0",
"project_urls": {
"Changelog": "https://github.com/DaymaNKinG990/py-udp/blob/main/CHANGELOG.md",
"Documentation": "https://github.com/DaymaNKinG990/py-udp#readme",
"Homepage": "https://github.com/DaymaNKinG990/py-udp",
"Issues": "https://github.com/DaymaNKinG990/py-udp/issues",
"Repository": "https://github.com/DaymaNKinG990/py-udp"
},
"split_keywords": [
"udp",
" networking",
" rust",
" async",
" socket",
" server",
" client"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "5d088cdd38b6b9e7016fc0fbf8f1ce725db4229cea2a8b5457a277a99722e73d",
"md5": "45ea95f2267bb50d3ac50c746deaa827",
"sha256": "d73d5a9d0002bd213e4fc0cb4e9a0c1c250afcf140def3e70eac6befb0bfe276"
},
"downloads": -1,
"filename": "py_udp_rust-0.2.0-cp312-cp312-win_amd64.whl",
"has_sig": false,
"md5_digest": "45ea95f2267bb50d3ac50c746deaa827",
"packagetype": "bdist_wheel",
"python_version": "cp312",
"requires_python": ">=3.12",
"size": 346495,
"upload_time": "2025-08-04T09:41:47",
"upload_time_iso_8601": "2025-08-04T09:41:47.344618Z",
"url": "https://files.pythonhosted.org/packages/5d/08/8cdd38b6b9e7016fc0fbf8f1ce725db4229cea2a8b5457a277a99722e73d/py_udp_rust-0.2.0-cp312-cp312-win_amd64.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-04 09:41:47",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "DaymaNKinG990",
"github_project": "py-udp",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "py-udp-rust"
}