github のプロジェクトにSphinxドキュメントを良さげな感じにおきたい 其の一
大分前にこんな感じの事をしたので、その時の覚え書き。githubで管理されているOSSなんかでは良く、下記のようなURLでドキュメントを公開しているプロジェクトがありますよね。
http://[account_name].github.com/[repository_name]/
- account_name(アカウント名)がサブドメイン
- repository_nameが対象のリポジトリ名
これどうやってんだろう?と思ってたのがきっかけです。以下手順を見てみましょう。前提として既にgithub上にリポジトリを持っていることとします。
GitHub Pagesを用意する
そもそも、上のURL体系でページが参照できるのは、Github Pagesのおかげのようなので、まずはこれを用意します。Github Pagesを利用していないリポジトリで上のようなURLにアクセスすると、ご丁寧にページの作り方が書いてあります。
この通りにやってみましょう。
$ cd /path/to/repo-name $ git symbolic-ref HEAD refs/heads/gh-pages $ rm .git/index $ git clean -fdx $ echo "My GitHub Page" > index.html $ git add . $ git commit -a -m "First pages commit" $ git push origin gh-pages
これを実行をすると何が起こるか簡単に言うと、本当に中身が空っぽなブランチを作ってるという事らしいです。
ブランチを切り替える
この時にブランチの状況はこのように masterとgh-pages の二つが作成されていて、カレントは「gh-pages」に向いています。
$ git branch * gh-pages master
「ls」を実行すると、index.htmlだけが存在しているのが確認できます。
$ ls index.html
この状態で、最初のURL体系でアクセスすると、"My GitHub Page" が見れると思います。やったね。
もとの master ブランチに移動したい時は下記のようにすると戻れます。
$ git checkout master Switched to branch 'master' $ git branch gh-pages * master
Sphinx ドキュメントを置いてみる
さて index.html だけでは寂しいので、Sphinxのドキュメントを「gh-pages」に置いてみましょう。
# とりあえずindex.htmlは消してpushしておく $ git checkout gh-pages $ git rm index.html $ git commit -m 'remove index.html' $ git push origin gh-pages # sphinxドキュメントを作成する $ sphinx-quickstart # 後は指示にしたがってお好みで作りましょう。 # ここでは、build ディレクトリと sourceディレクトリを分けた設定にしています。 $ tree . ├── Makefile ├── build └── source ├── _static ├── _templates ├── conf.py └── index.rst
Sphinxのプロジェクトが出来たらmake html しましょう。make html すると「build/html」にHTMLファイル群が作成されますが、それをそのまま gh-pagesにpushしてもドキュメントは表示されません。
gh-pages ブランチのルートが、Web上で表示する時のドキュメントルートになっている感じなので、作ったファイルをgh-pagesのルートにコピーしてやります。そしたらaddしてpushしましょう。
$ make html $ cp -pr build/html/* ./ $ git add . $ git commit -m 'add sphinx docment' $ git push origin gh-pages
さて今度はどのように見えるでしょう。
アレ? おかしいですね? スタイルシートが利いてないぽいですね。。
Jekyllを使わないようする
そもそも GitHub Pages は Jekyll という静的コンテンツを作成するためのシステムを利用しています。このJekyll は アンダースコアではじまる「_static」のようなディレクトリは旨く処理してくれないらしいです。
なので、それを回避するためにはルートディレクトリに「.nojekyll」というファイルを置けば、明示的にJekyllを利用しない形でコンテンツを配置できるっぽいです。
$ touch .nojekyll $ git add . $ git commit -m 'add .nojekyll' $ git push origin gh-pages
これでどうなってでしょう?
おぉ見れるようになりましたね! 長くなったんで今日はここまでにしましょう。まだこのままだと、ドキュメントを更新するために、いちいちmasterとgh-pages ブランチを切り替えないといけないですよね。次回は、その辺をgit submoduleを使って対応してみたいと思います。
余談
- 「.nojekyll」の代わりにsphinxのプラグインである「sphinx to github」を使うという選択肢もあります。詳しくは参考をURLを参照してください。
virtualenv の --no-site-packages オプションを間違って覚えてた
こんにちわこんにちわ。唐突ですが、皆さんvirtualenv 使ってますか?今まではvirtualenv を使うときにシステムに入ってるsite-packagesを使わないように、以下のようなオプション指定していました。
$ virtualenv --no-site-package hoge
ところが、社内の先生 id:shimizukawa (社内で先生とは不思議な表現だが、先生は先生なので大丈夫だ問題ない) に正しくは「--no-site-packages」だよ。と教えてもらいました。
え?けど期待するように動いてましたけど?て言ったら、「愛されゆるふわプログラマー」で皆さんおなじみの id:feiz 先輩が「オプションが前方一致なんじゃない?」と教えてもらいました。
えーまじかー。と思って、調べてみたら確かに「前方一致」だった・・・orz
一番短くて、「--no」だけでも 「--no-site-packages」が適用されるのを確認した(どうでもいい)
$ virtualenv --no hoge
余談
- どちらかというとこっちの方が大事な話ですが、virtualenv は1.7 から「--no-site-packages」を指定しなくてもデフォルトの挙動でシステムのsite-packagesが使われないようになりました。代わりに、システムのsite-packagesを利用するための「 --system-site-packages」というオプションが追加されています。
- Changes & News — virtualenv 1.7 documentation
ちなみに、1.7で「--no-site-packages」オプションを指定すると下記のように、「もうそれ非推奨だぜ。」と言われます。
$ virtualenv --no-site-packages hoge The --no-site-packages flag is deprecated; it is now the default behavior. New python executable in hoge/bin/python
ではではアデュー
Sphinx で自動的にAPIリファレンスを作成したい
今日はこのネタです。タイトルの通りなんですが、PythonでそもそもAPIリファレンス的なドキュメントをどうやって作ったら良いのか知りませんでした。
他の言語であれば下記のようなツールを過去に使った事がありました。
- Java なら Javadoc
- Perl なら pod2html
- PHP なら PHPDocumentor
(今ならもっと賢いツールありそうだけど。。。)
Pythonなら?
ではPythonであればどのような選択肢があるでしょう。調べた限りではまず下記のような選択肢がありました。
- pydoc -w でHTML生成 (pydocで簡単なPythonファイルのドキュメントを作成する)
- Epydocを利用する (Epydoc - 偏った言語信者の垂れ流し)
javadocやらphpdocmentorやらのように、まるっとソースからHTMLを生成するだけであれば、これで十分かもしれません。ただPythonには Sphinxという便利なドキュメンテーションツールがあるので、できれば、reST で且つSphinx用にアウトプットしてくれるツールが欲しいなと思いました。
Sphinxなら?
Sphinxの場合は「sphinx.ext.autodoc 」というエクステがあり、reSTファイル上に下記のように書く事で、ドキュメント生成時に、ソースのdocstringを読み取ってくれて、それをアウトプットとして反映してくれます。
.. automodule:: hoge.fuga
ただ「autodoc」は 「..automodule::」という記述を自分で、reSTファイルに必要な分だけ埋め込む必要がありました。できればjavadocのように丸っとソースファイルのパスを丸投げして、あとは勝手にreSTファイルにしてもらいたいなぁとか思ってましたが。。。
それ sphinx-apidoc で出来るよ!
あるやん。あるやん。何あきらめてん。ちゃんとドキュメントよまなあかんやん。試合はあきらめたら終わりやで > おれ
どうやらSphinxには1.1あたりから「sphinx-apidoc」というツールが同梱されていて、それを使えば、ソースファイルから丸っと、autodocの記載されたreSTファイル群 or Sphinxプロジェクトを作れるそうです。
簡単使い方
- Sphinx 1.1.2 を利用して説明します。
大体使い方はこんな感じ、「apps」ディレクトリ以下にPythonアプリが入ってるとして、docs以下にSphinxプロジェクトを作成する感じです。
$ sphinx-apidoc -F -o docs/ apps/
- 「-F」オプション は Sphinxドキュメントを一から作る(sphinx-quickstart) 挙動が含まれます。既に運用しているSphinxドキュメントがあり、単純にreSTファイルだけあればいいよという場合には「-F」オプションはいらないでしょう。
- 覚えておくと良さそうなオプションは「-f (--force)」オプションでしょうか。既に 出力先のディレクトリに同名のファイルがある場合には、ファイル書き出しの処理をスキップするので毎回上書きしてあげた方が更新漏れがなさそうな気がします。
こんな風になる。
手元の Jinja2のソースに対して、sphinx-apidocを掛けるとこんな感じになりました。
ファイル構成はこんな感じ
docs/ ├── Makefile ├── _build ├── _static ├── _templates ├── conf.py ├── index.rst ├── jinja2.rst ├── jinja2.testsuite.res.rst ├── jinja2.testsuite.rst └── make.bat
余談
- これで少しは真面目に「docstring」でコメントを書くモチベーションも上がりそうですね。(本当か?)
以上おわり。
pypi.python.org が落ちてたら
最近 http://pypi.python.org が良く落ちる。そんな時にはどうしたらいいんだろうとか思ってた。そしたら今まさにTwitterでこんなやり取りが見れられた。
なんと!「~/.pip/pip.conf」でかけばいいのか! 恥ずかしながら「python.jp」にミラーがあるのも初めて知った!ww
[install] index-url=http://pypi.python.jp/
refs: https://twitter.com/#!/voluntas/status/158544204975448064
直接教えてもらった訳ではないけど、@methane さん、@voluntas さん ありがとうございました。助かりました。
追記(2011/01/16)
コメントで しみずかわ先生(id:shimizukawa) に「--use-mirrors」オプション使えよ。このゴミくず。という生暖かいコメントを頂いたので追記します。ありがとうございます! m(_ _)m
Configuration — pip 1.0.2.post1 documentation
オプションを見る限り上の例に近い感じだと「pip.conf」に下記のよう記載すれば良いらしい。
[install] use-mirrors = true mirrors = http://d.pypi.python.org http://b.pypi.python.org
また「http://pypi.python.jp/」はオリジナルの「pypi」とは多少異なっていて、不完全な物ならしいという事がツイートで分かりました。内容は下記URLを参照してください。
余談
- インターネッツすごい
blinker モジュール
Flask使い始めの頃に「before_request」やら「teardown_request」の当たりで利用されているのを見て「なんだこれ?」って思って、そのまま放置してたやつ。
Blinker: Blinker Documentation
簡単に言うとオブジェクトの間のシグナルの送信/受信の仕組みを提供してくれるっぽい。簡単な使い方を紹介する。
インストール
pip install blinker
簡単な使い方
下記のようなコードを例にしましょう。
#!/usr/bin/env python #-*- coding:utf8 -*- from blinker import signal class Person(object): def __init__(self, name): self.name = name def __repr__(self): return self.name def say_my_name(lover): print "Hello! my name is %s." % lover def drillbits(lover): print "drillbits love %s !!!!" % lover def oyakata(lover): print "oyakata love %s !!!!" % lover #create person object podhmo = Person('podhomo') pasberth = Person('pasberth') tell_k = Person('tell-k') #create signal mysignal = signal('love') #connect mysignal.connect(say_my_name) #send signal mysignal.send(pasberth) mysignal.send(podhmo) mysignal.send(tell_k)
やっている事はこんな感じです。
- (create signal) signal関数で名前付きのsignalを作る
- (connect) connect関数で、シグナルを送信したときに実行される関数を登録
- (send signal) シグナルを送信する、send関数の引数は、connectで登録した関数の引数としてわたされる。
これを実行するとこんな、三つのPersonオブジェクトが自己紹介をします。
Hello! my name is pasberth. Hello! my name is podhomo. Hello! my name is tell-k.
シグナルに登録(connect)できる関数は同じ引数であれば複数登録する事も可能です。またconnect関数にsender引数を渡すことで、シグナル送信されたオブジェクトによって、関数の呼び分けすることもできます。
たとえば上のコードをこんな風にしてみましょう。
#connect mysignal.connect(say_my_name) mysignal.connect(drillbits, sender=pasberth) mysignal.connect(oyakata, sender=podhmo)
このようにsenderを設定すると下記のようになります。
- say_my_name は シグナル送信の全てで実行される。
- drillbits 関数 は シグナル送信時の引数がpasberthでないと実行されない。(drillbitsはpasberthにしか興味がない)
- oyakata 関数 は シグナル送信時の引数がpodhmoでないと実行されない。(oyakataはpodhmoにしか興味がない)
実行結果はこの通りです
Hello! my name is pasberth. drillbits love pasberth !!!! Hello! my name is podhomo. oyakata love podhomo !!!! Hello! my name is tell-k.
基本的に実行順序はconnectされた順となります。あまり普段はお世話になる機会はそれほどなさそうですが、ドキュメントにはもう少しくわしく利用方法も書いてあるので、暇があったら、また調べてみたいと思います。
余談
- なおこの記事に登場する、変数名および、関数名、クラス名などは作者の想像上のものであり、実在する人物・団体とは一切関係はございません。フィクションです。フィクション。
hb qp bp study 新年LT&ビアバッシュ2012 にいってきた。
今日はビアバッシュにいってきました。
hb qp bp study 新年LT&ビアバッシュ2012
普段の勉強会テイストよりも、終止新年会ムードで面白かったですねw
個人的には @inoshiro さんの顔を認識できたのと、@richardx64 さんが覚えててくれたのが嬉しかったですw
とりあえずハッシュタグ #bphbqpstudy2012 からさらった資料をまとめておきます。
漏れてたら教えて下しあ。発表はもっとあったので全然少ないはず。
普通に為になるのから、黒い感じのや、熱い思いのこもったLTまで色々堪能させていただきました。
スタッフの皆さん、発表者の皆さん ありがとうございました。そしてお疲れさまでした。m(_ _)m
@haru860 さん
@hebikuzure さん
@urasoko さん
@rywo さん
@kazeburo さん (追記:2011/01/16)
refs: http://blog.nomadscafe.jp/2012/01/hb-qp-bp-study-lt2012.html
余談
そういえば妙に採用募集ネタが多かったですね。奇遇にも下記の会社でも、主にデザイナーさんを募集中らしいので、応募してみたい人は
「採用に応募したいです! @tell_k からの紹介です! http://jobs.beproud.jp #しみずかわ」
と気軽に呟くといいらしいですよ!!!!
なんか今ちゃんと見たらエンジニアの採用は募集してなかった。。。けどけど腕に覚えのある「Webデザイナー」さんは絶賛募集中です!! てへぺろ(・ω<)
Inflectorしたい
今日は時間ないので手抜き。その昔 symfony(sが小文字のバージョンの方だよ)というPHPのフレームワークを触ってたときに、「sfInflector」というライブラリが割と好きでよく使ってました。このの記事にあるヤツです。
Pythonでもそういうのやるライブラリあるかなーと探したのがこれ。
ソースを見た限りではRailsのソレに影響を受けているていうかソレな感じ。取り急ぎは、camelizeとunderscoreだけ欲しかったので、簡単な使い方だけをメモとして残す。なんかSpanish対応とかしてるっぽいので、時間があったらもう少しくわしく書くかも。
簡単な使い方
インストールはpipでできます。
pip install Inflector
こんな感じに使う
#-*- coding:utf8 -*- from inflector import Inflector print Inflector().camelize('camel_case') #=> CamelCase print Inflector().underscore('UnderScore') #=> under_score
やんなとか怒られそうだけど、PHPの時は動的にクラス名を補完してインスタンスを作るとかに使ってた。
#-*- coding:utf8 -*- from inflector import Inflector class DrillbitsHaskell(object): """ new type drillbits """ sex = "female" job = "high school student" hoge_code = "drillbits_haskell" db = globals()[Inflector().camelize(hoge_code)]() print db #=> <__main__.DrillbitsHaskell object at 0x10048e050> print db.sex #=> female print db.job #=> high school student