Metadata-Version: 2.4
Name: live-alembic
Version: 0.3.3
Summary: A live migration system for Alembic.
Author-email: Olof Tjerngren <olof@tjerngren.net>
License-Expression: LGPL-3.0-or-later
Project-URL: Repository, https://gitlab.com/Resample2545/live-alembic
Project-URL: Issues, https://gitlab.com/Resample2545/live-alembic/-/issues
Keywords: alembic,sqlalchemy,migrations,database,schema,ddl
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Database
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: alembic>=1.7.7
Requires-Dist: sqlalchemy>=2.0.31
Requires-Dist: click>=8.0.3
Requires-Dist: jinja2>=3.1.6
Provides-Extra: postgresql
Requires-Dist: psycopg2-binary>=2.9; extra == "postgresql"
Provides-Extra: mysql
Requires-Dist: PyMySQL>=1.1; extra == "mysql"
Provides-Extra: mariadb
Requires-Dist: PyMySQL>=1.1; extra == "mariadb"
Provides-Extra: cockroachdb
Requires-Dist: sqlalchemy-cockroachdb; extra == "cockroachdb"
Requires-Dist: psycopg2-binary>=2.9; extra == "cockroachdb"
Provides-Extra: mssql
Requires-Dist: pymssql; extra == "mssql"
Dynamic: license-file

# Live Alembic

Apply database migrations without migration files. Live Alembic uses Alembic's
autogeneration to diff your SQLAlchemy models against the live database and
applies DDL directly — no `versions/` directory, no commit-to-run cycle.

## Install

```bash
pip install live-alembic
```

## Quickstart

**1. Create `migrate_env.py`** in your project root:

```python
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base

# SQLite
db_url = "sqlite:///myapp.db"

# PostgreSQL
# db_url = "postgresql+psycopg2://user:password@localhost/mydb"

# MySQL / MariaDB
# db_url = "mysql+pymysql://user:password@localhost/mydb"

Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    id    = Column(Integer, primary_key=True)
    name  = Column(String(100))
    email = Column(String(255))

target_metadata = Base.metadata

# Optional: List of tables to ignore (e.g. tables managed by other applications)
# ignore_tables = ["some_external_table"]
```

**2. Check for pending changes:**

```bash
livealembic check
```

Exits `0` if the schema is in sync, `1` if changes are pending.

**3. Apply changes:**

```bash
livealembic migrate
```

## CLI Reference

```
livealembic check   [--file PATH] [--format text|json] [--verbose]
livealembic migrate [--file PATH] [--format text|json] [--verbose]
livealembic --version
```

| Command   | Description                        | Exit code          |
|-----------|------------------------------------|--------------------|
| `check`   | Show pending changes, do not apply | 1 if changes exist |
| `migrate` | Apply pending changes              | 1 on error         |

| Option          | Default          | Description                             |
|-----------------|------------------|-----------------------------------------|
| `--file PATH`   | `migrate_env.py` | Path to your configuration module       |
| `--format json` | `text`           | Machine-readable JSON output            |
| `--verbose`     | off              | Include raw operation details in output |

### Example output

```
  Create table "orders"
  Add column 'phone' (VARCHAR(20)) to table 'users'
  Drop column 'legacy_id' from table 'users'
  Alter column 'status' on 'orders' to type INTEGER
```

### CI / CD usage

```bash
# Fail the pipeline if the schema has drifted
livealembic check --file config/migrate_env.py

# Apply during deployment
livealembic migrate --file config/migrate_env.py
```

## Package Entry Points

Other libraries can automatically include SQLAlchemy models into the application's migration metadata by registering an entry point under the `live_alembic.models` group. Live Alembic dynamically loads all registered entry points under this group and merges their tables into the application's `target_metadata`.

The entry point can point to:
* A SQLAlchemy `MetaData` instance.
* A SQLAlchemy Declarative Base (or registry) subclass with a `metadata` attribute.
* A SQLAlchemy `Table` object.
* A module—in which case Live Alembic will inspect its attributes to discover any `MetaData`, Declarative Base, or `Table` instances.

Example registration in a library's `pyproject.toml`:

```toml
[project.entry-points."live_alembic.models"]
my_library_models = "my_library.models:metadata"
```

## Hooks

Define `before_migrate` and/or `after_migrate` in `migrate_env.py` to run data
migrations in the same transaction as the schema change:

```python
from live_alembic import Changes
from sqlalchemy import text

def before_migrate(changes: Changes, connection):
    if changes.added_column("users", "full_name"):
        connection.execute(
            text("UPDATE users SET full_name = first_name || ' ' || last_name")
        )

def after_migrate(changes: Changes, connection):
    if changes.dropped_column("users", "legacy_token"):
        connection.execute(text("DELETE FROM audit_log WHERE action = 'token_refresh'"))
```

Both hooks receive a `Changes` helper and the active connection.  If a hook
raises, the transaction is rolled back (schema + data).

See [documentation/usage/usage.org](documentation/usage/usage.org) for the full
hooks API, database-specific notes, and programmatic API docs.

## Testing

Complete development tests require `docker compose` for database integration.

### Local Tests

Run the standard test suite against SQLite (no Docker required):

```bash
make test
```

### Database Integration Tests

Start database services and run tests against a specific backend:

```bash
make test-postgresql
make test-mysql
```

Or run against all supported databases sequentially:

```bash
make test-all
```

### Test Matrix (Tox)

Run the full matrix of supported Python versions and databases:

```bash
make tox
```

### Coverage

Generate a coverage report for the SQLite tests:

```bash
make coverage
```
