2014年9月17日水曜日

PyCon JP 2014の2日目に参加してきた

遅くなってしまいましたが2日目です。1日目のレポートの続き。タイムテーブルはこちら

Poster Session

今年からJob Fairというのが始まったようで、午前中Speakerセッションがなかったので、Poster Sessionを聞きに行きました。

Sphinxの中の方々がいらっしゃって、少しお話できました。Sphinxには仕事でお世話になっているので、近いうち自分からも事例報告のようなことができたらな、と思っています。

それから昨日一番早い時間の発表でDeep Learningのお話をしていたTanakaさんがプロジェクト・マーという別のプロジェクトをやってらっしゃるそうで、少しお邪魔しました。月面などの写真から、人面の部分を機械学習を使って発見するそうです。研究室時代に人工衛星で地上を撮影した狭い範囲の写真から、Google Mapで緯度経度を見つけてくる泥臭い作業をやっていたのを思い出してしまいました。Deep Learningなんかで人の顔写真を学習データとしてマッチングを行うと精度がよすぎるので、むしろある程度ノイズを載せてあげたほうが、宇宙人みたいな顔が見つけられて面白いらしいです。わかります、ロマンは人を動かす。

Oktavia - Search Engine 

Oktaviaというサーチエンジンを開発されている方のお話。Sphinxのドキュメントサーチを置き換えるのがプロジェクトの目標だそう。基本的に現存するサーチエンジンの多くは転置インデックス方式なんですが、FMインデックスという手法を使うことで検索の高速化をはかっています。以前情報検索アルゴリズムを勉強し際にちょっと触れたことがあるんですが、すっかり忘れてしまっていたので再勉強が必要そうです。発表でも共有されていた、高速文字列解析の世界(PFIの岡野原さんの著書です)、こちらも良さげですね。




パッケージングの今

毎年似たような内容で発表されているそう。pythonにはsetuptoolsを入れると使えるeasy_installとpipがありますが、そのあたりのお話。

これまで、pipを入れるためには先にez_setup.pyからsetuptoolsのインストールが必要でしたが、いまはget-pip.pyというので直接pipがインストールできるそうです。また、python3.4だと標準でpipがインストールされるんだとか。setuptoolsはいらない子やったんや!\(^o^)/

あとは自分で作ったライブラリなどのパッケージングのやり方も紹介してくださいました。ちょうど今作っているプロダクトの一部を切り離してライブラリにしようと考えていたのでとてもありがたいお話でした。



正規表現リテラルは本当に必要なのか?

pythonにもsedで書かれるようなs/original/replace/gのような正規表現リテラルを導入したほうが良いのか?という問題提起のお話で、とても身近な話なので大変聴きやすく、面白かったです。perlやjavascriptなんかでは文字列リテラルが使えるわけですが、pythonにも必要なのでしょうか?誰しもこれがあればもっと楽に書けるのに、といった経験はあるのではないでしょうか。スピーカーの方がおっしゃってたように、言語仕様が複雑になってしまうという大きなデメリットがあるし、自分のユースケースの場合現状の文字列関数でさほど苦労していなかったり、Pythonで文字列処理をする場合はほかのコマンドで処理したものを入力したりするためにあまり困ることがないので、個人的には必要ないと思っています。

それから、reモジュールを使う際、何度も使う正規表現はre.compileによって先にpatternをコンパイルしておく、という使い方をしますが、これはre.searchで毎回正規表現を指定すると何度もコンパイルが走って無駄だからと思っておりました。しかし内部の実装を見ると、re.searchやre.matchで_compileというメソッドを呼び出しており、これは
def _compile(*key):
    cachekey = (type(key[0]),) + key
    p = _cache.get(cachekey)
    // 以下略

となっています。すなわち、基本的にキャッシュが効くので内部で明示的にre.compileと同じように処理されるわけです。これは目から鱗でした。ただ、当然キャッシュが増えすぎるとパージが発生してしまい、compileの処理だけでなくキャッシュに対するIOのオーバーヘッドが大きくなるので気をつける必要があります。


ということで総括すると、今年は去年以上に持ち帰るものが多かったPyConでした。

最後のLTから写真撮影、抽選会(なんとPepperくんが当選番号を選んでくれる!!)まで終始アットホームな雰囲気でした。2年連続して参加してみると主催側の人の顔ぶれもわかってきたりしてより身近に感じられます。来年も、必ずいきます!

2014年9月13日土曜日

PyCon JP 2014の1日目に参加してきた

