sphinx doctest poetry pytestを使用したプログラム開発フローまとめ(個人用)
こういう系はいろんな人がまとめているので再度まとめる必要性はないのですが、個人的な備忘録としてまとめていきます。詳しい説明は省略してます。
個人で簡単なパッケージを作成することを考えています。
また、今回の内容ではないですが、Pythonの実装のポイントはこちら(https://qiita.com/sugulu_Ogawa_ISID/items/c0e8a5e6b177bfe05e99)が非常に参考になりました。
準備
pip install sphinx
pip install sphinx_rtd_theme
pip install poetry
0. 開発ディレクトリ作成
mkdir dirname_package
1. document、test、src用のディレクトリを作成
docs
にSphinxドキュメント、tests
にテストコード、packagename
にコードを置きます。
cd dirname_package
mkdir packagename tests docs
2. sphinxのプロジェクト準備
対話形式で入力必要ですが、こだわりがなければ基本的にEnter key押す感じでOKです。
私は最初の ソースディレクトリとビルドディレクトリを分ける(y / n) [n]:
はyes
にしてます。
sphinx-quickstart docs
3. conf.pyの編集
docs/source/conf.py
を以下のように編集します。
import os
import sys
sys.path.insert(0, os.path.abspath('../../packagename/')
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.todo',
'sphinx.ext.viewcode',
'sphinx.ext.napoleon',
]
html_theme = 'sphinx_rtd_theme'
4. poetry準備
pyproject.toml
がない場合に以下のコマンドをdirname_package
直下で実行します。
後でpoetry add
でパッケージを追加してもいいですが、下の画像のようにこの段階でも追加できます。
poetry init
[f:id:yamayou_1:20210301235917p:plain]
5. このパッケージの専用のpoetry仮想環境を作成
poetry install
このpoetry仮想環境内で実行する場合は以下のようにします。
poetry run pytest ./tests/test.py
poetry run python ./packagename/script.py
6. 適当な関数を作成とdoctest
最初に、__init__.py
を作成した後に、例として簡単な関数をpackagename
内に作成します。
docstringの形式は以下のURLを参考にしてください。
[https://qiita.com/yokoc1322/items/ebf25c9cb779ff5ebc9c:title]
cd packagename
touch __init__.py
def add_integer_value(a: int, b: int) -> int:
"""add number
This function sums up two arguments.
Args:
a (int): a value to be added
b (int): b value to be added
Returns:
int: summation of a and b
Example:
>>> add_integer_value(1, 2)
3
>>> add_integer_value(3, -4)
-1
"""
return a + b
この時、以下のようにしてdoctestを行います。
poetry run python -m doctest main.py
#7. docstringから自動でドキュメントを作成
画像のように綺麗になります。
cd ../
sphinx-apidoc -f -o ./docs/source ./src
cd docs
make html
open build/html/index.html
[f:id:yamayou_1:20210302003259p:plain]
pytest
多人数で作成または相手がいるような場合はpytestでユニットテストなどを行った方が良いですが、個人で簡単なものを作る場合は書いてないかもしれません。。。
書く場合は以下のようにtests
下にテストコードを書いて実行しましょう。
cd tests
touch __init__.py
import pytest
from packagename.main import add_integer_value
@pytest.fixture
def sample_var():
a, b = 1, 2
return a, b
def test_add_integer_value(sample_var):
""" 整数値の足し算
"""
sum_value = add_integer_value(*sample_var)
assert sum_value == 3
cd ../
poetry run pytest tests/test_add_integer_value.py
補足
以上が基本的な構成・流れですが、補足としてloggerやconstantを扱う例を載せておきます。
cd packagename
mkdir config
config
フォルダ内に以下のlogging.json
を保存します。
{
"version": 1,
"disable_existing_loggers": "False",
"root": {
"level": "DEBUG",
"handlers": [
"consoleHandler",
"logFileHandler"
]
},
"handlers": {
"consoleHandler": {
"class": "logging.StreamHandler",
"level": "DEBUG",
"formatter": "consoleFormatter",
"stream": "ext://sys.stdout"
},
"logFileHandler": {
"class": "logging.FileHandler",
"level": "DEBUG",
"formatter": "logFileFormatter",
"filename": "./log_file.log",
"mode": "w",
"encoding": "utf-8"
}
},
"formatters": {
"consoleFormatter": {
"format": "[%(asctime)s] %(levelname)s: file=%(name)s func_name=%(funcName)s message=%(message)s"
},
"logFileFormatter": {
"format": "[%(asctime)s] %(levelname)s: file=%(name)s func_name=%(funcName)s message=%(message)s"
}
}
}
作成したファイルのパスを定数としてアクセスできるようにしておきます。その場合、以下のようなconstants.py
を作成します。
from pathlib import Path
HOME = Path(__file__).resolve().parent
# logging config file
LOGGING_CONFIG_FILEPATH = HOME / "config" / "logging.json"
あとは、以下の関数内でconfigファイルを読み込めばOKです。
import logging
from logging import Formatter, StreamHandler, FileHandler, config, getLogger
from json import load
from packagename.constants import LOGGING_CONFIG_FILEPATH
def get_logger(name: str):
with open(LOGGING_CONFIG_FILEPATH, "r", encoding="utf-8") as f:
config.dictConfig(load(f))
logger = logging.getLogger(name)
return logger
使うときは以下のようにpackagename.logger.get_logger
をインポートします。
from packagename.logger import get_logger
logger = get_logger("main")
logger.info("test")
Discussion