Don't writing python scripts, writing python libraries.

Don't writing python scripts, writing python libraries.

はじめに

pythonでscriptを書いていくだけだと辛い事が多い。 たとえ、作成するアプリでは使われないコードであってもライブラリとして作っておいた方が良い。 具体的には以下の様にする。

  • misc的なものもpython packageにする
  • 作ったパッケージをeditable modelでinstallする
  • bin 以下に置きたいスクリプトは自前のmisc libraryを呼ぶようにする
  • (sys.path考えてのcwdの調整はダメ絶対)

これを守ると結構スクリプトを書く時の苦労が減る。 個人的には本番では利用せず手元で利用するような便利スクリプト系の機能を書く際に利用するproject特有のmisc libraryという位置付けのpackageを作ったら捗った(後々成長してきた場合にはpackageを分割するかもしれない)。

misc packageの作り方

ここで言う、misc packageというのは、各プロジェクトリポジトリ内に一緒に管理されるpython packageのことで、特にpypiにuploadされるなどは念頭に入れていない。

pythonのvenv環境作成

綺麗な環境があると便利なのでvirtualenvを使うことにする。既に環境が存在している人はここを飛ばしても良い。 例えば、冒頭のmisc packageを作るという話であれば既存のprojectの環境で良いと思う。

# sudo pip install virtualenv
virtualenv foo --python=`which python3.4`
cd foo
. bin/activate

virtualenvの環境を手軽に有効にするためにvirtualenv wrapperなどを使う人もいるらしいが。個人的には以下のような設定が.bashrcなどにあれば十分だと思っている。

alias foo=". ~/venvs/foo/bin/activate && cd ~/venvs/foo/"

cookiecutterのインストール

残念ながらpythonには標準でpackageを作るためのscaffold(project template)が付いていない。 packageの作成に慣れた人であれば、自分用のscaffoldを持っていたり、必要十分な設定を熟知していたりするかもしれないが、ココでは作業コストを下げるためにどうするかということを考えたい。

今おそらく一番メジャーなpackage templateは cookiecutter だと思うのでこれを使うことにする。

pip install cokkiecutter

環境作成時にinstallされたpackageのversionの違いで右往左往したくなければversionを固定しておいても良いかもしれない プロダクション運用では不要なパッケージではある可能性があるのでrequirements.txtという名前のファイルではなくrequirements-dev.txtという名前にしている。

pip freeze | tee requirements-dev.txt
binaryornot==0.4.0
chardet==2.3.0
click==5.1
cookiecutter==1.2.1
future==0.15.2
Jinja2==2.8
MarkupSafe==0.23
ruamel.base==1.0.0
ruamel.yaml==0.10.12
wheel==0.24.0
whichcraft==0.1.1

coockiecutterの利用

python package用のproject templateには以下の2種類があるがとりあえずminimalの方を使う。

気に入らないところが出てきたら自分でproject templateを書くことになるかもしれない。とりあえず最初の内はてきとうにあるものを使うという方針で行く。後々気に入らない部分を直すことを考えると手元にcloneして使った方が便利かもしれない。

とりあえず sandbox という名前のpackageを作ることにする

git clone https://github.com/borntyping/cookiecutter-pypackage-minimal.git
cookiecutter cookiecutter-pypackage-minimal
author_name [Louis Taylor]: podhmo podhmo
author_email [louis@kragniz.eu]: ababjam61@gmail.com
package_name [cookiecutter-pypackage-minimal]: sandbox
package_version [0.1.0]:
package_description [An opinionated, minimal cookiecutter template for Python packages]:
package_url [https://github.com/borntyping/cookiecutter-pypackage-minimal]:
readme_pypi_badge [True]:
readme_travis_badge [True]:
readme_travis_url [https://travis-ci.org/borntyping/cookiecutter-pypackage-minimal]:

(travis用の設定など邪魔なので消したい) 今回作っているのはpypiなどに公開しない単なるmisc的なものをまとめるためのpackageなのであまり色々拘る必要はない。以下の事が確認できれば良い。

  • installできるかどうか
  • importして使えるかどうか
  • テストが実行できるかどうか

インストール自体はeditable modeで行う。

cd sandbox
pip install -e .
python setup.py test
running test

残念ながらすぐにテストが実行されるようには設定されなかった。以下の追加の作業が必要。

mkdir sandbox/tetsts/
touch sandbox/tetsts/__init__.py

setup.pyも書き換える。

diff --git a/setup.py b/setup.py
index f9b72fd..926c4ba 100644
--- a/setup.py
+++ b/setup.py
@@ -11,7 +11,8 @@ setuptools.setup(
     description="An opinionated, minimal cookiecutter template for Python packages",
     long_description=open('README.rst').read(),
 
-    packages=setuptools.find_packages(),
+    packages=setuptools.find_packages(exclude=["tests.*"]),
+    test_suite="sandbox.tests",
 
     install_requires=[],

テストが動くようになった。

$ python setup.py test
running test
running egg_info
writing sandbox.egg-info/PKG-INFO
writing dependency_links to sandbox.egg-info/dependency_links.txt
writing top-level names to sandbox.egg-info/top_level.txt
reading manifest file 'sandbox.egg-info/SOURCES.txt'
writing manifest file 'sandbox.egg-info/SOURCES.txt'
running build_ext

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

作業としてはこれで終わり。後は開発環境ではこのpackageをインストールしておくようにrequirements-dev.txtを書き換える

-e ./sandbox

作ったpackageがインストールできることを確認しておく。

$ python
Python 3.4.2 (default, Oct 15 2014, 21:23:36) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sandbox
>>> sandbox.__version__
'0.1.0'
>>> ^D

いろいろ直したい部分が見つかるので自分でproject templateを書き直すことになりそう。

参考

真面目に頑張りたい場合にはpypaの情報を見ると良い。