PyConは去年に引き続き2年目の参加。聴講したセッションの中で気になったものをあげてみます。ちなみにカンファレンスのタイムテーブルはこちら

(2014/09/15 発表資料など公開されたものを追加)

KeyNote


herokuのKenneth Reitzさん。自己紹介の途中で入ってきたのでわからなかったんですが、あとから見てみると、今やこれなしではやっていけないPythonのデファクトHTTPライブラリであるrequestsの開発者さんらしいです。お世話になっています。

スライドがオシャレなんですよね。デザインからフォントから。聞き入ってしまいました。Simple is better than complex. Complex is better than complicated.うんうん、同感。

何の話が肝なのかな、と聞いてたら、Python2とPython3の話題に。会場の人でそれぞれ使っている人、挙手してくださいっていうのがあったんですが、ざっと見2:1ぐらいに見えました。でも、ライブラリのダウンロード数の統計では、数10:1とかの割合だそうです。圧倒的Python2の強さ。

プレゼンのまとめとしては、みんなのPython2/Python3に対する意見をどんどんシェアしてくれってことでした。自分はPython3を入れたら使えないライブラリがあったりして、即アンインストールしてしまったクチです。すみません。。今はvirtualenvなんかが充実してるので、これを期にもう一度インストールしてみます。

そんなスピーカーさん曰く、Python3のBenefitは?と聞かれたら、No Benefit.と即答(苦笑)

ちなみに去年はdropboxの中の人が基調講演されてたんですが、そちらも面白かった。基調講演だけでも十分満足できる、それがPyConなんです。

ご本人がほかのカンファレンスで発表された同じ資料が上がってました。

Deep Learning for Image Recognition in Python 

これが今日の発表の中で一番面白かった発表。DeepLearningの技術的な話というより使ってみた、という話なんですが、OpenCVで顔認識してそれを分類してみる、という、まさに自分が研究室時代に同期と作っていたWebアプリに近しいものがあって、すごく楽しく聞かせてもらいました。

今を輝く某アイドルグループ48が出てきてその部分映像化禁止になったり、総合プロデューサーを今回のPyConのプラチナスポンサーでもあるソフトバンクのPepperくんにやらせようっていうやりたい放題なキャッチーな話題選びがナイス。Pepperくんに喋らせる言葉もセンスがあって、終始笑いの絶えない講演でした。

でも何より、Kaggleっていうデータマイニングのコンペサイトがあることが知れたのが自分としては一番の収穫。最近だとCodeIQでもデータ分析のカテゴリがあったりTopCoderでもそんな話題があったりしますが、こんな手軽に参加できるコンペサイトがあるんですね。これで悶々とデータ分析したいけど、ネタが見つからない日々とはおさらばできそう。


The esperanto generator

なんと現役中学1年生のスピーカーさん。若いエキスを吸って嫉妬するために聞いてみました。タイトルではEsperantoって銘打ってたけどオレオレ言語をつくろうっていう話でした。まさかのPythonコードを1行も書いてないっていう衝撃発表もあったけど、その本人の熱い思いみたいなところは会場の大人たちに伝わっていたんじゃないかなと思います。自分も中1のころはちょうどインターネットやプログラミングに対する興味・ワクワクが半端無くみなぎってた頃。それを思い出したんですが、それと同時に大人たちに紛れてその成果を発表しちゃおう、っていう姿勢に嫉妬です。今後の活動に期待してます。

PyCharm活用術

ずっとお会いしたかったSphinxの中の人、Shimizukawaさんの発表。お仕事ではSphinx、大変お世話になっております。SphinxのProposalもいっぱい出したけど何故かPyCharmの話が通ったとのことで、PyCharmの魅力を余すことなく教えていただきました。

自分もプライベートProjectでPyCharm使っているけど、無料版なのでリモートデバッグできなかったり、JSなどほかの言語とあんまり連携できてなかったりするんで、やっぱり有料版の購入検討したほうがいいかなぁ。そうなると全部入りのIntelliJを買うか・・。いつの時代も開発環境に関する悩みは尽きないです。


という感じでざっくりでしたが初日のレポートでした。

2014年5月15日木曜日

kickstarterのプロジェクトを紹介するブログをはじめてみる

http://kickstarter-navi.blogspot.jp/

クラウドファンディングサイト、kickstarterのプロジェクトを紹介するブログを始めました。Web業界に身を置く以上、常に最先端のテクノロジには触れておきたい、という大義名分はさておき、昔ながらのガジェオタ基質を奮い立たせるために、kickstarterのプロジェクトを紹介していくブログを初めてみました。

