active_revisions = set(
self._get_ancestor_nodes(heads, include_dependencies=True)
)
+
# Emit revisions to drop in reverse topological sorted order.
downgrade_revisions.intersection_update(active_revisions)
active_revisions.difference(self._get_ancestor_nodes(roots))
)
- if not downgrade_revisions:
+ if (
+ target_revision is not None
+ and not downgrade_revisions
+ and target_revision not in heads
+ ):
# Empty intersection: target revs are not present.
+
raise RangeNotAncestorError("Nothing to drop", upper)
return downgrade_revisions, heads
--- /dev/null
+.. change::
+ :tags: bug, versioning, regression
+ :tickets: 838
+
+ Fixed regression in new revisioning traversal where "alembic downgrade
+ base" would fail if the database itself were clean and unversioned;
+ additionally repairs the case where downgrade would fail if attempting
+ to downgrade to the current head that is already present.
def teardown_class(cls):
clear_staging_env()
+ def test_downgrade_base_no_version(self):
+ self._assert_downgrade("base", [], [], set())
+
+ def test_downgrade_to_existing(self):
+ self._assert_downgrade(
+ self.a.revision, [self.a.revision], [], {self.a.revision}
+ )
+
def test_upgrade_path(self):
self._assert_upgrade(
self.e.revision,