2to3 — автоматический перевод кода Python 2 в 3

2to3 — это Python программа, которая считывает исходный код Python 2.x и применяет серию фиксеров для преобразования его в правильный Python код 3.x. Стандартная библиотека содержит богатый множество фиксеров, которые будут обрабатывать почти весь код. Библиотека поддержки 2to3 lib2to3, однако, является гибкой и универсальной библиотекой, поэтому можно написать свои собственные фиксеры для 2to3. lib2to3 также можно адаптировать к пользовательским приложениям, в которых код Python должен редактироваться автоматически.

Использование 2to3

2to3 обычно устанавливается вместе с интерпретатором Python в виде сценария. Он также находится в каталоге Tools/scripts корня Python.

Основные аргументы 2to3 — это список файлов или каталогов, которые нужно преобразовать. Каталоги рекурсивно просматриваются для Python исходников.

Вот пример исходного файла Python 2.x, example.py:

def greet(name):
    print "Hello, {0}!".format(name)
print "What's your name?"
name = raw_input()
greet(name)

Его можно преобразовать в код Python 3.x через 2to3 в командной строке:

$ 2to3 example.py

Будет напечатана разница с исходным файлом. 2to3 также может записывать необходимые изменения прямо в исходный файл. (Резервная копия исходного файла создаётся, если также не указан -n.) Запись изменений обратно разрешена с помощью флага -w:

$ 2to3 -w example.py

После преобразования example.py выглядит так:

def greet(name):
    print("Hello, {0}!".format(name))
print("What's your name?")
name = input()
greet(name)

Комментарии и точные отступы сохраняются на протяжении всего процесса перевода.

По умолчанию 2to3 запускает множество предопределённых фиксеров. Флаг -l перечисляет все доступные фиксеры. Явное множество фиксеров для запуска может быть предоставлено с помощью -f. Точно так же -x явно отключает фиксер. В следующем примере выполняются только фиксеры imports и has_key:

$ 2to3 -f imports -f has_key example.py

Эта команда запускает все фиксеры, кроме apply:

$ 2to3 -x apply example.py

У некоторых фиксеров есть явный номер, что означает, что они не запускаются по умолчанию и должны быть указаны в командной строке для запуска. Здесь помимо фиксеров по умолчанию запускается фиксер idioms:

$ 2to3 -f all -f idioms example.py

Обратите внимание, как передача all включает все фиксеры по умолчанию.

Иногда 2to3 находит место в исходном коде, которое необходимо изменить, но 2to3 не может исправить это автоматически. В этом случае 2to3 выведет предупреждение под разницей для файла. Вы должны устранить это предупреждение, чтобы у вас был совместимый код 3.x.

2to3 также может выполнять рефакторинг доктестов. Чтобы включить данный режим, используйте флаг -d. Обратите внимание, что в доктестах только будет произведён рефакторинг. Это также не требует, чтобы модуль был правильным Python. Например, с помощью этой опции также можно отрефакторировать примеры, подобные доктестам, в документе reST.

Параметр -v позволяет выводить дополнительную информацию о процессе перевода.

Поскольку некоторые операторы print могут быть проанализированы как вызовы функций или операторы, 2to3 не всегда может читать файлы, содержащие функцию print. Когда 2to3 обнаруживает присутствие директивы компилятора from __future__ import print_function, он изменяет свою внутреннюю грамматику, чтобы интерпретировать print() как функцию. Это изменение также можно включить вручную с помощью флага -p. Используйте -p для запуска фиксеров в коде, для которого уже были преобразованы операторы print.

Параметр -o или --output-dir позволяет указать альтернативный каталог для записи обработанных выходных файлов. При его использовании требуется флаг -n, поскольку файлы резервных копий не имеют смысла, если не перезаписывают входные файлы.

Добавлено в версии 3.2.3: Добавлена опция -o.

Флаг -W или --write-unchanged-files указывает 2to3 всегда записывать выходные файлы, даже если в файл не требуется никаких изменений. Это наиболее полезно с -o, т. к. всё дерево исходных текстов Python копируется с переводом из одного каталога в другой. Данный параметр подразумевает флаг -w, поскольку в противном случае у него не было бы смысла.