日本でもCAMPFIREなどのクラウドファンディングサイトが登場し始めていますが、まだまだシリコンバレーを中心に広がるクラウドファンディングの波には乗りきれていないと思います。もちろん英語も壁になっているでしょうが、それだけでなく、形がある商品のような場合余計に送料がかかるなど、kickstarterで出資するハードルは高いと思われます。ですので、そのあたりの不安を払拭するためのレポートなんかも掲載していけたらな、と、もやっとながら考えております。

とりあえずここと同じくてっとり早くbloggerで始めましたが、プロジェクト同士のつながりや、最新の出資額の表示ウィジェットを作ったりいろいろやってみたいので、そのうちWordpressなりに移行予定。

2014年5月13日火曜日

Windows7にsetuptoolsをインストールする際のエラー

Windows7にPython2.7をインストールした後、pipを使うためにまずsetuptools(easy_installコマンド)をインストールしようと思い、公式からez_setup.pyをとってきて実行、一瞬コマンドプロンプトが立ち上がって、無事インストール完了。と思いきや、easy_installが使えない。パスが通ってないかな?と思って確認するも、問題なし。。

ううむ、もう一度ez_setup.pyを実行してみると、一瞬、赤い文字が・・・。いやーな予感。。コマンドプロンプトからコマンドでez_setup.pyを実行してみたところ、以下のようなエラーがでていることを確認しました。

長らく使っているPythonを入れてこんな序盤で躓くとは思ってもいませんでした。


Python2.xにありがちなUnicodeのエラーが。でもなんでこんなところで出ているんでしょう?よく見ると、registryの文字が。どうやらレジストリ周りにUnicodeが含まれている疑いが。レジストリエディタを見てみたところ、以下のような怪しい文字列を発見。 


変な中華ソフトをインストールした記憶はないし、レジストリのキーにマルチバイト文字を入れるなんてけしからん、と思ってたのですが。いろいろ調べてみると、VLCが犯人であることが判明。UTF-16によるエンコーディングバグなのだとか。こういうバグを踏むことが多くてついてない今日このごろ。

とはいえレジストリのこんな特殊なキーを拾ってきてデコードエラーを吐くPythonもPythonだよなー、と思いつつも、なかなかPython3.x系に乗り換えられないのでした。

Versions

  • Windows 7 64bit
  • Python 2.7.6 x86-64
  • setuptools 3.6




2014年5月11日日曜日

pythonでファイルアップロードの進捗をリアルタイム取得する

pythonでサーバに対しurllib2やrequestsなどのモジュールでファイルをアップロードする場合、基本的に
urllib2.urlopen(request)

requests.post()
の形式で投げることになりますが、f.read()のような形で、引数としてファイル全体を与えてしまった場合、アップロードが完了するまで待たなければなりません。そのため、大きなファイルのアップロードなどでは特に、本当にアップロードが進んでいるのか知ることができず不便でした。

そこで、StringIOを使ってファイルをchunkに分割してロードできるようにし、read()が走るたびにコールバックを呼ぶようにしてやることで、アップロード中の進捗状況を知ることができるようになります。こちらを参考にしてStringIOを継承してコールバック関数を呼ぶためには、以下のように書けます。
from StringIO import StringIO
class BufferReader(StringIO):
    def __init__(self, buf='',
                 callback=None,
                 cb_args=(), cb_kwargs={}):
        self._callback = callback
        self._cli_manager = cli_manager
        self._progress = 0
        self._cb_args = cb_args
        self._cb_kwargs = cb_kwargs
        StringIO.__init__(self, buf)

    def __len__(self):
        return self.len

    def read(self, n=-1):
        chunk = StringIO.read(self, n)
        self._progress += int(len(chunk))
        self._cb_kwargs.update({'progress': self._progress})
        if self._callback:
            try:
                self._callback(*self._cb_args, **self._cb_kwargs)
            except Exception, e: # catches exception from the callback
                raise BaseException, e

これで、
req = urllib2.Request(url, BufferReader(f.read(), callback=callback_func))
res = urllib2.urlopen(req)
とすることでcallback_funcにファイルアップロードの進捗を渡すことが可能になります。

ただし、multipartによるPOSTでファイルをアップロードする場合には、requests.post(files={'file': (filename, BufferReader(filebuffer))})の形式ではStringIOを使っても上記のread()が正しくchunkごとに呼ばれないようです。この場合はurllib3のencode_multipart_formdata()を使ってあらかじめmultipart用のデータを作り、この結果をBufferReaderに噛ませたあとrequests.post(files=)に入れてやることでアップロードするなどの方法をとる必要があります。

