Skip to main content

pytest-async-benchmark: Modern pytest benchmarking for async code. ๐Ÿš€

Project description

pytest-async-benchmark ๐Ÿš€

Modern pytest benchmarking for async code with beautiful terminal output and advanced comparison tools.

โœจ Features

  • ๐ŸŽฏ Async-First: Designed specifically for benchmarking async def functions
  • ๐Ÿ”Œ Pytest Integration: Seamless integration as a pytest plugin with full pytest-asyncio support
  • ๐ŸŽจ Rich Output: Beautiful terminal reporting powered by Rich!
  • ๐Ÿ“Š Comprehensive Stats: Min, max, mean, median, std dev, percentiles, and more
  • โš–๏ธ A vs B Comparisons: Compare different implementations side-by-side
  • ๐Ÿ“ˆ Multi-Scenario Analysis: Benchmark multiple scenarios with detailed comparison tables
  • ๐ŸŽฏ Performance Grading: Automatic performance scoring and analysis
  • โšก Auto Calibration: Intelligent round and iteration detection
  • ๐Ÿ”„ Quick Compare: One-line comparison utilities
  • ๐Ÿ† Winner Detection: Automatic identification of best-performing implementation
  • ๐Ÿš€ Easy to Use: Simple fixture-based API with native async/await support
  • ๐Ÿ”ง pytest-asyncio Compatible: Works perfectly with pytest-asyncio's event loop management

๐Ÿ“ฆ Installation

For Existing pytest-asyncio Users ๐Ÿš€

Already testing async APIs (FastAPI, Quart, aiohttp)? You're all set with the basic installation:

pip install pytest-async-benchmark
# or
uv add pytest-async-benchmark

You'll get the full async/await experience immediately since you already have pytest-asyncio!

For New Users

Choose your installation based on your needs:

# Full installation with async/await support (recommended)
pip install pytest-async-benchmark[asyncio]
uv add pytest-async-benchmark --optional asyncio

# Basic installation (simple interface)
pip install pytest-async-benchmark
uv add pytest-async-benchmark

Quick Check โœ…

Already using @pytest.mark.asyncio in your tests? Then the basic installation is all you need:

# If you already have tests like this:
@pytest.mark.asyncio
async def test_my_api():
    # Your existing async test code
    pass

# Then just add pytest-async-benchmark and use:
@pytest.mark.asyncio
async def test_my_api_performance(async_benchmark):
    result = await async_benchmark(my_async_function)
    assert result['mean'] < 0.01

๐Ÿš€ Quick Start

pytest-async-benchmark automatically adapts to your environment, providing two convenient interfaces:

Async Interface (with pytest-asyncio)

When pytest-asyncio is installed, use the natural async/await syntax:

import asyncio
import pytest

async def slow_async_operation():
    await asyncio.sleep(0.01)  # 10ms
    return "result"

@pytest.mark.asyncio
@pytest.mark.async_benchmark(rounds=5, iterations=10)
async def test_async_performance(async_benchmark):
    # Use await with pytest-asyncio for best experience
    result = await async_benchmark(slow_async_operation)
    
    # Your assertions here
    assert result['mean'] < 0.02

Simple Interface (without pytest-asyncio)

For simpler setups, the sync interface works automatically:

import asyncio
import pytest

async def slow_async_operation():
    await asyncio.sleep(0.01)
    return "result"

@pytest.mark.async_benchmark(rounds=5, iterations=10)
def test_sync_performance(async_benchmark):
    # No await needed - sync interface
    result = async_benchmark(slow_async_operation)
    
    # Your assertions here
    assert result['mean'] < 0.02  # Should complete in under 20ms

Flexible Configuration Syntax

pytest-async-benchmark supports two syntax options for configuring benchmarks:

Option 1: Marker Syntax (Recommended)

@pytest.mark.async_benchmark(rounds=5, iterations=10)
async def test_with_marker(async_benchmark):
    result = await async_benchmark(slow_async_operation)
    assert result['rounds'] == 5  # From marker

Option 2: Function Parameter Syntax

async def test_with_parameters(async_benchmark):
    result = await async_benchmark(slow_async_operation, rounds=5, iterations=10)
    assert result['rounds'] == 5  # From function parameters

๐Ÿ”ง Interface Detection & Flexibility

pytest-async-benchmark automatically detects your environment and provides the best interface:

