sqlalchemy / alembic

A database migrations tool for SQLAlchemy.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

autogenerate: alembic keeps creating tables that return False on `include_name`

puilp0502 opened this issue · comments

Describe the bug

alembic revision --autogenerate always creates create_table op regardless of the table's existence, if the include_name function returns False for that table.

Expected behavior

alembic revision --autogenerate should not generate create_table op for tables which return False on include_name

To Reproduce

Please try to provide a Minimal, Complete, and Verifiable example, with the migration script and/or the SQLAlchemy tables or models involved.
See also Reporting Bugs on the website.

The code for reproduction is available here.

The repo has the following setup:

  • Basic postgresql container via docker-compose.yml
  • Alembic configuration, with custom include_name function
  • Sample model definition

The model.py contains two models, namely Unmanaged and User.
We tell alembic not to track Unmanged table via include_name here.

However, when we run alembic revision --autogenerate to generate the migrations, it creates a create_table op for unmanaged table:

...
def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('app_user',
    sa.Column('username', sa.String(length=32), nullable=False),
    sa.Column('password', sa.String(length=512), nullable=False),
    sa.PrimaryKeyConstraint('username')
    )
    op.create_table('unmanaged',
    sa.Column('key', sa.String(length=64), nullable=False),
    sa.Column('value', sa.String(length=1024), nullable=False),
    sa.PrimaryKeyConstraint('key')
    )
    # ### end Alembic commands ###
...

Additionally, if we re-run alembic revision --autogenerate (after applying migrations via alembic upgrade head), it tries to re-create the unmanaged table:

...
def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('unmanaged',
    sa.Column('key', sa.String(length=64), nullable=False),
    sa.Column('value', sa.String(length=1024), nullable=False),
    sa.PrimaryKeyConstraint('key')
    )
    # ### end Alembic commands ###
...

Versions

  • OS: macOS 14.2.1
  • Python: Python 3.10, Python 3.12
  • Alembic: alembic 1.13.1
  • SQLAlchemy: 2.0.23
  • Database: PostgreSQL 15.4 (Debian 15.4-2.pgdg120+1)
  • DBAPI: psycopg2 2.9.9

Additional context
I believe the root cause is that autogen_context.run_name_filters is not called for tables present in the AutogenContext object here, even though we're filtering the table list retrieved via inspector, thus leaving unmanaged tables in a perpetual no-yet-created status.

If my diagnosis is correct, then the fix also seems trivial. I can provide a PR if you want.

Have a nice day!

the include_name hook only applies to reflected tables, not model metadata tables.

to omit model tables from autogenerate the best approach is to use a separate MetaData collection for "unmanaged" tables. Otherwise the include_object hook applies to model and reflected objects equally.