祢占堂

はい

やましろ先生がアヘ顔ダブルピースで溶鉱炉に沈んでから 2 ヶ月が経った #ymsr

はい

f:id:drillbits:20140216144623j:plain

死にました

詳細は割愛します。死んだので送別会をしました。

f:id:drillbits:20140216144914j:plain

渋谷の北海道ではなく、なんか水の上の良いところでやりました。

これでもし、やましろ先生が

こんな感じで出てきても川に落として殺すことで送別会が成り立って便利、みたいな話をしてました。

思い出

一緒に仕事したこととかないんですけど、それ以外のところにはだいたい彼がいました。

  • 最初に参加した Twitter オフ
  • モンハンオフ/合宿
  • java-ja との出会い
  • その他様々なオフや勉強会

特に java-ja との出会いはエンジニアコミュニティとの出会いであり、転職のきっかけであり、つまりは年収 2 倍です。まあ会場には ymsr 先生のおかげで 3 倍になった人もいた。

心情

人見知りなぼくが勉強会とかで壁役をしてると、たいてい彼がやってきて「Twitter にあるまじきイケメンです」とか「java-ja にあるまじきイケメンです」とか言って誰かに紹介してくれました。

ぼくがそっちに行ったときにも、その勢いで紹介していただいてあの世での地位を築いていきたい。

まだ行かないけど。

ありがとう、やましろ先生。これからもよろしく。

こちらからは以上です。

NHK 番組表 API を触る為の Python クライアント作った

はい

有給とったはいいけど自宅の空調から異音がして全取っ替えを頼んだら 5 時間近く立ち会いでどこにも行けず暇になったので作った。

使い方は README を、API の詳細は公式ドキュメントを読めばいいと思う。例によって Python 3.3 じゃないと動きません。

その他

実装的にはたいしたことやらないので雑多なこと色々やった。

バージョン番号の埋め込み

setup.py の setup 関数に指定するやつ、普通はそのまま書くけど、 SQLAlchemy のこれパクって nhk.__version__ で参照できる番号と同じになるようにした。便利かどうかはよくわからない。

egg じゃなくて wheel で配布するようにした

2014 年なんで。

$ pip install wheel
$ python setup.py bdist_wheel upload

drone.io 使った

テストするのに API KEY 必要なので、テストコードで環境変数をみるようにして drone.io 使うようにした。

Builds | nhk-api

drone.io のスクリプトはこんなの。

pip install -e .[testing]
python setup.py test
pip install wheel
python setup.py sdist bdist_wheel

環境変数 NHK_API_KEY は drone.io の設定の Environment Variables ってとこに入れる。

でもこれ普通に API 利用回数消費するので実行しすぎるとテスト全部失敗することになる。。。

ResourceWarning 出てるけど放置した

Build #3 | nhk-api
なんか出てるけど直してない。

ResourceWarning in python 3.2+ · Issue #1882 · kennethreitz/requests · GitHub
これかなー。

実用性

自作の録画サーバーに組み込んで使うかというと、

  • 民法には同様の API がない
  • API の仕様上 2 日分 しか取得できない(従来の epg 取得方法なら 1 週間ぐらい)
  • NHK だけ特別扱いして実装するのがだるい
  • オフラインでも動作するようにしたい

使わないと思います。

追記



Python and Alchemy - Python Advent Calendar 2013

この記事は Python Advent Calendar 2013 のアレです。

Python には SQLAlchemy をはじめ、錬金術由来の名を持つパッケージがたくさんある。適当に列挙する。

SQLAlchemy

アルケミーすなわち錬金術。

Python では SQL ツールキットおよび ORM のライブラリ。

Mercurial

水銀。錬金術におけるもっとも重要な三原質のうちのひとつ。

Python では分散型バージョン管理システム

Flask

フラスコ。実験道具。

Python では軽量なウェッブアプリケーションフレームワーク

alembic

蒸留器。

SQLAlchemy の作者が作ったデータベースマイグレーションツール。