With pytest-asyncio (Recommended)

When pytest-asyncio is installed, use natural async/await syntax:

# Set in your pyproject.toml for automatic async test detection
[tool.pytest.ini_options]
asyncio_mode = "auto"

# Then use await syntax
@pytest.mark.asyncio
async def test_my_benchmark(async_benchmark):
    result = await async_benchmark(my_async_function)
    # Your assertions here

Benefits of pytest-asyncio integration:

  • โœ… Native async/await syntax support
  • โœ… Automatic event loop management
  • โœ… No RuntimeError: cannot be called from a running event loop
  • โœ… Better compatibility with async frameworks like FastAPI, Quart, aiohttp
  • โœ… Cleaner test code with standard async patterns

Without pytest-asyncio (Simple Setup)

When pytest-asyncio is not available, the simple interface works automatically:

# No pytest-asyncio required
def test_my_benchmark(async_benchmark):
    result = async_benchmark(my_async_function)  # No await needed
    # Your assertions here

Benefits of simple interface:

  • โœ… No additional dependencies required
  • โœ… Simpler setup for basic use cases
  • โœ… Perfect for getting started quickly
  • โœ… Automatic event loop management internally

๐ŸŽฏ Core Usage Examples

Interface Flexibility

Async Interface (with pytest-asyncio)

@pytest.mark.asyncio
@pytest.mark.async_benchmark(rounds=10, iterations=100, warmup_rounds=2)
async def test_with_marker(async_benchmark):
    """Use marker for consistent, visible configuration."""
    result = await async_benchmark(my_async_function)
    assert result['rounds'] == 10  # Configuration is explicit and visible

Simple Interface (without pytest-asyncio)

@pytest.mark.async_benchmark(rounds=10, iterations=100, warmup_rounds=2)
def test_with_marker_sync(async_benchmark):
    """Use marker for consistent, visible configuration - simple style."""
    result = async_benchmark(my_async_function)  # No await needed
    assert result['rounds'] == 10  # Configuration is explicit and visible

Two Configuration Syntaxes

Marker Syntax (Declarative)

# With pytest-asyncio
@pytest.mark.asyncio
@pytest.mark.async_benchmark(rounds=10, iterations=100, warmup_rounds=2)
async def test_with_marker_async(async_benchmark):
    result = await async_benchmark(my_async_function)
    assert result['rounds'] == 10

# Without pytest-asyncio
@pytest.mark.async_benchmark(rounds=10, iterations=100, warmup_rounds=2)
def test_with_marker_sync(async_benchmark):
    result = async_benchmark(my_async_function)
    assert result['rounds'] == 10

Function Parameter Syntax (Dynamic)

# With pytest-asyncio
@pytest.mark.asyncio
async def test_with_parameters_async(async_benchmark):
    result = await async_benchmark(
        my_async_function,
        rounds=10,
        iterations=100,
        warmup_rounds=2
    )
    assert result['rounds'] == 10

# Without pytest-asyncio
def test_with_parameters_simple(async_benchmark):
    result = async_benchmark(
        my_async_function,
        rounds=10,
        iterations=100,
        warmup_rounds=2
    )
    assert result['rounds'] == 10

Combined Syntax (Override)

Both interfaces support parameter precedence where function parameters override marker settings:

@pytest.mark.async_benchmark(rounds=5, iterations=50)  # Default config
async def test_with_override(async_benchmark):  # Works with or without @pytest.mark.asyncio
    """Function parameters override marker settings."""
    result = await async_benchmark(  # Use 'await' only with pytest-asyncio
        my_async_function,
        rounds=20  # This overrides marker's rounds=5
        # iterations=50 comes from marker
    )
    assert result['rounds'] == 20      # Function parameter wins
    assert result['iterations'] == 50  # From marker

Basic Benchmarking

@pytest.mark.asyncio
async def test_my_async_function(async_benchmark):
    async def my_function():
        # Your async code here
        await some_async_operation()
        return result
    
    # Benchmark with default settings (5 rounds, 1 iteration each)
    stats = await async_benchmark(my_function)
    
    # Access comprehensive timing statistics
    print(f"Mean execution time: {stats['mean']:.3f}s")
    print(f"Standard deviation: {stats['stddev']:.3f}s")
    print(f"95th percentile: {stats['p95']:.3f}s")

