Open7
NixでPython環境を作成するのに躓いたところなど
4つぐらい方法がありそう
- pythonの管理はpipやuv, poetryを使い、nixでは管理しない
- nixpkgsの
python3Packages.*
で管理 - poetry2nixを使う
- dream2nixを使う
Nixを学習するにあたって
注意点
- flake, nix-commandsあたりのexperimental-featureが割と標準になっている
- nix-channelでの管理やnix-*系のコマンドもあるので調べにくい
- 書き方が多いしツールも多いのでベスプラがわかりにくい
学習方法
学習曲線がどうのという感じがするが過渡期だったりシンプルゆえに書き方が多かったりすることがデカそう。以下の順でやればそんなに躓くことはないと思う。
- 文法
- flake
- build, run, developなどよく使うコマンド
以下の「Nix入門: ハンズオン編」がこの順なのでそれを見れば良いと思う。
参考にした資料など
Nix入門: ハンズオン編
公式リファレンス パッケージ検索超ざっくりの説明
- flakeはいくつかのderivationを生成する関数
- derivationはざっくりDockerfileだと思っていい
- store objectはざっくりコンテナイメージだと思っていい
dream2nixでPython環境を作る
dream2nix自体はpythonだけではなくnodeやphp、rust、haskellなどのパッケージ管理をnixで統合的に取り扱えるflake。
pythonだとpyproject.tomlを元にパッケージを管理してくれる。
メリデメ
- pyproject.tomlで書けるので楽
- nixpkgsにないpythonパッケージもインストールしやすい
- moduleが初学者には自明でなさすぎて辛い
- 環境(darwin arm, linux x86など)ごとにlockファイルを作らないといけない
- dream2nixで作成した複数の自前パッケージを依存させるなどをするとパッケージのconflictがきつい
- これはnixpkgsのpython3Packagesだと発生しないはず
- 依存パッケージをdevShellでeditableにできる
- ローカルの自前パッケージを編集する時とかに便利
localのパッケージに依存する
- flake.nixでdream2nixモジュールを作るときにpackageSets.selfpkgsに自身のpackagesを入れてdepsに渡す
- depsで指定
- mkDerivationのpropagatedBuildInputsで指定
まででとりあえず動く。
devShellでpython -m app.pyのように動かしたい場合はpip.editablesにパスを入れるとローカルパッケージがeditableになるので反映される。(毎回nix runで動かせば問題ないが、devShellに入った方が起動が早い)
# default.nix
...
deps =
{ selfpkgs, ... }:
{
python = selfpkgs.python;
adapters = selfpkgs.localpackage;
};
inherit (pyproject.project) name version;
mkDerivation = {
src = ...;
propagatedBuildInputs = [ config.deps.localpackage ];
};
...
pip = {
requirementsList = pyproject.build-system.requires or [ ] ++ pyproject.project.dependencies or [ ];
flattenDependencies = true;
editables = {
localpackage = "./packages/localpackage";
};
};
}
nixpkgsの python3Packages.* で管理
- かなり充実しているのでほとんどこれだけで済む
- バージョンがほぼ固定されているのでローカルの共通パッケージとか作るときにconflictが発生しなくて嬉しい
- マイナーなパッケージは結構ないので自分でビルドする必要がある
- vscodeでinterpreter指定はどうやるんだろ
これが一番良い気がする
nix fmt
nix fmtコマンドでformatできるが、flake側でformatterを指定する必要がある。
formatterも色々あるっぽい。
- nixpkgs-fmtは更新が停止してnixfmtが公式に格上げされたっぽい(but not yet stable)
- nixfmtが.gitignoreなどを無視して.direnvとかの.nixも読みにいくので動かない
- excludesなどの設定もない
- https://github.com/NixOS/nixfmt/issues/151
- treenixからnixfmtを呼ぶのが現時点で最良っぽい
- treenixなら他の言語も大体formatできる
一旦以下のような設定に落ち着いた。
# flake.nix
let
treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix;
in {
formatter = treefmtEval.config.build.wrapper;
checks = {
formatting = treefmtEval.config.build.check self;
};
}
# treefmt.nix
{ pkgs, ... }:
{
projectRootFile = "flake.nix";
programs = {
nixfmt.enable = true;
ruff-check.enable = true;
ruff-format.enable = true;
};
settings = {
global.excludes = [
"excludedir/*"
];
};
}
nix bundleとかbinary cacheも書きたい
今のところ
- nix bundleはbundlerが色々あるがあんまりstableな印象を受けない
- 1ファイルになってくれるのはありがたい
- しかし更新時に一部だけで済むbinary cacheの方が効率が良い場合が多そう
- binary cacheはnix copy s3://... とかで作れる
- これだとgcが大変なのでDL頻度とか記録しつつ良い感じにGCするためにatticとかcachixがあるんじゃないかと予想