Добавлено в версии 3.2.3: Добавлен флаг -W.

Параметр --add-suffix указывает строку, добавляемую ко всем именам выходных файлов. Флаг -n требуется при указании этого параметра, поскольку резервное копирование не требуется при записи с разными именами файлов. Пример:

$ 2to3 -n -W --add-suffix=3 example.py

Запишет преобразованный файл с именем example.py3.

Добавлено в версии 3.2.3: Добавлена опция --add-suffix.

Для перевода всего проекта из одного дерева каталогов в другое используйте:

$ 2to3 --output-dir=python3-version/mycode -W -n python2-version/mycode

Фиксеры

Каждый шаг преобразования кода инкапсулируется в фиксер. Команда 2to3 -l перечисляет их. Как задокументировано выше, каждый из них можно включать и выключать индивидуально. Они описаны здесь более подробно.

apply

Удаляет использование apply(). Например, apply(function, *args, **kwargs) преобразуется в function(*args, **kwargs).

asserts

Заменяет устаревшие имена методов unittest на правильные.

Из В
failUnlessEqual(a, b) assertEqual(a, b)
assertEquals(a, b) assertEqual(a, b)
failIfEqual(a, b) assertNotEqual(a, b)
assertNotEquals(a, b) assertNotEqual(a, b)
failUnless(a) assertTrue(a)
assert_(a) assertTrue(a)
failIf(a) assertFalse(a)
failUnlessRaises(exc, cal) assertRaises(exc, cal)
failUnlessAlmostEqual(a, b) assertAlmostEqual(a, b)
assertAlmostEquals(a, b) assertAlmostEqual(a, b)
failIfAlmostEqual(a, b) assertNotAlmostEqual(a, b)
assertNotAlmostEquals(a, b) assertNotAlmostEqual(a, b)
basestring

Преобразует basestring в str.

buffer

Преобразует buffer в memoryview. Данный фиксер не является обязательным, поскольку API memoryview похож на API buffer, но не совсем то же самое.

dict

Исправляет методы итерации словаря. dict.iteritems() преобразуется в dict.items(), dict.iterkeys() в dict.keys() и dict.itervalues() в dict.values(). Аналогичным образом dict.viewitems(), dict.viewkeys() и dict.viewvalues() преобразуются соответственно в dict.items(), dict.keys() и dict.values(). Он также охватывает существующие случаи использования dict.items(), dict.keys() и dict.values() в вызове list.

except

Преобразует except X, T в except X as T.

exec

Преобразует оператор exec в функцию exec().

execfile

Удаляет использование execfile(). Аргумент execfile() заключён в вызовы open(), compile() и exec().

exitfunc

Изменяет назначение sys.exitfunc на использование модуля atexit.

filter

Обёртывает использование filter() в вызове list.

funcattrs

Исправляет атрибуты функции, которые были переименованы. Например, my_function.func_closure преобразуется в my_function.__closure__.

будущее

Удаляет операторы from __future__ import new_feature.

getcwdu

Переименовывает os.getcwdu() в os.getcwd().

has_key

Изменяет dict.has_key(key) на key in dict.

idioms

Данный дополнительный фиксер выполняет несколько преобразований, которые делают код Python более идиоматическим. Сравнение типов, например type(x) is SomeClass и type(x) == SomeClass, преобразуется в isinstance(x, SomeClass). while 1 становится while True. Данный фиксер также пытается использовать sorted() в соответствующих местах. Например, данный блок:

L = list(some_iterable)
L.sort()

изменяется на:

L = sorted(some_iterable)
import

Обнаруживает родственный импорт и преобразует их в относительный импорт.

imports

Обрабатывает переименования модулей в стандартной библиотеке.

imports2

Обрабатывает другие модули, переименованные в стандартной библиотеке. Он отделён от фиксера imports только из-за технических ограничений.

input

