2to3 - автоматизированный перевод кода Python 2 на 3

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

Применение 2to3

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

Основными аргументами 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 выполняет множество predefined fixers. Флаг -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 или:option:!–output-dir позволяет задать альтернативный каталог для обрабатываемых выходных файлов для записи. Этот параметр подразумевает флаг -w, т.к. в противном случае он не имеет смысла.

Добавлено в версии 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 перечисляет их. Ссылаясь на documented above, каждый из них может быть включен или выключен индивидуально. Далее они описаны более подробно.

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 почти полностью совпадает с 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__.

future

Удаляет операторы 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)).

intern

Преобразует 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класса (__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

Добавьте дополнительные скобки в том месте, где они требуются для list comprehensions. Например, [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() в: func: „functools.reduty“.

reload

Конвертирует reload() в importlib.reload().

renames

Меняет sys.maxint на sys.maxsize.

repr

Заменяет апостроф 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

Исходный код: Lib/lib2to3/


Примечание

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