Fixed #30870 -- Fixed showing that RunPython operations are irreversible by migrate --plan.

Thanks Hasan Ramezani for the initial patch and Kyle Dickerson for the
report.
This commit is contained in:
Mariusz Felisiak 2019-10-14 09:37:45 +02:00
parent 05186c03a3
commit 06d34aab7c
4 changed files with 53 additions and 5 deletions

View File

@ -343,21 +343,21 @@ class Command(BaseCommand):
def describe_operation(operation, backwards): def describe_operation(operation, backwards):
"""Return a string that describes a migration operation for --plan.""" """Return a string that describes a migration operation for --plan."""
prefix = '' prefix = ''
is_error = False
if hasattr(operation, 'code'): if hasattr(operation, 'code'):
code = operation.reverse_code if backwards else operation.code code = operation.reverse_code if backwards else operation.code
action = code.__doc__ if code else '' action = (code.__doc__ or '') if code else None
elif hasattr(operation, 'sql'): elif hasattr(operation, 'sql'):
action = operation.reverse_sql if backwards else operation.sql action = operation.reverse_sql if backwards else operation.sql
else: else:
action = '' action = ''
if backwards: if backwards:
prefix = 'Undo ' prefix = 'Undo '
if action is None: if action is not None:
action = str(action).replace('\n', '')
elif backwards:
action = 'IRREVERSIBLE' action = 'IRREVERSIBLE'
is_error = True is_error = True
else:
action = str(action).replace('\n', '')
is_error = False
if action: if action:
action = ' -> ' + action action = ' -> ' + action
truncated = Truncator(action) truncated = Truncator(action)

View File

@ -13,3 +13,7 @@ Bugfixes
``has_keys``, or ``has_any_keys`` lookup on ``has_keys``, or ``has_any_keys`` lookup on
:class:`~django.contrib.postgres.fields.JSONField`, if the right or left hand :class:`~django.contrib.postgres.fields.JSONField`, if the right or left hand
side of an expression is a key transform (:ticket:`30826`). side of an expression is a key transform (:ticket:`30826`).
* Prevented :option:`migrate --plan` from showing that ``RunPython`` operations
are irreversible when ``reverse_code`` callables don't have docstrings or
when showing a forward migration plan (:ticket:`30870`).

View File

@ -371,6 +371,28 @@ class MigrateTests(MigrationTestBase):
' Raw SQL operation -> IRREVERSIBLE\n', ' Raw SQL operation -> IRREVERSIBLE\n',
out.getvalue() out.getvalue()
) )
out = io.StringIO()
call_command('migrate', 'migrations', '0005', plan=True, stdout=out, no_color=True)
# Operation is marked as irreversible only in the revert plan.
self.assertEqual(
'Planned operations:\n'
'migrations.0005_fifth\n'
' Raw Python operation\n'
' Raw Python operation\n'
' Raw Python operation -> Feed salamander.\n',
out.getvalue()
)
call_command('migrate', 'migrations', '0005', verbosity=0)
out = io.StringIO()
call_command('migrate', 'migrations', '0004', plan=True, stdout=out, no_color=True)
self.assertEqual(
'Planned operations:\n'
'migrations.0005_fifth\n'
' Raw Python operation -> IRREVERSIBLE\n'
' Raw Python operation -> IRREVERSIBLE\n'
' Raw Python operation\n',
out.getvalue()
)
finally: finally:
# Cleanup by unmigrating everything: fake the irreversible, then # Cleanup by unmigrating everything: fake the irreversible, then
# migrate all to zero. # migrate all to zero.

View File

@ -0,0 +1,22 @@
from django.db import migrations
def grow_tail(x, y):
pass
def feed(x, y):
"""Feed salamander."""
pass
class Migration(migrations.Migration):
dependencies = [
('migrations', '0004_fourth'),
]
operations = [
migrations.RunPython(migrations.RunPython.noop),
migrations.RunPython(grow_tail),
migrations.RunPython(feed, migrations.RunPython.noop),
]