Pelican

蒸留器のひとつ。形がペリカンに似ていることからそう呼ばれた。または金星のシンボル。

Python では静的サイトのジェネレーター。

Elixir

エリクサー、エリクシール、霊薬であり万能薬。賢者の石と同一あるいはそこから作成される液体。

最近は言語のほうが有名だけど、こっちは ORM というか SQLAlchemy のラッパー。開発はたぶん止まってる。

なんでそんなに錬金術用語が多いのか

たぶん Python が蛇だから。蛇というのは錬金術では重要なシンボルで、よくみるのはウロボロスっていう自分の尾を噛んで環になってる蛇(有翼の竜とされることもある)。

鋼の錬金術師とかにもでてくる。ていうか PyPy のロゴがまさにそれ。

他にも、十字架にかけられた蛇が賢者の石を表していたりする。

そもそも錬金術とは

化学以前に存在した、卑金属を貴金属(黄金)に変えて一攫千金メイクマネー秒速1億センチメートルなやつ、とかじゃない。

黄金とは完全な物質、完全な精神のことであり、非金属を変成させて黄金を得るというのは、不完全な人間を完全な存在に変えるプロセスが婉曲的に表現されたもので、こっちのほうが夢がある*1

錬金術では「一なるもの(第一質量)」が変化して様々な存在になるとされていて、その変化に携わるのが「乾 ・ 湿 ・ 熱 ・ 冷」という属性。

その第一質量と属性を結びつけるのが「エーテル」とか「第五元素」「プネウマ」で、それを操ることができれば物質を自由に錬成することができる。で、それをうまいこと抽出して集めたものが賢者の石とか呼ばれる。

錬金術とシンボル

錬金術の文献には数多くのシンボルが使われてる。

錬金術の実験とか知識は非キリスト的なやつだったので、弾圧をのがれたりするために、そういうシンボルとか暗号で技術を伝承していった。オープンソースだけど歴史的経緯を知らないと誰も読めないみたいな感じになってる。

そのうちのひとつが蛇。有翼のやつは水銀、無翼なやつは硫黄を表してて、争っている絵は化学反応を象徴してる。だから Python のロゴにも蛇が二匹いるのかもしれない。

錬金術の変成過程には必ず「黒化(死・腐敗)」「白化(復活・浄化)」「赤化(完成)」がある。ウロボロスはこの死と再生のイメージをもってる。あとその円環構造が全一思想という「全が一を作り、一は全に影響を与える」というのも表してる。

まとめ

Pelican のドキュメントにはこう書かれてる。

「ペリカン」という名前の由来

フランス語で「notebook」という意味の「calepin」のアナグラムだよ。

Why the name “Pelican”?

錬金術まったく関係ない。

他のパッケージについても、錬金術に言及してるテキストとかないっぽいし、単にプログラマが錬金術とか魔術とか好きなだけという感じがする。

真相はぼくよりもっと長く Python 使ってるおじさんたちのが知ってそう。

Next Advent は Hi_king 氏です。

*1:ただ、黄金の錬成は副産物だけど、でも無意味というわけではなくて、それはそれで大切な作業だった。大いなる作業。物質的かつ霊的作業。

ミラクルライト作った - プリキュア Advent Calendar 2013 #cure_advent

この記事はプリキュア Advent Calendar 2013のやつです。

大きなお友達は基本的にミラクルライトもらえないみたいなので Python で作った。プリキュアに力を与えてテストを実行する。

pypi: https://pypi.python.org/pypi/miraclelight
github: https://github.com/drillbits/miraclelight

$ pip install miraclelight

これで miraclelight コマンドができるけど、今回はテスト用意するのめんどくさいのでリポジトリに入ってるサンプルのテストを実行する。

$ git clone git@github.com:drillbits/miraclelight.git
$ cd miraclelight
$ python setup.py install
$ tree
.
├── README.rst
├── setup.py
├── src
│   └── miraclelight
│       └── __init__.py
└── tests
    ├── __init__.py
    └── test_sample.py

