# Contributing to acelery

Thanks for your interest in contributing! This document explains how to set up a development environment, run the tests, and submit changes.

## Table of Contents

- [Code of Conduct](#code-of-conduct)
- [Getting Started](#getting-started)
- [Development Setup](#development-setup)
- [Project Structure](#project-structure)
- [Coding Standards](#coding-standards)
- [Testing](#testing)
- [Submitting Changes](#submitting-changes)
- [Reporting Issues](#reporting-issues)
- [Release Process](#release-process)
- [Recognition](#recognition)

## Code of Conduct

This project follows the conventional expectation that all participants behave respectfully, inclusively, and constructively. Please assume good faith and keep discussions focused on the work.

## Getting Started

### Prerequisites

- **Python 3.10+** (the CI matrix tests 3.10, 3.11, 3.12, and 3.13)
- **[uv](https://docs.astral.sh/uv/)** for dependency management
- **Git** and a GitHub account
- **Docker** (or local installs of **Redis 7+** and **RabbitMQ 3+**) to run the integration tests
- Familiarity with `asyncio` and Celery

## Development Setup

1. **Fork and clone**
   ```bash
   git clone https://github.com/<your-username>/acelery.git
   cd acelery
   ```

2. **Install dependencies**
   ```bash
   uv sync --all-groups --all-extras
   ```
   This installs runtime dependencies plus the `dev` and `test` extras (Celery types, pytest, pytest-asyncio, pytest-mock, pytest-timeout, coverage, pre-commit).

3. **Install pre-commit hooks** (recommended)
   ```bash
   uv run pre-commit install
   ```
   The hooks run `ruff` (lint + format), `mypy`, `pyupgrade`, and a handful of generic checks (trailing whitespace, YAML/TOML validity, merge-conflict markers, etc.). The same hook configuration runs in CI, so passing locally usually means passing CI.

4. **Start the broker and result backend for tests**
   ```bash
   docker run -d --name acelery-rabbit -p 5672:5672 rabbitmq:3-management
   docker run -d --name acelery-redis  -p 6379:6379 redis:7
   ```
   You can override the defaults via environment variables:
   ```bash
   export CELERY_BROKER_URL="amqp://guest:guest@localhost:5672//"
   export CELERY_RESULT_BACKEND="redis://localhost:6379/"
   ```

## Project Structure

```
acelery/
├── acelery/             # Main package
│   ├── __init__.py             # Public API re-exports (async_task, AIOResult, AIOExecutable)
│   ├── task.py                 # @async_task decorator + worker lifecycle signals
│   ├── runner.py               # Asyncio Runner (polyfill for Python 3.10)
│   ├── result.py               # AIOResult: async-friendly Celery result + trigger_or_join_task
│   ├── executable.py           # AIOExecutable: async wrapper over Celery Signature / Task
│   └── errors.py               # Custom exceptions (e.g. MaxPendingInterruptsError)
├── tests/
│   └── test_integration.py     # Integration tests against a live RabbitMQ + Redis
├── .github/workflows/          # CI: lint, test, build, release
├── .pre-commit-config.yaml     # ruff, mypy, pyupgrade, generic hooks
├── pyproject.toml              # Project metadata, deps, pytest config
├── README.md
├── LICENSE
└── CONTRIBUTING.md             # This file
```

## Coding Standards

### Python Style

- Target Python **3.10+** syntax (`pyupgrade --py310-plus` is enforced).
- Use modern type hints (`X | None`, built-in generics, `ParamSpec`, `TypeVar` etc.). Type hints are required for public functions, methods, and class attributes.
- Maximum line length follows `ruff` defaults; no Black-specific tuning.
- Choose meaningful, readable names. Prefer clarity over cleverness.

### Tooling

| Tool | Purpose | How it's run |
| --- | --- | --- |
| [`ruff`](https://docs.astral.sh/ruff/) | Lint + format | `uv run pre-commit run ruff` / `ruff-format` |
| [`mypy`](https://mypy.readthedocs.io/) | Static type checking | `uv run pre-commit run mypy` |
| [`pyupgrade`](https://github.com/asottile/pyupgrade) | Auto-modernize syntax | Pre-commit hook |
| [`pre-commit`](https://pre-commit.com/) | Orchestrates the above | `uv run pre-commit run --all-files` |

Run everything locally before pushing:
```bash
uv run pre-commit run --all-files
```

### Docstrings

- Write docstrings for all public functions, classes, and methods.
- Use **Google-style** docstrings (`Args:`, `Returns:`, `Raises:`).
- Include examples for non-trivial APIs.

## Testing

The suite is integration-heavy: it spins up real Celery workers against a live RabbitMQ broker and Redis backend.

### Running Tests

```bash
# Run everything (requires RabbitMQ + Redis reachable)
uv run pytest

# Verbose, fail fast
uv run pytest -vv -x

# Coverage report
uv run pytest --cov=acelery --cov-report=term-missing

# A single file or test
uv run pytest tests/test_integration.py
uv run pytest tests/test_integration.py::test_name
```

`pytest-asyncio` is configured in `auto` mode (see `pyproject.toml`), so `async def` tests are detected without per-test markers. A 60-second global timeout is enforced via `pytest-timeout`.

### Test Requirements

- New features must come with tests that exercise them end-to-end against a real worker where reasonable.
- Cover error paths and edge cases (timeouts, retries, missing results, pubsub races).
- The CI test matrix runs against Python 3.10–3.13 **and** Pydantic v1 and v2 — keep your code compatible with both Pydantic majors (`acelery/result.py` shows the pattern).

## Submitting Changes

1. Create a feature branch off `main`:
   ```bash
   git checkout -b <short-descriptive-name>
   ```
2. Make focused, atomic commits. Aim for clear commit messages that describe the **why** as well as the **what**.
3. Ensure `uv run pre-commit run --all-files` and `uv run pytest` both pass locally.
4. Push the branch and open a PR against `main`. Include:
   - A short summary of the change and motivation.
   - Linked issues (if any).
   - Notes on backward compatibility, if relevant.
   - A test plan or a description of the tests you added.
5. Address review feedback by pushing additional commits (avoid force-pushing during review unless asked, so reviewers can see what changed).

PRs run the full CI matrix (lint, type-check, build, integration tests on Python 3.10–3.13 × Pydantic v1/v2). All checks must be green before merge.

## Reporting Issues

When filing an issue, please include:

- A minimal reproduction (Python version, Celery version, Pydantic version, broker/backend used).
- The full traceback if applicable.
- Expected vs. actual behavior.
- Relevant logs (worker output is especially useful for task-runtime bugs).

For security issues, do **not** open a public issue — contact the maintainers privately.

## Release Process

Releases are automated via the `release.yml` workflow:

- Version numbers are derived from git tags via `hatch-vcs` (no manual version bumps in `pyproject.toml`).
- A tagged release triggers the lint/test gate, builds wheels and sdists with `uv build`, and publishes to (Test)PyPI.
- Changelog entries / release notes are authored on the GitHub Release.

Maintainers cut releases; contributors do not need to publish anything manually.

## Recognition

Contributors are credited in release notes. Thank you for helping improve acelery! 🚀
