python で pyenv + poetry + tox + pytest に optional で
-
pytest の拡張
pytest-mock + pytest-cov
-
linter/formatter
black + isort + flake8 + mypy
-
API の文書化
pdoc
-
動的バージョニング
poetry-dynamic-versioning
-
CI/CD
gh-actions
特に注釈がなければ, 各種情報の背景は 2022年12月あたり.
本例では python 3.7 環境でエラーが発生するようにしている.
- OS は Linux または Windows を想定
- 任意の python 環境は pyenv で構築
Windows の場合は pyenv-win で代替 - 仮想環境は poetry で構築
グループ機能が便利なのでバージョンは 1.2 以上. - 本例では python 3.7 / 3.8 を想定
3.8 は現行バージョンで, 3.7 は後方互換の最小バージョンとした開発を行っている状況など.
※ 3.7 未満は依存関係がカオスなので全力回避 - テストは tox + pytest
- 面倒なことはしない
flowchart TD
subgraph system
id11(python >= 3.7)
id12(poetry >= 1.2)
subgraph pyenv
id21(python = 3.7)
id22(python = 3.8)
end
subgraph project
id31(.venv)
subgraph .tox
id41(py37)
id42(py38)
end
end
end
id12 .-> id11
id12 --> |poetry run python| id31
id12 --> |poetry run tox| .tox
id41 .-> id21
id31 & id42 .-> id22
- Automatic installer を利用
- 詳細は pyenv installer
- 環境毎の違いは Troubleshooting / FAQ
選択肢が多いので Installation からお好みで.
Chocolatey 以外は環境変数の設定が必要になるので詳細を参考に.
候補を確認
$ pyenv install -l
とある環境での最新は 3.7.9 / 3.8.10 だったのでインストール
$ pyenv install 3.7.9
$ pyenv install 3.8.10
インストール済みバージョンの確認
$ pyenv versions
[2022/12/07] この時点での最新は 1.2.2 で ドキュメント より
Poetry requires Python 3.7+. It is multi-platform and the goal is to make it work equally well on Linux, macOS and Windows.
予めシステムに python 3.7 以上をインストール要.
poetry を動作させるために必要であって, プロジェクトへの制約ではない.
Installation を参考にお好みで.
設定を確認
$ poetry config --list
virtualenvs.in-project = null
なら下記を一度だけ実行
$ poetry config virtualenvs.in-project true
もしもプロジェクト毎に有効にしたいのであれば
$ poetry config virtualenvs.in-project true --local
好みの問題ではあるが, 本例では全体設定としておく.
任意の場所で
$ poetry new --src python-poetry-example
ディレクトリ
python-poetry-example
├─ pyproject.toml
├─ README.md
├─ src
│ └─ python_poetry_example
│ └─ __init__.py
└─tests
└─ __init__.py
プロジェクトルートに移動
$ cd python-poetry-example
以降は特に注釈がない限りはプロジェクトルートでコマンドを実行している
使用する python を指定
$ pyenv local 3.8.10 3.7.9
有効になっているバージョンを確認
$ python -V
Python 3.8.10
本例では 3.8.10 を現行バージョンと想定している.
動作確認を行った環境では,
pyenv local 3.8.10 3.7.9
ならpython -V
で3.8.10
pyenv local 3.7.9 3.8.10
ならpython -V
で3.7.9
最初に指定をしたバージョンが有効になる.
仮想環境の構築にも影響があるので要注意.
ディレクトリ
python-poetry-example
├─ .python-version (New!)
├─ pyproject.toml
├─ README.md
├─ src
│ └─ python_poetry_example
│ └─ __init__.py
└─tests
└─ __init__.py
以下のように指定をしておく.
[tool.poetry.dependencies]
python = "^3.7"
意味は 3.7 <= python version < 4.0 と若干緩め.
依存するモジュールによっては制限を厳しくする必要もある.
3.8.10 ベースで構築.
$ poetry env use python
確認は
$ poetry env info
ディレクトリ
python-poetry-example
├─ .python-version
├─ pyproject.toml
├─ README.md
├─ .venv (New!)
│ └─ ...
├─ src
│ └─ python_poetry_example
│ └─ __init__.py
└─tests
└─ __init__.py
適当な機能をまとめた utils.py
と, そのテストコードを配置する.
ディレクトリ
python-poetry-example
├─ .python-version
├─ pyproject.toml
├─ README.md
├─ .venv
│ └─ ...
├─ src
│ └─ python_poetry_example
│ ├─ __init__.py
│ └─ utils.py (New!)
└─tests
├─ __init__.py
└─ test_utils.py (New!)
poetry add
でも構わないが, 本例では諸事情から pyproject.toml
に直接記述をする.
[tool.poetry.group.dev]
optional = true
[tool.poetry.group.dev.dependencies]
tox = "^3.27.1"
[tool.poetry.group.test]
optional = true
[tool.poetry.group.test.dependencies]
pytest = "^7.2.0"
[tool.pytest.ini_options]
addopts = [
"--import-mode=importlib",
]
pythonpath = "src"
- [2022/12/09] tox >= 4.0.0 で仮想環境を認識できない不具合を確認
Linux Mint 21 / Windows10 共に, アクティブになっている1つの環境しか認識されない.
本例では 3.7 が認識されずスキップされる.
issue では Tox 4 breaks in CI/CD pipelines where user does not exist #2702 が似ている.
4系で環境変数周りが大幅に変更された影響と思われるので様子見が必要.
インストール
$ poetry install --with dev
インストールでエラーがでるようならロックファイルの更新で対応
$ poetry update
確認
$ poetry show
[tox]
envlist =
py{37,38}
skipsdist = true
isolated_build = true
[testenv]
allowlist_externals =
poetry
commands_pre =
poetry install --with test -v
commands =
poetry run pytest -v
py37
/py38
はpyenv local
で指定されたバージョンを参照するtox
側のキーワード.
もしも 3.11.x が必要ならpy311
となる.
ディレクトリ
python-poetry-example
├─ .python-version
├─ poetry.lock
├─ pyproject.toml
├─ README.md
├─ tox.ini (New!)
├─ .venv
│ └─ ...
├─ src
│ └─ python_poetry_example
│ ├─ __init__.py
│ └─ utils.py
└─tests
├─ __init__.py
└─ test_utils.py
$ poetry run tox
本例では python 3.7 環境でエラーが発生するようにしている.
ディレクトリ
python-poetry-example
├─ .python-version
├─ poetry.lock
├─ pyproject.toml
├─ README.md
├─ tox.ini
├─ .tox (New!)
│ └─ ...
├─ .venv
│ └─ ...
├─ src
│ └─ python_poetry_example
│ ├─ __pycache__
│ │ └─ ...
│ ├─ __init__.py
│ └─ utils.py
└─tests
├─ __pycache__
│ └─ ...
├─ __init__.py
└─ test_utils.py
[tool.poetry]
name = "python-poetry-example"
version = "0.1.0"
description = ""
authors = ["name <email>"]
readme = "README.md"
packages = [{include = "python_poetry_example", from = "src"}]
[tool.poetry.dependencies]
python = "^3.7"
[tool.poetry.group.dev]
optional = true
[tool.poetry.group.dev.dependencies]
tox = "^3.27.1"
[tool.poetry.group.test]
optional = true
[tool.poetry.group.test.dependencies]
pytest = "^7.2.0"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[tool.pytest.ini_options]
addopts = [
"--import-mode=importlib",
]
pythonpath = "src"
[tox]
envlist =
py{37,38}
skipsdist = true
isolated_build = true
[testenv]
allowlist_externals =
poetry
commands_pre =
poetry install --with test -v
commands =
poetry run pytest -v
/.tox
/.venv
/.python-version
/poetry.lock
__pycache__/
.python-version
は環境次第でマイナーバージョンに大きな差があるため.poetry.lock
はお好みで.- 最終的にはPython.gitignoreを元に調整.
基本で目的は果たしているものの, 心許ないので一手間を加える場合もある.
好みもあるので以降は optional となる.
-
mocker fixture の追加
-
coverage reports の追加
./pyproject.toml
...
[tool.poetry.group.test]
optional = true
[tool.poetry.group.test.dependencies]
pytest = "^7.2.0"
pytest-mock = "^3.10.0"
pytest-cov = "^4.0.0"
...
./tox.ini
[tox]
envlist =
clean
py{37,38}
report
skipsdist = true
isolated_build = true
[testenv]
allowlist_externals =
poetry
commands_pre =
poetry install --with test -v
commands =
poetry run pytest --cov --cov-append --cov-report=term-missing -v
[testenv:clean]
deps = coverage
skip_install = true
commands_pre = # nop
commands =
poetry run coverage erase
[testenv:report]
deps = coverage
skip_install = true
commands_pre = # nop
commands =
poetry run coverage report -m
poetry run coverage html
...
-
インストール
$ poetry install --with test
-
実行
$ poetry run tox -r -e clean,py37,py38,report
並列で行う場合は,
./tox.ini
... [testenv] ... depends = py{37,38}: clean report: py{37,38} # Required if -p is enabled on Windows. # https://github.com/tox-dev/tox/pull/2641 setenv = PYTHONIOENCODING=utf-8 ...
を追記し
$ poetry run tox -r -e clean,py37,py38,report -p all
順序は
depends
で解決するので適当でもよい.
-
コードの整形に利用.
-
import
の並び替えに利用. -
構文チェックに利用.
poetry
経由で利用するのでオリジナルは使えない.[2022/12/11] pflake8 は
max-line-length
が反映されなかったので選択肢を変更した.79 / 88 / 120 宗派のため.
-
型ヒントに利用.
取り敢えず組み込んでおき, いつでも optional から変更できるように配慮.
flowchart LR
subgraph solution
subgraph formatter
black
isort
black .- isort
end
subgraph linter
flake8
mypy
end
end
vscode
環境とそれ以外を考慮しつつ, 最終的にリポジトリへのコミットで同一性を担保する方向で.
solution
の設定はpyproject.toml
で一元管理vscode
はpoetry
で作成した仮想環境を利用するように設定tox
に確認用の環境を仕込んでおく- pre-commit でコミットをフックする
flowchart LR
subgraph tox
id_tox(solution)
end
subgraph poetry
id_poetry(solution)
end
subgraph vscode
id_vscode(solution)
end
subgraph pre-commit
id_pre-commit(solution)
end
tox .-o poetry
id_terminal(terminal)
id_py(*.py)
id_repo[(repo)]
id_git(git)
id_terminal .-> id_git
vscode .-> id_git
id_terminal --> |poetry run tox solution| id_tox --> |dry-run| id_py
id_terminal ---> |poetry run solution| id_poetry --> |run| id_py
id_vscode --> id_py
id_py .-o id_repo
id_pre-commit --> id_py
id_git .-> |git commit| pre-commit .-> id_repo
./pyproject.toml
...
[tool.poetry.group.dev.dependencies]
black = "^22.10.0"
isort = "^5.10.1"
Flake8-pyproject = "^1.2.2"
mypy = "^0.991"
pre-commit = "^2.20.0"
tox = "^3.27.1"
...
[tool.black]
line-length = 88
skip-string-normalization = true
[tool.isort]
profile = "black"
line_length = 88
multi_line_output = 3
include_trailing_comma = true
[tool.flake8]
max-line-length = 88
extend-ignore = ["E203", "E266", "W503",]
max-complexity = 10
extend-exclude = [".venv", "dist", ".github",]
[tool.mypy]
ignore_errors = true
#disallow_untyped_defs = true
#ignore_missing_imports = true
#no_implicit_optional = true
#show_error_context = true
#show_column_numbers = true
#warn_return_any = true
#warn_unused_ignores = true
#warn_redundant_casts = true
exclude = ["dist/",]
...
mypy
を ignore_errors = true
で実質的に無効にしているので注意.
./tox.ini
[tox]
envlist =
py{37,38}
black
isort
flake8
mypy
skipsdist = true
isolated_build = true
...
[testenv:black]
deps = black
commands_pre = # nop
commands =
poetry run black . --check --diff --color
[testenv:isort]
deps =
isort
colorama
commands_pre = # nop
commands =
poetry run isort . --check --diff --color
[testenv:flake8]
deps = Flake8-pyproject
commands_pre = # nop
commands =
poetry run flake8p .
[testenv:mypy]
deps = mypy
commands_pre = # nop
commands =
poetry run mypy .
./.pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-added-large-files
- id: check-toml
- id: check-yaml
- id: end-of-file-fixer
- id: mixed-line-ending
args: [--fix=lf]
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]
- repo: https://github.com/psf/black
rev: 22.12.0
hooks:
- id: black
language_version: python3
- repo: https://github.com/pycqa/isort
rev: 5.10.1
hooks:
- id: isort
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
- id: flake8
additional_dependencies: [Flake8-pyproject]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.991
hooks:
- id: mypy
-
インストール
$ poetry install --with dev
-
vscode
環境以外で直接実行$ poetry run black . $ poetry run isort . $ poetry run flake8 . $ poetry run mypy .
-
vscode
環境以外で tox 経由で実行$ poetry run tox black $ poetry run tox isort $ poetry run tox flake8 $ poetry run tox mypy
-
pre-commit
を編集時に適用する$ poetry run pre-commit install
- 実行パス
.
の由来や除外するディレクトリ- black
デフォルト動作は.gitignore
を利用する.
思想が垣間見れるのは, ココ や ココ. - isort
Compatibility with black を謳っているので追従している. - flake8
何もしない. - mypy
デフォルト動作は隠しディレクトリを除外する.
- black
ライブラリ色の強いプロジェクトでは API の文書化が必要なので, ここでは pdoc を利用した方法を示す.
sphinx でも大差はない.
./pyproject.toml
...
[tool.poetry.group.docs]
optional = true
[tool.poetry.group.docs.dependencies]
pdoc = "^12.3.0"
tomli = {version = "^2.0.1", python = "<3.11"}
...
./docs/make.py
from pathlib import Path
import pdoc
try:
import tomllib
except ModuleNotFoundError:
import tomli as tomllib
if __name__ == '__main__':
here = Path(__file__).parent
project_root_dir = here / '..'
toml_path = project_root_dir / 'pyproject.toml'
with open(toml_path, mode='rb') as f:
toml_dict = tomllib.load(f)
project_name = toml_dict['tool']['poetry']['name']
module_name = toml_dict['tool']['poetry']['packages'][0]['include']
version = toml_dict['tool']['poetry']['version']
# Render docs
pdoc.render.configure(
docformat='google',
footer_text=f'{project_name} {version}',
)
pdoc.pdoc(
project_root_dir / 'src' / module_name,
output_directory=project_root_dir / 'docs/build',
)
宗教上の理由がある場合は下記を参照.
...use numpydoc or Google docstrings?
-
インストール
$ poetry install --with docs
-
実行
$ poetry run python ./docs/make.py
VCS を基点に動的なバージョン管理を行う.
poetry-dynamic-versioning を利用する.
利用するのはデフォルト動作で, poetry build
を実行している間だけ有効であることに注意.
flowchart LR
id_1(start)
id_2(end)
subgraph sdist/wheel
subgraph targets
id_t1[pyproject.toml]
id_t2[__init__.py]
id_t3[__version__.py]
id_t3 .-o id_t2
end
end
subgraph versioning
id_v1[git tag v0.1.0]
subgraph build
id_b1[poetry build]
end
id_v1 --> build
end
build .-> sdist/wheel
id_1 ==> versioning ==> id_2
"0.0.0" の由来は
Poetry's typical
version
setting is still required in[tool.poetry]
, but you are encouraged to useversion = "0.0.0"
as a standard placeholder.
./pyproject.toml
[tool.poetry]
...
version = "0.0.0"
...
[build-system]
requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning"]
build-backend = "poetry_dynamic_versioning.backend"
[tool.poetry-dynamic-versioning]
enable = true
vcs = "git"
style = "pep440"
[tool.poetry-dynamic-versioning.substitution]
folders = [
{ path = "src" }
]
...
./src/python_poetry_example/__version__.py
__version__ = '0.0.0'
./src/python_poetry_example/__init__.py
from .__version__ import __version__
-
プラグインのインストール
$ poetry self add "poetry-dynamic-versioning[plugin]"
-
プラグインのアンインストール
$ poetry self remove poetry-dynamic-versioning
-
バージョニング
-
タグをつける
v0.0.0
からv0.1.0
にする場合$ git tag v0.1.0
-
ビルドを実行する
$ poetry build
./dist
内に含まれる対象/関連ファイルのみ影響を受ける.よってリリース後の
python_poetry_example.__version__
などは意図した動作になる. -
-
拡張 3 - API の文書化 と連携する場合について
poetry-dynamic-versioning
を手動で実行する方法も考えられるがとても煩雑になる.よって VCS からタグを取得する方向で済ませる.
flowchart LR subgraph versioning id_v1[git tag v0.1.0] end subgraph documentation id_d1[poetry run python ./docs/make.py] end build[(./docs/build)] versioning ==> documentation id_d1 .-> build
./pyproject.toml
... [tool.poetry.group.docs] optional = true [tool.poetry.group.docs.dependencies] pdoc = "^12.3.0" tomli = {version = "^2.0.1", python = "<3.11"} GitPython = "^3.1.29" ...
./docs/make.py
import os from pathlib import Path import git import pdoc try: import tomllib except ModuleNotFoundError: import tomli as tomllib if __name__ == '__main__': here = Path(__file__).parent project_root_dir = here / '..' toml_path = project_root_dir / 'pyproject.toml' with open(toml_path, mode='rb') as f: toml_dict = tomllib.load(f) project_name = toml_dict['tool']['poetry']['name'] module_name = toml_dict['tool']['poetry']['packages'][0]['include'] version = toml_dict['tool']['poetry']['version'] if version == '0.0.0': repo_dir = project_root_dir / '.git' if os.path.isdir(repo_dir): repo = git.Repo(repo_dir) if repo.tags: tags = sorted(repo.tags, key=lambda t: t.commit.committed_datetime) latest_tag = tags[-1] version = str(latest_tag) if version.startswith('v'): version = version[1:] # Render docs pdoc.render.configure( footer_text=f'{project_name} {version}', ) pdoc.pdoc( project_root_dir / 'src' / module_name, output_directory=project_root_dir / 'docs/build', )
ここでは GitHub Actions を利用した例となる.
デプロイ先は
- パッケージは TestPyPI
- API ドキュメントは GitHub Pages
flowchart LR
event_1(on: push)
event_2(on: pull_request)
event_3(on: release)
event_4(on: workflow_dispatch)
subgraph test.yml
direction LR
id_t1[black\ndry-run]
id_t2[isort\ndry-run]
lint-pr
lint-local
mypy
test
id_t1 --> id_t2
id_t2 --> lint-local --> mypy
id_t2 --> lint-pr --> mypy
mypy --> test
end
subgraph testpypi.yml
testpypi_1[build]
--> testpypi_2[deploy]
end
subgraph docs.yml
docs_1[build]
--> docs_2[deploy]
end
event_1 ==> test.yml
event_2 ==> test.yml
event_3 ==> testpypi.yml
testpypi_2 .-> o1[(TestPyPI)]
testpypi.yml ====> |on: workflow_call| docs.yml
event_4 ==> docs.yml
docs_2 .-> o2[(gh-pages)]
./github/python-version.txt
3.8
各ファイルで用いる, 開発上の現行バージョンを指定.
./github/workflows/test.yml
name: Test
on: [ push, pull_request ]
permissions:
contents: read
jobs:
black:
if: true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version-file: .github/python-version.txt
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install 'poetry>=1.2'
poetry install --with dev --no-interaction
- name: Lint with black
run: |
poetry run tox -e black
isort:
if: true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version-file: .github/python-version.txt
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install 'poetry>=1.2'
poetry install --with dev --no-interaction
- name: Lint with isort
run: |
poetry run tox -e isort
lint-pr:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: TrueBrain/actions-flake8@v2
lint-local:
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version-file: .github/python-version.txt
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install 'poetry>=1.2'
poetry install --with dev --no-interaction
- name: Lint with flake8
run: |
poetry run tox -e flake8
mypy:
if: true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version-file: .github/python-version.txt
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install 'poetry>=1.2'
poetry install --with dev --no-interaction
- name: Lint with mypy
run: |
poetry run tox -e mypy
test:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
python-version: ['3.7', '3.8']
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install 'poetry>=1.2'
poetry install --with dev --no-interaction
- name: Test with pytest
run: |
poetry run tox -e py
test
は対象範囲が変わる都度, 設定を変更する必要がある.
./github/workflows/testpypi.yml
name: Publish the package to TestPyPI
on:
workflow_dispatch:
release:
types: [published]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version-file: .github/python-version.txt
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install 'poetry>=1.2'
poetry self add 'poetry-dynamic-versioning[plugin]'
- name: Build
run: |
poetry build
- name: publish
env:
TESTPYPI_API_TOKEN: ${{ secrets.TESTPYPI_API_TOKEN }}
run: |
poetry config repositories.test-pypi https://test.pypi.org/legacy/
poetry config pypi-token.test-pypi $TESTPYPI_API_TOKEN
poetry publish -r test-pypi
docs:
if: true # true if documentation is needed.
needs: deploy
permissions:
contents: read
pages: write
id-token: write
uses: ./.github/workflows/docs.yml
docs
は API の文書化が不要なら false
に設定.
./github/workflows/docs.yml
# Workflow for deploying static content to GitHub Pages
name: Deploy static content to Pages
# build the documentation whenever there are new commits on main
on:
workflow_dispatch:
workflow_call:
# security: restrict permissions for CI jobs.
permissions:
contents: read
jobs:
# Build the documentation and upload the static HTML files as an artifact.
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-python@v4
with:
python-version-file: .github/python-version.txt
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install 'poetry>=1.2'
poetry install --with docs --no-interaction
- name: Build
run: |
poetry run python ./docs/make.py
- uses: actions/upload-pages-artifact@v1
with:
path: docs/build/
# Deploy the artifact to GitHub pages.
# This is a separate job so that only actions/deploy-pages has the necessary permissions.
deploy:
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v1
-
on: push
$ git push
-
on: pull_request
PR
-
on: release
$ git tag v0.1.0 $ git push origin v0.1.0
v0.1.0
をリリース -
on: workflow_dispatch
デバッグ用に手動でイベントをキック.
-
on: workflow_dispatch
docs.yml
を手動で実行するとmain
ブランチ(default)が渡される. -
on: workflow_call
testpypi.yml
経由で実行されるとon: release
でv0.1.0
ブランチが渡される.gh-pages のブランチ保護ルールに後者が利用できるように追記が必要.
例えばv*
などとしておく.
Poetry
や依存関係のキャッシュを行うことでアクションの実行時間を低減する.
分量が多いため issue で扱う.