pyhatebuのソースコードを読んでみる (1)

Dive Into Pythonの11章を読んでいる途中のbonlifeです。毎日少しずつでもPythonに触れていようと心がけてます。
今は他の人が書いたコードを読んだ方が勉強になる時期なんじゃないかしら、と思ったので最近ちょっと話題の「pyhatebu0.7 - Pythonではてなブックマークをアレコレするためのラッパー」を読んでみることにしました。素人なので間違い、勘違いがあると思いますので、お気づきになった賢者の方はご指摘お願いいたします。

まず、pyhatebuはsvn関連のファイルを除くと、以下の3ファイルで構成されています。

  • __init__.py (モジュール初期化する例のアレ)
  • pyhatebu.py (メイン処理)
  • wsseauth.py (AtomAPI用で使うWSSE認証まわり)
  • __init__.py
from pyhatebu import PyHatebu

このファイルでは、pyhatebu.py から PyHatebu クラスをインポートしているだけですね。

  • pyhatebu.py

このファイルには色々と書いてありますね。40行以上コメントがある親切設計。その後、author、versionなどを設定。続くモジュールのインポート部分が参考になりました。

  • [54-58行目]
try:
    # for Python 2.5
    from xml.etree import ElementTree
except:
    from elementtree import ElementTree

なるほど。ElementTree の配置場所というか、格納モジュールがPython2.5から変わってるんですね。どうせなら、この勢いで cElementTree にも try しちゃえば良いのに、とか思ったり。(ってそこまで速度が要求される処理でもないし、cElementTree 入ってる人の方が少ないだろうし、ってことでしょうか。)
次の日付文字列操作部分でも発見ありです。(って私みたいな初心者が他人のソースコード読むと発見ばかりだったりするんですが。)

  • [62-74行目]
def make_datetime(dttext):
    """
    function to parse datetime string and
    convert it to datetime.datetime object.

    >>> d = make_datetime('2005-04-07T18:36:00+09:00')
    >>> d
    datetime.datetime(2005, 4, 7, 18, 36)
    >>> d.hour, d.minute, d.second
    (18, 36, 0)
    """
    dttext = dttext.replace('+09:00', '')
    return datetime.datetime(*time.strptime(dttext, "%Y-%m-%dT%H:%M:%S")[:6])

文字列から日付型変換と演算」ってところでも話題に挙がってたのですが、これは日付文字列からdatetimeオブジェクトを得るナイスな方法ですね。Python 2.5からはdatetimeモジュールで strptime がサポートされましたが、それ以前はtimeモジュールにしか strptime がなかったりするので、struct_time を datetime に変換する必要があったりするわけで。
ここでは、time の前にあるシングルアスタリスクで time.strptime の結果を9個の要素を持つタプルに展開して、その前6個をそのまま datetime.datetime に渡していますね。(とか言いつつ、引数の展開まわりはまだちゃんと理解できていません…。) とりあえず、これはなかなか便利そう。他には、この関数内で、タイムゾーン部分を単純に削除してます。(単純に削除しちゃって良いものなのか、よく分かりませんが、きっと大丈夫なんでしょう。)
続いて、はてブのレスポンスを HtebuItem のインスタンスとして返すための def resp2HatebuItem(src) です。urllib2 を拡張したヤツの Responseを ElementTree を駆使してパースして、上手いこと情報を格納。最終的にソースコードの後ろの方に出てくる HatebuItem クラスのインスタンスを返します。
ただ、ここで驚いたのが以下の部分です。

  • [85-86行目]
        if t.endswith('}title'):
            d['title'] = elem.text

うわ、なんだか endswith の引数には変な括弧が入っちゃってるよ!どういうことなんでしょう、と思って調べてみると、どうやら ElementTree が返す tag の情報は以下のような文字列になっているみたいです。

{http://purl.org/atom/ns#}entry
{http://purl.org/atom/ns#}title
{http://purl.org/atom/ns#}link

仕方がないですが、なんとなく気持ち悪いですね…。xml.minidom あたりを使って、素直に getElementsByTagName で取得した方がキレイっぽいような。(でも、ElementTree の方が速いし、基本的には扱いやすいみたいです。) elif の連続も仕方ないんですよね。むぅ。やってる処理自体はパースした内容に応じて、辞書に次々と値を格納しているだけですので、それほど難しくないですね。
ということで、こんな感じで一通り読んでみます。途中ですが、続きはまた明日以降。