Python Monthly Topics

最近気になるツール「Hatch」Pythonプロジェクトを管理する

福田@JunyaFffです。今月の「Python Monthly Topics」は、Pythonプロジェクトの管理ツール「Hatch」を紹介します。

はじめに

Pythonで新しいプロジェクトを作る時にどのように始めますか? 新しいライブラリを作りたい、仕事で新しいPythonのプロジェクトが始まる、といったような場面で、プロジェクトのディレクトリ構成やフォーマッターやタスクランナーなどをどのように管理するか悩んだことはありませんか?

Python以外の言語、たとえばRustではCargo、JavaScriptではnpm、RubyではBundlerなど、言語ごとにプロジェクトの管理を支援するツールがあります。PythonにもPythonプロジェクトを管理するさまざまなツールがありますが、今回はその中の1つ「Hatch」に焦点を当てて紹介します。

Hatchのロゴマーク

Hatchとは

Hatchは、Pythonプロジェクトの管理を支援するコマンドラインツールです。デフォルトでディレクトリ構成が決められており、バージョン管理もでき、タスクを登録して実行することもできます。

比較対象になるツールとして、Poetrypdmがあります。どのツールでも同じようなことができますが、それらと異なるHatchの特徴として大きく2点が挙げられます。

  • Pythonインタープリターを管理できる
  • 既定の設定が充実している
    • ビルドやテスト、フォーマッターなどが既定の状態で利用できる

Python環境をpyenvや公式のインストーラーなどで管理する必要がなく、Hatchだけで完結できます。公式サイトのWhy Hatch?にも there is support for everything one might require. 必要なものはすべてサポート とあり、既定の設定が充実している点は、好みは分かれますが、サクッと新しいプロジェクトを作りたいときに便利です。

さらに、Hatchの内部では、フォーマットや静的コード解析に過去に本連載でも紹介したRuffを採用しており、またuvも設定で利用可能なため、高速である点も特徴のひとつです。

Hatchの設定は、pyproject.tomlファイルを使用して行います。pyproject.tomlファイルは、Pythonのパッケージングに関する設定を記述するためのファイルです。

プロジェクトのメタデータは標準に基づいており、ビルド システムはPEP 517 / PEP 660と互換性があるため、他のツールからの移行も簡単です。

また、Hatchはpypaで管理されているリポジトリです。開発も非常に活発で、記事執筆時点(2024年5月27日)での最新のバージョンは1.11.1になります。

Hatchにできること

Hatchにできることは以下の通りです。

  • プロジェクトのディレクトリ構成やpyproject.tomlファイルを自動作成できる
  • コードフォーマットや静的解析、テストを他のツールをインストールせずに実行できる
  • タスクランナー機能でプロジェクトに必要なタスクを登録でき、自動化しやすい
  • プロジェクトのビルド、PyPIへのデプロイが大きな設定変更なしでできる
  • プロジェクトのバージョンを管理できる
  • Pythonインタープリターを管理できる

Hatchを使ってみよう

Hatchの主な使い方を紹介します。

また実際にHatchを利用して、小さなサンプルプロジェクトを作成してみました。Hatchでプロジェクトを作成した直後のブランチと、最低限の変更をしたブランチがあります。本記事と合わせて、ブランチの差分をご参考ください。

Hatchのインストール

HatchはLinux、macOS、Windowsで動作し、インストール方法にはさまざまな方法があります。今回はMacでグローバルに利用できるように公式のインストーラーを利用しました。

$ curl -Lo hatch-universal.pkg https://github.com/pypa/hatch/releases/latest/download/hatch-universal.pkg
$ sudo installer -pkg hatch-universal.pkg -target /

以下のコマンドを実行して、Hatchがインストールされていることを確認します。

$ hatch --version
Hatch, version 1.11.1

Hatchのコマンド

Hatchにはさまざまなコマンドが用意されています。以下はHatchの主要なコマンドの一覧です。hatch -hでヘルプを確認できます。

  • new: 新しいプロジェクトを作成する
  • python: Pythonインタプリターを管理する
  • env: プロジェクトの仮想環境を管理する
  • shell: プロジェクトの仮想環境に入る
  • fmt: プロジェクトのフォーマットを行う
  • run: プロジェクトのスクリプトを実行する
  • build: プロジェクトをビルドする
  • test: テストを実行する
  • version: プロジェクトのバージョンを表示または更新する
  • config: グローバルな設定を確認する
  • project: プロジェクトの情報を確認する