2014年4月29日火曜日

seesaaからbloggerへ引っ越した

一昨日、とりあえず以前から使っていたseesaaブログで再開します。と言った矢先ですが、2日間ブログの投稿をしてみて管理画面の重さに辟易。今日アクセスしてみたら、ほかの方のseesaaブログもかなり重くアクセスできない状態が続いてイライラしていたのでBloggerにお引っ越ししました。

seesaaからBloggerに(少ない)記事をエクスポート・インポートしましたが、意外と簡単でした。

こちらを参考にさせていただきました。
seesaaはベースがMovableTypeですので、seesaaからMovableTypeのMT形式に変換。その後、seesaa独自のタイムタグを標準のタイムタグに書き換え、MTをBlogger用のXMLに変換するサイトでXMLを出力し、Bloggerからインポートするだけです。

Blogger少し使ってみた感覚ですが、編集画面がGoogleDocsと同じようなUIで使いやすいですね。とてもサクサクしています。あとはテンプレートも後々いじってみようと思います。

2014年4月27日日曜日

iTunesのライブラリデータ iTunes Music Library.xmlを読む

今作ろうとしているアプリに、iTunesのメタデータのインポート機能をもたせようと思っているので、試してみました。

iTunesの曲情報はすべてitlファイルというバイナリファイルに書かれていますが、同時にAppleの他の製品などから読み出しやすいように、xmlファイルも吐き出されるようになっています。このファイルはユーザごとに場所が決まっているようです。

http://support.apple.com/kb/HT1660?viewlocale=ja_JP

自分が使っているMac OSX 10.8.5と、iTunes 11.1.2というバージョンにおいては、iTunes Library.xmlではなくiTunes Music Library.xmlというファイル名になっていました。環境によって微妙に違いがあるのかな。

このファイルを見てみると、
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Major Version</key><integer>1</integer>
<key>Minor Version</key><integer>1</integer>

となっており、Appleの独自フォーマットPropertyListで定義されているようです。これはMac OSXでは一般的な.plistという拡張子のファイルで使われているフォーマットとなっています。

Wikipediaによると、辞書を
<dict>
<key>key</key>
<string>value</string>
</dict>

のような形式で保存するのが特徴のようです。

このファイルをPythonで扱うには、XMLをParseしないといけないかな、と思っていたんですが、ありました。plistlibというモジュール。しかもPython 2.6以上ではすべてのプラットフォームで標準で入っているようです。
import plistlib
import pprint

def read_itunes_xml():
pl = plistlib.readPlist('/Users/<username>/Music/iTunes/iTunes Music Library.xml')
pp = pprint.PrettyPrinter(indent=2)
print pp.pprint(pl)

このようにするだけで、簡単にiTunesライブラリのメタデータを表示することが出来ました。

pl['Tracks']の中には、すべての楽曲のAlbum, Artist, Bit RateなどのMP3タグを元にしたメタデータが入っています。

2014年4月26日土曜日

SeesaaでSyntaxハイライト

privateモードではてなブログをつけていた時期があって、はてなのシンタックスハイライターに慣れていたのですが、Seesaaには標準でこれがないらしいです。

なんとかできないものかと思ったのですが、google-code-prettifyが使えるそうです。
http://google-code-prettify.googlecode.com/

SeesaaではブログテンプレートのHTMLとCSSが編集できるので、これを導入してみようと思います。
JSとCSSの2ファイルがあればいいので、ダウンロードしてブログ内にホストしてもいいのですが、面倒なのでひとまずGoogleが書いているように以下のJSを読みこめば、すぐに使えるようになります。

デザイン > PC > デザイン設定 → HTML

から新しいHTMLテンプレートを作成します。

<script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script>

このままでもsyntax highlight自体は動きますが、フォントやサイズなど気に入らない部分をCSSの設定から変更します。

デザイン > PC > デザイン設定 → デザイン設定

から今選択しているテンプレート名をクリックすればCSSが編集できます。
当ブログでは以下のような設定を入れました。

pre{
line-height: 1.2;
font-family: Consolas, Monaco, Lucida Console, monospace;
overflow: auto;
border-radius: 3px;
}



Dropbox APIをPythonで使ってみた

pythonからユーザのDropbox内を閲覧したり、変更したりする方法を紹介します。
検索してみたところ、そもそも日本語の文献が少ないのと、最新のOAuth2.0に対応している資料が少なかったので記しておきます。

