Bitbucket is a code hosting site with unlimited public and private repositories. We're also free for small teams!

Close

技術書の写経

  • ローカルで使える SCM を用意
  • ひたすらサンプルコードを写して実行
  • 実行するたびにコミット(コミットログにページ番号を含める)
  • 疑問点があったらコミットログや本に書き込む
  • 章ごとにタグを打つ

4.7 APIの開発プロセス

APIの開発プロセス

  • 高レベルな関数の提供
    • 低レベル関数と両方提供するといいよ -> 14章 Facade パターン
  • 名前空間木の構築
  • コードの分割
  • 段階的な廃止プロセスの使用
  • egg の使用

4.7.2 名前空間木の構築

  • アプリケーションのAPI構築設計でシンプルな方法

    -> ユースケースを元に名前空間木を構築

  • 新しいユースケースごとに構造の変更を行うことで、使いやすいAPI設計に役立つ。

  • リリースされたパッケージを変更するには、段階的な廃止プロセスを踏む必要がある。

-> 11章 テストを通して名前空間木を構築する

4.7.3 コードの分割

  • 小さいことは美しい
  • 関数やメソッドは 25〜30 行程度。1画面に収まる大きさに。
  • 1クラスに 10 メソッド以上あると、全体像を把握しづらくなるので分割。
  • 1モジュールが 500 行以上になるなら分割すべき。

4.7.4 eggの使用

  • Python eggs

  • 同一フォルダに全コードベースを集中させずに、各パッケージをリリースできる。

    Java の JAR パッケージのように 名前空間パッケージ を簡単に構築できる。

    例) acme.templates をパッケージ分割して配布

  • setuptools を使用する

    Namespace Packages

    • 大きなパッケージは小さなeggの集合として配布したほうが扱いやすい

      • 通常 Python は一箇所以上の場所からパッケージの内容を取出すことができない
    • パッケージを namespace package と宣言

      • ただのモジュールとサブパッケージのコンテナとして認識される
    • The PEAK Developer's Centerの日本語訳

    • 続き1

    • 続き2

    • 仮想パッケージの __init__.py では、次のコードを含まなければいけない:

      __import__('pkg_resources').declare_namespace(__name__)
      
  • acme/templates/ -> acme.templates 名前空間として利用可能に。

    • acme.pdf は別の場所の acme/ フォルダに置ける。

-> 6章 eggベースのアプリケーションのビルド、リリース、デプロイについて

4.7.5 段階的な廃止プロセス

  • 既にパッケージがリリースされて、使われている場合、変更は慎重に。
  • 両のバージョンのAPIを含む中間リリースを出して段階的に。
  • warnings モジュール使うと、警告管理用にフィルタを作れる

4.8 役に立つツール

  • pep8

    • シンプルなPEP8チェックツール:

      $ easy_install pep8
      
  • Pylint

    • 品質管理指標の計算と命名規則チェック:

      $ easy_install logilab.pylintinstaller
      
  • CloneDigger

    • 重複コード検出ツール:

      $ easy_install CloneDigger
      

第5章 パッケージを作る

手順

  • 基本のコードテンプレートを用意
  • パッケージ作成の基本的な手順紹介
  • テスト駆動開発アプローチの簡単な導入
  • リリース手順の整備

特に知りたいこと

  • distutils, setuptools, distribute の違い

5.1 すべてのパッケージに共通のパターン

  • 複数 egg を取りまとめるためのマスター egg
  • distutils と setuptools で名前空間パッケージを構成、リリース、配布する方法を学ぶ
  • "acme.sql" フォルダに "acme" フォルダ、その下に "sql" フォルダを入れる

5.1.1 setup.py: すべてをコントロールするスクリプト

  • ルートフォルダに setup.py を置いて distutils 向けのメタデータを定義

  • setup 関数呼び出し時に引数として渡す

    • name は egg の完全な名前
  • コマンド一覧:

    $ python ./setup.py --help-commands
    

