Я подумал, что немного добавлю к стратегии, отстаиваемой ответом Вима, - сначала получу подходящую версию Django, работающую как с 2.7, так и с 3.x, - и нарисую некоторые тактики, которые сработали для меня.
Python 2.7 - это ваш запасной модуль, пока вы не нажмете на 3.x
- ваши тесты должны выполняться на обоих
- не используйте 3.x специфические функции, такие как f-строки
- сначала Python 3.x, потом только Django 2.x, который не работает на 2.7
- начать рано, не переоценивать, но избегать подхода большого взрыва
- файл за файлом сначала.
- Начните с кода самого низкого уровня, например, библиотек утилит, для которых у вас есть наборы тестов.
- если возможно, попробуйте постепенно объединить ваши изменения с производственными ветками 2.7 и поддерживать ваш код переноса 3.x в актуальном состоянии с изменениями prod.
С какой минорной версии Django начать?
Мои критерии здесь заключаются в том, что миграция Django может быть достаточно вовлечена (и на самом деле требует больше размышлений, чем 2 => 3 работы). Поэтому я бы перешел к последней и лучшей версии 1.11, так что вы уже предоставляете некоторую ценность своим 2.7 пользователям. Там, наверное, большое количество клиньев совместимости предварительно 2.x на 1.11 и вы будете получать свои 2.x устаревания предупреждения.
С какой минорной версии Python 3.x начать?
Лучше всего учитывать все аспекты, такие как доступность ваших сторонних библиотек, поддержка из набора CI / devops и доступность выбранных вами образов ОС сервера. Вы всегда можете установить 3.8 и, например, попробовать установить pip-файл вашего needs.txt.
Используйте git (или любую другую scm, которую вы используете) и virtualenv .
- отдельные
requirement.txt
файлы, но ...
- если у вас есть git-репозиторий на основе файлов, вы можете указать для каждого venv одну и ту же кодовую строку с помощью a
pip install -e <your directory>
. это означает, что в 2 разных терминалах вы можете запустить 2.7 и 3.x против одного и того же юнит-теста (ов).
- вы даже можете запускать серверы Django 2.7 и 3.x параллельно на разных портах и указывать на них Firefox и Chrome.
- часто делайте коммиты (по крайней мере, в ветке портирования) и изучайте git bisect .
использовать 2to3
Да, он сломает код 2.7 и Django, если вы позволите. Так...
запустить его в режиме предварительного просмотра или для одного файла. посмотрите, что он сломает, но и посмотрите, что он сделал правильно.
дросселируйте это только до определенных преобразований, которые не нарушают 2.7 или Django. print x
=> print (x)
и except(Exception) as e
2 ежу понятно.
Вот как выглядела моя задушенная команда:
2to3 $tgt -w -f except -f raise -f next -f funcattrs -f print
- запускайте его файл за файлом, пока вы действительно не будете уверены.
используйте sed или awk вместо вашего редактора для массовых конверсий.
Преимущество состоит в том, что по мере того, как вы будете лучше осознавать специфические проблемы ваших приложений, вы можете создавать набор изменений, которые можно запускать как для одного файла, так и для нескольких файлов, и выполнять большую часть работы, не нарушая 2.7 или Django. Примените это после вашего подходящего удушения прохода 2to3 . Это оставляет вас с остаточными очистками в вашем редакторе и позволяет пройти тесты.
(опционально) начать работать черным на 2.7 кода.
black, который является средством форматирования кода, использует Python 3 AST для выполнения своего анализа. Он не пытается запустить код, но он помечает синтаксические ошибки, которые мешают ему перейти на стадию AST. Вам нужно будет поработать над глобальной магией, чтобы попасть туда, и вам придется потратить на пользу черных.
Другие люди сделали это - учитесь у них.
Прослушивание # 155 Практические шаги по переходу на Python 3 должны дать вам несколько идей о работе. Посмотрите на шоу ссылки для этого. Они любят обсуждать ход Instagram (?), Который включал постепенную корректировку запуска кода 2.7 для синтаксиса 3.x на общей кодовой базе и в той же ветке git, пока не наступит день запуска.
Смотрите также Консервативное руководство по портированию Python 3
и Instagram делают плавный переход на Python 3 - новый стек
Вывод
Ваше время для Django 1.11 EOL (апрель 2020 г.) довольно короткое, поэтому, если у вас есть ресурсы для разработки от 2+, я бы подумал сделать следующее параллельно:
DEV # 1: начать с удара Django 1.11 (теория состоит в том, что Django 1.11, вероятно, лучше всего позиционировать как точку перехода к Django 2.x), используя 2.7.
DEV # 2: начните работу с Python 3.6 / 3.7 вашего кода не-Django. Поскольку код на данный момент совместим с 2.7, объедините его с # 1 на ходу.
Посмотрите, как выполняются обе задачи, оцените риск проекта, связанный с Django, и как выглядит боль в Python 3. Вам уже не хватает Python 2.7 EOL, но устаревший веб-фреймворк, вероятно, более опасен, чем устаревший Python 2.7, по крайней мере, на несколько месяцев. Так что я бы не стал слишком долго ждать, чтобы начать миграцию с Django 1.9, и ваша работа не будет потрачена впустую. Когда вы увидите прогресс, вы начнете видеть риски проекта лучше.
Ваш первоначальный прогресс 2to3 будет медленным, но инструменты и руководство достаточно хороши, чтобы вы быстро набрали скорость, поэтому не думайте об этом, прежде чем начать набирать опыт. Сторона Django зависит от вашей подверженности критическим изменениям в структуре, поэтому я думаю, что лучше начинать рано.
PS (спорно / личное мнение) я не использовал шесть или другие консервы 2-к-3 библиотеки мостовых много.
Это не потому, что я не доверяю - это замечательно для сторонних библиотек - скорее, я не хотел добавлять сложную постоянную зависимость (и мне было лень читать ее документ). Я долгое время писал код 2.7 в синтаксисе, совместимом с 3.x, поэтому я не чувствовал необходимости использовать их. Ваш пробег может меняться и не идти по этому пути, если кажется, что много работы .
Вместо этого я создал py223.py (57 LOC, включая комментарии) с этим типом контента, большая часть которого связана с обходными путями для устаревания и изменения имени в стандартной библиотеке.
try:
basestring_ = basestring
except (NameError,) as e:
basestring_ = str
try:
cmp_ = cmp
except (NameError,) as e:
# from http://portingguide.readthedocs.io/en/latest/comparisons.html
def cmp_(x, y):
"""
Replacement for built-in function cmp that was removed in Python 3
"""
return (x > y) - (x < y)
Затем импортируйте из этого py223, чтобы обойти эти конкретные проблемы. В дальнейшем я буду просто канаву импортировать и переместить те странно , isinstance(x, basestr_)
чтобы , isinstance(x, str)
но я знаю заранее , есть немного , чтобы беспокоиться о.