Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed #23341 -- Better stacktrace error for makemigrations #3100

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions django/db/migrations/graph.py
Expand Up @@ -35,11 +35,11 @@ def __init__(self):
def add_node(self, node, implementation):
self.nodes[node] = implementation

def add_dependency(self, child, parent):
def add_dependency(self, migration, child, parent):
if child not in self.nodes:
raise KeyError("Dependency references nonexistent child node %r" % (child,))
raise KeyError("Migration %s dependencies references nonexistent child node %r" % (migration, child))
if parent not in self.nodes:
raise KeyError("Dependency references nonexistent parent node %r" % (parent,))
raise KeyError("Migration %s dependencies references nonexistent parent node %r" % (migration, parent))
self.dependencies.setdefault(child, set()).add(parent)
self.dependents.setdefault(parent, set()).add(child)

Expand Down
6 changes: 3 additions & 3 deletions django/db/migrations/loader.py
Expand Up @@ -230,19 +230,19 @@ def build_graph(self):
if parent[0] != key[0] or parent[1] == '__first__':
# Ignore __first__ references to the same app (#22325)
continue
self.graph.add_dependency(key, parent)
self.graph.add_dependency(migration, key, parent)
for key, migration in normal.items():
for parent in migration.dependencies:
if parent[0] == key[0]:
# Internal dependencies already added.
continue
parent = self.check_key(parent, key[0])
if parent is not None:
self.graph.add_dependency(key, parent)
self.graph.add_dependency(migration, key, parent)
for child in migration.run_before:
child = self.check_key(child, key[0])
if child is not None:
self.graph.add_dependency(child, key)
self.graph.add_dependency(migration, child, key)

