Metadata-Version: 2.4
Name: mutate4py
Version: 0.1.0
Summary: Mutation testing for Python with an embedded-in-source manifest
License-Expression: MIT
License-File: LICENSE
Keywords: coverage,mutate,mutation,quality,testing
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# mutate4py

Mutation testing for Python. Discovers mutation sites, applies each one, runs your
tests, and reports killed, survived, and uncovered mutations — with an
**embedded-in-source manifest** so differential reruns survive a clone with zero CI
setup.

A faithful Python port of [unclebob/mutate4go](https://github.com/unclebob/mutate4go),
with the user-facing contract cross-checked against
[unclebob/clj-mutate](https://github.com/unclebob/clj-mutate). Where Python forces a
divergence (coverage acquisition, the manifest hash) it is marked `[PY]` and
justified in [`docs/spec.md`](docs/spec.md).

## Install

```bash
uvx mutate4py        # run without installing
uv tool install mutate4py
```

## Usage

```bash
mutate4py path/to/file.py --test-command "pytest" --lcov lcov.info
```

Generate `lcov.info` with [coverage.py](https://coverage.readthedocs.io/):

```bash
pytest --cov --cov-branch --cov-report=lcov:lcov.info
```

See `mutate4py --help` and the [spec](docs/spec.md) for the full flag set.

## How it differs from mutate4go (`[PY]`)

- **`--max-workers` uses clone-per-worker, not tree-copy+`cwd`** — mutate4go's
  tree-copy model is unsound under Python editable installs (`pip install -e .`), so
  each worker gets its own `uv`-provisioned venv instead.
- **Coverage is acquired explicitly** — `--lcov` / `--cov-cmd` / `--reuse-coverage`
  (Python has no universal `-coverprofile` equivalent).
- **Manifest hash is structural** (`ast.dump()`), so reformatting and comment edits
  don't trigger a re-test, but any behavior-affecting edit does.
- **Operators are localized** to Python: adds `and`/`or`, `True`/`False`, and the
  identity/membership negation flips `is`/`is not` and `in`/`not in`.

## Develop

Python ≥ 3.10, stdlib `ast` (zero runtime deps), packaged with `hatchling`.

```bash
uv sync
uv run mutate4py --help
uv run pytest
```
