Ian Lewis
Ian Lewis is a web developer living in Tokyo Japan. His current interests are in Django, python, alternative databases and rapid web application development. About Me...
  • growltestrunner の pynotify 対応 / pynotify の使い方

    最近、会社の AE35 さんが growltestrunner を作っていて、 modipyd を使って、ファイルを更新したタイミングで自動テストを自動的に実行してくれて、growlで通知するように素敵な環境を設定した。

    俺はlinuxなので、当然 growl がないけど、Mac OS の growl みないな libnotify があって、pynotify と言うpythonバインディングがあるから、pynotifyでも使えるように、 fork を作った。

    ちなみに、pynotify はこういう使い方

    import pynotify
    pynotify.init("My App")
    n = pynotify.Notification("Title", "Message", "/path/to/my/icon.png")
    n.show()
    
    Send feedback このエントリーを含むはてなブックマーク はてなブックマーク - growltestrunner の pynotify 対応 / pynotify の使い方
  • BPStudy #29 テスト駆動開発

    BPStudy #29 のテスト駆動開発の話でペアプログラミングで、Last Recently Used キャッシュ (LRU)を自動テストやりながら、実装しようという部分がありました。

    最初に僕は二つのリストで10分くらいで実装したんですけど、やっぱりパフォーマンスが出ないと思ったから、時間が終わったまでに、pythonの辞書で書き直した。

    最終版はこれでした。

    lru.py

    #:coding=utf8:
    
    class LRU(object):
    
        def __init__(self, size=2):
            self.size = size
            self.name_list = []
            self.value_dict = {}
    
        def put(self, name, value):
            if name not in self:
                self.name_list.append(name)
            self.value_dict[name] = value
            if len(self.name_list) > self.size:
                old_name = self.name_list[0]
                del self.name_list[0]
                self.value_dict.pop(old_name)
    
        def get(self, name):
            if name in self.name_list:
                self.name_list.remove(name)
                self.name_list.append(name)
                return self.value_dict[name]
            else:
                return None
    
        def __contains__(self, key):
            try:
                self.value_dict[key]
                return True
            except KeyError:
                return False
    
        def __setitem__(self, key, value):
            self.put(key, value)
    
        def __getitem__(self, key):
            return self.get(key)
    
        def __len__(self):
            return len(self.name_list)
    

    lru_test.py

    from unittest import TestCase
    
    from lru import LRU
    
    class LRUTestCase(TestCase):
        def test_put(self):
            lru = LRU()
            lru.put("monjudoh", "monju")
            self.assertEquals(lru.get("monjudoh"), "monju")
    
        def test_multi_put(self):
            lru = LRU()
            lru.put("monjudoh", "monju")
            self.assertEquals(lru.get("monjudoh"), "monju")
            lru.put("monjudoh", "monju2")
            self.assertEquals(lru.get("monjudoh"), "monju2")
            self.assertEquals(len(lru), 1)
    
        def test_loss(self):
            lru = LRU()
            lru.put("monjudoh", "monju1")
            lru.put("ian", "monju2")
            lru.put("test", "monju3")
            self.assertEquals(lru.get("monjudoh"), None)
    
        def test_use(self):
            lru = LRU()
            lru.put("monjudoh", "monju1")
            lru.put("ian", "monju2")
            self.assertEquals(lru.get("monjudoh"), "monju1")
            lru.put("test", "monju3")
            self.assertEquals(lru.get("ian"), None)
            self.assertEquals(lru.get("monjudoh"), "monju1")
    
        def test_size(self):
            lru = LRU(size=4)
            lru.put("monjudoh", "monju1")
            self.assertEquals(len(lru), 1)
            lru.put("ian", "monju2")
            self.assertEquals(len(lru), 2)
            lru.put("test", "monju3")
            self.assertEquals(len(lru), 3)
            lru.put("test2", "monju4")
            self.assertEquals(len(lru), 4)
            lru.put("test3", "monju5")
            self.assertEquals(len(lru), 4)
            lru.put("test5", "monju6")
    
        def test_bigger(self):
            lru = LRU(size=4)
            lru.put("monjudoh", "monju1")
            lru.put("ian", "monju2")
            lru.put("test", "monju3")
            self.assertEquals(lru.get("monjudoh"), "monju1")
            lru.put("test2", "monju4")
            lru.put("test3", "monju5")
            self.assertEquals(lru.get("ian"), None)
            self.assertEquals(lru.get("test"), "monju3")
            self.assertEquals(lru.get("test2"),"monju4")
            self.assertEquals(lru.get("test3"),"monju5")
    
    Send feedback このエントリーを含むはてなブックマーク はてなブックマーク - BPStudy #29 テスト駆動開発
  • mercurialで、インメモリで、勝手チェンジセットをコミットする方法

    mercurial はpythonで書かれて、わかりやすいAPIを用意しているので、触りたいと思って、インメモリでコミットをしようとするとどうすればいいかというのを調べてみた。

    mercurialは、リポジトリオブジェクト(localrepository)があって、そのしたに、チェンジコンテキスト(changectx)がって、その下に、ファイルコンテキスト(filectx)があると言う仕組みになる。触るのが意外と簡単です。

    普段のmercurialはディスクにあるファイルの処理をするんですけども、インメモリの処理をするために、memctxと、memfilectx のインメモリチェンジコンテキストとファイルコンテキストが用意してあります。

    勝手コミットをするとこうなります。

    それで、hg update たたくと、新しいファイルができました。

    $ hg update
    1 files updated, 0 files merged, 0 files removed, 0 files unresolved

    ファイルの更新は同じく新しいファイルの内容を渡せば、勝手にdiffしてくれます。

    Send feedback このエントリーを含むはてなブックマーク はてなブックマーク - mercurialで、インメモリで、勝手チェンジセットをコミットする方法
  • 働くのをやめた人たち

    今日、MiCHiLU がこのリンクをTwitter に投稿した >> 働くことをやめた人たち 。いわゆるニートの話だけど、お金が困ったら、振込してもらったり、お腹空いたら、ご飯を奢ってもらったり、するという。

    それを見たら、そういう生活はどうだろうと思いました。生きていけるお金があるだけで満足する人はどうしても、「怠け者」だと僕は思う。もし、会社のため、お金のために働くのが、哲学的に自分に合わないと思うなら、運が向かない人たちのため、貧乏の人たちのため、体が不自由の人たちのため、社会の改善のため、平等のため、働く理由がたくさんたくさんあると思います。

    仕事は会社で「毎日嫌なことをやり続ける」ということではないと思う。人生は生きている時間だと思っています。それで、仕事は人生の中に行う実績だと思っています。生きていけるだけで満足するのがあまりにももったいないと思うので、目的を探して、非営利の仕事(ホームレス施設で働くのとか)しても、自分の会社を作っても、自分で決めて何でもいいので、満足せず何かをして欲しいと思っている。実績が出ないと、生きている時間をくれた意味がありませんから。

    と思いますけど、みんなはどう思いますか? 気になったら、意見をください。

    Send feedback このエントリーを含むはてなブックマーク はてなブックマーク - 働くのをやめた人たち
  • pytyrantはpython-tokyotyrantよりずっと速い

    夏のPython温泉Bob様が作ってくれたピュアーパイソンクライアントpytyrant酒徳さんpython-tokyotyrantより速いという話を聴いたとmoriyoshiさんに言った。それで、moriyoshiさんはprofileのテストを作ってくれたけど、結果として、pytyrantとpython-tokyotyrantはあまり変わらないのが出た。

    でも、このコードは一つのスレッドでテストしている。複数のクライアントが同時に接続している場合はどうかと思って、今日テストを作ってみた。

    これを実行するとpytyrantのほうがずっと速い.

    python-tokyotyrant
    ********************
    Running 20 threads took 6.755 seconds
    Running 20 threads took 5.392 seconds
    Running 20 threads took 5.516 seconds
    Running 20 threads took 27.191 seconds
    Running 20 threads took 30.575 seconds
    Running 20 threads took 34.699 seconds
    pytyrant
    ********************
    Running 20 threads took 1.748 seconds
    Running 20 threads took 1.736 seconds
    Running 20 threads took 1.716 seconds
    Running 20 threads took 8.922 seconds
    Running 20 threads took 8.716 seconds
    Running 20 threads took 8.746 seconds
    理由が分からないけども、python-tokyotyrantはPyRexを使ったわけですかね?
    Send feedback このエントリーを含むはてなブックマーク はてなブックマーク - pytyrantはpython-tokyotyrantよりずっと速い
  • Django modelformset_factory便利

    Django は複数のフォームのデータを同時に扱えるために、FormSetsというものを用意しているんですけど、実は、ModelFormのFormSetでも使える。クエリーの結果のデータのModelFormを一個一個、一つのページに出すにはこんなコードを書ける。

    from django.forms.models import modelformset_factory
    
    formset = modelformset_factory(
        MyModel,
        fields=('status','content'),
        extra=0,
    )(queryset=MyModel.objects.filter(status=1))
    

    便利

    Send feedback このエントリーを含むはてなブックマーク はてなブックマーク - Django modelformset_factory便利
  • daemontoolsを使ってdjango fastcgiのデーモンを設定する

    daemontoolsの上にdjango fastcgiを使うのは簡単にできるけど、正しいユーザとして、フォアグラウンドに起動するにはbashとdaemontoolsの設定する必要がある。

    フォアグラウンドに起動するには、daemonize=falseを指定する必要がある。

    それで、起動するデイモンはユーザを指定するオプションがないとrootユーザとして、起動する。runfcgi はそういうオプションがないので、daemontools の setuidgid ツールを使う。

    setuidgidのコマンドになるので、プロセスの標準パイプを正しく接続するには、bashのexecコマンドを使う。

    /service/myapp/run

    #!/bin/bash
    
    BASEDIR="/home/www/"
    PIDFILE="$BASEDIR/app.pid"
    
    exec setuidgid www python /home/www/django-prj/manage.py runfcgi \
        --settings=settings_production method=threaded  port=8001 \
        pidfile=$PIDFILE daemonize=false 2>&1
    
    Send feedback このエントリーを含むはてなブックマーク はてなブックマーク - daemontoolsを使ってdjango fastcgiのデーモンを設定する
  • PHPの empty値の話

    社内チャットで、PHPの NULL、"0"、FALSE、array(), ""の扱い方について、話があった。PHP爆発しろという結論が相変わらず出てきた。

    [14:25:02] key: 互換性維持のため
    [14:25:18] key: 空の比較ならempty使うべし、と思った。<マニュアル読んだ感想文
    [14:25:30] key: http://jp.php.net/empty
    [14:25:37] key: 次のような値は空であると考えられます。:
    
    "" (空文字列)
    0 (0 は整数)
    "0" (0は文字列)
    NULL
    FALSE
    array() (空の配列)
    var $var;(変数が宣言されているが、クラスの中で値が設定されていない)
    [14:27:51] key: アタマが痛くなりそうなbad know howすぎる
    [14:27:52] tokibito: え
    [14:28:17] tokibito: "0"
    [14:28:21] tokibito: trueになんの
    [14:29:27] key: php -r 'var_dump("0" == true);'
    [14:29:30] key: bool(false)
    [14:29:34] key: ならない
    [14:29:39] tokibito: <?php
    $i = "0";
    var_dump(empty($i));
    ?>
    [14:29:40] Ian Lewis: それは仕様なんですよ。
    [14:29:47] tokibito: true
    [14:30:02] Ian Lewis: "0" == false == ""
    [14:30:06] Ian Lewis: なんだけど、
    [14:30:13] Ian Lewis: "0" != ""
    [14:30:21] Ian Lewis: そうなんですよ!
    [14:30:25] key: キモイ!
    [14:31:13] Ian Lewis: transitiveじゃない
    [14:31:31] Ian Lewis: "0" == false == "" == ??? ??????爆発
    

    実は、javascriptと同じく、 === を使わなくちゃだめなんですけど、値を直接に if 文に入れると != trueみたいな一貫性が全然ない処理を行ってしまって、結構バグが出やすい現象だね。

    Send feedback このエントリーを含むはてなブックマーク はてなブックマーク - PHPの empty値の話
  • mercurial でアクティブなブランチのみを表示する方法

    merucurial の hg branchesっていうコマンドを打つと、inactiveブランチが普段に出てうるさいので、表示しないようにしてみた。これを .hgrc に追加した

    [alias]
    branches = branches -a
    

    普通は、この表示になる

    ian@laptop:~/src/prj$ hg branches
    default                     1662:1fa310d3052a
    hoge                        1661:62d737e7146e
    hoge_inactive               1623:ba27ba59a257 (inactive)
    hoge_closed                 670:1c3134ca4a95 (closed)
    

    修正後に、hg branchesを叩くと、綺麗にでる。

    ian@laptop:~/src/prj$ hg branches
    default                     1662:1fa310d3052a
    hoge                        1661:62d737e7146e
    
    Send feedback このエントリーを含むはてなブックマーク はてなブックマーク - mercurial でアクティブなブランチのみを表示する方法
  • Scalaの勉強

    今日は Scala ハッカソン にいけなくて、せっかくなので、Scalaをちょっと勉強しようと思って、インストールしてみた。Scalaは Python, Rubyみたいに、関数型プログラミングができて、JavaのJVMの上に動く言語ので、可能性が結構広く見える。俺だって、Scalaさえあれば、Javaで頑張る気がないと思う。

    基本的なところから始まるんですが、気になったところから、書いておこう。

    Scalaは変数を定義する方法が二つある、val と varで定義する。定数は val で定義して、変数は var で定義する。valで定義したのを変更しようとしたらエラーがでる。

    scala> val my_constant = "定数"
    my_constant: java.lang.String = 定数
    
    scala> var my_variable = "変数"
    my_variable: java.lang.String = 変数
    
    scala> my_constant = "変更"
    <console>:6: error: not found: value my_constant
    val synthvar$0 = my_constant;
                     ^
    <console>:4: error: not found: value my_constant
           my_constant = "変更"
           ^
    

    配列のアイテムは ()で取る。

    scala> var my_list = new Array[String](3)
    my_list: Array[String] = Array(null, null, null)
    
    scala> my_list(0) = "my_list 1"
    
    scala> my_list(1) = "my_list 2"
    
    scala> my_list(2) = "my_list 3"
    
    scala> my_list(1)
    res4: String = my_list 2
    

    Scalaでは、無名関数を定義することができる。pythonの lambda と似ていること。でも、無名関数を変数として、保存できないみたい。関数の引数だけに使えるみたい。

    scala> my_list.foreach(value => println(value))
    my_list 1
    my_list 2
    my_list 3
    
    scala> my_list.foreach(value => println(value))
    my_list 1
    my_list 2
    my_list 3
    

    メソッドは def で定義する。引数のタイプは ':' で定義しないといけないけど、返すデータのタイプは大体分かってくれる。下のリターンタイプは Intと割り出してくれた。リターン値は関数の最後の文の値になる。

    scala> def my_func(value:Int) = if (value > 10) value else 10
    my_func: (Int)Int
    
    scala> my_func(123)
    res6: Int = 123
    
    scala> my_func(5)
    res7: Int = 10
    

    リターンタイプを手動で定義する場合は、こう書けばいい。引数の定義の後に、コロンを付けて、その後にリターンタイプを定義する。

    scala> def my_func(value:Int): Int = if (value > 10) value else 10
    my_func: (Int)Int
    

    具体的なプログラムを書こうと思って、この間のPythonハッカソンで id:yuroyoro さんが発表してくれたscala の twitterクライアント (python ハッカソンなのになぜかscalaの話)をもとにして、atnd.orgのイベントの参加者リストを返すプログラムを作った。。

    import scala.xml._
    import scala.io.Source
    
    //1627
    object AtndClient {
        def main(args: Array[String]) {
            val url =
                "http://api.atnd.org/events/users/?event_id=%s".format(args.first)
            (XML.loadString(
                    Source.fromURL(url, "utf-8").getLines.mkString) \\ "user"
            ).foreach(
                user =>
                    println((user \\ "nickname")(0).child.text)
            )
        }
    }
    AtndClient.main(args)
    // vim: set ts=4 sw=4 et:
    
    Send feedback このエントリーを含むはてなブックマーク はてなブックマーク - Scalaの勉強