# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

```bash
# Run all tests
uv run pytest

# Run a single test file
uv run pytest tests/test_contracting.py

# Run a single test function
uv run pytest tests/test_contracting.py::test_square_root

# Run tests with coverage (100% required)
uv run pytest --cov --cov-fail-under=100

# Format code
uv run black .

# Lint
uv run flake8

# Type checking
uv run pyright .

# Build distribution
uv build
```

## Architecture

ContractMe is a design-by-contract framework for Python. The public API is exported from [src/contractme/__init__.py](src/contractme/__init__.py):

- `@precondition(lambda ...)` — validates caller inputs before execution
- `@postcondition(lambda result, ...: ...)` — validates function outputs after execution
- `@annotated` — automatically validates PEP-593 `Annotated` type constraints at call boundaries
- Runtime control: `ignore_preconditions()`, `check_preconditions()`, `ignore_postconditions()`, `check_postconditions()`

### Core modules

**[contracting.py](src/contractme/contracting.py)** — The main implementation. `ContractedFunction` wraps callables and checks pre/postconditions.

**Parameter matching for condition lambdas**: When a condition lambda is called, the framework uses `inspect.getfullargspec` to introspect its parameter names and selects only the matching arguments from the function's call kwargs (resolved via `get_kw_from_call`). This means a lambda `lambda x: x > 0` on a function `def f(x, y)` only receives `x`. Postcondition lambdas can additionally declare `result` (the return value) and `old` (an `OldHolder` deep-copy of all params captured before execution, accessed as `old.param_name`). If the lambda uses `**kwargs` it receives everything.

**Error messages**: Failed contracts raise `AssertionError` with a message that identifies whether it is a precondition (caller bug) or postcondition (callee bug), the source text of the failing predicate (extracted via `show_source()` / `inspect.getsource()` — similar to pytest's assertion introspection), and a formatted dump of the relevant argument values. An optional `message` string can be passed to `@precondition`/`@postcondition` to override the auto-extracted source text.

**`OldHolder`**: Deep-copies all call kwargs before execution so postconditions can compare pre/post state.

**Contracts are skipped** when Python runs with `-O` (optimized flag) via the `__debug__` guard.

**[annotations.py](src/contractme/annotations.py)** — The `@annotated` decorator introspects a function's `Annotated[T, constraints...]` signatures and auto-generates preconditions for inputs and postconditions for the return value by delegating to `typecheck.py`. **Known limitations**: dataclasses, enums, class inheritance, and exact type matching (e.g. distinguishing `int` from `bool`) are not supported and untested.

**[typecheck.py](src/contractme/typecheck.py)** — Two-phase validation: `get_first_structure_error()` checks structural correctness (e.g., is this actually a `list`?), then `get_constraints_errors()` checks value constraints (e.g., `Ge`, `Lt`, `MinLen`). Handles nested and recursive types, unions, tuples, sets, dicts, and `annotated-types` predicates.

**[testing.py](src/contractme/testing.py)** — Hypothesis integration. `get_generator(f)` builds a Hypothesis strategy from a function's contracts. `autotest(f)` runs property-based testing automatically; `test_with_examples(f, *examples)` checks specific inputs against contracts.

### Release process

Changelog entries go in `README.md` under `# Changelog`. To release a new version: update the changelog, bump the version in `pyproject.toml`, run `uv build`, push, then git-tag as `v<number>`.

If the release process in `README.md` changes, update this section accordingly.

### Key constraints

- Python 3.13+ required (uses PEP-695 type syntax, pattern matching)
- 100% test coverage is enforced in CI and pre-commit hooks
- Black line length is 100 chars
- Pyright is used for static type checking
