Opened 9 years ago

Closed 7 years ago

#25192 closed Bug (fixed)

Can't Squash Migration that uses migrations.RunPython.noop in Python 2

Reported by: James Pulec Owned by: Shai Berger
Component: Migrations Version: 1.8
Severity: Normal Keywords: py2
Cc: Shai Berger Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When trying to squash a set of migrations, if one of them uses migrations.RunPython.noop for a backwards or forward operation, a ValueError is raised due to an attempt to serialize an unbound method. Not sure if there should be a special check for that operation when attempting to run squashmigrations with Python2.

Traceback:

Traceback (most recent call last):
  File "manage.py", line 17, in <module>
    execute_from_command_line(sys.argv)
  File "/var/venv/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/var/venv/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 330, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/var/venv/local/lib/python2.7/site-packages/django/core/management/base.py", line 393, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/var/venv/local/lib/python2.7/site-packages/django/core/management/base.py", line 444, in execute
    output = self.handle(*args, **options)
  File "/var/venv/local/lib/python2.7/site-packages/django/core/management/commands/squashmigrations.py", line 141, in handle
    fh.write(writer.as_string())
  File "/var/venv/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 166, in as_string
    operation_string, operation_imports = OperationWriter(operation).serialize()
  File "/var/venv/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 124, in serialize
    _write(arg_name, arg_value)
  File "/var/venv/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 87, in _write
    arg_string, arg_imports = MigrationWriter.serialize(_arg_value)
  File "/var/venv/local/lib/python2.7/site-packages/django/db/migrations/writer.py", line 435, in serialize
    % (value.__name__, module_name, get_docs_version()))
ValueError: Could not find function noop in django.db.migrations.operations.special.
Please note that due to Python 2 limitations, you cannot serialize unbound method functions (e.g. a method declared and used in the same class body). Please move the function into the main module body to use migrations.

Change History (9)

comment:1 by Tim Graham, 9 years ago

Triage Stage: UnreviewedAccepted

comment:2 by Tim Graham, 8 years ago

Keywords: py2 added
Summary: Can't Squash Migration that uses migrations.RunPython.noop in Python2Can't Squash Migration that uses migrations.RunPython.noop in Python 2

comment:3 by Paul Bormans, 8 years ago

I was hitting the same issue (when squashing migrations) and learned that you can simply add a global function to the migration script that does nothing (or copy from the existing noop) and refer to that from the RunPython function.
Paul

comment:4 by Shai Berger, 7 years ago

Cc: Shai Berger added

I found a funny workaround: In my project, I added this squashmigrations command (that is, a file management/commands/squashmigrations.py in one of my projects' apps):

"""
A squashmigrations command which does some monkeypatching on the RunPython operation
to allow squashing migrations which use RunPython.noop, even on Python 2
"""
from django.core.management.commands.squashmigrations import Command as DjangoCommand
from django.db.migrations import RunPython


# A staticmethod decorator is needed (out of a class!) because we are going to
# monkeypatch this function into a class and it will be introspected by code that
# will think it is an unbound instance method without the decorator.
@staticmethod
def noop(apps, schema_editor):
    return None


class Command(DjangoCommand):

    def handle(self, **options):
        # Monkeypatch
        RunPython.noop = noop
        # Invoke original
        return super(Command, self).handle(**options)

Note the oddity of the @staticmethod decorator on a function that isn't in a class.

I suppose we could use the same idea in fixing the bug in Django as well...

comment:5 by Tim Graham, 7 years ago

Resolution: wontfix
Status: newclosed

Closing due to the end of Python 2 support in master in a couple weeks.

comment:7 by Shai Berger, 7 years ago

Owner: changed from nobody to Shai Berger
Status: newassigned

comment:8 by Shai Berger, 7 years ago

Has patch: set

comment:9 by Tim Graham <timograham@…>, 7 years ago

Resolution: fixed
Status: assignedclosed

In 437e0ba:

[1.11.x] Fixed #25192 -- Fixed squashmigrations crash with RunPython.noop on Python 2.

Thanks Adam Johnson for review.

Note: See TracTickets for help on using tickets.
Back to Top