From c8bac4b556cf4716dc9003e5da48060cb72ba7cb Mon Sep 17 00:00:00 2001 From: Markus Holtermann Date: Thu, 8 Jan 2015 18:00:04 +0100 Subject: [PATCH] Fixed #24098 -- Added no-op attributes to RunPython and RunSQL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks Loïc Bistuer and Tim Graham for the discussion and review. --- django/db/migrations/operations/special.py | 15 +++++++++----- docs/ref/migration-operations.txt | 16 +++++++++++++++ docs/releases/1.8.txt | 5 +++++ .../1_auto.py | 2 +- .../2_auto.py | 2 +- .../3_auto.py | 2 +- .../3_squashed_5.py | 2 +- .../4_auto.py | 2 +- .../5_auto.py | 2 +- .../6_auto.py | 2 +- .../7_auto.py | 2 +- .../app1/1_auto.py | 2 +- .../app1/2_auto.py | 2 +- .../app1/2_squashed_3.py | 2 +- .../app1/3_auto.py | 2 +- .../app1/4_auto.py | 2 +- .../app2/1_auto.py | 2 +- .../app2/1_squashed_2.py | 2 +- .../app2/2_auto.py | 2 +- .../1_auto.py | 2 +- .../2_auto.py | 2 +- .../3_squashed_5.py | 2 +- .../6_auto.py | 2 +- .../7_auto.py | 2 +- tests/migrations/test_operations.py | 20 +++++++++++++++++++ 25 files changed, 72 insertions(+), 26 deletions(-) diff --git a/django/db/migrations/operations/special.py b/django/db/migrations/operations/special.py index 96fd2cc63c..00caa08684 100644 --- a/django/db/migrations/operations/special.py +++ b/django/db/migrations/operations/special.py @@ -61,6 +61,7 @@ class RunSQL(Operation): Also accepts a list of operations that represent the state change effected by this SQL change, in case it's custom column/table creation/deletion. """ + noop = '' def __init__(self, sql, reverse_sql=None, state_operations=None): self.sql = sql @@ -100,9 +101,9 @@ class RunSQL(Operation): def describe(self): return "Raw SQL operation" - def _run_sql(self, schema_editor, sql): - if isinstance(sql, (list, tuple)): - for sql in sql: + def _run_sql(self, schema_editor, sqls): + if isinstance(sqls, (list, tuple)): + for sql in sqls: params = None if isinstance(sql, (list, tuple)): elements = len(sql) @@ -111,8 +112,8 @@ class RunSQL(Operation): else: raise ValueError("Expected a 2-tuple but got %d" % elements) schema_editor.execute(sql, params=params) - else: - statements = schema_editor.connection.ops.prepare_sql_script(sql) + elif sqls != RunSQL.noop: + statements = schema_editor.connection.ops.prepare_sql_script(sqls) for statement in statements: schema_editor.execute(statement, params=None) @@ -175,3 +176,7 @@ class RunPython(Operation): def describe(self): return "Raw Python operation" + + @staticmethod + def noop(apps, schema_editor): + return None diff --git a/docs/ref/migration-operations.txt b/docs/ref/migration-operations.txt index 46b87f44c4..dcac7f26a6 100644 --- a/docs/ref/migration-operations.txt +++ b/docs/ref/migration-operations.txt @@ -245,6 +245,14 @@ operation that adds that field and so will try to run it again). The ability to pass parameters to the ``sql`` and ``reverse_sql`` queries was added. +.. attribute:: RunSQL.noop + + .. versionadded:: 1.8 + + Pass the ``RunSQL.noop`` attribute to ``sql`` or ``reverse_sql`` when you + want the operation not to do anything in the given direction. This is + especially useful in making the operation reversible. + .. _sqlparse: https://pypi.python.org/pypi/sqlparse RunPython @@ -321,6 +329,14 @@ set ``atomic=False``. ``schema_editor.connection.alias``, where ``schema_editor`` is the second argument to your function). +.. staticmethod:: RunPython.noop + + .. versionadded:: 1.8 + + Pass the ``RunPython.noop`` method to ``code`` or ``reverse_code`` when + you want the operation not to do anything in the given direction. This is + especially useful in making the operation reversible. + SeparateDatabaseAndState ------------------------ diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt index 3a522ee741..427ec5d493 100644 --- a/docs/releases/1.8.txt +++ b/docs/releases/1.8.txt @@ -457,6 +457,11 @@ Migrations * A :ref:`generic mechanism to handle the deprecation of model fields ` was added. +* The :attr:`RunPython.noop ` + and :meth:`RunSQL.noop() ` class + attribute/method were added to ease in making ``RunPython`` and ``RunSQL`` + operations reversible. + Models ^^^^^^ diff --git a/tests/migrations/test_migrations_squashed_complex/1_auto.py b/tests/migrations/test_migrations_squashed_complex/1_auto.py index 25edcfa290..bf12688063 100644 --- a/tests/migrations/test_migrations_squashed_complex/1_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/1_auto.py @@ -7,5 +7,5 @@ from django.db import migrations class Migration(migrations.Migration): operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex/2_auto.py b/tests/migrations/test_migrations_squashed_complex/2_auto.py index 9107c35868..1d952ad0df 100644 --- a/tests/migrations/test_migrations_squashed_complex/2_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/2_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("migrations", "1_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex/3_auto.py b/tests/migrations/test_migrations_squashed_complex/3_auto.py index 98e679fc12..d780968115 100644 --- a/tests/migrations/test_migrations_squashed_complex/3_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/3_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("migrations", "2_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex/3_squashed_5.py b/tests/migrations/test_migrations_squashed_complex/3_squashed_5.py index ac1bcdee6d..f7dde03524 100644 --- a/tests/migrations/test_migrations_squashed_complex/3_squashed_5.py +++ b/tests/migrations/test_migrations_squashed_complex/3_squashed_5.py @@ -15,5 +15,5 @@ class Migration(migrations.Migration): dependencies = [("migrations", "2_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex/4_auto.py b/tests/migrations/test_migrations_squashed_complex/4_auto.py index 8fab746542..c39b16e454 100644 --- a/tests/migrations/test_migrations_squashed_complex/4_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/4_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("migrations", "3_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex/5_auto.py b/tests/migrations/test_migrations_squashed_complex/5_auto.py index 5dda63aae5..754fe2d253 100644 --- a/tests/migrations/test_migrations_squashed_complex/5_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/5_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("migrations", "4_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex/6_auto.py b/tests/migrations/test_migrations_squashed_complex/6_auto.py index 5ca558bc3b..65d829cd32 100644 --- a/tests/migrations/test_migrations_squashed_complex/6_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/6_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("migrations", "5_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex/7_auto.py b/tests/migrations/test_migrations_squashed_complex/7_auto.py index e9f5533364..f1b3cd3e49 100644 --- a/tests/migrations/test_migrations_squashed_complex/7_auto.py +++ b/tests/migrations/test_migrations_squashed_complex/7_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("migrations", "6_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/1_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/1_auto.py index 25edcfa290..bf12688063 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/1_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/1_auto.py @@ -7,5 +7,5 @@ from django.db import migrations class Migration(migrations.Migration): operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_auto.py index dcd67ca101..13a844275b 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("app1", "1_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_squashed_3.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_squashed_3.py index d74691fe44..521e70f5d2 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_squashed_3.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_squashed_3.py @@ -14,5 +14,5 @@ class Migration(migrations.Migration): dependencies = [("app1", "1_auto"), ("app2", "2_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/3_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/3_auto.py index f2b64db833..aa0e86e560 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/3_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/3_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("app1", "2_auto"), ("app2", "2_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/4_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/4_auto.py index fa36f18566..145e495a18 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/4_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/4_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("app1", "3_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_auto.py index dcd67ca101..13a844275b 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("app1", "1_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_squashed_2.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_squashed_2.py index fcd43bd0c6..6ef4dba71e 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_squashed_2.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_squashed_2.py @@ -14,5 +14,5 @@ class Migration(migrations.Migration): dependencies = [("app1", "1_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/2_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/2_auto.py index 9743fc92a2..35fc7b8c1c 100644 --- a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/2_auto.py +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/2_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("app2", "1_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_erroneous/1_auto.py b/tests/migrations/test_migrations_squashed_erroneous/1_auto.py index 25edcfa290..bf12688063 100644 --- a/tests/migrations/test_migrations_squashed_erroneous/1_auto.py +++ b/tests/migrations/test_migrations_squashed_erroneous/1_auto.py @@ -7,5 +7,5 @@ from django.db import migrations class Migration(migrations.Migration): operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_erroneous/2_auto.py b/tests/migrations/test_migrations_squashed_erroneous/2_auto.py index 9107c35868..1d952ad0df 100644 --- a/tests/migrations/test_migrations_squashed_erroneous/2_auto.py +++ b/tests/migrations/test_migrations_squashed_erroneous/2_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("migrations", "1_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_erroneous/3_squashed_5.py b/tests/migrations/test_migrations_squashed_erroneous/3_squashed_5.py index ac1bcdee6d..f7dde03524 100644 --- a/tests/migrations/test_migrations_squashed_erroneous/3_squashed_5.py +++ b/tests/migrations/test_migrations_squashed_erroneous/3_squashed_5.py @@ -15,5 +15,5 @@ class Migration(migrations.Migration): dependencies = [("migrations", "2_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_erroneous/6_auto.py b/tests/migrations/test_migrations_squashed_erroneous/6_auto.py index 5ca558bc3b..65d829cd32 100644 --- a/tests/migrations/test_migrations_squashed_erroneous/6_auto.py +++ b/tests/migrations/test_migrations_squashed_erroneous/6_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("migrations", "5_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_migrations_squashed_erroneous/7_auto.py b/tests/migrations/test_migrations_squashed_erroneous/7_auto.py index e9f5533364..f1b3cd3e49 100644 --- a/tests/migrations/test_migrations_squashed_erroneous/7_auto.py +++ b/tests/migrations/test_migrations_squashed_erroneous/7_auto.py @@ -9,5 +9,5 @@ class Migration(migrations.Migration): dependencies = [("migrations", "6_auto")] operations = [ - migrations.RunPython(lambda apps, schema_editor: None) + migrations.RunPython(migrations.RunPython.noop) ] diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py index 90ec456f84..f3e33b0f7e 100644 --- a/tests/migrations/test_operations.py +++ b/tests/migrations/test_operations.py @@ -1494,6 +1494,15 @@ class OperationTests(OperationTestBase): operation.database_backwards, "test_runsql", editor, new_state, project_state) + def test_run_sql_noop(self): + """ + #24098 - Tests no-op RunSQL operations. + """ + operation = migrations.RunSQL(migrations.RunSQL.noop, migrations.RunSQL.noop) + with connection.schema_editor() as editor: + operation.database_forwards("test_runsql", editor, None, None) + operation.database_backwards("test_runsql", editor, None, None) + def test_run_python(self): """ Tests the RunPython operation @@ -1620,6 +1629,17 @@ class OperationTests(OperationTestBase): self.assertEqual(definition[1], []) self.assertEqual(sorted(definition[2]), ["atomic", "code"]) + def test_run_python_noop(self): + """ + #24098 - Tests no-op RunPython operations. + """ + project_state = ProjectState() + new_state = project_state.clone() + operation = migrations.RunPython(migrations.RunPython.noop, migrations.RunPython.noop) + with connection.schema_editor() as editor: + operation.database_forwards("test_runpython", editor, project_state, new_state) + operation.database_backwards("test_runpython", editor, new_state, project_state) + @unittest.skipIf(sqlparse is None and connection.features.requires_sqlparse_for_splitting, "Missing sqlparse") def test_separate_database_and_state(self): """