9.02.2015

Python3.2: TypeError in subprocess Module When Using Bytes Command String

Python3.2: subprocess モジュールでコマンドラインを bytes で書くと TypeError が発生

 

事象

POSIX互換環境の Python 3.2 で subprocess#call を呼び出すとき
コマンドを bytes で書きつつ shell モードを有効にすると、以下の意味不明なエラーが出る。

$ python
Python 3.2.5 (default, Sep  1 2015, 23:07:07)
[GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> subprocess.call(b'echo', shell=True)
(snip)
TypeError: Can't convert 'int' object to str implicitly
>>>

コマンドを str で渡せばよいのだが、それだとコマンドライン自体が SJIS などの非UTF-8で表現されている場合に困ってしまう。

 

原因

子プロセスを生成するところで、args に ['/bin/sh', '-c', 101, 99, 104, 111] というパラメータが渡っていた。
['/bin/sh', '-c'] + list(b'echo') のようなコードで作られたようだ。

1バイトごとに分解され int となったものが暗黙的に str に変換されずに TypeError が送出される。

Python 3.3 では修正済み。

 

対応方法

Python 3.2 をサポートしないのが賢明と思われるが、以下のようなワークアラウンドでも回避できそうだ。

import subprocess


NOT_USE_SHELL = sys.version_info[:2] == (3, 2) and not sys.platform == 'win32'

cmd = b'echo'

if NOT_USE_SHELL:
    ret_code = subprocess.call(['/bin/sh', '-c', cmd], shell=False)
else:
    ret_code = subprocess.call(cmd, shell=True)

 

話題になったのが 5年以上前ということもあり、Google検索しても情報が出てこないのがつらい。

0 件のコメント:

コメントを投稿