vimでPythonのコードを書いているときにflymake?っぽい感じをだす

Vim環境でPythonコードのflymakeっぽいことをしたかったのですが、 これといった決め手となる記事がなくて苦労したので、 メモを残しておきます。 (どなたか既存の記事をご存知であれば、教えてください。)

準備

まずPythonのlintライクなツールとしては、 PyCheckerPylintPyFlakes が有名です。

それぞれのモジュールに対するまとまった記事としては、以下が参考になります。

python 用 lint、Pyflakes vs. pyChecker vs. pylint - 傀儡師の館.Python - 楽天ブログ(Blog)

Ubuntu Linuxではapt-getで簡単にインストールできました。 (easy_install経由等でも簡単にインストール可能だと思います。)

$ sudo apt-get install pychecker
$ sudo apt-get install pylint
$ sudo apt-get install pyflakes

各ツールをvimと連携させる

以下の記事を参考にPython用の設定を模索してみました。

errormarker.vim で flymake(Emacsの) る - 8時40分が超えられない - subtech

pylintは設定ファイルがないと警告を出すので適当なところに設定ファイルを 置いて [1] 、コマンドオプションに指定します。また警告等のメッセージのみ出力させたいので、 「reports=no」に設定を変えておきます。

""" $HOME/.vim/ftplugin/python/flyquickfixmake.vim
""" setting for pylint
setlocal makeprg=/usr/bin/pylint\ --rcfile=$HOME/.pylint\ -e\ %
setlocal errorformat=%t:%l:%m

if !exists("g:python_flyquickfixmake")
    let g:python_flyquickfixmake = 1
    au BufWritePost *.py make
endif
$ pylint --generate-rcfile > ~/.pylint
$ diff -u pylint.config-org /home/hattori/.pylint
--- pylint.config-org   2009-06-29 00:49:16.000000000 +0900
+++ /home/hattori/.pylint       2009-06-29 00:48:07.000000000 +0900
@@ -71,7 +71,8 @@
 files-output=no

 # Tells wether to display a full report or only the messages
-reports=yes
+###reports=yes
+reports=no

 # Python expression which should return a note less than 10 (10 is the highest
 # note). You have access to the variables errors warning, statement which

pyflakesを利用する場合は、flyquickfixmake.vimを以下のようにします。

""" $HOME/.vim/ftplugin/python/flyquickfixmake.vim
""" setting for pyflakes
setlocal makeprg=/usr/bin/pyflakes\ %
setlocal errorformat=%f:%l:%m

if !exists("g:python_flyquickfixmake")
    let g:python_flyquickfixmake = 1
    au BufWritePost *.py make
endif

pycheckerはPython2.6に対応していないためか、エラーを大量に出力したため 使用をあきらめました。

設定が終われば、Pythonのコードをvimで開いて、保存したときにコードチェックが 行われるようになります。

使用感

pylintは重厚なツールで一回のチェックが長いです。 ただしPEP8ベースの構文チェックも行えるので、それを利用したいのであれば 唯一の選択肢となります。外部に公開するようなモジュールのコードチェックに 使用するのがよいのではないでしょうか。

pycheckerは依存するモジュールまでチェックしているようで、 求めているものとは違っていました。(深追いしていないので、私の認識が おかしいだけかもしれません。ただ単にPython2.6だからエラーはいてたのかも。)

pyflakesは動作が軽く、インタプリタ言語でlintライクな チェックを行うのにはちょうど良いのではないでしょうか。 私が求めていたものに一番近かったので、今後はこれを使っていこうと思います。

くわしくは調べていませんが、 pyflakes.vimというスクリプト もあるみたいです。

vim:QuickFixのめも

:cn     " 次のエラーへジャンプ
:cp     " 前のエラーへジャンプ
:cope   " QuickFixリストを表示
:ccl    " QuickFixリストを閉じる

Vim documentation: quickfix

footnote

[1](2009-07-04追記) 設定ファイルは $HOME/.pylintrc に置けば良いですね。

release pyprof2html version0.1.0 and 0.1.1

pyprof2html のバージョン0.1.0と0.1.1を立て続けに リリースしました。

pyprof2htmlはPythonのプロファイルデータをHTMLまたは テキストデータに変換するモジュールです。

version0.1.0から PyPIにも登録 しています。