3 directories, 5 files

カレントディレクトリに Python の unittest が discover してくれそうなやつがあるので、そのまま実行すればいい。*1

$ miraclelight

実行すると、このように表示されて止まる。

ライトをふって プリキュアを おうえんしてね!(Press enter, enter, enter)
( ^q^)ノシ

このままだとテストは永久に実行されず、プロジェクトは崩壊し、世界が砂漠になってもうダメです。

エンターキーを連打してプリキュアを応援しましょう。

10 エンターで 1 テストケース倒せる。

このテストランナーを使うと Jenkins で自動的に定期テストとかいっさいできなくなるけど、そんな人任せじゃダメだと思う。年末あたりに滅びかける世界は救えないと思う。「みんなで力を合わせれば不可能はない」とプリキュア 5 つの誓いの 6 つ目にもある。

がんばってすべてのテストを倒そう。

技術的な話

基本的には標準の unittest 拡張しただけだけど、普通にエンター入力すると改行されてしまうので、こんな感じで防いでる。

import fcntl
import os
import sys
import termios

fd = sys.stdin.fileno()

oldterm = termios.tcgetattr(fd)
newattr = termios.tcgetattr(fd)
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(fd, termios.TCSANOW, newattr)

oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)

try:
    c = sys.stdin.read(1)
finally:
    termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
    fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)

参考: http://stackoverflow.com/a/5004022

*1:ちなみに開始ディレクトリを指定したい場合は unittest と同じで miraclelight discover -s などとする。

Django + MySQL 5.5 でモデルオブジェクトの datetime の値が生成時と生成後で変わる

class Diavolo(models.Model):
    ctime = models.DateTimeField(auto_now_add=True)

っていう生成時に現在日時を自動的に保存してくれるやつを作るじゃないですか。

>>> d1 = Diavolo.objects.create()
>>> d2 = Diavolo.objects.get(pk=d1.pk)
>>> d1.ctime == d2.ctime
False

はい。

>>> d1.ctime
datetime.datetime(2013, 10, 25, 13, 32, 25, 244575)
>>> d2.ctime
datetime.datetime(2013, 10, 25, 13, 32, 25)

つらい。

MySQL を使っている場合、Django の ORM は models.DateTimeField を MySQL の TIMESTAMP 型として扱うけど、MySQL 5.5 はマイクロ秒をサポートしてない。

でも Model.objects.create() の戻り値のオブジェクトは INSERT するために生成されたやつなので、この時点ではマイクロ秒がそのまま残ってる。

対して、改めてデータベースから取得したやつは truncate されてる。なので

class DiavoloMapper(ModelMapper):
    class Meta:
        model = Diavolo

def get_diavolo_as_dict(id):
    obj = Diavolo.objects.get(pk=id)
    return DiavoloMapper(obj).as_dict()

みんな大好き bpmappers を使ったこんな Mapper があったとして、こういうテスト書くと落ちる。

from testfixtures import compare

class TestGetDiavoloAsDict(TestCase):
    def _getTarget(self):
        from mappers import get_diavolo_as_dict
        return get_diavolo_as_dict

    def _callFUT(self, id):
        func = self._getTarget()
        return func(id)

    def test_one(self):
        obj = Diavolo.objects.create(pk=1)
        dct = self._callFUT(id=1)

        compare(dct, dict(id=1, ctime=obj.ctime))

なので obj じゃなくて改めてモデルオブジェクトを取得してくるか、マイクロ秒を切り取るかしないといけない。まあ ctime みたいな auto_now_add されるやつはいっそテストしなくてもいいけど。

ちなみにローカルで sqlite 使ってたりするとこのテスト通る。こわいですね。

flake8 で Python のコードをチェックするときにオプションを渡すやつ

いつの間にか pep8 の 79 文字制限のところがゆるくなってたのを教えてもらった。

チーム内で合意がとれるならまあいいんじゃね、的な感じ。