Advanced Configuration

๐ŸŽฏ Two Configuration Syntaxes

pytest-async-benchmark offers two flexible ways to configure your benchmarks:

๐Ÿท๏ธ Marker Syntax (Recommended)

Use pytest markers for declarative, visible configuration:

@pytest.mark.asyncio
@pytest.mark.async_benchmark(rounds=10, iterations=100, warmup_rounds=2)
async def test_high_precision_benchmark(async_benchmark):
    """High precision benchmark with marker configuration."""
    result = await async_benchmark(my_async_function)
    
    # Configuration is visible and consistent
    assert result['rounds'] == 10
    assert result['iterations'] == 100

Benefits:

  • โœ… Visible configuration - Parameters are clear at test level
  • โœ… IDE support - Better tooling and autocomplete
  • โœ… Test discovery - Easy to find all benchmark tests
  • โœ… Consistent configs - Same settings across related tests

โš™๏ธ Function Parameter Syntax

Use function parameters for dynamic, flexible configuration:

@pytest.mark.asyncio
async def test_dynamic_benchmark(async_benchmark):
    """Dynamic benchmark with runtime configuration."""
    # Configuration can be computed or conditional
    rounds = 20 if is_production else 5
    
    result = await async_benchmark(
        my_async_function,
        rounds=rounds,
        iterations=50,
        warmup_rounds=1
    )

Benefits:

  • โœ… Dynamic configuration - Runtime parameter calculation
  • โœ… Conditional logic - Different configs based on environment
  • โœ… Per-call customization - Each benchmark call can differ

๐Ÿ”„ Combined Syntax (Best of Both)

Function parameters override marker parameters:

@pytest.mark.asyncio
@pytest.mark.async_benchmark(rounds=5, iterations=50, warmup_rounds=1)
async def test_with_overrides(async_benchmark):
    """Use marker defaults with selective overrides."""
    
    # Quick test with marker defaults
    quick_result = await async_benchmark(fast_function)
    
    # Precision test with overridden rounds
    precise_result = await async_benchmark(
        slow_function,
        rounds=20  # Overrides marker's rounds=5
        # iterations=50 and warmup_rounds=1 come from marker
    )
    
    assert quick_result['rounds'] == 5   # From marker
    assert precise_result['rounds'] == 20  # From function override

Traditional Configuration

@pytest.mark.asyncio
async def test_with_custom_settings(async_benchmark):
    result = await async_benchmark(
        my_async_function,
        rounds=10,        # Number of rounds to run
        iterations=5,     # Iterations per round
        warmup_rounds=2   # Warmup rounds before measurement
    )

With Function Arguments

@pytest.mark.asyncio
async def test_with_args(async_benchmark):
    async def process_data(data, multiplier=1):
        # Process the data
        await asyncio.sleep(0.01)
        return len(data) * multiplier
    
    result = await async_benchmark(
        process_data,
        "test_data",      # positional arg
        multiplier=2,     # keyword arg
        rounds=3
    )

โš–๏ธ A vs B Comparison Features

Quick Comparison

from pytest_async_benchmark import quick_compare

async def algorithm_v1():
    await asyncio.sleep(0.002)  # 2ms
    return "v1_result"

async def algorithm_v2():
    await asyncio.sleep(0.0015)  # 1.5ms - optimized
    return "v2_result"

# Quick one-liner comparison
def test_algorithm_comparison():
    winner, results = quick_compare(algorithm_v1, algorithm_v2, rounds=5)
    assert winner == "algorithm_v2"  # v2 should be faster

Detailed A vs B Analysis

from pytest_async_benchmark import a_vs_b_comparison

def test_detailed_comparison():
    # Compare with beautiful terminal output
    a_vs_b_comparison(
        "Original Algorithm", algorithm_v1,
        "Optimized Algorithm", algorithm_v2,
        rounds=8, iterations=20
    )

Multi-Scenario Benchmarking

from pytest_async_benchmark import BenchmarkComparator

def test_multi_scenario():
    comparator = BenchmarkComparator()
    
    # Add multiple scenarios
    comparator.add_scenario(
        "Database Query v1", db_query_v1,
        rounds=5, iterations=10,
        description="Original database implementation"
    )
    
    comparator.add_scenario(
        "Database Query v2", db_query_v2,
        rounds=5, iterations=10,
        description="Optimized with connection pooling"
    )
    
    # Run comparison and get results
    results = comparator.run_comparison()
    
    # Beautiful comparison table automatically displayed
    # Access programmatic results
    fastest = results.get_fastest_scenario()
    assert fastest.name == "Database Query v2"