また、各コマンドにサブコマンドがあります。サブコマンドでも-hでヘルプを確認できます。

$ hatch -h
...
$ hatch new -h
...
$ hatch python -h
...

まずは新しいプロジェクトを作成し、フォーマッターやリンターを実行してみましょう。

hatchコマンドの入力補完機能

Hatchの機能を見ていく前に、コマンドの入力補完機能を紹介します。

Hatchは多くのコマンドを提供しているため、コマンドを入力する際にタブキーを利用した補完機能があると便利です。公式ドキュメントにいくつかのシェルの補完設定が記載されています。hatchを利用する場合には、補完の設定をしておくと良いでしょう。

zshの場合
$ _HATCH_COMPLETE=zsh_source hatch > ~/.hatch-complete.zsh
~/.zshrcに追記する場合
. ~/.hatch-complete.zsh

他のシェルでの補完設定は、以下のリンクを参照してください。

新しいプロジェクトを作成する

Hatchでは、以下のコマンドを実行して、新しいプロジェクトを作成します。

$ hatch new myproject

コマンドを実行すると、以下のようにプロジェクトが作られ、ファイル一覧が出力されます。

$ hatch new myproject  
myproject
├── src
│   └── myproject
│       ├── __about__.py
│       └── __init__.py
├── tests
│   └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml

pyproject.tomlファイルを確認してみましょう。[build-system]"hatchling.build"が指定され、[project]にプロジェクトのメタデータが出力されています。必要に応じてプロジェクトのメタデータを変更してください。

続いて、この初期プロジェクトでHatchの機能を使ってみましょう。

Hatchによるテスト⁠フォーマット⁠登録済みのスクリプトの実行

Hatchでは、Hatchとしてすでに登録されているテストやフォーマットの実行、デフォルトで登録済みのスクリプトの実行ができます。

Hatchによるコードフォーマットや静的解析

Hatchではfmtサブコマンドで、プロジェクトのフォーマットと静的解析ができます。デフォルトでRuffが採用されており、いくつかのルールが設定されています。

hatch fmtを実行すると、フォーマットと静的解析が行われます。

$ hatch fmt
All checks passed!
3 files left unchanged

fmtサブコマンドには以下のようなオプションがあります。

オプション 説明
--check フォーマットのチェックを行う
--preview 修正箇所を表示する
--lint, -l 静的解析のみを行う
--format, -f フォーマットのみを行う

そのほかのオプションについては、以下の公式サイトを参照してください。

デフォルトで設定されているフォーマッターのルールは以下の通りです。フォーマッターのルールは、プロジェクトのpyproject.tomlファイルで変更できます。

Hatch によるテスト

次にテストについて見てみましょう。testサブコマンドで実行できます。Hatchではデフォルトでpytestが採用されています。

$ hatch test
============================ test session starts ============================
platform darwin -- Python 3.12.3, pytest-8.2.0, pluggy-1.5.0
rootdir: /Users/gihyo/dev/gihyo-python-monthly_sample/pdfifysvg
configfile: pyproject.toml
plugins: rerunfailures-14.0, mock-3.14.0, xdist-3.6.1
collected 0 items

=========================== no tests ran in 0.00s ===========================

また、testサブコマンドには以下のオプションがあります。

オプション 説明
--randomize, -r テストの実行順序をランダムにする
--parallel, -p テスト実行の並列化
--cover, -c テストのカバレッジを計測
--all, -a すべてのPythonバージョンでテストを実行
--python, -py 特定のPythonバージョンでテストを実行

そのほかのオプションは、以下の公式サイトを参照してください。

Hatchではカバレッジの計測もデフォルトでサポートされています。coverageが利用されています。

$ hatch test -py 3.11 -c
───────────────────────────── hatch-test.py3.11 ─────────────────────────────
============================ test session starts ============================
platform darwin -- Python 3.11.2, pytest-8.2.0, pluggy-1.5.0
rootdir: /Users/gihyo/dev/gihyo-python-monthly_sample/pdfifysvg
configfile: pyproject.toml
plugins: rerunfailures-14.0, mock-3.14.0, xdist-3.6.1
collected 1 item                                                            

tests/test_pdfysvg.py .                                               [100%]