作りたいアプリがデスクトップアプリでファイルの操作を行うため今回はそのためのTipsとなりますが、サーバ上のWebアプリであっても基本的には同様の使い方ができるかと思います。

本当はBox.comを利用したかったのですが、DropboxはPythonからのAPIのアクセスができるような公式のフレームワークを準備してくれていることと、BoxのAPIは後に紹介するOAuthによるユーザ認可のプロセスが自動リダイレクトを想定しているため有効期限が30秒しか無いなど、デスクトップアプリからだと著しく使いにくくなるため、ひとまずDropboxを利用することに。

1. 作成するアプリケーションの登録


https://www.dropbox.com/developers/apps
からアプリケーションの登録をします。




DatastoresというのはDropboxをDBのように使ってしまうためのAPIみたいです。通常のDropboxアプリからWindowsやMacのファイルを共有させる用途で使うのであればCore APIが必要になりますので、Files and Datastoresを選択します。

登録が終わったらアプリ名の画面に行き、登録したアプリを選択します。

するとApp keyとApp secretが表示されるので、これらを後のAPIでの利用のために控えておきましょう。

2. Dropbox API Python SDKのダウンロード


pipを使っている方は、
pip install dropbox

で入ります。ダウンロードが必要な方はこちらからダウンロード
https://www.dropbox.com/developers/core/sdks/python

Dropboxのサイトからダウンロードした場合は、いくつかのExampleも同梱されています。

余談ですが、2013年のPyCon APACに参加した際、DropboxのエンジニアによるKeynoteがあったのですが、Dropboxでは至るところにPythonを使っているらしいです。デスクトップアプリすらもPython製だとか。

3. access_tokenの取得


ユーザが初めて作成サードパーティのDropboxアプリを利用する際には、TwitterやFacebookと同じようにユーザによる認証・認可が必要になります。

2014/4/16現在ではDropbox SDKのバージョンは2.0となっており、OAuth2.0を使うのが標準となっているようです。自分がOAuthを最後に触ったのがもう数年前でOAuth1.0の頃だったのですが、OAuth2.0ではSSLによる通信を必須にすることで、access_secretを設定しなくてもよくなっているそうです。

以下にコードを示します。
まず認可するためのURLを生成して、ユーザがこのURLにブラウザからアクセスし、今回作成したアプリの利用を許可してもらったあとに表示されるコードを入力してもらう、という流れになっています。Webアプリの場合は、このコードをDropboxのサイトからのリダイレクトで渡すことができるので、ユーザによるコピー&ペーストの手間を省くことができます。これをデスクトップアプリでやろうとすると、恐らく内部にブラウザを立てる必要がありそうです。

import dropbox

APP_KEY = '上で取得したAPP_KEY'
APP_SECRET = '上で取得したAPP_SECRET'

def get_access_token_from_dropbox():
    flow = dropbox.client.DropboxOAuth2FlowNoRedirect(APP_KEY, APP_SECRET)
    url = flow.start()
    print 'access to the url below and allow this application, then copy PIN on your browser.'
    print url
    print 'put PIN code here.'
    pin = raw_input()

user_meta = {}
(user_meta['access_token'], user_meta['username']) = flow.finish(pin)
return user_meta

ここで取得したaccess_tokenは、今回のApp keyのアプリからのアクセスの場合使いまわすことができますので、何らかの方法で永続化しておけばよいでしょう。

4. SDKを使ってファイルをアップロードしてみる


先ほど取得したアクセストークンを使って、DropboxClientのインスタンスを作ります。
PNGファイルを一つアップロードしてみましょう。

client = dropbox.client.DropboxClient(token)
with open('hoge.png', 'rb') as f:
    file_meta = client.put_file('/testtest.png', f.read(), overwrite=True)
    print file_meta

非常に簡単に書けることがわかります。

参考にしたサイト
http://dkpyn.com/blog/1182

ブログ再開します

Webエンジニアになって早2年。節目のタイミングで考えることもいろいろあるので、ブログを再開してみようと思います。
自宅サーバもあるのでホントはWordpressなどに移行したいところであるが、環境整備していたら満足してしまいそうなので、今回はカタチから入るのはよして手っ取り早く以前のブログを引き継ぐことにします。
みなさんよろしくお願いします。

今作りたいもののアイデアがあるので、その状況をアップデートしていくつもり。
細かいTipsなどはGistにでも書いてリンク貼ってきます。