このブログの Python 環境を mise に移行した

このブログは Nikola というPython製の静的サイトジェネレーターで作っています。
そのPython環境を、HomebrewのPythonで作ったvenvから mise 管理に移行しました。
ついでに、何年も放置していた requirements.txt も整理しました。
移行前の状態
ブログのディレクトリーには venv/ があり、ビルドの前に source venv/bin/activate するという、ごく普通の運用でした。
改めて中身を確認すると、次のような問題がありました。
- venvの元になっているPythonはHomebrewの
python@3.13でした。 venvは/opt/homebrew/opt/python@3.13を参照しているので、brew upgradeするたびに中のPythonが勝手に入れ替わります。 作成時は3.13.5だったものが、いつの間にか3.13.16になっていました。 - 一方、miseのグローバル設定では
python = "3.13.7"を指定していて、Pythonが2系統混在していました。 -
requirements.txtは126行ありました。JupyterLabやipykernelなど、ビルドに使わないものまで並んでいます。 昔pip install Nikola[extras]した環境をpip freezeした結果が、そのまま残っていたようです。 -
requirements.txtにはNikola==8.3.1と書かれているのに、venvに入っているのは8.3.3でした。 venvを作り直すと古いバージョンに戻ってしまいます。
Python のバージョンを決める
まず、NikolaがどのPythonに対応しているかを確認しました。
- Nikolaの最新版は8.3.3(2025年5月リリース)で、そこから新しいリリースは出ていません。
- PyPI上の条件は
requires_python >=3.8で、動作確認済みとして挙がっているのは3.13までです。 - GitHubには「
nikola autoがPython 3.14で落ちる」というIssueがあります。 エラーはRuntimeError: There is no current event loopです。 修正はmasterにマージ済みですが、まだリリースされていません。
というわけで、Python 3.13で固定することにしました。3.14に上げるのはNikolaの次のリリースを待ってからにします。
mise はパッケージまで管理できるのか
miseでPythonのバージョンを管理するなら、パッケージもmiseに任せてvenvを不要にできないか調べてみました。 調べてみると、miseにはパッケージに関わる機能がいくつかあります。
- pypiバックエンド(
"pypi:nikola" = "8.3.3") - CLIツールをツールごとの専用venvに入れる機能です。
with = [...]で追加パッケージを同じ環境に入れることはできます。 ただ、間接的な依存のバージョンを固定する手段はなく、requirements.txtも読めません。 ドキュメントにも「アプリケーションのライブラリーはuvやpipで管理するプロジェクト環境に置く」とあります。 -
mise deps([deps.pip]/[deps.uv]) -
requirements.txtなどの変更時にpip install -rやuv syncを自動で実行します。 まだ実験的機能で、ドキュメントによると、pipプロバイダーは仮想環境の作成や選択をしません。 venvの存在が前提です。 _.python.venv- venvを作成して有効化する機能です。パッケージのインストールはしません。
.default-python-packages- Pythonのバージョンごとに全体へ入れるパッケージを指定する機能です。非推奨で、2027.11.0からは読み込まれなくなります。
結局、miseが受け持てるのは「venvを作る」「venvを有効にする」「venvにインストールする」ところまでで、パッケージを置く場所としてのvenvはなくせません。 役割を次のように分けることにしました。
- mise: Python本体のバージョンを固定し、venvの作成と有効化を自動で行う
- venv: Nikolaなどのパッケージをプロジェクトごとに分けて置く
mise.toml
ブログのリポジトリー直下に、次の mise.toml を置きました。
[tools] python = "3.13" [env] # venv を自動で作成・有効化する(uv で作るため --seed で pip も入れる) _.python.venv = { path = "venv", create = true, uv_create_args = ["--seed"] }
これで、ディレクトリーに cd するだけでvenvが有効になります。source venv/bin/activate は不要になりました。
venvの元になるPythonもmise管理のものに変わったので、Homebrewの更新に引きずられることもありません。
ひとつ引っかかったのは、uvがインストールされているとmiseがuvでvenvを作ることです。
uvで作ったvenvにはpipが入らないので、uv_create_args = ["--seed"] を指定してpipも入れるようにしました。
これで今までどおり pip install -r requirements.txt が使えます。
requirements.txt の整理
Nikola本体の依存パッケージは、Nikolaをインストールすれば自動で入ります。
そこで、直接必要なものだけを書くことにしました。
最初はNikola、MermaidのMarkdown拡張、nikola auto 用のaiohttpとwatchdogだけにしてビルドしてみましたが、エラーが2つ出ました。
- ギャラリーの
metadata.ymlを読むのにruamel.yamlが必要でした。 - テーマはMakoですが、Nikolaは起動時にjinjaテンプレートプラグインを読み込むのでJinja2も必要でした。
この2つを加えたのが最終版です。
# Nikola 本体(依存パッケージは自動で入る) Nikola==8.3.3 # MARKDOWN_EXTENSIONS で使う Mermaid 拡張 markdown-inline-mermaid==1.0.4 # nikola auto(Nikola の extras のうち必要なものだけ) aiohttp==3.14.5 watchdog==6.0.0 # galleries/*/metadata.yml の読み込み ruamel.yaml==0.19.1 # Nikola が起動時に jinja テンプレートプラグインを読み込むため(テーマは Mako) Jinja2==3.1.6 # Markdown 本体(Nikola の依存だが、出力に直接効くためバージョンを固定) Markdown==3.11.1
venvに入るパッケージは134個から35個に減りました。
移行前後のビルド結果を比べる
移行前の環境と移行後の環境でそれぞれフルビルドし、出力を比べました。 ビルド時間はどちらも約3分で、変わりませんでした。 差分は約2800ファイルありましたが、中身を見るとほとんどは見た目に関係ないものでした。
- rSTのコードブロックには、ビルドのたびにランダムなID(
rest_code_<uuid>)が振られます。HTMLの差分の大半はこれでした。 - 画像はPillowのバージョンが変わってバイナリーは変わりましたが、ピクセル単位では同じでした。
実際に表示が変わったのは、Markdownを3.8.2から3.11.1に上げた影響を受けた64記事でした。
- 行末で閉じている
**の強調が太字にならず、記号のまま表示される - 閉じタグのない
<ins datetime=...>がHTMLとして扱われず、エスケープされて表示される
どちらも、元の記事の書き方がゆるかったことによるものです。Markdownを古いバージョンに固定すれば元どおりになりますが、最新版を使うことにしました。 気になる記事は、見つけたときに直していくつもりです。
移行中に出会ったビルドエラー
移行後の確認中に、2回目以降の nikola build が AttributeError: 'str' object has no attribute 'task' で落ちることがありました。
最初は移行のせいかと疑いましたが、移行前の環境でも同じ状態から再現しました。
Nikolaの既知の問題(Issue #3406)で、2020年から未解決です。
原因は post-list ディレクティブです。
このブログの一部の記事では、末尾に post-list で同じタグの記事一覧を表示しています。
Nikolaは一覧に載せた記事を依存関係として登録するので、記事どうしが互いの一覧に載ると循環依存になります。
すると、ビルドツールのdoitが実行できるタスクを見つけられなくなり、このエラーで止まります。
根本的な対策は post-list の使い方を見直すことですが、今回は見送りました。
エラーが出たら nikola clean でキャッシュを消してビルドし直せば、正常に戻ります。
まとめ
- miseはPython本体のバージョン管理とvenvの自動化を担当し、パッケージはvenvに置く、という分担に落ち着きました。
-
requirements.txtはpip freezeの結果ではなく、直接必要なパッケージだけを書く形にしました。 -
cdするだけで環境が整うようになり、Homebrewの更新を気にする必要もなくなりました。
コメント
Comments powered by Disqus