ツールlist
-
pyenv: Python管理-> asdf - conda: Pythonの環境管理
- poetry: 依存パッケージの管理
- Python Packages (py-pkgs.org): Python Packageの作成方法
- cookiecutter: テンプレートからPython Projectを作成するCLIツール
- PyPI (Python Package Index): Python packageを公開するハブ
- Test Python Package Index: Python packageをテスト公開するチェック用
- python-semantic-release: Pythonのリリースを自動化するツール
- flake8, black, isort: Formater、Linter
- pipx
- asdf: asdf is a tool version manager. All tool version definitions are contained within one file (.tool-versions) which you can check in to your project's Git repository to share with your team, ensuring everyone is using the exact same versions of tools.
Install asdf
asdf
asdf plugin-add python
asdf install python 3.11.0
Poetry (依存パッケージ管理)
Poetryのインストール
asdf plugin-add poetry
asdf install poetry 1.7.1
プロジェクト内にvirtualenv作成
poetry config virtualenvs.in-project true
Package作成
- cookiecutterのインストール
pip install cookiecutter # Macなら brew install cookiecutterでも可
- cookiecutterを使ってtemplateからprojectの作成
cookiecutter https://github.com/py-pkgs/py-pkgs-cookiecutter.git
Packageの中身の実装
自分でPackageで実現したい内容を実装する。
ディレクトリ構成は、How to package a Pythonを参考にする。↓以下参照
pycounts
├── CHANGELOG.md ┐
├── CONDUCT.md │
├── CONTRIBUTING.md │
├── docs │ Package documentation
│ └── ... │
├── LICENSE │
├── README.md ┘
├── pyproject.toml ┐
├── src │
│ └── pycounts │ Package source code, metadata,
│ ├── __init__.py │ and build instructions
│ ├── moduleA.py │
│ └── moduleB.py ┘
└── tests ┐
└── ... ┘ Package tests
Packageのビルド
poetry build
dist
(pyproject.toml
の dist_path
で指定されたディレクトリ)に wheelとsrcが生成される
Version更新
poetry version
コマンドを使ってVersionを更新する
poetry version <rule>
rule:
major
minor
patch
premajor
preminor
prepatch
- etc
あとで紹介するPython Semantic Release (PSR)を使用する場合には、こちらはスキップして可。
Pypi (Package公開用)
Packageを公開する方法
Test設定 (1回のみ)
- アカウント作成: https://test.pypi.org/account/register/ (すでに持っていればスキップ)
- テスト用のsource追加
poetry source add test-pypi https://test.pypi.org/simple/
- API keyを取得し、poetry configに設定 (
test-pypi
としているのに注意)poetry config pypi-token.test-pypi pypi-xxxxxx
本番設定 (1回のみ)
- アカウント作成: https://pypi.org/account/register (すでに持っていればスキップ)
- API keyを取得し、poetry configに設定 (
pypi
)poetry config pypi-token.pypi pypi-xxxxx
Test pypiに公開
- buildする
poetry build
- test pypiにPublishする
e.g. https://test.pypi.org/project/autonote/
poetry publish -r test-pypi
Test pypiのpackageを確認
test pypiで公開したバージョンをインストールする
poetry add --source test-pypi autonote==0.1.1a0
詳細: https://python-poetry.org/docs/repositories/
Test Pypiで公開したバージョンでの挙動の確認をしたりする。
Pypiに公開
- buildする
poetry build
- pypiにPublishする
poetry publish
Python Semantic Release (PSR)
semantic commit messageを見てリリースを勝手にうまい具合にやってくれるツール.
PSRの設定
Install
poetry add --dev python-semantic-release
以下をtomlに追加
[tool.semantic_release]
version_variable = "pyproject.toml:version"
version_source = "tag"
PSRのコマンド
-
Versionを確認 (コミットやTag作成などしない):
semantic-release print-version # 次のバージョン semantic-release print-version --current # 今のバージョン
-
新しいバージョンを発行、コミット、新規タグ作成をローカルで実行。
semantic-release version
うまく行かない場合
semantic-release version -v DEBUG
-v DEBUG
をつけてどこがおかしいのか確認。get_current_version_by_tag
で取れてない場合は、tomlファイルに指定したTagに値が存在しているか確認。Creating new version debug: get_current_version_by_tag() debug: get_last_version(, pattern='(\d+\.\d+\.\d+(-beta\.\d+)?)') debug: get_last_version -> 0.1.3 debug: get_current_version_by_tag -> 0.1.3 debug: get_current_release_version_by_tag() debug: get_last_version(, pattern='v?(\d+\.\d+\.\d+(?!.*-beta\.\d+))') debug: get_last_version -> 0.1.3 debug: get_current_release_version_by_tag -> 0.1.3 Current version: 0.1.3, Current release version: 0.1.3 debug: evaluate_version_bump('0.1.3', None) debug: Commits found since last release: 0 debug: get_new_version('0.1.3', '0.1.3', None, False, True) debug: get_new_version -> 0.1.3 No release will be made.
-
Publish
semantic-release publish
このコマンドがすること:
- ChangeLogファイルの更新
-
semantic-release version
の実行 (ローカルでコミット、Tag生成). - 変更をGitにPush
-
build_command
の実行と dist fileをアップロード -
semantic-release changelog
の実行とGitHubなどVCS providerへのポスト - GitHub releaseにDist fileを添付
個人的にはローカルからPublishしたくないので、ここらへんはGitHub Actionsに設定したほうがいいかなと思っています。
Lint
poetry run isort --check --diff .
poetry run black --check --diff .
poetry run flake8 .
flake8でlintの対象外にしたい場合は、excludeを書ける
[flake8]
exclude =
# No need to traverse our git directory
.git,
# There's no value in checking cache directories
__pycache__,
# The conf file is mostly autogenerated, ignore it
docs/source/conf.py,
# The old directory contains Flake8 2.0
old,
# This contains our built documentation
build,
# This contains builds of flake8 that we don't want to check
dist
.venv
GitHub Actions
cookiecutterから持ってきたci-cdだと毎回mainにpushするたびにリリースされるのでCIとReleaseに分割。
CI
Pull Request作成時とmain branchにPushされたときに実行するもの (test, lint, codecov, docsなどを実行)
name: dev
on:
pull_request:
push:
branches:
- main
jobs:
ci:
# Set up operating system
runs-on: ubuntu-latest
# Define job steps
steps:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.9"
- name: Check-out repository
uses: actions/checkout@v3
- name: Load cached Poetry installation
id: cached-poetry
uses: actions/cache@v3
with:
path: ~/.local # the path depends on the OS
key: poetry # increment to reset cache
- name: Install poetry
if: steps.cached-poetry.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1
- name: Restore cached dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pypoetry
key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }}
restore-keys: |
${{ runner.os }}-poetry-
- name: Install package
run: poetry install
- name: Lint
run: |
poetry run isort --check --diff .
poetry run black --check --diff .
poetry run flake8 .
- name: Test with pytest
run: poetry run pytest tests/ --cov=<package_name> --cov-report=xml
- name: Use Codecov to track coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage.xml # coverage report
- name: Build documentation
run: poetry run make html --directory docs/
<package_name>
自分のものへ変更
semantic-pull-request
リリースをcommit messageベースで判定するので、commit message(pull requestのtitleをcommit messageに使うとして)をCIでチェックする
詳細: https://github.com/amannn/action-semantic-pull-request
name: semantic-pull-request
on:
pull_request:
types:
- opened
- edited
- synchronize
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Release
あまりいいやり方じゃないかもしれませんが、自分でReleaseを手動で作成するのがめんどくさい (タグをsemantic-releaseに自動で決めてほしい) ので、releaseしたいときに、 dispatch_workflowを実行してその中で semantic-release publish
を実行するactionを作成
name: release
on:
workflow_dispatch:
jobs:
releaase:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.9"
- name: Check-out repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Load cached Poetry installation
id: cached-poetry
uses: actions/cache@v3
with:
path: ~/.local # the path depends on the OS
key: poetry # increment to reset cache
- name: Install poetry
if: steps.cached-poetry.outputs.cache-hit != 'true'
uses: snok/install-poetry@v1
- name: "Restore cached dependencies"
uses: actions/cache@v3
with:
path: ~/.cache/pypoetry
key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }}
restore-keys: |
${{ runner.os }}-poetry-
- name: Install package
run: poetry install
- name: Use Python Semantic Release to prepare release
env:
# This token is created automatically by GH Actions
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git config user.name github-actions
git config user.email github-actions@github.com
poetry run semantic-release publish
- name: Publish to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
- name: Test install from TestPyPI
run: |
pip install \
--index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple \
<package_name>
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
<package_name>
自分のものへ変更
ただこれだとpoetry run semantic-release publish
で更新した toml
内のversionをpushできてないのでいつまでもtomlのバージョンが古いままになっている。(version_sourceをtagにしてかつversion_variable = "pyproject.toml:version"
にしてるのが良くないのか)要改善。
ToDo
- GitHub Actionsを含めたリリースフロー改善
- Documentation