๐Ÿ“Š Comprehensive Statistics

Each benchmark returns detailed statistics:

{
    'min': 0.001234,      # Minimum execution time
    'max': 0.005678,      # Maximum execution time  
    'mean': 0.002456,     # Mean execution time
    'median': 0.002123,   # Median execution time
    'stddev': 0.000234,   # Standard deviation
    'p50': 0.002123,      # 50th percentile (median)
    'p90': 0.003456,      # 90th percentile
    'p95': 0.004123,      # 95th percentile
    'p99': 0.004789,      # 99th percentile
    'rounds': 5,          # Number of rounds executed
    'iterations': 1,      # Number of iterations per round
    'raw_times': [...],   # List of raw timing measurements
    'grade': 'A',         # Performance grade (A-F)
    'grade_score': 87.5   # Numeric grade score (0-100)
}

๐ŸŽจ Beautiful Terminal Output

Basic Benchmark Output

๐Ÿš€ Async Benchmark Results: test_my_function
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“
โ”ƒ Metric      โ”ƒ Value      โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ
โ”‚ Min         โ”‚ 10.234ms   โ”‚
โ”‚ Max         โ”‚ 15.678ms   โ”‚
โ”‚ Mean        โ”‚ 12.456ms   โ”‚
โ”‚ Median      โ”‚ 12.123ms   โ”‚
โ”‚ Std Dev     โ”‚ 1.234ms    โ”‚
โ”‚ 95th %ile   โ”‚ 14.567ms   โ”‚
โ”‚ 99th %ile   โ”‚ 15.234ms   โ”‚
โ”‚ Grade       โ”‚ A (87.5)   โ”‚
โ”‚ Rounds      โ”‚ 5          โ”‚
โ”‚ Iterations  โ”‚ 1          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โœ… Benchmark completed successfully!

A vs B Comparison Output

โš–๏ธ  A vs B Comparison Results
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“
โ”ƒ Scenario                โ”ƒ Algorithm A โ”ƒ Algorithm B โ”ƒ Winner    โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ
โ”‚ Mean Time              โ”‚ 2.456ms     โ”‚ 1.789ms     โ”‚ B ๐Ÿ†      โ”‚
โ”‚ Median Time            โ”‚ 2.234ms     โ”‚ 1.678ms     โ”‚ B ๐Ÿ†      โ”‚
โ”‚ 95th Percentile        โ”‚ 3.456ms     โ”‚ 2.345ms     โ”‚ B ๐Ÿ†      โ”‚
โ”‚ Standard Deviation     โ”‚ 0.567ms     โ”‚ 0.234ms     โ”‚ B ๐Ÿ†      โ”‚
โ”‚ Performance Grade      โ”‚ B (76.2)    โ”‚ A (89.1)    โ”‚ B ๐Ÿ†      โ”‚
โ”‚ Improvement            โ”‚ -           โ”‚ 27.2%       โ”‚ -         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
๐Ÿ† Winner: Algorithm B (27.2% faster)

๐Ÿ—๏ธ Project Structure

pytest-async-benchmark/
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ pytest_async_benchmark/
โ”‚       โ”œโ”€โ”€ __init__.py          # Main exports and API
โ”‚       โ”œโ”€โ”€ plugin.py            # Pytest plugin and fixtures
โ”‚       โ”œโ”€โ”€ runner.py            # Core benchmarking engine
โ”‚       โ”œโ”€โ”€ display.py           # Rich terminal output formatting
โ”‚       โ”œโ”€โ”€ stats.py             # Statistical calculations
โ”‚       โ”œโ”€โ”€ utils.py             # Utility functions
โ”‚       โ”œโ”€โ”€ analytics.py         # Performance analysis tools
โ”‚       โ””โ”€โ”€ comparison.py        # A vs B comparison functionality
โ”œโ”€โ”€ examples/
โ”‚   โ”œโ”€โ”€ pytest_examples.py      # Comprehensive pytest usage examples
โ”‚   โ”œโ”€โ”€ quart_api_comparison.py  # Real-world API endpoint comparison
โ”‚   โ””โ”€โ”€ comparison_examples.py   # Advanced comparison features demo
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ test_async_bench.py      # Core functionality tests
โ”‚   โ”œโ”€โ”€ test_comparison.py       # Comparison feature tests
โ”‚   โ”œโ”€โ”€ test_demo.py             # Demo test cases
โ”‚   โ””โ”€โ”€ conftest.py              # Test configuration
โ”œโ”€โ”€ pyproject.toml               # Package configuration
โ””โ”€โ”€ README.md                    # This file