sdist

  • リリースツリーを1つかそれ以上のアーカイブファイルにまとめる

  • システム非依存の配布パッケージを作成するためのもっとも簡単な方法

  • setup に追加の引数 version を与えることで、アーカイブにバージョン番号を与えられる

  • 実行することで、dist フォルダに配布可能なアーカイブが作成される:

    $ python ./setup.py sdist
    ...
    $ ls dist/
    acme.sql-0.1.1.tar.gz
    
  • 配布物に C 言語で書かれたライブラリや拡張モジュールがある場合、対象システム上でコンパイルできる必要がある

MANIFEST.in ファイル

  • sdist が実行されると distutils は以下のようなファイルをリリースツリーに含める

    • py_modules, packages, scripts オプションに含まれる Python ソースファイル
    • ext_modules オプションに列挙される C ソースファイル
    • test/test*.py に一致するファイル
    • README, README.txt setup.py, setup.cfg ファイル
  • 他に含めたいファイルがある場合、MANIFEST.in テンプレートファイルを setup.py と同じディレクトリに配置して、そこに必要なファイルを列挙する

  • 一行に1つづつ、対象/除外ルールを記述:

    include HISTORY.txt
    include README.txt
    include CHANGES.txt
    include CONTRIBUTORS.txt
    include LICENSE
    recursive-include *.txt *.py
    
  • テンプレート用コマンド一覧

build と bdist

  • build コマンドはビルド済の配布物を作成できる。

  • パッケージのビルドは次の4ステップ

    1. build_py
    2. build_clib
    3. build_ext
    4. build_scripts
  • 各ステップは独立したコマンドとして呼び出し可

  • クロスコンパイルできないので、常にビルドを行なったシステム用になる

  • bdist コマンドはバイナリ配布物をビルドし、dist/ にアーカイブを作成する:

    $ python ./setup.py bdist
    ...
    $ ls dist/
    acme.sql-0.1.1.macosx-10.6-x86_64.tar.gz  acme.sql-0.1.1.tar.gz
    
  • C のコードが含まれているなら、ソース以外にもできるだけ多くの種類のバイナリ配布を提供することが重要。

    • 最低限でも Windows 向けのバイナリ配布は用意するべき。

疑問点

  • build と bdist の違いがいまいちよくわかってない
    • build はアーカイブしないだけ?
  • 「バイナリリリースには Python ツリーに直接コピーできるようなツリーが含まれる」?
    • bdist してできたアーカイブを解凍してもできてないような…なんだろう?

bdist_egg

ビルド済配布物を作成するなら bdist ではなく bdist_egg を利用すべき。

  • setuptool で拡張されたコマンド (distutils には無い)

  • bdist のようなバイナリ配布物を作成するが、ツリー構造はソース配布物に似ている:

    $ python ./setup.py bdist_egg
    ...
    $ ls dist/
    acme.sql-0.1.1-py2.6.egg                  acme.sql-0.1.1.macosx-10.6-x86_64.tar.gz  acme.sql-0.1.1.tar.gz
    
  • egg 形式のアーカイブはダウロード後に展開され、sys.path にフォルダが追加されることで利用可に。

    • bdist で作ったパッケージの例:

      インストールすると acme.sql というディレクトリが site-packages に直接コピーされる

    • bdist_egg で作ったパッケージの例:

      インストールすると site-packages に acme.sql-0.1.1-py2.6.egg ディレクトリが作られる

      easy-install.pth によって検索パスに追加される

  • 参考: プロジェクトの配布

install

パッケージを Python にインストールする。

  • ビルド済でなければビルドしてからインストール
  • ソース配布物は一次フォルダに展開してから同じようにインストール
  • install_requires メタデータに定義された、他の依存パッケージもインストール

