]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
De-duplicate Revision.down_revision helpers.
authorSimon Bowly <simon.bowly@gmail.com>
Thu, 20 May 2021 21:46:04 +0000 (07:46 +1000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 21 May 2021 13:05:30 +0000 (09:05 -0400)
Fixes an issue when downgrading a revision where dependencies
are duplicated (e.g. by specifying the down_revision in depends_on).
This causes the down migrations to fail to remove the head, which is
caught by an assertion.

Added logic to de-duplicate the entries in _normalized_down_revisions
and _all_down_revisions without altering revision order.

This change revises the previous approach taken in
8d5a9a1b0d32fff5726010afffa48cc0fb738238 to address the problem
more generally outside of the topological algorithm.

Fixes: #843
Change-Id: I3517fb102b38c783c9a61bfb8dabc02c1fc89c4b

alembic/script/revision.py
tests/test_revision.py
tests/test_version_traversal.py

index f2055663bf0ecd8025d81497be9ed9df42721263..f2b4f7069ecc64fd1bcda6d403a87672fe0e76b8 100644 (file)
@@ -863,15 +863,10 @@ class RevisionMap(object):
 
                 candidate_rev = id_to_rev[candidate]
 
-                # immediate ancestor nodes, use a set to uniquify
-                _u = set()
                 heads_to_add = [
                     r
                     for r in candidate_rev._normalized_down_revisions
-                    if r in todo
-                    and r not in current_heads
-                    and r not in _u
-                    and (_u.add(r) or True)
+                    if r in todo and r not in current_heads
                 ]
 
                 if not heads_to_add:
@@ -1424,7 +1419,7 @@ class Revision(object):
 
     @property
     def _all_down_revisions(self):
-        return (
+        return util.dedupe_tuple(
             util.to_tuple(self.down_revision, default=())
             + self._resolved_dependencies
         )
@@ -1435,7 +1430,7 @@ class Revision(object):
         that are still dependencies of ancestors.
 
         """
-        return (
+        return util.dedupe_tuple(
             util.to_tuple(self.down_revision, default=())
             + self._normalized_resolved_dependencies
         )
index ef1202a08aef931866375c53e197c07dfea5da86..c2c1410fac6bb575f4c46789c91d1af73fdce9f1 100644 (file)
@@ -1575,7 +1575,7 @@ class NormalizedDownRevTest(DownIterateTest):
                 Revision("b2", "b1", dependencies="a3"),
                 Revision("b3", "b2"),
                 Revision("b4", "b3", dependencies="a3"),
-                Revision("b5", "b4"),
+                Revision("b5", "b4", dependencies="b4"),
             ]
         )
 
@@ -1587,6 +1587,11 @@ class NormalizedDownRevTest(DownIterateTest):
         # "a3" is not included because ancestor b2 is also dependent
         eq_(b4._normalized_down_revisions, ("b3",))
 
+    def test_dupe_dependency(self):
+        b5 = self.map.get_revision("b5")
+        eq_(b5._all_down_revisions, ("b4",))
+        eq_(b5._normalized_down_revisions, ("b4",))
+
     def test_branch_traversal(self):
         self._assert_iteration(
             "b4",
index d3709d2a9dec03b988e7f148356b35c98b38377e..e9399df66e3182973b0e646a247fc7d783967d88 100644 (file)
@@ -1147,6 +1147,14 @@ class DependsOnOwnDownrevTest(MigrationTest):
             set(["a2"]),
         )
 
+    def test_traverse_down(self):
+        self._assert_downgrade(
+            self.a1.revision,
+            self.a2.revision,
+            [self.down_(self.a2)],
+            set(["a1"]),
+        )
+
 
 class DependsOnBranchTestFour(MigrationTest):
     @classmethod