]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Ensure "alembic current" won't unnecessarily mutate the database
authorNikolay Edigaryev <edigaryev@gmail.com>
Fri, 15 May 2020 21:18:47 +0000 (17:18 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 15 May 2020 21:25:31 +0000 (17:25 -0400)
The ``alembic current`` command no longer creates an ``alembic_version``
table in the database if one does not exist already, returning no version
as the current version. This allows checking for migrations in parallel
without introducing race conditions.  Pull request courtesy Nikolay
Edigaryev.

Fixes: #694
Closes: #695
Pull-request: https://github.com/sqlalchemy/alembic/pull/695
Pull-request-sha: fd3e3b8faf7a41dd4c35daca6c7d224e983ab496

Change-Id: I500ab9ec1fe74b5e20e6aecfe598bce7e9cdef96

alembic/command.py
alembic/operations/base.py
alembic/runtime/migration.py
docs/build/unreleased/694.rst [new file with mode: 0644]
tests/test_command.py

index 7d19e3c6b61a8366026e95694dc24f27efd7b71b..c925b18bcd4ae00f926b1cb524e6bcdbc1fbcfc8 100644 (file)
@@ -511,7 +511,9 @@ def current(config, verbose=False, head_only=False):
 
         return []
 
-    with EnvironmentContext(config, script, fn=display_version):
+    with EnvironmentContext(
+        config, script, fn=display_version, dont_mutate=True
+    ):
         script.run_env()
 
 
index 30bd87fe7c22bbab20114748c712da8c3e866237..86b50ca56dc0654424bb4b38358f059a24e3ca90 100644 (file)
@@ -127,7 +127,6 @@ class Operations(util.ModuleClsProxy):
                     "args": args,
                     "apply_kw": apply_kw,
                     "doc": fn.__doc__,
-                    "meth": fn.__name__,
                 }
             )
             globals_ = {"op_cls": op_cls}
index 48408a4fb0854cdd8a48c950af971f047b44f137..5c8590d6c4fd895014241295f61288ab6fbe7507 100644 (file)
@@ -497,7 +497,9 @@ class MigrationContext(object):
         else:
             heads = self.get_current_heads()
 
-            if not self.as_sql and not heads:
+            dont_mutate = self.opts.get("dont_mutate", False)
+
+            if not self.as_sql and not heads and not dont_mutate:
                 self._ensure_version_table()
 
         head_maintainer = HeadMaintainer(self, heads)
diff --git a/docs/build/unreleased/694.rst b/docs/build/unreleased/694.rst
new file mode 100644 (file)
index 0000000..0d62b28
--- /dev/null
@@ -0,0 +1,10 @@
+.. change::
+    :tags: bug, commands
+    :tickets: 694
+
+    The ``alembic current`` command no longer creates an ``alembic_version``
+    table in the database if one does not exist already, returning no version
+    as the current version. This allows checking for migrations in parallel
+    without introducing race conditions.  Pull request courtesy Nikolay
+    Edigaryev.
+
index 4102f29fe399cb955cc9204141410828c847246a..a616e9cc189f84ac7d984b91063b4d4c86c7e79c 100644 (file)
@@ -17,6 +17,7 @@ from alembic.script import ScriptDirectory
 from alembic.testing import assert_raises
 from alembic.testing import assert_raises_message
 from alembic.testing import eq_
+from alembic.testing import is_false
 from alembic.testing import is_true
 from alembic.testing import mock
 from alembic.testing.env import _get_staging_directory
@@ -33,6 +34,7 @@ from alembic.testing.fixtures import capture_context_buffer
 from alembic.testing.fixtures import capture_engine_context_buffer
 from alembic.testing.fixtures import TestBase
 from alembic.util import compat
+from alembic.util.sqla_compat import _connectable_has_table
 
 
 class _BufMixin(object):
@@ -201,6 +203,7 @@ finally:
 class CurrentTest(_BufMixin, TestBase):
     @classmethod
     def setup_class(cls):
+        cls.bind = _sqlite_file_db()
         cls.env = env = staging_env()
         cls.cfg = _sqlite_testing_config()
         cls.a1 = env.generate_revision("a1", "a1")
@@ -232,6 +235,12 @@ class CurrentTest(_BufMixin, TestBase):
 
         eq_(lines, set(revs))
 
+    def test_doesnt_create_alembic_version(self):
+        command.current(self.cfg)
+        engine = self.bind
+        with engine.connect() as conn:
+            is_false(_connectable_has_table(conn, "alembic_version", None))
+
     def test_no_current(self):
         command.stamp(self.cfg, ())
         with self._assert_lines([]):