#29290: Previously squashed migration fails under Python 3 with "multiple leaf
nodes" error
--------------------------------------+------------------------
Reporter: Ed Morley | Owner: nobody
Type: Bug | Status: new
Component: Migrations | Version: 1.11
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
--------------------------------------+------------------------
== Context ==
Whilst Django 2.0 / master have dropped support for Python 2, for many
existing Python 2.7 projects the common path to the ideal "Django 2 +
Python 3" end state will be an interim step of "Django 1.11 + Python 3".
As such, it seems in the best interests of making that transition as easy
as possible, to reduce the number of people left behind on older Django
versions.
== STR ==
1. Clone [https://github.com/edmorley/testcase-django-squashmigrations-
py3compat testcase-django-squashmigrations-py3compat]
2. `mkvirtualenv dj111-py2 -p python2.7`
3. `pip install Django==1.11.12`
4. `./manage.py squashmigrations testapp 0002 --noinput`
5. `./manage.py migrate`
6. `mkvirtualenv dj111-py3 -p python3.6`
7. `pip install Django==1.11.12`
8. `./manage.py migrate`
== Expected ==
The migrate command at step 8 completes successfully, or else a less
misleading error message shown.
== Actual ==
Step 8 results in:
{{{#!python
CommandError: Conflicting migrations detected; multiple leaf nodes in the
migration graph:
(0002_some_change, 0001_squashed_0002_some_change in testapp).
To fix them run 'python manage.py makemigrations --merge'
}}}
Running the suggested `manage.py makemigrations --merge` fails too (and it
shouldn't be necessary anyway):
{{{#!python
Traceback (most recent call last):
...
File ".../django/core/management/commands/makemigrations.py", line 272,
in handle_merge
raise ValueError("Could not find common ancestor of %s" %
migration_names)
ValueError: Could not find common ancestor of
{'0001_squashed_0002_some_change', '0002_some_change'}
}}}
== Additional notes ==
* If the bytestring prefix (`b'...'`) is removed from the migration names
specified in `replaces` in the generated squashed migration, the migration
succeeds.
* If prior to squashing the migration, `from __future__ import
unicode_literals` is added to `settings.py`, then the generated migration
does not contain bytestring prefixes. Adding to `settings.py` is necessary
since this project uses the default `AppConfig` rather than a manually
specified one.
* The above was using Python 2.7.14 and Python 3.6.4.
* Related tickets #25906 and #24949, though they seem broader in scope,
and don't reference the misleading "multiple leaf nodes" error
specifically (which was one of the most confusing aspects when debugging
this).
== Thoughts on fixes ==
* Ideally the `migrate` command's graph traversal would coerce all
migration names to string before comparing, which would make the above
"just work" even on previously created squashed migrations.
* Alternatively the `squashmigration` command could coerce the migration
names specified in `replaces` to string before even under Python 2, to
ensure the generated migration is correct. However this will still mean
existing projects have to make manual edits to existing migrations.
* It might also be worth adding `from __future__ import unicode_literals`
to the `startproject` template `settings.py` to catch cases where people
don't point at a custom `AppConfig`.
* Failing all of the above, it would be good to make the error message
less misleading and/or mention this case explicitly in the docs.
Especially since the current docs suggested workaround of adding
`unicode_literals` and re-running `makemigrations` doesn't work for
squashed migrations (it still results in the `multiple leaf nodes` error
unless the squashed migration is hand-edited). Docs in question:
* https://docs.djangoproject.com/en/1.11/topics/migrations/#supporting-
python-2-and-3
* https://docs.djangoproject.com/en/1.11/topics/python3/
Side note: It's not clear whether an app not having a specified
`AppConfig` is fine, or considered legacy/deprecated. If the latter it
would be great to clarify this in the docs, and state the disadvantages or
even add a deprecation warning.
--
Ticket URL: <https://code.djangoproject.com/ticket/29290>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/051.69aec83f80c3f978aac0605c9815c63f%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.