# 2to3 --- Python 2 から 3 への自動コード変換

2to3 は、 Python 2.x のソースコードを読み込み、一連の 変換プログラム (fixer) を適用して正しい Python 3.x のコードに変換する Python プログラムです。標準ライブラリはほとんど全てのコードを取り扱うのに十分な fixer を含んでいます。ただし 2to3 を構成している `lib2to3` は柔軟かつ一般的なライブラリなので、 2to3 のために独自の fixer を書くこともできます。

バージョン 3.11 で非推奨、バージョン 3.13 で削除予定: The `lib2to3` module was marked pending for deprecation in Python 3.9 (raising `PendingDeprecationWarning` on import) and fully deprecated in Python 3.11 (raising `DeprecationWarning`). The `2to3` tool is part of that. It will be removed in Python 3.13.

## 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)

これは、コマンドラインから 2to3 を呼び出すことで、Python 3.x コードに変換されます:

    $ 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 はファイルの変更点の下に警告を表示します。 3.x に準拠したコードにするために、あなたはこの警告に対処しなくてはなりません。

2to3 は doctest の修正もできます。このモードを有効化するには `-d` フラグを指定して下さい。 doctest だけ が修正されることに注意して下さい。これは、モジュールが有効な Python コードであることを要求しないということでもあります。例えば、 reST ドキュメント中の doctest に似たサンプルコードなども、このオプションで修正することができます。

`-v` は、変換処理のより詳しい情報の出力を有効化します。

いくつかの print 文は関数呼び出しとしても文としても解析できるので、 2to3 は print 関数を含むファイルを常に読めるとは限りません。 2to3 は `from __future__ import print_function` コンパイラディレクティブが存在することを検出すると、内部の文法を変更して `print()` を関数として解釈するようになります。 `-p` フラグによって手動でこの変更を有効化することもできます。 print 文を変換済みのコードに対して変換プログラムを適用するには `-p` を使用してください。同様に、`exec()` を関数として解釈させるには `-e` を使用してください。

`-o` または `--output-dir` で処理結果の出力先ディレクトリを変更出来ます。入力ファイルを上書きしないならバックアップは意味をなさないので、オプション `-n` フラグが要ります。

バージョン 3.2.3 で追加: `-o` オプションが追加されました。

`-W` または `--write-unchanged-files` により、たとえファイルに変更が必要なくても常にファイルを出力するように 2to3 に指示することが出来ます。これは、 `-o` とともに使って、Python ソースツリー全体を変換して別のディレクトリに書き出す際に最も有用です。

バージョン 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` に変換します。 `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()` に変換されます。また、 `list` の呼び出しの中で `dict.items()`, `dict.keys()`, `dict.values()` を使用している場合はそれをラップします。

except

  `except X, T` を `except X as T` に変換します。

exec

  `exec` 文を `exec()` 関数に変換します。

execfile

  `execfile()` の使用を削除します。 `execfile()` への引数は `open()`, `compile()`, `exec()` の呼び出しでラップされます。

exitfunc

  `sys.exitfunc` への代入を `atexit` モジュールの使用に変更します。

filter

  `list` 呼び出しの中で `filter()` を使用している部分をラップします。

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 コードをより 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

  暗黙の相対インポート (sibling imports) を検出して、明示的な相対インポート (relative imports) に変換します。

imports

  標準ライブラリ中のモジュール名の変更を扱います。

imports2

  標準ライブラリ中の別のモジュール名の変更を扱います。単に技術的な制約のために `imports` とは別になっています。

input

  `input(prompt)` を `eval(input(prompt))` に変換します。

intern

  `intern()` を `sys.intern()` に変換します。

isinstance

  `isinstance()` の第 2 引数の重複を修正します。例えば `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

  `list` 呼び出しの中の `map()` をラップします。また、 `map(None, x)` を `list(x)` に変換します。 `from future_builtins import map` を使うと、この変換プログラムを無効にできます。

metaclass

  古いメタクラス構文 (クラス定義中の `__metaclass__ = Meta`) を、新しい構文 (`class X(metaclass=Meta)`) に変換します。

methodattrs

  古いメソッドの属性名を修正します。例えば `meth.im_func` は `meth.__func__` に変換されます。

ne

  古い不等号の構文 `<>` を `!=` に変換します。

next

  イテレータの `next()` メソッドの使用を `next()` 関数に変換します。また `next()` メソッドを `__next__()` に変更します。

nonzero

  `__nonzero__()` を `__bool__()` に変更します。

numliterals

  8 進数リテラルを新しい構文に変換します。

operator

  `operator` モジュール内のさまざまな関数呼び出しを、他の、しかし機能的には同等の関数呼び出しに変換します。必要に応じて、`import collections.abc` などの適切な `import` ステートメントが追加されます。以下のマッピングが行われます。

  対象 | 変換先
  --- | ---
  `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)` に変換します。例外の代わりにタプルを使用することは 3.0 で削除されたので、`E` がタプルならこの変換は不正確になります。

raw_input

  `raw_input()` を `input()` に変換します。

reduce

  `reduce()` が `functools.reduce()` に移動されたことを扱います。

reload

  `reload()` を `importlib.reload()` に変換します。

renames

  `sys.maxint` を `sys.maxsize` に変更します。

repr

  バッククォートを使った repr を `repr()` 関数に置き換えます。

set_literal

  `set` コンストラクタの使用を set リテラルに置換します。この変換プログラムはオプションです。

standarderror

  `StandardError` を `Exception` に変更します。

sys_exc

  廃止された `sys.exc_value`, `sys.exc_type`, `sys.exc_traceback` の代わりに `sys.exc_info()` を使うように変更します。

throw

  ジェネレータの `throw()` メソッドの API 変更を修正します。

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

  `list` 呼び出しの中で使われている `zip()` をラップします。これは `from future_builtins import zip` が見つかった場合は無効にされます。

## `lib2to3` --- 2to3's library

ソースコード: Lib/lib2to3/

バージョン 3.11 で非推奨、バージョン 3.13 で削除予定: Python 3.9 switched to a PEG parser (see PEP 617) while lib2to3 is using a less flexible LL(1) parser. Python 3.10 includes new language syntax that is not parsable by lib2to3's LL(1) parser (see PEP 634). The `lib2to3` module was marked pending for deprecation in Python 3.9 (raising `PendingDeprecationWarning` on import) and fully deprecated in Python 3.11 (raising `DeprecationWarning`). It will be removed from the standard library in Python 3.13. Consider third-party alternatives such as LibCST or parso.

注釈

`lib2to3` API は安定しておらず、将来、劇的に変更されるかも知れないと考えるべきです。