Metadata-Version: 2.4
Name: django-baseshift-brancher
Version: 1.3.2
Summary: Run Django and pytest against a Baseshift clone of an already-migrated PostgreSQL database.
Author: Baseshift
License-Expression: LicenseRef-Proprietary
Project-URL: Homepage, https://baseshift.io
Keywords: django,pytest,postgresql,baseshift
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Django
Classifier: Framework :: Django :: 3.2
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: Framework :: Pytest
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Django>=3.2
Provides-Extra: pytest
Requires-Dist: pytest>=6.2; extra == "pytest"
Requires-Dist: pytest-django>=4.5; extra == "pytest"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-django>=4.5; extra == "dev"
Requires-Dist: psycopg[binary]>=3.1; extra == "dev"
Dynamic: license-file

# django-baseshift-brancher

**Run your Django test suite against an already-migrated PostgreSQL clone, so tests don't need to run `CREATE DATABASE` or migrations on every run.**

On a large Django project, a lot of test time goes to building the test database and replaying every migration. `django-baseshift-brancher` skips both steps. It uses [brancher by Baseshift](https://baseshift.com/brancher) to create one ready-to-use PostgreSQL clone per test worker, already migrated to the schema of your current git checkout. Then it points pytest or Django's test runner at those clones.

- Works with **pytest / pytest-django** (`pytest -n N`) and **Django's `manage.py test`** (`--parallel N`)
- **No changes to `settings.py`**
- Migrated snapshots are **cached per migration commit** and shared across branches

---

## Requirements

| Requirement | Version |
|---|---|
| Python | 3.8 – 3.13 |
| Django | 3.2, 4.2, 5.0 – 6.0 |
| Database | PostgreSQL |
| brancher by Baseshift | The `baseshift` binary must be on your `PATH` ([install brancher](https://baseshift.com/brancher)) |
| Git | Your project must be a git repository |

---

## Install

```bash
pip install django-baseshift-brancher

# If pytest-django isn't installed yet:
pip install "django-baseshift-brancher[pytest]"
```

---

## Quick start

Run these from your Django project root (the directory that contains `manage.py`).

### 1. Create the clones

```bash
export DJANGO_SETTINGS_MODULE=yourproject.settings
unset BASESHIFT_BRANCHES_FILE DATABASE_URL PGHOST PGPORT

django-baseshift-brancher clone --count 4
```

`--count` is the number of databases to create. You need **one per test worker**.

The command writes the clone details to `.brancher/clones.json`, prints them as JSON, and prints the `export` line you need next (on stderr).

### 2. Run the tests

**pytest**

```bash
export BASESHIFT_BRANCHES_FILE="$PWD/.brancher/clones.json"
pytest -n 4
```

**Django test runner**

```bash
export BASESHIFT_BRANCHES_FILE="$PWD/.brancher/clones.json"
python manage.py test --testrunner django_baseshift_brancher.DiscoverRunner --parallel 4
```

### 3. Clean up

```bash
baseshift stop --all
```

---

## How it works

### Snapshots follow your migration history

`clone` reads your git history. **Every commit that changes migration files gets its own migrated snapshot.**

- **Adding migration files** builds on the previous snapshot. Branches that split off from the same migration commit share it.
- **Changing or deleting existing migration files** starts over from an empty snapshot, because the new schema can't be built on top of the old one.
- **Rebasing** creates new commits, so the rebased checkout gets a new snapshot on top of its new parent. Branches that split off before the rebase keep their own chain.

Snapshots don't have names and you never manage them yourself. Parent snapshots are picked automatically.

### Test workers map to clones

| Runner | Worker ID | Clone used |
|---|---|---|
| pytest-xdist | `gw0`, `gw1`, … (0-based) | `gw0` → 1st clone |
| Django `--parallel` | `"1"`, `"2"`, … (1-based) | `"1"` → 1st clone |

`pytest -n 4` and `--parallel 4` each need `--count 4` (or more).

### What happens to your `DATABASES` setting

- `USER` and `PASSWORD` are **kept** as you configured them.
- `HOST`, `PORT` and `NAME` are **replaced** with the clone's values.
- Test migrations are **turned off** (the clone is already migrated).

### pytest plugin

The plugin loads automatically. It assigns each worker to a clone and forces `--reuse-db` and `--no-migrations`. **Don't pass `--create-db`.**

---

## Configuration

| Environment variable | Required | Purpose |
|---|---|---|
| `DJANGO_SETTINGS_MODULE` | Yes | Your Django settings module |
| `BASESHIFT_BRANCHES_FILE` | Yes, when running tests | Absolute path to `.brancher/clones.json`. **Tests only read the clones from this variable.** A `clones.json` in the current directory is not picked up automatically. |
| `BASESHIFT_INIT_SQL` | No | SQL that runs on each new snapshot **before** `migrate`. Use it for anything your migrations assume already exists, such as extensions. |

Example:

```bash
export BASESHIFT_INIT_SQL="CREATE EXTENSION IF NOT EXISTS pg_trgm"
```

**Other setup commands:** once the clones are running, run any extra project setup yourself against their connection strings (for example, a management command like `ensure_celery_broker_schema`).

---

## Troubleshooting

| Symptom | Likely cause | Fix |
|---|---|---|
| Tests connect to your normal dev/CI database | `BASESHIFT_BRANCHES_FILE` isn't set in the shell running the tests | `export BASESHIFT_BRANCHES_FILE="$PWD/.brancher/clones.json"` |
| Some workers fail or no clone is found for them | Fewer clones than workers | Re-run `clone` with `--count` ≥ `-n` / `--parallel` |
| Tests try to create the database | `--create-db` was passed | Remove `--create-db` |
| A migration fails with a missing extension | The extension has to exist before migrations run | Set `BASESHIFT_INIT_SQL` and re-run `clone` |
| `baseshift: command not found` | brancher isn't installed | Install it from [baseshift.com/brancher](https://baseshift.com/brancher) |

---

## For AI coding agents

Use this exact sequence from the Django project root. Replace `N` with the number of parallel test workers.

```bash
export DJANGO_SETTINGS_MODULE=<project>.settings
unset BASESHIFT_BRANCHES_FILE DATABASE_URL PGHOST PGPORT
django-baseshift-brancher clone --count N
export BASESHIFT_BRANCHES_FILE="$PWD/.brancher/clones.json"
pytest -n N                     # or: python manage.py test --testrunner django_baseshift_brancher.DiscoverRunner --parallel N
baseshift stop --all
```

Rules:

- Don't edit `settings.py`.
- Don't pass `--create-db`.
- Re-run `clone` after checking out a commit with different migrations.
- `BASESHIFT_BRANCHES_FILE` must be exported in the **same shell** that runs the tests.
- Always run `baseshift stop --all` when you're done.

---

## About Baseshift

[Baseshift](https://baseshift.com) gives every developer, coding agent and pull request its own isolated, writable, masked clone of your real database, running in your cloud and ready in seconds. It supports PostgreSQL, MySQL, MongoDB and MariaDB. It also adds guardrails for database changes, such as schema change detection and query risk checks, so issues are caught before they reach production.

This package is the Django integration for [brancher by Baseshift](https://baseshift.com/brancher).

## License

Proprietary. See [baseshift.com](https://baseshift.com) for terms.
