Thank you for your interest in contributing! This document provides guidelines and instructions for contributing to easylimit.
This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to opensource@man8.com.
Before creating bug reports, please check existing issues to avoid duplicates.
When creating a bug report, include:
- Clear and descriptive title
- Steps to reproduce the problem
- Expected vs actual behavior
- Environment details (Python version, OS, easylimit version)
- Relevant logs or error messages
Enhancement suggestions are welcome! Please:
- Use a clear and descriptive title
- Provide detailed description of the proposed functionality
- Explain why this enhancement would be useful
- Include examples if applicable
- Fork the repository and create a branch from
main - Make your changes following the coding standards below
- Add tests if you're adding functionality
- Ensure all tests pass by running
uv run pytest - Run code quality checks (linting, formatting, type checking)
- Update documentation if needed (README, docstrings, CHANGELOG)
- Submit a pull request with a clear description
# Clone your fork
git clone https://github.com/YOUR-USERNAME/easylimit.git
cd easylimit
# Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create virtualenv and install dependencies
uv sync --all-extras --dev
# Activate virtualenv (optional, uv run works without activation)
source .venv/bin/activate# Run all tests
uv run pytest
# Run only non-legacy tests
uv run pytest -m 'not legacy'
# Run with coverage
uv run pytest --cov=easylimit --cov-report=html
# Run specific test file
uv run pytest tests/test_rate_limiter.py
# Run single test
uv run pytest tests/test_rate_limiter.py::TestRateLimiter::test_basic_rate_limitingAll code must pass these checks before being merged:
# Lint code (checks for errors and style issues)
uv run ruff check .
# Format code (auto-formats to project style)
uv run ruff format .
# Check formatting without modifying files
uv run ruff format --check .
# Type check
uv run mypy src/
# Run all checks (what CI runs)
uv run ruff check . && uv run ruff format --check . && uv run mypy src/ && uv run pytest- Line length: 119 characters maximum
- Quotes: Double quotes (enforced by ruff format)
- Indentation: Spaces, no tabs
- Follow PEP 8 guidelines (enforced by ruff)
- All functions must have type annotations
- Use
typingmodule for complex types - Mypy strict mode is enforced:
disallow_untyped_defs=true- No implicit Optional
- All overloads must be properly typed
- Tests live in
tests/directory - Use pytest for all tests
- Class-based test organization:
class Test* - Use markers for test categories:
@pytest.mark.legacy- Tests for deprecated API@pytest.mark.asyncio- Async tests
- Aim for high test coverage (currently 100%)
- All state mutations must be protected by
self._lock - Async methods must use
_to_thread()for state changes - Never block the event loop in async code
- Release locks during sleeps to prevent deadlocks
- Maintain compatibility with Python 3.8+
- Don't break existing API without deprecation cycle
- Use
@overloadfor type-safe API variants - Add
DeprecationWarningfor deprecated features
This project follows the Conventional Commits specification. Please read the full specification for details.
Format: <type>[optional scope]: <description>
Common types: feat, fix, docs, style, refactor, perf, test, build, ci, chore
Examples:
feat: add exponential backoff support
fix(async): resolve race condition in async_acquire
docs: update README with async examples
feat!: remove deprecated max_calls_per_second parameter # Breaking changeGuidelines:
- Use lowercase for type and description
- Keep first line under 72 characters
- Use imperative mood: "add" not "added"
- Reference issues in footer:
Fixes #123
- Update README.md if adding features or changing behavior
- Add docstrings for public APIs using Google-style format
- Update CHANGELOG.md following Keep a Changelog format
- Add examples in
examples/directory for significant features - Keep CLAUDE.md updated with architectural changes
Single source of truth: src/easylimit/__init__.py - __version__ variable
That's it! The build system automatically reads the version from there. Do not edit version anywhere else.
Follow Semantic Versioning:
- MAJOR version for incompatible API changes
- MINOR version for backwards-compatible new features
- PATCH version for backwards-compatible bug fixes
To release a new version:
- Update
__version__insrc/easylimit/__init__.py - Update
CHANGELOG.mdwith changes - Build and publish:
uv build && uv publish
CI tests on Python 3.8-3.13. If you want to test locally:
# Using pyenv to test multiple versions
pyenv install 3.8.18 3.9.18 3.10.13 3.11.9 3.12.7 3.13.2
pyenv local 3.8.18 3.9.18 3.10.13 3.11.9 3.12.7 3.13.2
# Run tests on each version
for version in 3.8 3.9 3.10 3.11 3.12 3.13; do
echo "Testing Python $version"
uv run --python $version pytest
doneBy contributing, you agree that your contributions will be licensed under the MIT License.
Feel free to:
- Open an issue with your question
- Start a discussion in GitHub Discussions
- Reach out to the maintainers at opensource@man8.com
Thank you for contributing! 🎉