Python界には小さな一歩ですが、私にとっては 非常に大きな一歩になりました。 まだまだ改善の余地ありまくりなので、 改良とリリースを継続していきたいです。


Mercurial(hg)のstatusとdiffをカラー化する

http://farm3.static.flickr.com/2454/3650199713_4f4d255d05.jpg

カラー化するのは以下の記事で十分なのですが、 詳しい設定はもうちょっと調べないとわかりませんでした。 日本語の記事が探した感じ見つからなかったので、メモを残しておこう。 [1]

status や diff を色分け表示にする - technolazy.snapshot

colordiffインストールとその他設定

淡々と。

$ sudo apt-get install colordiff
$ vim ~/.hgrc

これだけ。

結局、$HOME/.hgrcは以下のような感じに。色の詳細設定は [color]セクションを追加して設定します。MQ使ってない(ってか、 何かあんまりわかってない。)ので、qseriesは設定していません。

[defaults]
cdiff = -q

[extdiff]
cmd.cdiff = colordiff
opts.cdiff =

[extensions]
hgext.color =
hgext.extdiff =
color =

[color]
status.modified = green bold underline
status.added = magenta bold underline
status.removed = red bold blue_background
status.deleted = red underline
status.unknown = blue bold
status.ignored = black bold

diff.diffline = none
diff.extended = cyan bold
diff.file_a = red bold
diff.file_b = green
diff.hunk = yellow bold
diff.deleted = blue bold
diff.inserted = green bold
diff.changed = white
diff.trailingwhitespace = bold red_background

好みに合わせて適当にいじってください。

フォントカラー: black, red, green, yellow, blue, magenta, cyan, white
装飾          : bold, italic, underline, inverse
背景カラー    : black_background, red_background, green_background,
                yellow_background, blue_background, magenta_background,
                cyan_background, white_background

使ってみるとわかりますが、パイプ経由でlessとかすると カラー化されません。 結局、$HOME/.bashrcあたりにこんなのを追加しないとダメなのか。あー。

alias hgdiff='hg diff | colordiff | less -r'

footnote

[1]参考にしたのは2008年の記事なんだけど、あんまりMercurialって 使われてないのかな?gitとかのほうが使われてるのかな? カラー化自体あんまりしない? 思うんだけど、ツール名称の"Mercurial"とコマンド名"hg"って違い過ぎるよね。 あとhgでググるとレイザーラモンHGが出てくるw

LifeLog 2009.06.21

GR DIGITAL II

http://farm4.static.flickr.com/3387/3647143309_ee6a6c7b34.jpg

今日は雨。昨日は晴れ。

最近、誘惑に負けて GR DIGITAL II を購入したので 須磨まで自転車ででかけてみた。

もともと趣味レベルなのでうまくはないけれど、 今回はあまりうまく風景を撮れてないなぁ。 でもいろいろといじりがいがあっておもしろい。


fapws3マジ速い?件とweb.pyのプロファイルの話

fapws3がなにやらいい感じとのPostが目立つ今日この頃。 「最速」との言葉に弱い私もweb.pyに組み込んで試してみました。 web.pyのアプリの例は 以前Postしたもの を使います。

william-os4y's fapws3 at master - GitHub

web.py + fapws3

fapws3はWSGI対応なのでweb.pyにも簡単に組み込めます。 コード全体は Sandbox 上にありますので適当に見てください。 fapws3を固有部分のみ以下に示します。

import fapws._evwsgi as evwsgi
from fapws import base

if __name__ == '__main__':
    application = web.application(urls, globals()).wsgifunc()
    evwsgi.start("0.0.0.0", 8080)
    evwsgi.set_base_module(base)
    evwsgi.wsgi_cb(("", application))
    evwsgi.run()

web.py内、applicationクラスのwsgifunc()メソッドをコールしたものを fapws3のwsgi_cb()でコールバック登録します。 このあたりの書き方はfapws3サンプルにあったhello_world.py以下、 起動系のサンプルスクリプトがすべて同じ書き方になっているので それをそのまま使いました。 start()→set_base_module()→wsgi_cb()→run()のイメージですね。

ちなみにミドルウェアをかましたい場合は、以下のような感じです。 (リクエスト毎に"Hello Debug!"と出力するHelloMiddlewareミドルウェアを 追加しています。)