パッケージのアンインストール

  • setup.py にはアンインストールコマンドはない。
  • ベストは変更される全要素のスナップショットを作成 -> 全ファイルとディレクトリの記録を取る
    • install コマンドには record オプションがある
    • が、バックアップしてくれるわけではない
  • distutils2 になれば、プラットフォーム非依存のインストーラでもアンインストールができるはず
  • 現時点で一番簡単なのは、
    1. 作成されたファイルを削除
    2. site-packages/easy-install.pth ファイルから、そのファイルへの参照を全て削除

develop

  • setuptools が提供
  • パッケージと連携するのに便利
  • 実行したフォルダ上でビルドとインストールし、site-packages にリンクを作成
  • 開発時にソースコードのローカルコピーで開発を行ないながら、site-packages に配置したのと同じ状態
  • -u オプションでリンクを削除できる
  • 同じ名前の他のインストール済パッケージよりも常に優先される

test

パッケージに含まれる全テストを実行

  • コマンド実行でパッケージのフォルダを検索してテストスイートを探してくれる
  • zope.testing や Nose をフックするといい
    • setup の引数 test_suite, tests_require メタデータを使う

-> 11章 Nose の使いかた

register と upload

register:全メタデータをサーバにアップロード
upload:dist フォルダにあるビルド済アーカイブを全サーバにアップロード
  • デフォルトアップロード先は PyPI
  • 初回 register コマンドで .pypirc がホームディレクトリに作成

Python 2.6 での .pypirc の書式

  • 複数の PyPI サーバのユーザーとパスワードを管理できるようになった
  • PyPI で公開していないパッケージを管理する場合、PyPI 互換サーバを独自に動かすといい

新しいコマンドを作る

  • 標準以外の新しいコマンドを追加する distutils の機能
  • entry-points メタデータを使用して登録する
    • setuptools によって導入
    • パッケージをプラグインとして定義
    • クラスか関数への名前によるリンク

疑問

  • カスタムコマンドは setuptools.Command クラスを継承して用意しなきゃダメ?

setup.py の使い方まとめ

  • 3つの主要な機能

    • パッケージのビルド
    • パッケージのインストール (開発モードもあるよ)
    • PyPI への登録とアップロード
  • 1回の setup.py 実行で、複数コマンドを組合わせて利用できる:

    # パッケージを PyPI に登録し、ソース配布物と egg 形式配布物を作成、アップロードする
    $ python setup.py register sdist bdist_egg upload
    # 開発目的でインプレースインストール
    $ python setup.py develop
    # インストール
    $ python setup.py install
    

コマンドの別名

  • alias コマンド

  • コマンドの組合わせとその別名を setup.cfg に登録する

  • ソースとバイナリ配布物を PyPI に登録する release コマンドの例:

    $ python setup.py alias release register sdist bdist_egg upload
    running alias
    Writing setup.cfg
    $ python setup.py reloease
    

その他の重要なメタデータ

description:パッケージの簡単な説明
long_description:
 パッケージの完全な説明(reSTが使える)
keywords:パッケージを表わすキーワードのリスト
author:作成者か作成組織の名前
author_email:問い合わせ先メアド
url:プロジェクトのURL
license:ライセンス
packages:パッケージの全ての名前一覧. setuptools の find_packages 関数で算出
namespace_packages:
 名前空間パッケージの一覧

5.2 テンプレートベースのアプローチ

  • 共通の構造: 名前空間を表すフォルダと、それに含まれるファイルによる階層構造

  • コード生成ツールとテンプレートを使えば、全パッケージの構造を統一できる

    -> 生成的プログラミング

  • Python Paste が生成ツールとしてよく使われている

