summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2019-10-14 19:26:09 +0000
committerGerrit Code Review <gerrit@bbpush.zzzcomputing.com>2019-10-14 19:26:09 +0000
commit04f50747e66e6b545b7e515d2775298c290a4f58 (patch)
tree1d57618aa021bdffcad1ac92d1d64eeb9b6295c1
parentbad52b13b12b52b4eecca43866ab3a55da70a129 (diff)
parente90002d7fd325218c18f556daab94ab13b46877d (diff)
downloadalembic-04f50747e66e6b545b7e515d2775298c290a4f58.tar.gz
Merge "Accommodate for SQLAlchemy 1.4 deferral of index/unique names"
-rw-r--r--alembic/autogenerate/compare.py13
-rw-r--r--alembic/util/sqla_compat.py43
-rw-r--r--docs/build/unreleased/sqla14_4911.rst7
-rw-r--r--tests/test_autogen_indexes.py42
4 files changed, 92 insertions, 13 deletions
diff --git a/alembic/autogenerate/compare.py b/alembic/autogenerate/compare.py
index 49ceb21..cacedee 100644
--- a/alembic/autogenerate/compare.py
+++ b/alembic/autogenerate/compare.py
@@ -338,7 +338,9 @@ def _compare_columns(
class _constraint_sig(object):
def md_name_to_sql_name(self, context):
- return self.name
+ return sqla_compat._get_constraint_final_name(
+ self.const, context.dialect
+ )
def __eq__(self, other):
return self.const == other.const
@@ -529,7 +531,8 @@ def _compare_indexes_and_uniques(
metadata_names = dict(
(c.md_name_to_sql_name(autogen_context), c)
for c in metadata_unique_constraints.union(metadata_indexes)
- if c.name is not None
+ if isinstance(c, _ix_constraint_sig)
+ or sqla_compat._constraint_is_named(c.const, autogen_context.dialect)
)
conn_uniques_by_name = dict((c.name, c) for c in conn_unique_constraints)
@@ -556,7 +559,11 @@ def _compare_indexes_and_uniques(
)
metadata_indexes_by_sig = dict((ix.sig, ix) for ix in metadata_indexes)
unnamed_metadata_uniques = dict(
- (uq.sig, uq) for uq in metadata_unique_constraints if uq.name is None
+ (uq.sig, uq)
+ for uq in metadata_unique_constraints
+ if not sqla_compat._constraint_is_named(
+ uq.const, autogen_context.dialect
+ )
)
# assumptions:
diff --git a/alembic/util/sqla_compat.py b/alembic/util/sqla_compat.py
index 3733142..c3b10dc 100644
--- a/alembic/util/sqla_compat.py
+++ b/alembic/util/sqla_compat.py
@@ -183,15 +183,11 @@ def _column_kwargs(col):
def _get_index_final_name(dialect, idx):
- # trying to keep the truncation rules totally localized on the
- # SQLA side while also stepping around the quoting issue. Ideally
- # the _prepared_index_name() method on the SQLA side would have
- # a quoting option or the truncation routine would be broken out.
- #
- # test for SQLA quoted_name construct, introduced in
- # 0.9 or thereabouts.
- # this doesn't work in 0.8 and the "quote" option on Index doesn't
- # seem to work in 0.8 either.
+ if sqla_14:
+ return _get_constraint_final_name(idx, dialect)
+
+ # prior to SQLAlchemy 1.4, work around quoting logic to get at the
+ # final compiled name without quotes.
if hasattr(idx.name, "quote"):
# might be quoted_name, might be truncated_name, keep it the
# same
@@ -201,6 +197,35 @@ def _get_index_final_name(dialect, idx):
return dialect.ddl_compiler(dialect, None)._prepared_index_name(idx)
+def _get_constraint_final_name(constraint, dialect):
+ if sqla_14:
+ if constraint.name is None:
+ return None
+
+ # for SQLAlchemy 1.4 we would like to have the option to expand
+ # the use of "deferred" names for constraints as well as to have
+ # some flexibility with "None" name and similar; make use of new
+ # SQLAlchemy API to return what would be the final compiled form of
+ # the name for this dialect.
+ return dialect.identifier_preparer.format_constraint(
+ constraint, _alembic_quote=False
+ )
+ else:
+ return constraint.name
+
+
+def _constraint_is_named(constraint, dialect):
+ if sqla_14:
+ if constraint.name is None:
+ return False
+ name = dialect.identifier_preparer.format_constraint(
+ constraint, _alembic_quote=False
+ )
+ return name is not None
+ else:
+ return constraint.name is not None
+
+
def _dialect_supports_comments(dialect):
if sqla_120:
return dialect.supports_comments
diff --git a/docs/build/unreleased/sqla14_4911.rst b/docs/build/unreleased/sqla14_4911.rst
new file mode 100644
index 0000000..71463cb
--- /dev/null
+++ b/docs/build/unreleased/sqla14_4911.rst
@@ -0,0 +1,7 @@
+.. change::
+ :tags: change, compatibility
+
+ Some internal modifications have been made to how the names of indexes and
+ unique constraints work to make use of new functions added in SQLAlchemy
+ 1.4, so that SQLAlchemy has more flexibility over how naming conventions
+ may be applied to these objects.
diff --git a/tests/test_autogen_indexes.py b/tests/test_autogen_indexes.py
index c8eaffb..416444c 100644
--- a/tests/test_autogen_indexes.py
+++ b/tests/test_autogen_indexes.py
@@ -18,6 +18,7 @@ from alembic.testing import engines
from alembic.testing import eq_
from alembic.testing import TestBase
from alembic.testing.env import staging_env
+from alembic.util import sqla_compat
from ._autogen_fixtures import AutogenFixtureTest
py3k = sys.version_info >= (3,)
@@ -204,7 +205,12 @@ class AutogenerateUniqueIndexTest(AutogenFixtureTest, TestBase):
eq_(diffs[0][0], "add_table")
eq_(diffs[1][0], "add_index")
- eq_(diffs[1][1].name, "ix_extra_foo")
+ eq_(
+ sqla_compat._get_constraint_final_name(
+ diffs[1][1], config.db.dialect
+ ),
+ "ix_extra_foo",
+ )
eq_(diffs[2][0], "add_index")
eq_(diffs[2][1].name, "newtable_idx")
@@ -257,6 +263,40 @@ class AutogenerateUniqueIndexTest(AutogenFixtureTest, TestBase):
diffs = self._fixture(m1, m2)
eq_(diffs, [])
+ def test_nothing_changed_implicit_uq_w_naming_conv(self):
+ m1 = MetaData(
+ naming_convention={
+ "ix": "ix_%(column_0_label)s",
+ "uq": "uq_%(column_0_label)s",
+ }
+ )
+ m2 = MetaData(
+ naming_convention={
+ "ix": "ix_%(column_0_label)s",
+ "uq": "uq_%(column_0_label)s",
+ }
+ )
+
+ Table(
+ "nothing_changed",
+ m1,
+ Column("id1", Integer, primary_key=True),
+ Column("id2", Integer, primary_key=True),
+ Column("x", String(20), unique=True),
+ mysql_engine="InnoDB",
+ )
+
+ Table(
+ "nothing_changed",
+ m2,
+ Column("id1", Integer, primary_key=True),
+ Column("id2", Integer, primary_key=True),
+ Column("x", String(20), unique=True),
+ mysql_engine="InnoDB",
+ )
+ diffs = self._fixture(m1, m2)
+ eq_(diffs, [])
+
def test_nothing_changed_two(self):
m1 = MetaData()
m2 = MetaData()