from sqlalchemy import text
from sqlalchemy import types as sqltypes
from sqlalchemy.sql import expression
+from sqlalchemy.sql.elements import conv
from sqlalchemy.sql.schema import ForeignKeyConstraint
from sqlalchemy.sql.schema import Index
from sqlalchemy.sql.schema import UniqueConstraint
(inspector),
# fmt: on
)
- inspector.reflect_table(t, include_columns=None)
+ _InspectorConv(inspector).reflect_table(t, include_columns=None)
if autogen_context.run_object_filters(t, tname, "table", True, None):
modify_table_ops = ops.ModifyTableOps(tname, [], schema=s)
_compat_autogen_column_reflect(inspector),
# fmt: on
)
- inspector.reflect_table(t, include_columns=None)
+ _InspectorConv(inspector).reflect_table(t, include_columns=None)
+
conn_column_info[(s, tname)] = t
for s, tname in sorted(existing_tables, key=lambda x: (x[0] or "", x[1])):
_C = TypeVar("_C", bound=Union[UniqueConstraint, ForeignKeyConstraint, Index])
+class _InspectorConv:
+ __slots__ = ("inspector",)
+
+ def __init__(self, inspector):
+ self.inspector = inspector
+
+ def _apply_reflectinfo_conv(self, consts):
+ if not consts:
+ return consts
+ for const in consts:
+ if const["name"] is not None and not isinstance(
+ const["name"], conv
+ ):
+ const["name"] = conv(const["name"])
+ return consts
+
+ def _apply_constraint_conv(self, consts):
+ if not consts:
+ return consts
+ for const in consts:
+ if const.name is not None and not isinstance(const.name, conv):
+ const.name = conv(const.name)
+ return consts
+
+ def get_indexes(self, *args, **kw):
+ return self._apply_reflectinfo_conv(
+ self.inspector.get_indexes(*args, **kw)
+ )
+
+ def get_unique_constraints(self, *args, **kw):
+ return self._apply_reflectinfo_conv(
+ self.inspector.get_unique_constraints(*args, **kw)
+ )
+
+ def get_foreign_keys(self, *args, **kw):
+ return self._apply_reflectinfo_conv(
+ self.inspector.get_foreign_keys(*args, **kw)
+ )
+
+ def reflect_table(self, table, *, include_columns):
+ self.inspector.reflect_table(table, include_columns=include_columns)
+
+ # I had a cool version of this using _ReflectInfo, however that doesn't
+ # work in 1.4 and it's not public API in 2.x. Then this is just a two
+ # liner. So there's no competition...
+ self._apply_constraint_conv(table.constraints)
+ self._apply_constraint_conv(table.indexes)
+
+
@comparators.dispatch_for("table")
def _compare_indexes_and_uniques(
autogen_context: AutogenContext,
if conn_table is not None:
# 1b. ... and from connection, if the table exists
try:
- conn_uniques = inspector.get_unique_constraints( # type:ignore[assignment] # noqa
+ conn_uniques = _InspectorConv(inspector).get_unique_constraints(
tname, schema=schema
)
+
supports_unique_constraints = True
except NotImplementedError:
pass
if uq.get("duplicates_index"):
unique_constraints_duplicate_unique_indexes = True
try:
- conn_indexes = inspector.get_indexes( # type:ignore[assignment]
+ conn_indexes = _InspectorConv(inspector).get_indexes(
tname, schema=schema
)
except NotImplementedError:
conn_fks_list = [
fk
- for fk in inspector.get_foreign_keys(tname, schema=schema)
+ for fk in _InspectorConv(inspector).get_foreign_keys(
+ tname, schema=schema
+ )
if autogen_context.run_name_filters(
fk["name"],
"foreign_key_constraint",
]
conn_fks = {
- _make_foreign_key(const, conn_table) # type: ignore[arg-type]
- for const in conn_fks_list
+ _make_foreign_key(const, conn_table) for const in conn_fks_list
}
impl = autogen_context.migration_context.impl
from alembic.testing.suite._autogen_fixtures import _default_include_object
from alembic.testing.suite._autogen_fixtures import AutogenTest
from alembic.testing.suite._autogen_fixtures import ModelOne
+from alembic.testing.suite._autogen_fixtures import NamingConvModel
class AutogenerateDiffTest(ModelOne, AutogenTest, TestBase):
sa.PrimaryKeyConstraint('id')
)
op.drop_table('extra')
- op.add_column('address', sa.Column('street', sa.String(length=50), \
-nullable=True))
+ op.add_column('address', sa.Column('street', sa.String(length=50), nullable=True))
op.create_unique_constraint('uq_email', 'address', ['email_address'])
op.add_column('order', sa.Column('user_id', sa.Integer(), nullable=True))
op.alter_column('order', 'amount',
existing_type=sa.TEXT(),
server_default='x',
existing_nullable=True)
- op.drop_index('pw_idx', table_name='user')
+ op.drop_index(op.f('pw_idx'), table_name='user')
op.drop_column('user', 'pw')
- # ### end Alembic commands ###""",
+ # ### end Alembic commands ###""", # noqa: E501,
)
eq_(
template_args["downgrades"],
"""# ### commands auto generated by Alembic - please adjust! ###
- op.add_column('user', sa.Column('pw', sa.VARCHAR(length=50), \
-nullable=True))
- op.create_index('pw_idx', 'user', ['pw'], unique=False)
+ op.add_column('user', sa.Column('pw', sa.VARCHAR(length=50), nullable=True))
+ op.create_index(op.f('pw_idx'), 'user', ['pw'], unique=False)
op.alter_column('user', 'a1',
existing_type=sa.TEXT(),
server_default=None,
sa.ForeignKeyConstraint(['uid'], ['user.id'], )
)
op.drop_table('item')
- # ### end Alembic commands ###""",
+ # ### end Alembic commands ###""", # noqa: E501
)
def test_render_diffs_batch(self):
existing_type=sa.TEXT(),
server_default='x',
existing_nullable=True)
- batch_op.drop_index('pw_idx')
+ batch_op.drop_index(batch_op.f('pw_idx'))
batch_op.drop_column('pw')
# ### end Alembic commands ###""", # noqa,
"""# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('user', schema=None) as batch_op:
batch_op.add_column(sa.Column('pw', sa.VARCHAR(length=50), nullable=True))
- batch_op.create_index('pw_idx', ['pw'], unique=False)
+ batch_op.create_index(batch_op.f('pw_idx'), ['pw'], unique=False)
batch_op.alter_column('a1',
existing_type=sa.TEXT(),
server_default=None,
eq_(
template_args["upgrades"],
- """# ### commands auto generated by Alembic - please adjust! ###
+ f"""# ### commands auto generated by Alembic - please adjust! ###
op.create_table('item',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('description', sa.String(length=100), nullable=True),
sa.Column('order_id', sa.Integer(), nullable=True),
sa.CheckConstraint('len(description) > 5'),
- sa.ForeignKeyConstraint(['order_id'], ['%(schema)s.order.order_id'], ),
+ sa.ForeignKeyConstraint(['order_id'], ['test_schema.order.order_id'], ),
sa.PrimaryKeyConstraint('id'),
- schema='%(schema)s'
+ schema='{self.schema}'
)
- op.drop_table('extra', schema='%(schema)s')
- op.add_column('address', sa.Column('street', sa.String(length=50), \
-nullable=True), schema='%(schema)s')
- op.create_unique_constraint('uq_email', 'address', ['email_address'], \
-schema='test_schema')
- op.add_column('order', sa.Column('user_id', sa.Integer(), nullable=True), \
-schema='%(schema)s')
+ op.drop_table('extra', schema='{self.schema}')
+ op.add_column('address', sa.Column('street', sa.String(length=50), nullable=True), schema='{self.schema}')
+ op.create_unique_constraint('uq_email', 'address', ['email_address'], schema='{self.schema}')
+ op.add_column('order', sa.Column('user_id', sa.Integer(), nullable=True), schema='{self.schema}')
op.alter_column('order', 'amount',
existing_type=sa.NUMERIC(precision=8, scale=2),
type_=sa.Numeric(precision=10, scale=2),
nullable=True,
existing_server_default=sa.text('0'),
- schema='%(schema)s')
- op.create_foreign_key(None, 'order', 'user', ['user_id'], ['id'], \
-source_schema='%(schema)s', referent_schema='%(schema)s')
+ schema='{self.schema}')
+ op.create_foreign_key(None, 'order', 'user', ['user_id'], ['id'], source_schema='{self.schema}', referent_schema='{self.schema}')
op.alter_column('user', 'name',
existing_type=sa.VARCHAR(length=50),
nullable=False,
- schema='%(schema)s')
+ schema='{self.schema}')
op.alter_column('user', 'a1',
existing_type=sa.TEXT(),
server_default='x',
existing_nullable=True,
- schema='%(schema)s')
- op.drop_index('pw_idx', table_name='user', schema='test_schema')
- op.drop_column('user', 'pw', schema='%(schema)s')
- # ### end Alembic commands ###"""
- % {"schema": self.schema},
+ schema='{self.schema}')
+ op.drop_index(op.f('pw_idx'), table_name='user', schema='{self.schema}')
+ op.drop_column('user', 'pw', schema='{self.schema}')
+ # ### end Alembic commands ###""", # noqa: E501
)
eq_(
template_args["downgrades"],
- """# ### commands auto generated by Alembic - please adjust! ###
- op.add_column('user', sa.Column('pw', sa.VARCHAR(length=50), \
-autoincrement=False, nullable=True), schema='%(schema)s')
- op.create_index('pw_idx', 'user', ['pw'], unique=False, schema='%(schema)s')
+ f"""# ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('user', sa.Column('pw', sa.VARCHAR(length=50), autoincrement=False, nullable=True), schema='{self.schema}')
+ op.create_index(op.f('pw_idx'), 'user', ['pw'], unique=False, schema='{self.schema}')
op.alter_column('user', 'a1',
existing_type=sa.TEXT(),
server_default=None,
existing_nullable=True,
- schema='%(schema)s')
+ schema='{self.schema}')
op.alter_column('user', 'name',
existing_type=sa.VARCHAR(length=50),
nullable=True,
- schema='%(schema)s')
- op.drop_constraint(None, 'order', schema='%(schema)s', type_='foreignkey')
+ schema='{self.schema}')
+ op.drop_constraint(None, 'order', schema='{self.schema}', type_='foreignkey')
op.alter_column('order', 'amount',
existing_type=sa.Numeric(precision=10, scale=2),
type_=sa.NUMERIC(precision=8, scale=2),
nullable=False,
existing_server_default=sa.text('0'),
- schema='%(schema)s')
- op.drop_column('order', 'user_id', schema='%(schema)s')
- op.drop_constraint('uq_email', 'address', schema='test_schema', type_='unique')
- op.drop_column('address', 'street', schema='%(schema)s')
+ schema='{self.schema}')
+ op.drop_column('order', 'user_id', schema='{self.schema}')
+ op.drop_constraint('uq_email', 'address', schema='{self.schema}', type_='unique')
+ op.drop_column('address', 'street', schema='{self.schema}')
op.create_table('extra',
sa.Column('x', sa.CHAR(length=1), autoincrement=False, nullable=True),
sa.Column('uid', sa.INTEGER(), autoincrement=False, nullable=True),
- sa.ForeignKeyConstraint(['uid'], ['%(schema)s.user.id'], \
-name='extra_uid_fkey'),
- schema='%(schema)s'
+ sa.ForeignKeyConstraint(['uid'], ['test_schema.user.id'], name=op.f('extra_uid_fkey')),
+ schema='{self.schema}'
+ )
+ op.drop_table('item', schema='{self.schema}')
+ # ### end Alembic commands ###""", # noqa
+ )
+
+
+class AutogenerateNamingConvTest(NamingConvModel, AutogenTest, TestBase):
+ __only_on__ = "sqlite"
+
+ def _lines_equal(self, a, b):
+ # compare that a and b have all the same codelines, with the order
+ # not mattering (we are looking just for the right op.f() calls)
+ eq_(set(a.split("\n")), set(b.split("\n")))
+
+ def test_render_diffs_naming_conv(self):
+ template_args = {}
+ autogenerate._render_migration_diffs(self.context, template_args)
+ self._lines_equal(
+ template_args["upgrades"],
+ """# ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('x6',
+ sa.Column('q', sa.Integer(), nullable=False),
+ sa.Column('p', sa.Integer(), nullable=True),
+ sa.Column('r', sa.Integer(), nullable=True),
+ sa.Column('s', sa.Integer(), nullable=True),
+ sa.CheckConstraint('s < 20', name=op.f('userdef_x6_check_s')),
+ sa.CheckConstraint('s > 5', name=op.f('ck_x6_token_x6check1')),
+ sa.ForeignKeyConstraint(['p'], ['x4.q'], name=op.f('fk_x6_p_x4')),
+ sa.PrimaryKeyConstraint('q', name=op.f('pk_x6')),
+ sa.UniqueConstraint('r', name=op.f('uq_x6_token_x6r'))
+ )
+ op.drop_table('unnamed_sqlite')
+ op.drop_table('x5')
+ op.drop_index(op.f('db_x1_index_q'), table_name='x1')
+ op.create_index(op.f('ix_x1_q'), 'x1', ['q'], unique=False)
+ op.drop_constraint(op.f('db_x3_unique_q'), 'x3', type_='unique')
+ op.create_unique_constraint(op.f('uq_x3_token_x3r'), 'x3', ['r'])
+ op.create_unique_constraint(op.f('userdef_x3_unique_s'), 'x3', ['s'])
+ op.create_index('userdef_x4_idx_q', 'x4', ['q'], unique=False)
+ # ### end Alembic commands ###""", # noqa: E501
+ )
+
+ self._lines_equal(
+ template_args["downgrades"],
+ """# ### commands auto generated by Alembic - please adjust! ###
+ op.drop_index('userdef_x4_idx_q', table_name='x4')
+ op.drop_constraint(op.f('userdef_x3_unique_s'), 'x3', type_='unique')
+ op.drop_constraint(op.f('uq_x3_token_x3r'), 'x3', type_='unique')
+ op.create_unique_constraint(op.f('db_x3_unique_q'), 'x3', ['q'])
+ op.drop_index(op.f('ix_x1_q'), table_name='x1')
+ op.create_index(op.f('db_x1_index_q'), 'x1', ['q'], unique=False)
+ op.create_table('x5',
+ sa.Column('q', sa.INTEGER(), nullable=False),
+ sa.Column('p', sa.INTEGER(), nullable=True),
+ sa.Column('r', sa.INTEGER(), nullable=True),
+ sa.Column('s', sa.INTEGER(), nullable=True),
+ sa.CheckConstraint('s > 5', name=op.f('db_x5_check_s')),
+ sa.ForeignKeyConstraint(['p'], ['x4.q'], name=op.f('db_x5_foreign_q')),
+ sa.PrimaryKeyConstraint('q', name=op.f('db_x5_primary_q')),
+ sa.UniqueConstraint('r', name=op.f('db_x5_unique_r'))
+ )
+ op.create_table('unnamed_sqlite',
+ sa.Column('q', sa.INTEGER(), nullable=False),
+ sa.Column('r', sa.INTEGER(), nullable=True),
+ sa.PrimaryKeyConstraint('q'),
+ sa.UniqueConstraint('r')
+ )
+ op.drop_table('x6')
+ # ### end Alembic commands ###""", # noqa: E501
+ )
+
+
+class AutogenerateNamingConvWBatchTest(NamingConvModel, AutogenTest, TestBase):
+ __only_on__ = "sqlite"
+ configure_opts = {
+ "conv_all_constraint_names": True,
+ "render_as_batch": True,
+ }
+
+ def _lines_equal(self, a, b):
+ # compare that a and b have all the same codelines, with the order
+ # not mattering (we are looking just for the right op.f() calls)
+ eq_(set(a.split("\n")), set(b.split("\n")))
+
+ def test_render_diffs_naming_conv(self):
+ template_args = {}
+ autogenerate._render_migration_diffs(self.context, template_args)
+ self._lines_equal(
+ template_args["upgrades"],
+ """# ### commands auto generated by Alembic - please adjust! ###
+ op.create_table('x6',
+ sa.Column('q', sa.Integer(), nullable=False),
+ sa.Column('p', sa.Integer(), nullable=True),
+ sa.Column('r', sa.Integer(), nullable=True),
+ sa.Column('s', sa.Integer(), nullable=True),
+ sa.CheckConstraint('s < 20', name=op.f('userdef_x6_check_s')),
+ sa.CheckConstraint('s > 5', name=op.f('ck_x6_token_x6check1')),
+ sa.ForeignKeyConstraint(['p'], ['x4.q'], name=op.f('fk_x6_p_x4')),
+ sa.PrimaryKeyConstraint('q', name=op.f('pk_x6')),
+ sa.UniqueConstraint('r', name=op.f('uq_x6_token_x6r'))
+ )
+ op.drop_table('x5')
+ op.drop_table('unnamed_sqlite')
+ with op.batch_alter_table('x1', schema=None) as batch_op:
+ batch_op.drop_index(batch_op.f('db_x1_index_q'))
+ batch_op.create_index(batch_op.f('ix_x1_q'), ['q'], unique=False)
+
+ with op.batch_alter_table('x3', schema=None) as batch_op:
+ batch_op.drop_constraint(batch_op.f('db_x3_unique_q'), type_='unique')
+ batch_op.create_unique_constraint(batch_op.f('uq_x3_token_x3r'), ['r'])
+ batch_op.create_unique_constraint(batch_op.f('userdef_x3_unique_s'), ['s'])
+
+ with op.batch_alter_table('x4', schema=None) as batch_op:
+ batch_op.create_index('userdef_x4_idx_q', ['q'], unique=False)
+
+ # ### end Alembic commands ###""", # noqa: E501
+ )
+
+ self._lines_equal(
+ template_args["downgrades"],
+ """# ### commands auto generated by Alembic - please adjust! ###
+ with op.batch_alter_table('x4', schema=None) as batch_op:
+ batch_op.drop_index('userdef_x4_idx_q')
+
+ with op.batch_alter_table('x3', schema=None) as batch_op:
+ batch_op.drop_constraint(batch_op.f('userdef_x3_unique_s'), type_='unique')
+ batch_op.drop_constraint(batch_op.f('uq_x3_token_x3r'), type_='unique')
+ batch_op.create_unique_constraint(batch_op.f('db_x3_unique_q'), ['q'])
+
+ with op.batch_alter_table('x1', schema=None) as batch_op:
+ batch_op.drop_index(batch_op.f('ix_x1_q'))
+ batch_op.create_index(batch_op.f('db_x1_index_q'), ['q'], unique=False)
+
+ op.create_table('unnamed_sqlite',
+ sa.Column('q', sa.INTEGER(), nullable=False),
+ sa.Column('r', sa.INTEGER(), nullable=True),
+ sa.PrimaryKeyConstraint('q'),
+ sa.UniqueConstraint('r')
+ )
+ op.create_table('x5',
+ sa.Column('q', sa.INTEGER(), nullable=False),
+ sa.Column('p', sa.INTEGER(), nullable=True),
+ sa.Column('r', sa.INTEGER(), nullable=True),
+ sa.Column('s', sa.INTEGER(), nullable=True),
+ sa.CheckConstraint('s > 5', name=op.f('db_x5_check_s')),
+ sa.ForeignKeyConstraint(['p'], ['x4.q'], name=op.f('db_x5_foreign_q')),
+ sa.PrimaryKeyConstraint('q', name=op.f('db_x5_primary_q')),
+ sa.UniqueConstraint('r', name=op.f('db_x5_unique_r'))
)
- op.drop_table('item', schema='%(schema)s')
- # ### end Alembic commands ###""" # noqa
- % {"schema": self.schema},
+ op.drop_table('x6')
+ # ### end Alembic commands ###""", # noqa: E501
)