๐Ÿ“š Example Files Guide

๐Ÿ”ง examples/pytest_examples.py

Comprehensive pytest usage examples including:

  • Basic benchmarking with the async_benchmark fixture
  • Advanced configuration options
  • Performance assertions and testing patterns
  • Using markers for benchmark organization

๐ŸŒ examples/quart_api_comparison.py

Real-world API endpoint comparison demo featuring:

  • Quart web framework setup
  • API v1 vs v2 endpoint benchmarking
  • Live server testing with actual HTTP requests
  • Performance regression detection

โš–๏ธ examples/comparison_examples.py

Advanced comparison features showcase:

  • Multi-scenario benchmark comparisons
  • A vs B testing with detailed analysis
  • Performance grading and scoring
  • Statistical comparison utilities

๐ŸŒ Real-World Examples

FastAPI Endpoint Benchmarking

from fastapi import FastAPI
from fastapi.testclient import TestClient
import pytest

app = FastAPI()

@app.get("/api/data")
async def get_data():
    # Simulate database query
    await asyncio.sleep(0.005)
    return {"data": "example"}

@pytest.mark.asyncio
async def test_fastapi_endpoint_performance(async_benchmark):
    async def make_request():
        with TestClient(app) as client:
            response = client.get("/api/data")
            return response.json()
    
    result = await async_benchmark(make_request, rounds=10)
    assert result['mean'] < 0.1  # Should respond within 100ms
    assert result['grade'] in ['A', 'B']  # Should have good performance grade

Quart API Endpoint Comparison

See the complete example in examples/quart_api_comparison.py:

from pytest_async_benchmark import a_vs_b_comparison
import asyncio
import aiohttp

async def test_api_v1():
    async with aiohttp.ClientSession() as session:
        async with session.get('http://localhost:5000/api/v1/data') as resp:
            return await resp.json()

async def test_api_v2():
    async with aiohttp.ClientSession() as session:
        async with session.get('http://localhost:5000/api/v2/data') as resp:
            return await resp.json()

# Compare API versions
a_vs_b_comparison(
    "API v1", test_api_v1,
    "API v2 (Optimized)", test_api_v2,
    rounds=10, iterations=5
)

Database Query Benchmarking

@pytest.mark.asyncio
async def test_database_query_performance(async_benchmark):
    async def fetch_user_data(user_id):
        async with database.connection() as conn:
            return await conn.fetch_one(
                "SELECT * FROM users WHERE id = ?", user_id
            )
    
    result = await async_benchmark(fetch_user_data, 123, rounds=5)
    assert result['mean'] < 0.05  # Should complete within 50ms
    assert result['p95'] < 0.1    # 95% of queries under 100ms

๐ŸŽฏ Using Markers

@pytest.mark.async_benchmark
@pytest.mark.asyncio
async def test_performance(async_benchmark):
    # Your benchmark test
    result = await async_benchmark(my_async_function)
    assert result is not None

๐Ÿ“‹ API Reference

async_benchmark(func, *args, rounds=None, iterations=None, warmup_rounds=1, **kwargs)

Parameters:

  • func: The async function to benchmark
  • *args: Positional arguments to pass to the function
  • rounds: Number of measurement rounds (default: 5)
  • iterations: Number of iterations per round (default: 1)
  • warmup_rounds: Number of warmup rounds before measurement (default: 1)
  • **kwargs: Keyword arguments to pass to the function

Returns: A dictionary with comprehensive statistics including min, max, mean, median, stddev, percentiles, performance grade, and raw measurements.

Comparison Functions

  • quick_compare(func_a, func_b, **kwargs): Quick comparison returning winner and results
  • a_vs_b_comparison(name_a, func_a, name_b, func_b, **kwargs): Detailed comparison with terminal output
  • BenchmarkComparator: Class for multi-scenario benchmarking and analysis