5.2.1 Python Paste

  • Pylons の一部:

    $ paster create -t pylons helloworld
    $ cd helloworld
    $ paster serve --reload development.ini
    
  • Zope/Plone でも使われてる。ZopeSkel とか。

  • PasteScript パッケージが提供するテンプレート機能を使おう:

    $ easy_install PasteScript
    ...
    Successfully installed Paste PasteDeploy PasteScript
    
  • いくつかのテンプレートが標準で提供されている:

    $ paster create --list-templates
    Available templates:
      basic_package:  A basic setuptools-enabled package
      paste_deploy:   A web application deployed through paste.deploy
    
  • basic_package を使って acme.sql に必要なファイルを用意:

    $ paster create -t basic_package mypackage
    

5.2.2 テンプレートを作る

Python Paste == paster

paster の新しいテンプレートを作るために以下を用意する

  • paste.script.templates.Template を継承したテンプレート定義クラス
  • ファイル(Cheetah用または静的)とフォルダで構成された構造
  • paste.paster_create_template に定義クラスを登録するための setuptools の entry_points メタデータ

5.3 パッケージのテンプレートを作る

ひな形の作成

$ mkdir -p pbp.skels/pbp/skels

名前空間パッケージの設定

pbp.skels/pbp/__init__.py

setup.py の設置

pbp.skels/setup.py

Package クラス作成

pbp/skels/package.py

Package クラスでは以下のものを定義

  • テンプレート構造を含むフォルダ (_template_dir)
  • paster が表示するテンプレートの概要
  • テンプレート構造が Cheetah 用であるかどうかのフラグ
  • 名前/ラベル/デフォルト値 から構成され、paster がプロンプト上でユーザーに入力を促す変数のリスト
  • プロンプト上でパッケージ変数の入力が要求されることを確認する check_vars メソッド

テンプレートファイル用意

acme.sql 作成時にコピーしたい内容を格納する。

pbp/skels/tmpl/package
  • 書き換えたい変数を含むファイルはファイル名の末尾に _tmpl を追加
    • setup.py なら setup.py_tmpl
  • 作成されるフォルダ名に変数で設定された値を利用する場合は、変数名をを + で挟んだ名前にする
    • 名前空間パッケージフォルダなら +namespace_package+
    • package フォルダは +package+

開発用にインストール

$ python setup.py develop

paster のテンプレート一覧に pbp_package が表示される:

$ paster create --list-templates
Available templates:
  basic_package:  A basic setuptools-enabled package
  paste_deploy:   A web application deployed through paste.deploy
  pbp_package:    A namespaced package with a test environment

テンプレートを元にパッケージ生成

$ paster create -t pbp_package trying.it
...

5.4 開発サイクル

5.4.1 バージョン番号に使うべき値は?

決まった慣例は特にない

rc を末尾に付けるとリリース候補(release candidate)になるよ

  • 0.1, 0.2, 0.3
  • 0.1.0, 0.1.1, 0.1.2a, 0.1.2b
  • 0.1, 0.2rc1, 0.2rc2

唯一のルールは

  1. バージョンの数字の桁数は同じにしておくこと
  2. - を使わないこと(多くのツールでパッケージ名とバージョン名の区切文字として使われているので)

悪い例:

  • 0.1, 0.1.1-alpha, 0.1.1-b, 0.2
  • 0.1, 0.1-a, 0.1-b

5.4.2 ナイトリービルド

  • 開発中のパッケージを開発版(ナイトリービルド)としてリリースする

  • バージョン番号の末尾に dev という文字列をつける (0.1.2 の開発版は 0.1.2dev)

  • distutils を使えば setup.cfg に設定を書けば、build コマンド実行時に開発版を作成できる:

    [egg_info]
    tag_build = dev
    
    $ python setup.py bdist_egg
    ...
    $ ls dist/
    pbp.skels-0.1.0dev-py2.6.egg
    
  • その他にも tag_svn_revision タグなんかもあるよ:

    [egg_info]
    tag_build = dev
    tag_svn_revision = true
    

5.5 まとめ

  • 名前空間パッケージの作り方
  • setup.py の主な役割、パッケージのビルドとリリース方法
  • テンプレートベースのアプローチ
  • Paster の役割とパッケージスケルトンの作り方
  • パッケージのリリース方法

