Metadata-Version: 2.4
Name: larzmigrate
Version: 0.1.0
Summary: Schema migrations for SQL (any DB-API) and larzdb: ordered up/down, rollback, checksum drift detection. Pure Python, zero dependencies.
Author: larz-scripter
License: MIT
Project-URL: Homepage, https://github.com/larz-scripter/larzmigrate
Project-URL: Repository, https://github.com/larz-scripter/larzmigrate
Project-URL: Documentation, https://github.com/larz-scripter/larzmigrate#readme
Project-URL: Issues, https://github.com/larz-scripter/larzmigrate/issues
Keywords: migrations,schema-migration,database,sql,sqlite,rollback,versioning,alembic-alternative,zero-dependency,pure-python
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
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 :: Database
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# larzmigrate

**Schema migrations for SQL *and* larzdb. Pure Python, zero dependencies.**

Evolve a schema safely: write ordered migrations with an `up` and an optional
`down`, and larzmigrate applies the pending ones in order, records what it did,
and can roll back — against **any DB-API connection** (sqlite3, psycopg2, …) *or*
a larzdb database.

```python
import sqlite3
from larzmigrate import Migrator, SQLBackend

m = Migrator(SQLBackend(sqlite3.connect("app.db")))

m.add_sql("001_users",
          up="CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)",
          down="DROP TABLE users")

@m.migration("002_seed")
def seed(conn):
    conn.execute("INSERT INTO users (name) VALUES ('admin')")

m.migrate()        # apply everything pending, in order (idempotent)
m.rollback()       # undo the most recent migration
m.status()         # [("001_users", "applied"), ("002_seed", "applied")]
```

## What makes it different

- **Storage-agnostic.** The same migrator drives a **SQL** database (via any
  DB-API connection) or a **[larzdb](https://github.com/larz-scripter/larzdb)** /
  key-value store — pick the backend, write your migrations once.
- **Detects edited migrations.** Every migration is **checksummed**. If one that's
  already applied gets changed, `migrate()` errors (checksum drift) instead of
  silently diverging from what actually ran — the bug that bites teams.
- **Real rollback.** `down` migrations run in reverse; `rollback(steps=N)` undoes
  the last N.
- **Idempotent.** Re-running only applies what's pending; safe to run on every
  deploy.
- **Zero dependencies.** No Alembic, no ORM.

## Install

```bash
pip install larzmigrate
```

## Backends

```python
from larzmigrate import Migrator, SQLBackend, KVBackend, DictStore

# SQL: any DB-API connection (sqlite3, psycopg2, MySQLdb, ...)
Migrator(SQLBackend(connection))

# larzdb or any get/put store
Migrator(KVBackend(larzdb_database))
Migrator(KVBackend(DictStore()))     # in-memory
```

Function migrations receive the backend's **context** — the DB connection (SQL)
or the store (KV) — so they can do whatever that backend allows.

## Commands

```python
m.migrate()                  # apply all pending
m.migrate(target="003_x")    # apply up to (and including) an id
m.rollback()                 # undo the most recent
m.rollback(steps=3)          # undo the last 3
m.status()                   # [(id, "applied"|"pending"), ...]
m.pending(); m.applied()
```

## Tests

```bash
python -m unittest discover -s tests -v   # 13 tests incl. real sqlite3 + drift
```

## The Larz stack

Pure-Python, zero-dependency building blocks: **[larz](https://github.com/larz-scripter/larz)** · **[larzchain](https://github.com/larz-scripter/larzchain)** · **[larzmoney](https://github.com/larz-scripter/larzmoney)** · **[larzcrypt](https://github.com/larz-scripter/larzcrypt)** · **[larzdb](https://github.com/larz-scripter/larzdb)** · **[larzagent](https://github.com/larz-scripter/larzagent)** · **[larzchart](https://github.com/larz-scripter/larzchart)** · **[larzmark](https://github.com/larz-scripter/larzmark)** · **[larztask](https://github.com/larz-scripter/larztask)** · **[larzvault](https://github.com/larz-scripter/larzvault)** · **[larzvm](https://github.com/larz-scripter/larzvm)** · **[larzcache](https://github.com/larz-scripter/larzcache)** · **[larzvalidate](https://github.com/larz-scripter/larzvalidate)** · **[larzid](https://github.com/larz-scripter/larzid)** · **[larzrpc](https://github.com/larz-scripter/larzrpc)** · **[larzstate](https://github.com/larz-scripter/larzstate)** · **[larzhttp](https://github.com/larz-scripter/larzhttp)** · **[larzconf](https://github.com/larz-scripter/larzconf)** · **[larzcron](https://github.com/larz-scripter/larzcron)** · **[larzlimit](https://github.com/larz-scripter/larzlimit)** · **[larzlog](https://github.com/larz-scripter/larzlog)** · **[larzcli](https://github.com/larz-scripter/larzcli)** · **[larzretry](https://github.com/larz-scripter/larzretry)** · **[larztime](https://github.com/larz-scripter/larztime)** · **[larzpdf](https://github.com/larz-scripter/larzpdf)** · **[larzpack](https://github.com/larz-scripter/larzpack)** · **[larztemplate](https://github.com/larz-scripter/larztemplate)** · **[larzcolor](https://github.com/larz-scripter/larzcolor)** · **[larztable](https://github.com/larz-scripter/larztable)** · **[larzjson](https://github.com/larz-scripter/larzjson)** · **[larzbus](https://github.com/larz-scripter/larzbus)** · **larzmigrate**

## License

MIT © larz-scripter