def detect_conflicts(self):
"""
Expand Down
4 changes: 2 additions & 2 deletions tests/migrations/test_autodetector.py
Expand Up @@ -156,8 +156,8 @@ def test_arrange_for_graph(self):
graph.add_node(("testapp", "0001_initial"), None)
graph.add_node(("testapp", "0002_foobar"), None)
graph.add_node(("otherapp", "0001_initial"), None)
graph.add_dependency(("testapp", "0002_foobar"), ("testapp", "0001_initial"))
graph.add_dependency(("testapp", "0002_foobar"), ("otherapp", "0001_initial"))
graph.add_dependency("testapp.0002_foobar", ("testapp", "0002_foobar"), ("testapp", "0001_initial"))
graph.add_dependency("testapp.0002_foobar", ("testapp", "0002_foobar"), ("otherapp", "0001_initial"))
# Use project state to make a new migration change set
before = self.make_project_state([])
after = self.make_project_state([self.author_empty, self.other_pony, self.other_stable])
Expand Down
63 changes: 44 additions & 19 deletions tests/migrations/test_graph.py
Expand Up @@ -23,11 +23,11 @@ def test_simple_graph(self):
graph.add_node(("app_a", "0004"), None)
graph.add_node(("app_b", "0001"), None)
graph.add_node(("app_b", "0002"), None)
graph.add_dependency(("app_a", "0004"), ("app_a", "0003"))
graph.add_dependency(("app_a", "0003"), ("app_a", "0002"))
graph.add_dependency(("app_a", "0002"), ("app_a", "0001"))
graph.add_dependency(("app_a", "0003"), ("app_b", "0002"))
graph.add_dependency(("app_b", "0002"), ("app_b", "0001"))
graph.add_dependency("app_a.0004", ("app_a", "0004"), ("app_a", "0003"))
graph.add_dependency("app_a.0003", ("app_a", "0003"), ("app_a", "0002"))
graph.add_dependency("app_a.0002", ("app_a", "0002"), ("app_a", "0001"))
graph.add_dependency("app_a.0003", ("app_a", "0003"), ("app_b", "0002"))
graph.add_dependency("app_b.0002", ("app_b", "0002"), ("app_b", "0001"))
# Test root migration case
self.assertEqual(
graph.forwards_plan(("app_a", "0001")),
Expand Down Expand Up @@ -78,15 +78,15 @@ def test_complex_graph(self):
graph.add_node(("app_b", "0002"), None)
graph.add_node(("app_c", "0001"), None)
graph.add_node(("app_c", "0002"), None)
graph.add_dependency(("app_a", "0004"), ("app_a", "0003"))
graph.add_dependency(("app_a", "0003"), ("app_a", "0002"))
graph.add_dependency(("app_a", "0002"), ("app_a", "0001"))
graph.add_dependency(("app_a", "0003"), ("app_b", "0002"))
graph.add_dependency(("app_b", "0002"), ("app_b", "0001"))
graph.add_dependency(("app_a", "0004"), ("app_c", "0002"))
graph.add_dependency(("app_c", "0002"), ("app_c", "0001"))
graph.add_dependency(("app_c", "0001"), ("app_b", "0001"))
graph.add_dependency(("app_c", "0002"), ("app_a", "0002"))
graph.add_dependency("app_a.0004", ("app_a", "0004"), ("app_a", "0003"))
graph.add_dependency("app_a.0003", ("app_a", "0003"), ("app_a", "0002"))
graph.add_dependency("app_a.0002", ("app_a", "0002"), ("app_a", "0001"))
graph.add_dependency("app_a.0003", ("app_a", "0003"), ("app_b", "0002"))
graph.add_dependency("app_b.0002", ("app_b", "0002"), ("app_b", "0001"))
graph.add_dependency("app_a.0004", ("app_a", "0004"), ("app_c", "0002"))
graph.add_dependency("app_c.0002", ("app_c", "0002"), ("app_c", "0001"))
graph.add_dependency("app_c.0001", ("app_c", "0001"), ("app_b", "0001"))
graph.add_dependency("app_c.0002", ("app_c", "0002"), ("app_a", "0002"))
# Test branch C only
self.assertEqual(
graph.forwards_plan(("app_c", "0002")),
Expand Down Expand Up @@ -123,11 +123,11 @@ def test_circular_graph(self):
graph.add_node(("app_a", "0003"), None)
graph.add_node(("app_b", "0001"), None)
graph.add_node(("app_b", "0002"), None)
graph.add_dependency(("app_a", "0003"), ("app_a", "0002"))
graph.add_dependency(("app_a", "0002"), ("app_a", "0001"))
graph.add_dependency(("app_a", "0001"), ("app_b", "0002"))
graph.add_dependency(("app_b", "0002"), ("app_b", "0001"))
graph.add_dependency(("app_b", "0001"), ("app_a", "0003"))
graph.add_dependency("app_a.0003", ("app_a", "0003"), ("app_a", "0002"))
graph.add_dependency("app_a.0002", ("app_a", "0002"), ("app_a", "0001"))
graph.add_dependency("app_a.0001", ("app_a", "0001"), ("app_b", "0002"))
graph.add_dependency("app_b.0002", ("app_b", "0002"), ("app_b", "0001"))
graph.add_dependency("app_b.0001", ("app_b", "0001"), ("app_a", "0003"))
# Test whole graph
self.assertRaises(
CircularDependencyError,
Expand All @@ -146,3 +146,28 @@ def test_plan_invalid_node(self):

with self.assertRaisesMessage(ValueError, message):
graph.backwards_plan(("app_b", "0001"))

def test_missing_parent_nodes(self):
"""
Tests for missing parent nodes.
"""
# Build graph
graph = MigrationGraph()
graph.add_node(("app_a", "0001"), None)
graph.add_node(("app_a", "0002"), None)
graph.add_node(("app_a", "0003"), None)
graph.add_node(("app_b", "0001"), None)
graph.add_dependency("app_a.0003", ("app_a", "0003"), ("app_a", "0002"))
graph.add_dependency("app_a.0002", ("app_a", "0002"), ("app_a", "0001"))
with self.assertRaisesMessage(KeyError, "Migration app_a.0001 dependencies references nonexistent parent node ('app_b', '0002')"):
graph.add_dependency("app_a.0001", ("app_a", "0001"), ("app_b", "0002"))

def test_missing_child_nodes(self):
"""
Tests for missing child nodes.
"""
# Build graph
graph = MigrationGraph()
graph.add_node(("app_a", "0001"), None)
with self.assertRaisesMessage(KeyError, "Migration app_a.0002 dependencies references nonexistent child node ('app_a', '0002')"):
graph.add_dependency("app_a.0002", ("app_a", "0002"), ("app_a", "0001"))