第6章 アプリケーションを作る

アプリケーションのビルド、リリース、配布についての実例

6.1 Atomisator: 導入

  • Atomisator というアプリケーションを実装
    • コマンドラインツール
    • 複数のニュースフィードから情報収集
    • 1つのRSS XMLファイルを生成
    • Planet に似てる
  • 起動
    • 設定ファイルに書かれたフィード情報を読み込み
    • DB に格納
    • 新着のエントリ情報をDBから読み込み
    • XML ファイルに出力

6.2 全体像

  • パッケージをリストアップ
    • アプリケーションをいくつかに部品化
    • それぞれを独自に改良できるようにしておく
  • Atomisator を 4 つのパッケージに分割する
    • atomisator.parser
    • atomisator.db
    • atomisator.feed
    • atomisator.main: 設定ファイルの読み込み、3つのコマンドラインツールの提供
      • load_feeds: データの取得
      • generate_feed: XML ファイル構築
      • atomisator: 上2コマンドを連続実行
  1. atomisator.parser と atomisator.db は依存が無いので最初に作成
  2. 1 のパッケージに依存している atomisator.feed を作成
  3. 全てのパッケージを協調動作させるメインパッケージを作成

6.3 開発環境

  • 各パッケージが依存しているパッケージは install_requires メタデータで定義

  • virtualenv 使おうね

  • setuptools ではなく distribute を使うことが推奨されているので:

    $ virtualenv --distribute
    
  • virtualenvwrapper 使っていれば:

    $ mkvirtualenv --distribute bucho
    
  • 1.4.4 以降なら VIRTUALENV_USE_DISTRIBUTE を設定すれば OK

  • Python 2.6 からユーザー別の site-packages がサポートされた

    http://www.python.org/dev/peps/pep-0370

6.3.1 テストランナーを追加する

  • アプリケーション開発にはテストランナーが必要だよね

  • Nose 使うよ:

    $ pip install Nose
    
  • nosetests コマンドが追加される

-> 11章 テストランナーとは何か、の説明

疑問

  • 「複数のvirtualenv環境を持っているのであれば、環境別の名前をつけると良い」の理由

6.3.2 パッケージ構造を追加する

Atomisator/
└── packages/

6.4 パッケージを書く

次の順で作成していく

  1. atomisator.parser
  2. atomisator.db
  3. atomisator.feed
  4. atomisator.main

6.4.1 atomisator.parser

  • 標準的な RSS フィード取得ツール Universal Feed Parser
  • パッケージのラッパーには2つのタイプがある
    • 緩いラッパー
      • 外部ライブラリの API を使いやすくするヘルパ -> 14章 Facade デザインパターン
      • シンプルで車輪の再発明を避けられる
    • 完全なラッパー
      • 外部ライブラリ全機能の API を提供する
      • 外部ライブラリはブラックボックス化。
      • 外部ライブラリとそれ意外の依存をなくせる最善の選択
      • コード量が多くて大変
  • Universal Feed Parser のシンプルな Facade 関数を書く
  1. テンプレートから最初のパッケージを作成
  2. 最初に doctest
  3. テスト環境の構築
  4. doctest をパスするコードを書く

最初のパッケージを作る

  • pbp_package テンプレートを使って新規パッケージを作成:

    $ cd Atomisator/packages
    $ paster create -t pbp_package atomisator.parser
    
  • develop コマンド呼び出し:

    $ cd atomisator.parser
    $ python setup.py develop
    
  • README.txt の doctest を実行

    $ nosetests --with-doctest --doctest-extensions=.txt

  • setup.py の test コマンドでもテスト実行できるが、nosetests スクリプトの方が

    • 簡単にオプションを指定できる
    • 複数パッケージにまたがったテストを実行できる
  • ~/.noserc があると doctest-extensions オプションは無視される -> 詳細は 11 章

Recent activity

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.