僕はソフトウェアのインストールとか更新とかはメンドクサイので嫌い。だけど、Mercurialを1.4.3から2.1にして少しハズミがついて、IPython(http://ipython.org/)*1を入れる気になりました。http://ipython.org/download.html から ipython-0.12.win32-setup.exe をダウンロードしてインストール後に起動してみると、
hlen_b4_cell = self.readline.get_current_history_length()
AttributeError: 'module' object has no attribute 'get_current_history_length'
と言って起動失敗。
>>> dir(readline)
で調べてみると、get_history_length はあるけど、get_current_history_length はないですね。PyReadline(http://ipython.org/pyreadline.html)が古いらしい(pyreadline-1.5-win32 を使っていた)。https://launchpad.net/pyreadline/+download (最新版のソースは https://github.com/pyreadline/pyreadline)から pyreadline-1.7.1.win32.exe をダウンロードしてインストール。
これで、IPythonは動くようになりメデタシメデタシ。と思ったら、Catyが動かなくなってしまいました。ガーン。
最近のPyReadlineの使い方はどうも以前と変わったようです。PyReadlineはGNU readlineが使えない環境(主にWindows)用に準備されたものなので、以前は次のようにして使用していました。
if sys.platform == 'win32': import pyreadline as readline else: import readline
しかし最近は、こういう場合分けは不要で、単に import readline とすればいいようです。import pyreadline とすると変なことになります。
僕の環境で言えば、import pyreadline だと Python26/Lib/site-packages/pyreadline/__init__.py(のコンパイル済みファイル)がロードされ、 import readline だと Python26/Lib/site-packages/readline.py がロードされます。以前は readline.py がなかったのでしょう(1.5に戻して確認する気はない)。
プラットフォームによる場合分けは必要なくなったのですが、readlineが存在しない環境はあり得るので、結局次のようなコードが必要です(Kuwataさんが http://return0.info/note/2011-12.html#id2011-12-17 で書いています)。
try: import readline except: readline = None print '[Warning] readline module is not installed.' # ... if readline is not None: # ...
このような修正をしてCatyは起動するようになったのですが、今度はWin32 APIを使ったクリアスクリーンが動かなくなっちゃいました。
Error cls: Col 0, Line 1
Traceback (most recent call last):
File "./python\caty\front\console.py", line 322, in default
r = c(None)
File "./python\caty\core\facility\__init__.py", line 308, in __call__
r = self._command(input)
File "./python\caty\core\script\interpreter.py", line 91, in __call__
return self.cmd.accept(self)
File "./python\caty\core\command\__init__.py", line 226, in accept
return visitor.visit_command(self)
File "./python\caty\core\script\interpreter.py", line 102, in visit_command
return self._exec_command(node, self._do_command)
File "./python\caty\core\script\interpreter.py", line 148, in _exec_command
r = exec_func(node)
File "./python\caty\core\script\interpreter.py", line 109, in _do_command
return args[0].execute()
File "/cls.py", line 9, in execute
File "./lib/win32cls.py", line 67, in clear_screen
coord, byref(dwDummy))
ArgumentError: argument 4:: wrong type argument 4:
: wrong type
caty:root>
今まで動いていた次のコードがエラーしてるんですよね。いかなる因果関係なのかサッパリわかりません。ムー。
# 画面クリア def clear_screen (): csbi = CONSOLE_SCREEN_BUFFER_INFO() coord = COORD() # 初期値 coord.X = 0, coord.Y = 0 dwDummy = DWORD() hConOut = stdout_handle if GetConsoleScreenBufferInfo (hConOut, byref(csbi)): FillConsoleOutputCharacterA (hConOut, 32, csbi.dwSize.X * csbi.dwSize.Y, coord, byref(dwDummy)) FillConsoleOutputAttribute (hConOut, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, coord, byref(dwDummy)) # ここが 67 行目 SetConsoleCursorPosition (hConOut, coord)
動き出したIPythonでも不思議なことが起こります。Mercurialのライブラリも入れた(つうか結果的に入った)ので、IPythonからインポートしてみると:
In [7]: import mercurial.hg^A^[[0;32m^BIn [^A^[[1;32m^B8^A^[[0;32m^B]: ^A^[[0m^B
^A^[[0;32m^BIn [^A^[[1;32m^B8^A^[[0;32m^B]: ^A^[[0m^B
文字に直して貼りつけてますが、プロンプトとしてコントロールコードが出ているようです。どうも、ANSIエスケープシーケンスを使うモードに変わっているようです。mercurial.hg のなかでコンソールに影響する設定をしてるのでしょうかね。
複雑になったソフトウェアシステムでは、予期せぬ相互作用で不具合や奇妙な現象が生じるわけですが、もうメンドクサくて追いかける気力が湧きませんなー。
[追記]
IPythonのコンソールが壊れる原因は、どうやら、mercurial/windows.py のようだ。余分な部分を削り落とすと次のようなコード。Windowsのstdoutの不具合を修復する目的らしいが、他の所ではこれが迷惑だったりする。
# windows.py - Windows utility function implementations for Mercurial # # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. import sys class winstdout(object): '''stdout on windows misbehaves if sent through a pipe''' def __init__(self, fp): self.fp = fp def __getattr__(self, key): return getattr(self.fp, key) def close(self): try: self.fp.close() except IOError: pass def write(self, s): try: # This is workaround for "Not enough space" error on # writing large size of data to console. limit = 16000 l = len(s) start = 0 self.softspace = 0 while start < l: end = start + limit self.fp.write(s[start:end]) start = end except IOError, inst: if inst.errno != 0: raise self.close() raise IOError(errno.EPIPE, 'Broken pipe') def flush(self): try: return self.fp.flush() except IOError, inst: if inst.errno != errno.EINVAL: raise self.close() raise IOError(errno.EPIPE, 'Broken pipe') sys.__stdout__ = sys.stdout = winstdout(sys.stdout)
[/追記]
[追記]クリアスクリーンの問題は事情が分からないので、OSネイティブのclsコマンドを呼び出すことでとりあえず対処。[/追記]
*1:IPythonて、「高機能なPythonシェル」だと思っていたのですが、http://ipython.org/ipython-doc/rel-0.12/parallel/index.html とかを眺めると、なんか分散コンピューティングのプラットフォームを提供したりするんですね。スゴイ。