============================= 1 passed in 0.12s =============================
Combined data file .coverage.jrfk.local.79827.XpkHLYBx
Name                          Stmts   Miss Branch BrPart  Cover
---------------------------------------------------------------
src/pdfysvg/__init__.py           0      0      0      0   100%
src/pdfysvg/__main__.py           1      1      0      0     0%
src/pdfysvg/cli/__init__.py      10      0     10      0   100%
src/pdfysvg/cli/main.py          11      2      2      1    77%
tests/__init__.py                 0      0      0      0   100%
tests/test_pdfysvg.py            19      0      6      1    96%
---------------------------------------------------------------
TOTAL                            41      3     18      2    92%

次に、複数のPythonバージョンでのテストを実行してみましょう。pyproject.tomlファイルに以下のように設定します。

pyproject.tomlに複数のPythonバージョンでのテストを追加
[[tool.hatch.envs.hatch-test.matrix]]
python = ["3.8", "3.9", "3.10", "3.11", "3.12"]

テストを実行します。複数のテストが実行されます。

$ hatch test --all
...(長いので割愛)
─────────────────────────────────────────────────────────────────────────────── hatch-test.py3.8 
=============================================================================== 1 passed in 0.11s ─────────────────────────────────────────────────────────────────────────────── hatch-test.py3.9 =============================================================================== 1 passed in 0.19s ─────────────────────────────────────────────────────────────────────────────── hatch-test.py3.10 =============================================================================== 1 passed in 0.11s ─────────────────────────────────────────────────────────────────────────────── hatch-test.py3.11 =============================================================================== 1 passed in 0.10s ─────────────────────────────────────────────────────────────────────────────── hatch-test.py3.12 ========================================================================= 1 passed, 1 warning in 0.10s

Hatchによるスクリプトの実行

Hatchでは登録しているスクリプトをrunサブコマンドで実行できます。また、env showサブコマンドで、登録しているスクリプトを確認できます。

$ hatch env show
                  Standalone                  
┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━┓
┃ Name    ┃ Type    ┃ Dependencies ┃ Scripts ┃
┡━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━┩
│ default │ virtual │              │         │
├─────────┼─────────┼──────────────┼─────────┤
│ types   │ virtual │ mypy>=1.0.0  │ check   │
└─────────┴─────────┴──────────────┴─────────┘

Hatchではデフォルトでmypyを利用した型チェックのスクリプトが登録されています。登録してあるスクリプトは次のように実行します。

$ hatch run types:check
Success: no issues found in 5 source files

スクリプトだけでなく、Pythonのコードを直接実行することもできます。

$ hatch run python -c "print('Hello, Hatch!')"
Hello, Hatch!

HatchでのPythonインタープリターの管理

hatchではPythonインタープリターの管理も行うことができます。以下のコマンドを実行して、利用可能なPythonのバージョンを表示します。

$ hatch python show
      Available
┏━━━━━━━━━━┳━━━━━━━━━┓
┃ Name     ┃ Version ┃
┡━━━━━━━━━━╇━━━━━━━━━┩
│ 3.8      │ 3.8.19  │
├──────────┼─────────┤
│ 3.9      │ 3.9.19  │
├──────────┼─────────┤
│ 3.10     │ 3.10.14 │
├──────────┼─────────┤
│ 3.11     │ 3.11.9  │
├──────────┼─────────┤
│ 3.12     │ 3.12.3  │
├──────────┼─────────┤
│ pypy2.7  │ 7.3.15  │
├──────────┼─────────┤
│ pypy3.9  │ 7.3.15  │
├──────────┼─────────┤
│ pypy3.10 │ 7.3.15  │
└──────────┴─────────┘

必要なPythonのバージョンをインストールするには、以下のコマンドを実行します。

$ hatch python install 3.12
Installed 3.12 @ /Users/gihyo/Library/Application Support/hatch/pythons/3.12

これらのPythonインタープリターは自分のPC内で共通で管理されます。また、すべてのPythonインタープリターをインストールしておくには、以下のコマンドを実行します。

$ hatch python install all
Installed 3.8 @ /Users/gihyo/Library/Application Support/hatch/pythons/3.8
Installed 3.9 @ /Users/gihyo/Library/Application Support/hatch/pythons/3.9
Installed 3.10 @ /Users/gihyo/Library/Application Support/hatch/pythons/3.10
Installed 3.11 @ /Users/gihyo/Library/Application Support/hatch/pythons/3.11
The latest version is already installed: 3.12
Installed pypy2.7 @ /Users/gihyo/Library/Application Support/hatch/pythons/pypy2.7
Installed pypy3.9 @ /Users/gihyo/Library/Application Support/hatch/pythons/pypy3.9
Installed pypy3.10 @ /Users/gihyo/Library/Application Support/hatch/pythons/pypy3.10

