2024年5月: 最近気になるPythonプロジェクトの管理ツール「Hatch」について

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

はじめに

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

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

hatch logo

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

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

Tab completion - Hatch

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

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

フォーマットのみを行う

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

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

Default settings - Static analysis configuration - Hatch

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 test Reference - Hatch

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など別のツールで管理する必要があります。

Why not? - Hatch

仮想環境の管理

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.

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

簡単に美しいドキュメントを作成できました。

sphinx sample image

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

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

Hatchlingは、Python公式のPackaging User Guideでも設定方法が紹介されているビルドツールで、多くのサードパーティーライブラリで利用されています。 Python のプロジェクトをパッケージングする - 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の紹介記事を日本語で書く旨をお伝えすることができました。トークの動画も後日アップロードされると思いますので、気になった方はぜひご覧になってください。