Contributing to Hishel
Thank you for being interested in contributing to Hishel! We appreciate your efforts and welcome contributions of all kinds.
You can contribute by:
- Reviewing pull requests
- Opening an issue to report bugs or suggest features
- Adding a new feature
- ⭐ Starring the repository on GitHub - it helps the project grow!
This guide will help you understand the development process and repository structure.
Getting Started
Setting Up Your Development Environment
-
Fork the repository: Fork Hishel to your GitHub account
-
Clone and create a branch:
git clone https://github.com/username/hishel cd hishel git switch -c my-feature-name -
Install dependencies: This project uses
uvfor dependency management. Make sure you have it installed, then install the project dependencies:uv sync --all-extras --dev
Repository Structure
The scripts/ Folder
The scripts/ directory contains utility scripts to simplify development and maintenance tasks:
scripts/fix- Automatically fixes code style issues, formats code, and generates synchronous code from async codescripts/lint- Validates code quality (linting, formatting, type checking, async/sync consistency)scripts/test- Runs the test suite with coverage reportingscripts/unasync- Converts async code to sync code (see below for details)
Usage Example
# Fix code style and generate sync files
./scripts/fix
# Check code quality
./scripts/lint
# Run tests with coverage
./scripts/test
Critical: Async/Sync Code Generation
⚠️ IMPORTANT: Do not manually edit auto-generated synchronous files!
Hishel maintains both async and sync APIs without code duplication using an unasync strategy similar to httpcore.
How It Works
Write async code once - All shared async/sync functionality is written in async files:
hishel/_core/_storages/_async_*.py→ auto-generates →hishel/_core/_storages/_sync_*.pytests/_core/_async/*.py→ auto-generates →tests/_core/_sync/*.py
Automatic transformation - The scripts/unasync script converts async code to sync:
# Async code (you write this)
async def store(self, key: str) -> None:
async with self.connection as conn:
await conn.execute(...)
# Sync code (automatically generated)
def store(self, key: str) -> None:
with self.connection as conn:
conn.execute(...)
Using the Script
# Generate sync files from async files
./scripts/unasync
# Check if sync files are up-to-date (CI)
./scripts/unasync --check
# Or use helper scripts
./scripts/fix # Auto-generates sync files + formatting
./scripts/lint # Checks sync files are up-to-date
Development Rules
✅ DO:
- Write and edit async files only (_async_*.py)
- Run ./scripts/fix before committing
- Let the script generate all sync files
❌ DON'T:
- Manually edit sync files (_sync_*.py)
- Commit async changes without running unasync
- Modify the sync test files directly
Development Workflow
Before Submitting a PR
- Make your changes in the async versions of files
- Run the fix script:
./scripts/fix - Run the linter:
./scripts/lint - Run tests:
./scripts/test
Questions?
If you have questions about contributing, feel free to: - Open an issue for discussion - Ask in an existing pull request - Check the documentation
Thank you for contributing to Hishel! 🎉