HatchでのPythonインタープリターの管理の注意点

注意点として、2点あります。

1つめは、hatch pythonとすると、インストールしたPythonへのUSERPATHが追加される点です。ご自身ですでにPythonインタープリターを管理している場合は、注意してください。PATHを追加したくない場合には、--privateオプションを指定します。

$ hatch python install --private 3.12

2つめは、公式サイトにもありますが、Hatchではマイナーバージョンを指定したPythonインタープリターの管理ができません。Hatchで管理されている以外のバージョンのPythonインタプリターを利用する場合には、pyenvなど別のツールで管理する必要があります。

仮想環境の管理

Hatchでプロジェクト固有の仮想環境を管理していきましょう。1つのプロジェクトの中で複数の仮想環境を持つことができ、それぞれの仮想環境に依存するライブラリを管理できます。依存関係の管理は、pyproject.tomlファイルに記述します。依存関係については後述します。

デフォルトではdefaulttypesの仮想環境があります。 env showサブコマンドで仮想環境を確認しましょう。

$ hatch env show
                  Standalone
┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━┓
┃ Name    ┃ Type    ┃ Dependencies ┃ Scripts ┃
┡━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━┩
│ default │ virtual │              │         │
├─────────┼─────────┼──────────────┼─────────┤
│ types   │ virtual │ mypy>=1.0.0  │ check   │
└─────────┴─────────┴──────────────┴─────────

仮想環境を有効にするには、shellサブコマンドを実行します。

$ hatch shell
source "/Users/gihyo/Library/Application Support/hatch/env/virtual/myproject/xxxxx/myproject/bin/activate"

以下のコマンドで、仮想環境から抜けることができます。

$ exit

typesに入る場合には、以下のように実行します。

$ hatch shell types
source "/Users/gihyo/Library/Application Support/hatch/env/virtual/myproject/xxxxx/types/bin/activate"

仮想環境を削除するには、以下のコマンドを実行します。

$ hatch env remove default

依存関係の管理

プロジェクトに必要なライブラリの管理と、それぞれの仮想環境に必要なライブラリを管理について説明します。

必要なライブラリは、pyproject.tomlファイルに追加します。

まずプロジェクトに必要なライブラリは[project]セクションのdependenciesに追加しましょう。このセクションに追加したライブラリは、プロジェクトのすべての仮想環境で利用できます。以下の例ではhttpxを追加しています。

pyproject.tomlにライブラリを追加
[project]
dependencies = [
  "httpx"
]

プロジェクトの依存関係は、depサブコマンドで確認できます。

$ hatch dep show table 
 Project 
┏━━━━━━━┓
┃ Name  ┃
┡━━━━━━━┩
│ httpx │
└───────┘

Hatchでuvを利用するには

Hatchでuvを利用する場合、pyproject.tomlファイルに設定の追加が必要です。

pyproject.tomlにuvを追加
[tool.hatch.envs.default]
installer = "uv"

Hatchによる仮想環境の追加とスクリプトの登録⁠実行

仮想環境の追加、仮想環境への依存ライブラリの追加、スクリプトの登録、スクリプトの実行について紹介します。ここではドキュメンテーションツールのSphinxを例に説明します。

はじめに仮想環境と依存ライブラリを追加します。pyproject.tomlファイルに以下の定義を追加しましょう。[tool.hatch.envs.docs]が仮想環境のセクションです。この場合、docsという名前の仮想環境を作成します。extra-dependenciesが仮想環境への依存ライブラリを追加するセクションです。この場合、sphinxsphinx_materialを追加します。

pyproject.tomlにSphinxでのドキュメント作成のための仮想環境を追加
[tool.hatch.envs.docs]
extra-dependencies = [
  "sphinx",
  "sphinx_material",
]

登録した仮想環境と依存関係をenv showサブコマンドで確認します。docs環境の依存に、sphinxsphinx_materialが追加されていることがわかります。

$ hatch env show
                   Standalone                    
┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━┓
┃ Name    ┃ Type    ┃ Dependencies    ┃ Scripts ┃
┡━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━┩
│ default │ virtual │                 │         │
├─────────┼─────────┼─────────────────┼─────────┤
│ types   │ virtual │ mypy>=1.0.0     │ check   │
├─────────┼─────────┼─────────────────┼─────────┤
│ docs    │ virtual │ sphinx          │         │
│         │         │ sphinx-material │         │
└─────────┴─────────┴─────────────────┴─────────┘

shellサブコマンドでdocs仮想環境に入り、 Sphinxの初期設定を行います。Sphinxの初期設定の詳細は、Sphinxのドキュメントを参照してください。

$ hatch shell docs
$ sphinx-quickstart docs
...
Finished: An initial directory structure has been created.
...
$ exit

次に、Sphinxのビルドスクリプトを登録します。pyproject.tomlファイルに以下の定義を追加します。[tool.hatch.envs.docs.scripts]がセクションです。この場合、buildという名前のスクリプトを登録します。

pyproject.tomlにSphinxでのビルドを登録
[tool.hatch.envs.docs]
extra-dependencies = [
  "sphinx",
  "sphinx_material",
]
[tool.hatch.envs.docs.scripts]
build = "sphinx-build -M html docs/source docs/build"

登録したスクリプトをenv showサブコマンドで確認します。docs環境のスクリプトにbuildが登録されていることがわかります。

$ hatch env show
                   Standalone                    
┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━┓
┃ Name    ┃ Type    ┃ Dependencies    ┃ Scripts ┃
┡━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━┩
│ default │ virtual │                 │         │
├─────────┼─────────┼─────────────────┼─────────┤
│ types   │ virtual │ mypy>=1.0.0     │ check   │
├─────────┼─────────┼─────────────────┼─────────┤
│ docs    │ virtual │ sphinx          │ build   │
│         │         │ sphinx-material │         │
└─────────┴─────────┴─────────────────┴─────────┘

実行してみましょう。次のコマンドで実行します。hatch runコマンドにName:Scriptsでスクリプトを指定します。

$ hatch run docs:build
...
build succeeded, 1 warning.
The HTML pages are in docs/_build/html.

プロジェクト自体には影響を与えず、特定の仮想環境にのみ必要なライブラリを追加し、スクリプトを登録して実行が簡単にできます。簡単に美しいドキュメントを作成できました。

仮想環境で作成したドキュメント
仮想環境で作成したドキュメント

プロジェクトのビルド⁠デプロイ

HatchはPythonパッケージのビルドのバックエンドに、Hatchlingを使用しています。

Hatchlingは、Python公式のPackaging User Guideでも設定方法が紹介されているビルドツールで、多くのサードパーティーライブラリで利用されています。

ビルドは以下のコマンドで実行できます。distディレクトリにsdistとwheelが作成されます。

$ hatch build
────────────────────────────────────────── sdist ───────────────────────────────────────────
dist/myproject-0.0.1.tar.gz
────────────────────────────────────────── wheel ───────────────────────────────────────────
dist/myproject-0.0.1-py3-none-any.whl

デプロイにはpublishサブコマンドを利用します。どのリポジトリにデプロイするかは、pyproject.tomlファイルに記述します。

pyproject.tomlにデプロイ先のリポジトリを記述
[tool.hatch.publish]
repository = "pypi"

またいくつかの手順が追加で必要です。詳細については、公式ドキュメントをご参照ください。

Hatchによるプロジェクトのバージョン管理

以下のコマンドで、プロジェクトのバージョンを表示できます。

$ hatch version
myproject, version 0.1.0

バージョンを更新するには、以下のコマンドを実行します。

$ hatch version 0.2.0
myproject, version 0.2.0

まとめ

細かい設定を気にせず、サクッと新しいPythonプロジェクトを作りたいときには、Hatchが便利です。

Hatchは、uvやRuff同様、まだまだ開発途中で日々進化をしており、開発もとても活発です。本記事で紹介した内容はHatchの一部ですが、Hatchの公式ドキュメントにはさらに多くの機能が記載されています。うまく動かない場合は、公式ドキュメントを参照してください。

また今年のPyCon US 2024にて、今回取り上げた「Hatch」の作者であるOfek Lev氏のトークがありました。現地参加したPyCon US 2024にて、別のトークがあり見ることはできませんでしたが、ご本人に直接Hatchの紹介記事を日本語で書く旨をお伝えすることができました。トークの動画も後日アップロードされると思いますので、気になった方はぜひご覧になってください。

おすすめ記事

記事・ニュース一覧