class HelloMiddleware(object):

    def __init__(self, application):
        self.application = application

    def __call__(self, env, start_response):
        web.debug("Hello Debug!")
        return self.application(env, start_response)

if __name__ == '__main__':
    application = web.application(urls, globals()).wsgifunc()
    application = HelloMiddleware(application)
    evwsgi.start("0.0.0.0", 8080)
    evwsgi.set_base_module(base)
    evwsgi.wsgi_cb(("", application))
    evwsgi.run()

fapwsのコア部分はCで記述されているので、ちょっとコード読みがめんどくさいです。 興味があれば読んでみてはどうでしょうか。(私はあきらめてしまいました。)

さて性能は?

ローカルから以下コマンドで測定してみました。 5回ほど実行したおおよその平均値です。fapws速い。

$ ab -n100 http://0.0.0.0:8080/    # "Hello web.py"
$ ab -n100 http://0.0.0.0:8080/a/ # DBアクセス+テンプレート
[web.py] db,template
Requests per second:    30.40 [#/sec] (mean)

[web.py] non db,template
Requests per second:    106.45 [#/sec] (mean)

[web.py + fapws3] db,template
Requests per second:    50.49 [#/sec] (mean)

[web.py + fapws3] non db,template
Requests per second:    176.88 [#/sec] (mean)

[django mysite]
Requests per second:    14.32 [#/sec] (mean)

自分のDjangoサイトも測定してみましたが、、、思いのほかひどい結果。 それほどアクセスが無いにせよもう少し何とかしたいな。 nginx/fapws使うとか、キャッシュを有効にするためにツールで 定期的にアクセスするとか。

web.pyアプリをプロファイリング

web.py遅い遅いと言われますが、どこが遅いのか おせっかいにもプロファイルして見てみようということで、 web.pyアプリにプロファイラを仕込んでみました。

cProfile and hotshot

cProfileの結果 を見ていただければわかるのですが、 accept()待ちしているところも実行時間として測定されるので、若干期待していた 値と異なる場合があります。一回の測定時間を短くしたり、accept()待ち箇所は 測定者側で無視する等の対策が必要です。 (もう少し良い方法がないか探してみます。) hotshotでの実行結果 の結果は 小数点以下3桁くらいの表示ではあまりプロファイルとして有効なデータにはなっていませんね。

line_profiler

line_profiler は行毎の実行時間を出力してくれるPythonモジュールです。 作者の方曰くhotshotの行毎の測定は時間が掛かりすぎる云々。 確かにhotshotは測定にも解析にも時間が掛かります。 line_profilerは軽い動作でプロファイルしてくれます。 まずはインストール。

$ sudo easy_install line_profiler

使い方は測定したいメソッドを@profileでデコレートしてkernprofを「-l」指定で 実行するだけです。 実行結果は以下のようになります。

$ kernprof.py -l code.py
$ ls
code.py    code.py.lprof
$ python -m line_profiler code.py.lprof
Timer unit: 1e-06 s

File: code.py
Function: GET at line 19
Total time: 0.233386 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    19                                               @profile
    20                                               def GET(self, username):
    21         1         4376   4376.0      1.9          users = db.select('hellouser', wh
    22         1           10     10.0      0.0          isFound = False
    23         2          100     50.0      0.0          for u in users:
    24         1           20     20.0      0.0              if u.name == username:
    25         1            6      6.0      0.0                  isFound = True
    26         1            7      7.0      0.0          if not isFound:
    27                                                       db.query("INSERT INTO hellous
    28         1       228867 228867.0     98.1          return render.hello(username, isF

File: code.py
Function: GET at line 31
Total time: 9e-06 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    31                                               @profile
    32                                               def GET(self):
    33         1            9      9.0    100.0          return "Hello web.py"

内部のライブラリのコードまではプロファイルしないようです。 今回の私の用途には合いませんでしたが、特定のミドルウェアだけ 測定する、等の使い方ができるのでいいのではないでしょうか。

web.pyが遅い理由は次回書いてみます。では。


code reading to pyftpdlib (with Toky No.1 Soul Set)


vim tips(最近役に立ったvimのリンク集)と最近読んだ本


LifeLog 2009.06.01


Older Blog Posts