Python で TOML ファイルを読み書きする(tomllib, tomli)

TOML(Tom’s Obvious, Minimal Language)は、設定ファイル向けに設計されたフォーマットだ。Python 3.11 から標準ライブラリに tomllib が追加され、TOML の読み込みを外部ライブラリなしで行えるようになった。書き込みには tomli_w などのサードパーティライブラリを使う。

TOML の基本構文

TOML はセクション(テーブル)をブラケットで区切り、キーと値を = で結ぶシンプルな形式を取る。

[database]
host = "localhost"
port = 5432
name = "myapp"

[logging]
level = "DEBUG"
file = "app.log"

YAML や JSON と比べた特徴として、型が明示的である点が挙げられる。文字列は必ずクォートで囲む必要があり、YAML のような暗黙の型変換が起こらない。

tomllib で読み込む(Python 3.11 以降)

Python 3.11 以降では、標準ライブラリの tomllib をそのまま使える。

import tomllib

with open("config.toml", "rb") as f:
    data = tomllib.load(f)

print(data)

tomllib.load() はバイナリモード("rb")でファイルを開く必要がある点に注意しよう。テキストモードで開くと TypeError が発生する。

文字列から読み込む場合は tomllib.loads() を使う。

import tomllib

toml_str = """
[server]
host = "0.0.0.0"
port = 8080

[features]
auth = true
cache_ttl = 3600
"""

data = tomllib.loads(toml_str)
print(data["server"]["host"])  # 0.0.0.0
print(data["features"]["cache_ttl"])  # 3600

Python 3.10 以前では tomli を使う

Python 3.10 以前の環境では、tomllib は使えない。代わりにサードパーティの tomli をインストールする。API は tomllib と完全に互換性があるため、移行も容易だ。

pip install tomli

バージョンに応じて import 先を切り替えるイディオムが広く使われている。

import sys

if sys.version_info >= (3, 11):
    import tomllib
else:
    import tomli as tomllib

with open("config.toml", "rb") as f:
    data = tomllib.load(f)

このパターンは pyproject.toml を読み込むツール類でもよく見かける書き方だ。

TOML ファイルに書き込む

tomllib(および tomli)は読み込み専用であり、書き込み機能を持たない。TOML を書き出すには tomli_w を使う。

pip install tomli-w
import tomli_w

config = {
    "database": {
        "host": "localhost",
        "port": 5432,
        "name": "myapp",
    },
    "features": {
        "auth": True,
        "cache_ttl": 3600,
    },
}

with open("output.toml", "wb") as f:
    tomli_w.dump(config, f)

# 文字列として取得する場合
toml_str = tomli_w.dumps(config)
print(toml_str)

書き込みもバイナリモード("wb")で行う必要がある。出力は次のようになる。

[database]
host = "localhost"
port = 5432
name = "myapp"

[features]
auth = true
cache_ttl = 3600

TOML の型システム

TOML は型が厳密に定義されており、YAML のような暗黙の変換が起こらない。これは設定ファイルとしての信頼性を高めている。

TOML 型Python 型
文字列str
整数int
浮動小数点float
真偽値bool
日時datetime
配列list
テーブルdict

日時の扱いは TOML の特徴的な機能の一つだ。

import tomllib

toml_str = """
[event]
name = "launch"
date = 2025-01-15T10:00:00+09:00
"""

data = tomllib.loads(toml_str)
print(data["event"]["date"])
# 2025-01-15 10:00:00+09:00
print(type(data["event"]["date"]))
# <class 'datetime.datetime'>

クォートなしで日時を書くだけで datetime オブジェクトに変換されるため、日時の設定が多いアプリケーションでは便利に使える。

pyproject.toml との関係

TOML が Python で特に重要なのは、pyproject.toml がパッケージ管理の標準設定ファイルとして採用されているからだ。PEP 518 でビルドシステムの設定に TOML が選ばれ、PEP 621 でプロジェクトメタデータの記述にも使われるようになった。

[project]
name = "mypackage"
version = "1.0.0"
description = "A sample package"
requires-python = ">=3.9"
dependencies = [
    "requests>=2.28",
    "pyyaml>=6.0",
]

[build-system]
requires = ["setuptools>=68.0"]
build-backend = "setuptools.build_meta"

自作パッケージの設定を読み込むような場面では、tomllib を直接使って pyproject.toml をパースすることもある。

import tomllib

with open("pyproject.toml", "rb") as f:
    pyproject = tomllib.load(f)

version = pyproject["project"]["version"]
deps = pyproject["project"]["dependencies"]
print(f"v{version}, dependencies: {deps}")

YAML との使い分け

設定ファイルのフォーマット選択は、プロジェクトの性質によって判断が変わる。

TOML

型が明確で曖昧さが少なく、フラットな構成の設定ファイルに向いている。pyproject.toml など Python エコシステムとの親和性が高い

YAML

深いネスト構造やアンカー・エイリアスを使った定義の再利用に対応しており、Kubernetes の設定など複雑な構成管理に適している

シンプルなアプリケーション設定なら TOML、複雑な構成管理なら YAML という使い分けが一般的になりつつある。Python の標準ライブラリに読み込み機能が組み込まれている点も、TOML を選ぶ大きな理由の一つだろう。