Pythonを使ったプロジェクトのディレクトリ構造

Pythonプロジェクトの2つのパターン

  1. 使い捨てのスクリプトを書く
  2. パッケージとして整備しつつ外部のプログラムに使われるのを意識しつつ書く(メンテナンス性高い)

2.の用途として、自分が直面しているのはPyramidでWEBアプリを作るときです。

Pyramidは設定ファイルとして、PasteDeployを利用しています。

この設定ファイルから自パッケージ内のエントリポイントとなる関数名を取り出し、WSGIサーバーであるwaitressgunicornが利用することになります。

今回は2.のような場合について、どのようなディレクトリ構造がベストプラクティスなのかを調査しました。

ディレクトリ構造の研究

ディレクトリ構造を研究するために以下を参考にしました。

Pipenvは比較的新しいツールあまり言及している記事がありません。

実際、①と②にはPipenvは登場しません。

③には①と②に即したディレクトリ構造でありながら、かつPipenvを使って構成されていたので参考にしました。

基本的な構造

Pipenvを使わない場合

①を見るとディレクトリ構造は以下のようになっています。

* README.rst
* LICENSE
* setup.py
* requirements.txt
* sample/__init__.py
* sample/core.py
* sample/helpers.py
* docs/conf.py
* docs/index.rst
* tests/test_basic.py
* tests/test_advanced.py

sampleモジュールパッケージが自分が書くソースコードの中心となり、自分で書いたコードはこのディレクトリ以下に配置していくことになります。

setup.pysampleモジュールパッケージの依存関係を処理するためのもので、sampleサードパーティのライブラリが必要な場合などはここで処理していきます。

編集可能モード

(②を順に見ていくと登場しますが)

pipにはモジュールパッケージを編集可能モードとしてインストールできる機能があります。

例えば、上記のsampleモジュールパッケージでは

$ git clone git@github.com:kennethreitz/samplemod.git
$ cd samplemod/
$ pip install -e .

とすることでsampleモジュールパッケージを編集可能モードでインストールできます。

編集可能モードでのインストールのメリットとしては:

  1. インストールで必要な工程を踏んでいるので、sampleが必要としているサードパーティのライブラリを一遍にインストールできる
  2. 編集可能モードの名前の通りいつでもモジュールパッケージに修正を加えることができる
  3. このモジュールパッケージを使うときは標準ライブラリのように扱える(どこでもimport sampleでインポートできる)

Pipenvも使う場合

「依存関係の処理はsetup.pyで行われるが、Pipenvを使うメリットは何だろう?」と考えると、2つあると思います。

  1. 仮想環境(virtualenv)を作ってくれるので開発環境をシステム環境から隔離する
  2. sampleモジュールパッケージが直接的に依存していないライブラリを管理する(例えば、デバッグツールとテストツールなど)

1.に関して、Pythonの標準ライブラリvenvを使えばできてしまえますが、モジュールパッケージを使う準備するときについでに仮想環境を作ってくれるので便利です。

2.に関して、実際にrequestsライブラリ(③)を見てみると、Pipfileにはほとんどテストツールやリンカ用のツールが記述されています。

Pipenvで編集可能モード

また、requestsライブラリのPipfileには以下のような記述があります。

[packages]
"e1839a8" = {path = ".", editable = true, extras = ["socks"]}

これは、requestsライブラリを編集可能モードとしてインストールした痕跡ですね。

Pipenvではpipと同様に編集可能モードとしてモジュールパッケージをインストールすることができます。

$ git clone git@github.com:requests/requests.git
$ cd requests/
$ pipenv install -e .

pipと同様の使用感ですね。

一度、編集可能モジュールとしてインストールしてしまえばPipfileに記述されるので、別なシステムに移動した際でもPipenvを使っていれば勝手に処理してくれるようになります。

実際、requestsMakefileには仮想環境(virtualenv)初期化用のコマンドが記述されています。

上記のpipenv install -e .の代わりに

$ git clone git@github.com:requests/requests.git
$ cd requests/
$ make init  # pip install --upgrade pipenv && pipenv install --dev --skip-lock と同じ

とすれば、

  1. 仮想環境(virtualenv)を作る
  2. requestsモジュールパッケージを編集可能モードでインストールする(その依存関係にあるものも)
  3. テストツールやリンカ用のツールをインストールする

というのを一挙に終わらせてくれます。

あとは、pipenv shellとして仮想環境に入り開発に移ったり、pipenv run ほにゃららとコマンドを叩くだけです。楽ですね。

Docker

PipenvはPipfileの依存パッケージをシステムのPythonにインストールすることも容易です。

例えば、Pipenvが作る仮想環境の代わりにDockerで包んでしまう場合でも、

$ pipenv install --system

とすれば、Docker内ではmyprojectパッケージを標準ライブラリのように自由に使うことができそうです。

(やったことないけど)

感想

Pipfilesetup.pyrequirements.txtなど同じことを目的にしてるように見えるファイルがたくさんあるので混乱しますが、

目的を適切に分けて考えてツールを使えば便利に使えそうでした。

困ったときはrequestsライブラリのディクレトリ構造を参考にしていこうと思います。