今どきのPythonのライブラリ自作からPyPIへの登録

# 自分のライブラリをPyPIに登録したい

...が、PythonにはRubyの[bundler](http://bundler.io/)のようなものが
なく、(合ったとしても統一されてないと思う)
プロダクト別に自由なディレクトリ構成になっている状態...

せめて自分のプロダクトについては統一したいなあと思ったので
Pythonのライブラリを作る場合のディレクトリ構成や
環境構築などについてメモを書く。忘れちゃうので...

利用するPythonのバージョンは3.3以降を意識してる。
それより前(3.2, 3.1...2.x)は考慮しない。問題無いと思うけど...

# テスト目的で作成したライブラリ

![スクリーンショット 2013-10-16 8.08.53.png](https://qiita-image-store.s3.amazonaws.com/0/3985/635c711d-e9db-32a6-d59d-8dc3ce5a4d9a.png)

**[fizzbuzz](https://github.com/futoase/fizzbuzz)**というアレなライブラリを作った。
ライブラリというかコマンドラインツールだけれど。
このライブラリの構成を元に、メモを書いていく。

# ライブラリのディレクトリ・ファイル構成

以下のディレクトリ・ファイル構成とする。

```
fizzbuzz
└lib # ライブラリ本体
  └bin # 実行スクリプト本体
  └fizzbuzz # ライブラリ名のディレクトリ
      └ __init__.py # ライブラリimport時の初期化設定はここで 
  └test # テストファイル
requirements.txt # travis-ci及びsetup.pyで利用する。pip --freezeで作れる。
info.py # パッケージの作者情報などを収めるファイル
version.py # バージョン情報を収めるファイル
setup.py #キモとなるファイル
```

こういうのでいいんじゃないかな。

# pyvenvの環境をライブラリディレクトリ以下に構築する

Python 3.3より、```virtualenv``` が包含された。
ライブラリの動作テストを行うために、以下のコマンドで
ローカルなPython実行環境を作成する。

```
> pyvenv .venv
```

virtualenvの頃から使っているため、.venv以下に
pyvenvの環境を作るようにしているが、任意で良いと思う(.pvenvとか)。

ローカルなPython実行環境を構築したので、
```activate``` を shellの```source``` コマンドにて取り込む。
こうすることで、```.venv``` 以下のPython環境を使う形になる。(pythonコマンドとか)

```
> source .venv/bin/activate
```

## setuptoolsのインストール

virtualenvのとあるバージョンまでは
システムのライブラリをvirtualenvで取り込んでくれたりしたけど、
virtualenvの新しいバージョン及びpyvenvだと取り込んでもらえない。
pyvenvを実行するとピュアな環境が構築される。

そのため、```easy_install``` が無い状態で環境が作られる。
以下のコマンドを実行して```setuptools``` をセットアップしよう。

setuptoolsのPyPIページより引用。

```
> wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | python
```

これでeasy_installコマンドを実行し、PyPIにある
パッケージをインストールできるようになる。
が、easy_installでPyPIのパッケージをインストールするより、
```pip``` を使うほうが使いやすい。pipを入れよう...

## pip のインストール

easy_installを入れている状態であれば、pipは気軽にインストールすることができる。

```
> easy_install pip
```

以上で準備完了。

# 必要なライブラリのリストを作成する

自作ライブラリが他のライブラリを使っている場合、
setuptools.setup 関数に渡すhashに
install_requiresを指定しないといけない。
pipを利用すると気軽に必須ライブラリのリストを作ることができる。

```
> pip freeze > requirements.txt
```

TravisCIもrequirements.txtを利用するので

setup.pyにて、```requirement.txt``` を利用してinstall_requiresを指定するようにする。

```py
setup({
  install_requires: open('requirements.txt').read().splitlines(),
})
```

これでライブラリが必要としている外部ライブラリがインストールされる。

# パッケージの情報をどこに持たせるか

## パッケージ作成者の情報

PyPIで表示されるライブラリ作成者の情報について、どのファイルに持たせるか
なんか迷ったけど、package root直下に```info.py``` として置く形にした。

```py:info.py
# package information.
INFO = dict(
  name        = "PyFizzBuzz",
  description = "FizzBuzz cli tool",
  author      = "Keiji Matsuzaki",
  author_email = "futoase@gmail.com",
  license     = "MIT License",
  url         = "https://github.com/futoase/fizzbuzz",
  classifiers = [
    "Programming Language :: Python :: 3.2",
    "Programming Language :: Python :: 3.3",
    "License :: OSI Approved :: MIT License"
  ]
)
```

classifiersは、[ここのリスト](https://pypi.python.org/pypi?%3Aaction=list_classifiers)より自分のライブラリが
マッチしてそうなジャンルを選択し、設定する。

## パッケージバージョン

```version.py``` の中にVERSIONを指定する。

```py:version.py
VERSION = "0.0.3"
```

## MANIFEST.in ファイルの作成

**20131017追記**

```package_dir``` では```info.py```, ```version.py```, ```requirements.txt``` ファイルを指定していないため、
MANIFEST.inファイルを書かないといけない。
この記事を書いたときにチェックを怠って居たため、includeされていない問題を発見できませんでした。
ので追記。

```py:MANIFEST.in
include info.py
include version.py
include requirements.txt
```

# パッケージのテスト

pipコマンドを利用し、パッケージのテストを行う

```
> pip install .
```

自分自身のディレクトリ内で自分自身を指定してpip installを行うことで、
```pyvenv``` の環境内で自己のライブラリを利用することができる。

```
> pip list
konira (0.3.2)
pip (1.4.1)
PyFizzBuzz (0.0.3)
setuptools (1.1.5)
```

もし、pip install後、自分のライブラリにバグが合った場合は
pyvenvの環境以下で以下のコマンドを実行すれば良い。

```
> pip uninstall PyFizzBuzz
```

Gemfileに```gemspec``` を指定するような...気持ちでコマンドを実行すればいいと思う...

## 動作チェック

今回、fizzbuzzはコマンドとして実行されるようにしたので、
```.venv/bin/fizzbuzz``` にコマンドが置かれている。

```
(.venv) > fizzbuzz 10 | head -3        
1
2
Fizz
```

動作チェックは行えた。

# PyPIへの登録

PyPIへの登録を行っていない場合は、以下のコマンドを実行し、登録する。

```~/.piprc``` ファイルを生成していない場合はユーザー名、パスワードの登録を促される(はず)...

```
> python setup.py register
```

PyPIへパッケージのアップロードを行う。

```
> python setup.py sdist upload
```

[PyPIにライブラリのページが作成されればOK](https://pypi.python.org/pypi/PyFizzBuzz)

C拡張のライブラリの場合は異なるかもしれない。
(eggファイルのアップロードについては考慮していない...)

# PyPIへのアップロード後

一日のダウンロード数や、過去にアップロードしたバージョンのファイルの一覧などを
PyPIページから見ることができる。(要ログイン済)

結構楽しい。

# 余談

setuptoolsがdistributeと統合されたので、setuptoolsのみimportしている形になったけど、
統合される前は以下の形でsetup.pyにてimportするパッケージの切り分けをしていた。

```py:setup.py
try:
    import setuptools
except ImportError:
    from distribute_setup import use_setuptools
    use_setuptools()
from setuptools import setup, find_packages
```

distribute_setup.pyを[ここから落として](http://guide.python-distribute.org/installation.html)(なんか書いてる今アクセスできないや)、パッケージに含める形で対応していた。

setuptoolsに統一されてよかった。(この記事では下位互換性のことは考慮してないからこうできるのかもしれない...)