=================
Command Line Tool
=================
Advanced Alchemy provides a command-line interface (CLI) for common database operations and project management tasks.
Installation
------------
The CLI is installed with Advanced Alchemy with the extra ``cli``:
.. tab-set::
.. tab-item:: pip
:sync: key1
.. code-block:: bash
:caption: Using pip
python3 -m pip install advanced-alchemy[cli]
.. tab-item:: uv
.. code-block:: bash
:caption: Using `UV `_
uv add advanced-alchemy[cli]
.. tab-item:: pipx
:sync: key2
.. code-block:: bash
:caption: Using `pipx `_
pipx install advanced-alchemy[cli]
.. tab-item:: pdm
.. code-block:: bash
:caption: Using `PDM `_
pdm add advanced-alchemy[cli]
.. tab-item:: Poetry
.. code-block:: bash
:caption: Using `Poetry `_
poetry add advanced-alchemy[cli]
Basic Usage
-----------
The CLI can be invoked using the ``alchemy`` command:
.. code-block:: bash
alchemy --help
Global Options
--------------
The following options are available for all commands:
.. list-table:: Global options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``--config`` TEXT
- **Required**. Dotted path to SQLAlchemy config(s), it's an instance of ``SQLAlchemyConfig`` (sync or async). Example: ``--config path.to.alchemy-config.config``
* - ``--bind-key`` TEXT
- Optional. Specify which SQLAlchemy config to use
* - ``--no-prompt``
- Optional. Skip confirmation prompts
* - ``--verbose``
- Optional. Enable verbose output
Config
------
Here is an example of what **config** looks like.
If the file is named ``alchemy-config.py``, you would need to use it like this ``--config path.to.alchemy-config.config``
.. code-block:: python
:caption: alchemy-config.py
from sqlalchemy import create_engine
from advanced_alchemy.config import SQLAlchemyConfig
# Create a test config using SQLite
config = SQLAlchemyConfig(
connection_url="sqlite:///test.db"
)
Available Commands
------------------
Migration Commands
~~~~~~~~~~~~~~~~~~
These commands manage database migrations and revisions.
show-current-revision
^^^^^^^^^^^^^^^^^^^^^
Show the current revision of the database:
.. code-block:: bash
alchemy show-current-revision --config path.to.alchemy-config.config
.. list-table:: Options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``--verbose``
- Display detailed revision information
downgrade
^^^^^^^^^
Downgrade database to a specific revision:
.. code-block:: bash
alchemy downgrade --config path.to.alchemy-config.config [REVISION]
.. list-table:: Options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``--sql``
- Generate SQL output for offline migrations
* - ``--tag`` TEXT
- Arbitrary tag for custom env.py scripts
* - ``REVISION``
- Target revision (default: "-1")
upgrade
^^^^^^^
Upgrade database to a specific revision:
.. code-block:: bash
alchemy upgrade --config path.to.alchemy-config.config [REVISION]
.. list-table:: Options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``--sql``
- Generate SQL output for offline migrations
* - ``--tag`` TEXT
- Arbitrary tag for custom env.py scripts
* - ``REVISION``
- Target revision (default: "head")
stamp
^^^^^
Stamp the revision table with a specific revision without running migrations:
.. code-block:: bash
alchemy stamp --config path.to.alchemy-config.config REVISION
.. list-table:: Options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``--sql``
- Generate SQL output for offline migrations
* - ``--tag`` TEXT
- Arbitrary tag for custom env.py scripts
* - ``--purge``
- Delete all entries in version table before stamping
* - ``REVISION``
- Target revision to stamp (required)
**Use cases:**
- Initialize version table for existing database
- Mark migrations as applied without running them
- Reset migration history (with ``--purge``)
- Generate SQL for manual database stamping (with ``--sql``)
init
^^^^
Initialize migrations for the project:
.. code-block:: bash
alchemy init --config path.to.alchemy-config.config [DIRECTORY]
.. list-table:: Options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``--multidb``
- Support multiple databases
* - ``--package``
- Create __init__.py for created folder (default: True)
* - ``DIRECTORY``
- Directory for migration files (optional)
make-migrations
^^^^^^^^^^^^^^^
Create a new migration revision:
.. code-block:: bash
alchemy make-migrations --config path.to.alchemy-config.config
.. list-table:: Options
:header-rows: 1
:widths: 30 70
* - Option
- Explanation
* - ``-m``, ``--message`` TEXT
- Revision message
* - ``--autogenerate``/ ``--no-autogenerate``
- Automatically detect changes (default: True)
* - ``--sql``
- Export to .sql instead of writing to database
* - ``--head`` TEXT
- Base revision for new revision (default: "head")
* - ``--splice``
- Allow non-head revision as the "head"
* - ``--branch-label`` TEXT
- Branch label for new revision
* - ``--version-path`` TEXT
- Specific path for version file
* - ``--rev-id`` TEXT
- Specific revision ID
Inspection Commands
~~~~~~~~~~~~~~~~~~~
These commands inspect migration history and database state.
check
^^^^^
Check if the database is up to date with the current migration revision:
.. code-block:: bash
alchemy check --config path.to.alchemy-config.config
Returns exit code 0 if database is current, non-zero otherwise.
**Use cases:**
- CI/CD validation before deployment
- Pre-deployment smoke tests
- Health checks
heads
^^^^^
Show current available heads in the migration script directory:
.. code-block:: bash
alchemy heads --config path.to.alchemy-config.config
.. list-table:: Options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``--verbose``
- Display detailed head information
* - ``--resolve-dependencies``
- Resolve dependencies between heads
**Use cases:**
- Detect multiple heads (branch conflicts)
- Verify migration graph state
- Branch development coordination
history
^^^^^^^
List migration changesets in chronological order:
.. code-block:: bash
alchemy history --config path.to.alchemy-config.config
.. list-table:: Options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``--verbose``
- Display detailed revision information
* - ``--rev-range`` TEXT
- Revision range to display (e.g., 'base:head', 'abc:def')
* - ``--indicate-current``
- Indicate the current revision in output
**Use cases:**
- Audit migration history
- Generate migration documentation
- Review changes between revisions
show
^^^^
Show details of a specific revision:
.. code-block:: bash
alchemy show --config path.to.alchemy-config.config REVISION
**Examples:**
.. code-block:: bash
# Show head revision
alchemy show head --config path.to.alchemy-config.config
# Show specific revision
alchemy show abc123def --config path.to.alchemy-config.config
# Show base revision
alchemy show base --config path.to.alchemy-config.config
branches
^^^^^^^^
Show current branch points in the migration history:
.. code-block:: bash
alchemy branches --config path.to.alchemy-config.config
.. list-table:: Options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``--verbose``
- Display detailed branch information
**Use cases:**
- Identify branch points in migration graph
- Multi-team development coordination
- Branch-based development workflows
Branch Management Commands
~~~~~~~~~~~~~~~~~~~~~~~~~~
These commands manage branched migration workflows.
merge
^^^^^
Merge two revisions together, creating a new migration file:
.. code-block:: bash
alchemy merge --config path.to.alchemy-config.config REVISIONS
.. list-table:: Options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``-m``, ``--message`` TEXT
- Merge message
* - ``--branch-label`` TEXT
- Branch label for merge revision
* - ``--rev-id`` TEXT
- Specify custom revision ID
* - ``REVISIONS``
- Revisions to merge (e.g., 'abc123+def456' or 'heads')
**Examples:**
.. code-block:: bash
# Merge all heads
alchemy merge heads -m "merge feature branches" --config path.to.alchemy-config.config
# Merge specific revisions
alchemy merge abc123+def456 -m "merge database changes" --config path.to.alchemy-config.config
**Use cases:**
- Resolve multiple heads (branch conflicts)
- Consolidate parallel development branches
- Team coordination for database changes
Utility Commands
~~~~~~~~~~~~~~~~
These commands provide additional migration utilities.
edit
^^^^
Edit a revision file using the system editor (set via ``$EDITOR`` environment variable):
.. code-block:: bash
alchemy edit --config path.to.alchemy-config.config REVISION
**Examples:**
.. code-block:: bash
# Edit latest revision
alchemy edit head --config path.to.alchemy-config.config
# Edit specific revision
alchemy edit abc123def --config path.to.alchemy-config.config
ensure-version
^^^^^^^^^^^^^^
Create the Alembic version table if it doesn't exist:
.. code-block:: bash
alchemy ensure-version --config path.to.alchemy-config.config
.. list-table:: Options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``--sql``
- Generate SQL output instead of executing
**Use cases:**
- Database initialization workflows
- Manual database setup
- Generate SQL for DBA review (with ``--sql``)
list-templates
^^^^^^^^^^^^^^
List available Alembic migration templates:
.. code-block:: bash
alchemy list-templates --config path.to.alchemy-config.config
**Use cases:**
- Discover available templates for ``init`` command
- Template selection for new projects
Database Commands
~~~~~~~~~~~~~~~~~
These commands manage database tables and data.
drop-all
^^^^^^^^
Drop all tables from the database:
.. code-block:: bash
alchemy drop-all --config path.to.alchemy-config.config
.. warning::
This command is destructive and will delete all data. Use with caution.
dump-data
^^^^^^^^^
Dump specified tables from the database to JSON files:
.. code-block:: bash
alchemy dump-data --config path.to.alchemy-config.config --table TABLE_NAME
.. list-table:: Options
:header-rows: 1
:widths: 20 80
* - Option
- Explanation
* - ``--table`` TEXT
- Name of table to dump (use '*' for all tables)
* - ``--dir`` PATH
- Directory to save JSON files (default: ./fixtures)
Extending the CLI
-----------------
If you're using Click in your project, you can extend Advanced Alchemy's CLI with your own commands. The CLI provides two main functions for integration:
- ``get_alchemy_group()``: Get the base CLI group
- ``add_migration_commands()``: Add migration-related commands to a group
Basic Extension
~~~~~~~~~~~~~~~
Here's how to extend the CLI with your own commands:
.. code-block:: python
from advanced_alchemy.cli import get_alchemy_group, add_migration_commands
import click
# Get the base group
alchemy_group = get_alchemy_group()
# Add your custom commands
@alchemy_group.command(name="my-command")
@click.option("--my-option", help="Custom option")
def my_command(my_option):
"""My custom command."""
click.echo(f"Running my command with option: {my_option}")
# Add migration commands to your group
add_migration_commands(alchemy_group)
Custom Group Integration
~~~~~~~~~~~~~~~~~~~~~~~~
You can also integrate Advanced Alchemy's commands into your existing Click group:
.. code-block:: python
import click
from advanced_alchemy.cli import add_migration_commands
@click.group()
def cli():
"""My application CLI."""
pass
# Add migration commands to your CLI group
add_migration_commands(cli)
@cli.command()
def my_command():
"""Custom command in your CLI."""
pass
if __name__ == "__main__":
cli()
Typer integration
-----------------
You can integrate Advanced Alchemy's CLI commands into your existing ``Typer`` application. Here's how:
.. code-block:: python
:caption: cli.py
import typer
from advanced_alchemy.cli import get_alchemy_group, add_migration_commands
app = typer.Typer()
@app.command()
def hello(name: str) -> None:
"""Says hello to the world."""
typer.echo(f"Hello {name}")
@app.callback()
def callback():
"""
Typer app, including Click subapp
"""
pass
def create_cli() -> typer.Typer:
"""Create the CLI application with both Typer and Click commands."""
# Get the Click group from advanced_alchemy
alchemy_group = get_alchemy_group()
# Convert our Typer app to a Click command object
typer_click_object = typer.main.get_command(app)
# Add all migration commands from the alchemy group to our CLI
typer_click_object.add_command(add_migration_commands(alchemy_group))
return typer_click_object
if __name__ == "__main__":
cli = create_cli()
cli()
After setting up the integration, you can use both your ``Typer`` commands and Advanced Alchemy commands:
.. code-block:: bash
# Use your Typer commands
python cli.py hello Cody
# Use Advanced Alchemy commands
python cli.py alchemy upgrade --config path.to.config
python cli.py alchemy make-migrations --config path.to.config