はい

flake8 という便利なやつがこれをチェックしてくれるけど、デフォルトは 79 文字なので引数とか設定ファイルで文字数を変えてやる必要がある。

Jenkins とかのビルドサーバーなら、コマンドに引数でいいんだけど、ローカルでチェックしたいときちょっとだるい。

http://flake8.readthedocs.org/en/latest/config.html#global

[flake8]
max-line-length = 99

こういうのを ~/.config/flake8 に置けばいいけど、これだとチームごとに max-line-length とか違う場合に対応できない。

~/.config/flake8 というパスは flake8 の --config オプションで変えられるけど、vimrc で保存時に自動チェックするようにしてるので、動的に今いるプロジェクトの config のパスを与えるのがよくわからない。

autocmd FileType python autocmd BufWritePost <buffer> :!flake8 %

と思ってたら

setup.cfg でできた。~/.config/flake8 と同じ記法でプロジェクトのルートに置けばいい。setup.py も tox.ini もないプロジェクトあるのでどうかと思ってたんだけど、setup.py なくても setup.cfg で問題なかった。

http://flake8.readthedocs.org/en/latest/config.html#per-project

あと

flake8 はチェックをスルー死体業したい行に # NOQA って書くと無視してくれて便利。あまり使わないけど、Django の settings を階層化するのはよくやるので、そのときにはないと死ぬ。

おまけ

プリキュアハッカソンで pycure 作った

プリキュアハッカソンは普通に映画館に参戦すると事案が発生してしまう大友たちがDVDでプリキュア映画を鑑賞しつつプログラミングするやつです。

ほとんどの人が映画に夢中でコードを書かない中、めずらしくまじめにハッカソンしてたらできた。映画もちゃんと見ました。

pypi: https://pypi.python.org/pypi/pycure
github: https://github.com/drillbits/pycure

Acme::PrettyCure インスパイアードです。

$ pip install pycure

コマンド化してないので任意の対話シェルを起動するなどして動かす。

from pycure import Precure
p = Precure.now
p.title
# -> 'ドキドキ!プリキュア'
p.girls[0].name
# -> '相田マナ'
p.girls[0].transform()
# みなぎる愛! キュアハート!
# 愛を無くした悲しいジコチューさん、このキュアハートがあなたのドキドキ取り戻してみせる!
# 問答無用で以上が標準出力される
p.girls[0].name
# -> 'キュアハート'
# 名前が変更されてる

ちなみに変身から元に戻る関数は未実装です。

任意のプリキュアシリーズを取得したい場合は以下のような感じ。

from pycure import Precure
Precure.slugs
# -> ['', 'maxheart', 'splashstar', 'yes', 'gogo', 'fresh', 'heartcatch', 'suite', 'smile', 'dokidoki']
p = Precure["smile"]
# Precure は OrderedDict の拡張なのでキーを指定して取得
p.girls[2].name
# -> '黄瀬やよい'
p.girls[2].transform()
# ピカピカピカリンジャンケンポン! キュアピース!

ちなみにジャンケンができる機能は未実装です。

あと Acme 版と同じ仕様で、初代が変身する場合は相手の名前が引数に必要。

from pycure import Precure
p = Precure[""]
# 無印なので空文字がキー
p.title
# -> 'ふたりはプリキュア'
p.girls[0].name
# -> '美墨なぎさ'
p.girls[1].name
# -> '雪城ほのか'
p.girls[0].transform()
# pycure.girl.PartnerInvalidError になる
p.girls[0].transform("雪城ほのか")
# 光の使者、キュアブラック!
# 光の使者、キュアホワイト!
# ふたりはプリキュア!
# 闇の力のしもべ達よ!
# とっととお家に帰りなさい!
p.girls[0].name
# -> 'キュアブラック'
p.girls[1].name
# -> 'キュアホワイト'
# こちらも変身状態になってる

MaxHeart の強化フォームとかキュアエコーとか色々追加してないのある。

こちらからは以上です。