Python でライブラリの開発環境をととのえた
TL;DR
- poetry を入れろ
- test: pytest
- linter: pflake8
- formatter: black
- sphinx + github pages で docstring をドキュメントとして公開できるぞ
とりあえずコードを書ける環境を作る
僕の場合、最初からライブラリにするつもりがあったわけではないので、最低限の実行環境を整備しました。
ディレクトリ構成
${module_name}
、examples
、tests
ディレクトリを作成し、それぞれに メインプログラム、利用例(もしくは利用スクリプト)、テスト という形で配置しました。
(※ src
作った方がいいよなどのアドバイスがあればコメントへ)
また、ビルド処理をまとめるなどの用途でシェルスクリプトを作ったため、script
ディレクトリも作成しました。
仮想環境管理
流石に依存モジュールくらいはまとめたかったので venv
を利用しました。
python3 -m venv .venv
source .venv/bin/activate
上記コマンドを実行すると、シェルの左端に (.venv)
と表示されるようになるので準備完了です。pip install
で必要なモジュールを入れて、Python コマンドで実行しながら開発を進めていきます。
抜ける時はこう
deactivate
必要なモジュールが一通り入ったら、以下のコマンドで requirements.txt
に依存関係を出力しておきましょう。
pip freeze > requirements.txt
テスト
pytest を入れて使いました。
pip install pytest
実行には以下のようなコマンドを利用します。
pytest tests/
Tips:
- SubTestとfor文の組み合わせで PHP Unit の data provider のような書き方ができる。
-
requests
を Mock して通信を行う関数をテストすることができる。
最終結果
.
├── .venv #.gitignore
├── README.md
├── requirements.txt
├── examples
│ └── example.py
├── ${module_name}
│ ├── __init__.py
│ └── main.py
├── script
│ └── setup.sh
└── tests
└── v2
├── __init__.py
└── test.py
ビルドツールまわりを整備する
venv
requirements.txt
Pipfile
など色々試した末に Poetry を導入することにした。
実はそのせいで導入フローが カス venv前提になってしまっていますが許してください :bowing_man:
参考資料:
venv からは抜けておきましょう。
pip install poetry
poetry init
対話形式でプロジェクトの情報を入力すると、 pyproject.toml
というファイルが生成されます。
requirements.txt をもとに、ここの tool.poetry.dependencies
に依存関係を、 tool.poetry.dev-dependencies
に開発環境で必要なモジュールを書き込んでいきます。
[tool.poetry.dependencies]
python = "^3.9"
requests = "^2.26.0"
urllib3 = "^1.26.6"
[tool.poetry.dev-dependencies]
pytest = "^6.2.5"
また、コマンドからも追加できます。
# 依存関係に追加
poetry add django==2.2.8
# dev用
poetry add flake8 -D
最後にインストール
poetry install
タスクランナーの導入
Poetry の scripts はタスクランナー機能ではない らしいので、タスクランナーとしての機能を提供するプラグインを導入することにしました。
インストール
poetry add --dev taskipy
taskipy のタスク定義は pyproject.toml
に追記する形で定義できます。
[tool.taskipy.tasks]
example = "python examples/example.py"
test = "pytest tests"
実行は、 poetry run task ${task_name}
で行えます。
例:
poetry run task test
整形ツールの導入
今回は Linter として pyproject-flake8 を、 Formatter として black を導入しました。
pyproject-flake8 とは、 flake8 というフォーマッタの設定を、 pyproject.toml
に書き込めるようにするラッパーです
そもそも flake8 とは、
pycodestyle : コードがコーディング規約(PEP8)に準じているかを確認。
pyflakes : コードに論理的なエラーが無いかを確認。
mccabe : 循環的複雑度のチェック。
という3つのツールを実行してくれるやつで、Python開発ではよく使われている (らしい) です。
pyproject-flake8 のインストール
poetry add -D pyproject-flake8
toml ファイルへの設定は [tool.flake8]
に入力できます。
[tool.flake8]
max-line-length = 88
extend-ignore = "E203,E402,"
max-complexity = 10
black は python でよく使われている (らしい) フォーマッターで、あまり設定できる項目が少なく、デフォルトの設定を強制できる利点があるらしい (?) です。
PEP 8 -- Style Guide for Python Code に準拠しているらしいので、とりあえず :yoshi2:
インストール
poetry add black -D
設定
[tool.black]
line-length = 88
ちなみに小咄として、 black poetry と検索すると違うやつしかヒットしないので Python ってつけた方がいいですよ。
タスクランナーにも設定しておきます。
[tool.taskipy.tasks]
# 省略
lint = "poetry run pflake8 ${module_name} examples tests"
format = "poetry run black ${module_name} examples tests"
PyPI に公開する
参考資料:
PyPIのログイン情報を設定しておき、
poetry config http-basic.pypi username password
あとはビルドとアップロードを行うだけ
poetry publish --build
ちなみに TestPyPI を利用する方法については上記資料に詳しく載っています。
toml
ファイルについても、 PyPI のページに載せたい情報を記載しておくことを推奨します。
[tool.poetry]
name = "name"
version = "0.1.0"
description = "タイトルてきなやつ"
authors = ["ニックネーム <メールアドレス>"]
homepage = "https://github.com/hogehuga"
readme = "README.md"
# なんかタグ的なやつ
classifiers = [
"Development Status :: 2 - Pre-Alpha",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9"
]
どれぐらい PyPI でインストールされたか知りたい
PePy というサイトで PyPI でどれだけライブラリがインストールされたかを確認することができます。
バッジ画像も自動で作成されるので、 README.md
にリンクを貼って自慢しちゃいましょう!
ドキュメンテーション
python には docstring というやつがあり、各クラスや関数についてのドキュメントをコメントの形式で残すことができます。
コメントの形式は、 Google Style というやつがよく使われており、ドキュメント化しやすく、また、読みやすい形式として親しまれています。
コメントのイメージ (Google Style から引用):
def fetch_smalltable_rows(table_handle: smalltable.Table,
keys: Sequence[Union[bytes, str]],
require_all_keys: bool = False,
) -> Mapping[bytes, Tuple[str]]:
"""Fetches rows from a Smalltable.
Retrieves rows pertaining to the given keys from the Table instance
represented by table_handle. String keys will be UTF-8 encoded.
Args:
table_handle: An open smalltable.Table instance.
keys: A sequence of strings representing the key of each table
row to fetch. String keys will be UTF-8 encoded.
require_all_keys: If True only rows with values set for all keys will be
returned.
Returns:
A dict mapping keys to the corresponding table row data
fetched. Each row is represented as a tuple of strings. For
example:
{b'Serak': ('Rigel VII', 'Preparer'),
b'Zim': ('Irk', 'Invader'),
b'Lrrr': ('Omicron Persei 8', 'Emperor')}
Returned keys are always bytes. If a key from the keys argument is
missing from the dictionary, then that row was not found in the
table (and require_all_keys must have been False).
Raises:
IOError: An error occurred accessing the smalltable.
"""
Sphinx によってドキュメント化する
参考資料:Sphinxの使い方.docstringを読み込んで仕様書を生成
インストール
pip install sphinx
pip install sphinx_rtd_theme
作業ディレクトリ作成
sphinx-quickstart docs
作成されるディレクトリはこんな感じ
.
└── docs
├── Makefile
├── _build
├── _static
├── _templates
├── conf.py
├── index.rst
└── make.bat
conf.py
が python ビルド周りでいう setup.py
と同じような役割を持っていて、設定ファイル兼ビルド処理記述的な役割を果たしているっぽいです。
# 省略
# プログラムがあるディレクトリを `sys.path` に追加する。 (元々コメントアウトされている箇所を外して変更)
# 他の解説だと `'.'` とか `'${module_name}'` とかを指定せよと書かれていたが、僕はこれで動いた。
import os
import sys
sys.path.insert(0, '..')
# 省略
# プラグインを追加する (変更)
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.viewcode',
'sphinx.ext.todo',
'sphinx.ext.autosummary',
'sphinx.ext.napoleon',
'sphinx.ext.githubpages'
]
# 省略
# 出力されるドキュメントのスタイルを設定する。 (変更)
# よく Python 系のドキュメントで見る青黒ベースのスタイルになる。
html_theme = 'sphinx_rtd_theme'
# 省略
# docstring を埋め込むのに必要っぽい (追加)
autosummary_generate = True
ビルド
sphinx-apidoc -f -e -o ./docs ./${module_name}
cd docs
make html
sphinx-apidoc
はモジュールの階層から .rst
ファイルとしてドキュメントの構造を生成するコマンドで、 make html
で html ドキュメントとして出力できるやつです。
docs/html
をルートディレクトリとして git のリポジトリを作り、 Github Pages に設定することでドキュメントを簡単に公開することができます。
おまけ
.gitignore
.idea/
*.iml
.venv/
/dist/
/.pypirc
/docs/_build/
/docs/_static/
/docs/_templates/
/docs/*.rst
!/docs/index.rst
おわりに
いかががでしたか?
今回は Python の開発環境周りのセットアップについて調べてみました!
ご意見ご感想はコメントまでよろしくお願いします!
ps
sphinx の pyproject.toml への設定集約化はこれでいけそう?
sphinx-toolbox/sphinx-pyproject
Discussion