๐Ÿ“‹ Requirements

  • Python โ‰ฅ 3.9
  • pytest โ‰ฅ 8.3.5
  • pytest-asyncio โ‰ฅ 0.23.0 (automatically installed)

Note: Rich (for beautiful terminal output) is automatically installed as a dependency.

๐Ÿš€ Development

# Clone the repository
git clone https://github.com/yourusername/pytest-async-benchmark.git
cd pytest-async-benchmark

# Install dependencies
uv sync

# Run tests
uv run pytest tests/ -v

# Run examples
uv run pytest examples/pytest_examples.py -v

# Test real-world Quart API comparison
uv run python examples/quart_api_comparison.py

# See advanced comparison features
uv run python examples/comparison_examples.py

๐Ÿ› ๏ธ Code Quality and Formatting

This project uses Ruff for both linting and formatting:

# Check code for linting issues
uv run ruff check .

# Fix auto-fixable linting issues
uv run ruff check . --fix

# Check code formatting
uv run ruff format --check .

# Format code automatically
uv run ruff format .

# Run both linting and formatting in one go
uv run ruff check . --fix && uv run ruff format .

# Run all quality checks at once (linting, formatting, and tests)
uv run python scripts/quality-check.py

๐Ÿ“‹ Release Readiness Check

Before creating a release, verify everything is ready:

# Run comprehensive release check
uv run python scripts/release-check.py

# This checks:
# โœ… Git repository status
# โœ… Version consistency 
# โœ… Code formatting and linting
# โœ… Test suite passes
# โœ… Package builds successfully
# โœ… All required files exist

๐Ÿš€ Quick Quality Check

Run all quality checks at once:

# Run linting, formatting, tests, and release checks
python scripts/quality-check.py

# This will:
# ๐Ÿ”ง Fix linting issues automatically
# ๐ŸŽจ Format code with Ruff
# ๐Ÿงช Run the full test suite
# ๐Ÿ“‹ Check release readiness

๐Ÿš€ Automated Releases

This project uses GitHub Actions for automated testing and publishing to PyPI:

  • Continuous Integration: Tests run on every push for Python 3.9-3.13
  • Test Publishing: Automatic uploads to TestPyPI for testing releases
  • Production Releases: Secure publishing to PyPI using trusted publishing
  • Release Validation: Comprehensive checks ensure package quality

Creating a Release

  1. Update version in pyproject.toml and src/pytest_async_benchmark/__init__.py
  2. Run uv run python scripts/release-check.py to verify readiness
  3. Create a git tag: git tag v1.0.0 && git push origin v1.0.0
  4. Create a GitHub release to trigger automated PyPI publishing

See RELEASE_GUIDE.md for detailed release instructions.

๐Ÿค Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

๐Ÿ“„ License

MIT License - see LICENSE file for details.


Built with โค๏ธ for the async Python community

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_async_benchmark-0.2.0.tar.gz (181.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_async_benchmark-0.2.0-py3-none-any.whl (18.8 kB view details)

Uploaded Python 3

File details

Details for the file pytest_async_benchmark-0.2.0.tar.gz.

File metadata

  • Download URL: pytest_async_benchmark-0.2.0.tar.gz
  • Upload date:
  • Size: 181.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for pytest_async_benchmark-0.2.0.tar.gz
Algorithm Hash digest
SHA256 eed7eb2ec810709f263db3234add2bc2f50ca5553c083f98bcce2ec86634df65
MD5 ab446bd468800895b8db08be2a4b735c
BLAKE2b-256 d5097034885e055ad6f449f97e0b9a0e06343ac17f01bf2a5cc94b5e546f7680

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_async_benchmark-0.2.0.tar.gz:

Publisher: release.yml on mihailtd/pytest-async-benchmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pytest_async_benchmark-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pytest_async_benchmark-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7d2cd23c6c2ce2630849c38b9eb742df1b74ea378ecc53ca7b7754ba9bdc3683
MD5 b99323946a936dfdce9362432bd54f80
BLAKE2b-256 4b170ff79598ff109e8df60dcd455bcb98fef00281491a2f8a425a039815345d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pytest_async_benchmark-0.2.0-py3-none-any.whl:

Publisher: release.yml on mihailtd/pytest-async-benchmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page