Преобразует input(prompt) в eval(input(prompt)).

internal

Преобразует intern() в sys.intern().

isinstance

Исправляет повторяющиеся типы во втором аргументе isinstance(). Например, isinstance(x, (int, int)) преобразуется в isinstance(x, int), а isinstance(x, (int, float, int)) преобразуется в isinstance(x, (int, float)).

itertools_imports

Удаляет импорт itertools.ifilter(), itertools.izip() и itertools.imap(). Импорт itertools.ifilterfalse() также изменён на itertools.filterfalse().

itertools

Изменяет использование itertools.ifilter(), itertools.izip() и itertools.imap() на их встроенные эквиваленты. itertools.ifilterfalse() заменен на itertools.filterfalse().

long

Переименовывает long в int.

map

Обёртывает map() в вызове list. Он также изменяет map(None, x) на list(x). Фиксер from future_builtins import map отключает данный фиксер.

метакласс

Преобразует старый синтаксис метакласса (__metaclass__ = Meta в теле класса) в новый (class X(metaclass=Meta)).

methodattrs

Исправляет старые имена атрибутов метода. Например, meth.im_func преобразуется в meth.__func__.

ne

Преобразует старый синтаксис неравенства <> в !=.

next

Преобразует использование методов итератора next() в функцию next(). Он также переименовывает методы next() в __next__().

nonzero

Переименовывает __nonzero__() в __bool__().

numliterals

Преобразует восьмеричные литералы в новый синтаксис.

operator

Преобразует вызовы различных функций в модуле operator в другие, но эквивалентные вызовы функций. При необходимости добавляются соответствующие операторы import, например import collections.abc. Сделано следующее сопоставление:

Из В
operator.isCallable(obj) callable(obj)
operator.sequenceIncludes(obj) operator.contains(obj)
operator.isSequenceType(obj) isinstance(obj, collections.abc.Sequence)
operator.isMappingType(obj) isinstance(obj, collections.abc.Mapping)
operator.isNumberType(obj) isinstance(obj, numbers.Number)
operator.repeat(obj, n) operator.mul(obj, n)
operator.irepeat(obj, n) operator.imul(obj, n)
paren

Добавить лишние круглые скобки там, где они требуются при списковом включении. Например, [x for x in 1, 2] станет [x for x in (1, 2)].

print

Преобразует оператор print в функцию print().

raise

Преобразует raise E, V в raise E(V) и raise E, V, T в raise E(V).with_traceback(T). Если E является кортежем, перевод будет неправильным, поскольку замена исключений кортежами была удалена в версии 3.0.

raw_input

Преобразует raw_input() в input().

reduce

Обрабатывает перемещение reduce() в functools.reduce().

reload

Преобразует reload() в importlib.reload().

renames

Изменяет sys.maxint на sys.maxsize.

repr

Заменяет повторную обратную кавычку на функцию repr().

set_literal

Заменяет использование конструктора set заданными литералами. Данный фиксер не является обязательным.

standarderror

Переименовывает StandardError в Exception.

sys_exc

Изменяет устаревшие sys.exc_value, sys.exc_type, sys.exc_traceback на использование sys.exc_info().

throw

Исправляет изменение API в методе генератора throw().

tuple_params

Удаляет неявную распаковку параметров кортежа. Данный фиксер вставляет временные переменные.

types

Исправляет код, нарушенный при удалении некоторых элементов в модуле types.

unicode

Переименовывает unicode в str.

urllib

Обрабатывает переименование urllib и urllib2 в пакете urllib.

ws_comma

Удаляет лишние пробелы из элементов, разделенных запятыми. Данный фиксер не является обязательным.

xrange

Переименовывает xrange() в range() и переносит существующие вызовы range() в list.

xreadlines

Изменяет for x in file.xreadlines() на for x in file.

zip

Обёртывает использование zip() в вызове list. Он отключён, когда появляется from future_builtins import zip.

lib2to3 — библиотека 2to3


Примечание

API lib2to3 следует считать нестабильным и может кардинально измениться в будущем.