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入門: ハンズオン編
https://zenn.dev/asa1984/books/nix-hands-on
公式リファレンス
https://nix.dev/manual/nix/2.17/introduction
パッケージ検索
https://search.nixos.org/packages

澤田澤田

超ざっくりの説明

  • flakeはいくつかのderivationを生成する関数
  • derivationはざっくりDockerfileだと思っていい
  • store objectはざっくりコンテナイメージだと思っていい
澤田澤田

dream2nixでPython環境を作る

dream2nix自体はpythonだけではなくnodeやphp、rust、haskellなどのパッケージ管理をnixで統合的に取り扱えるflake。
pythonだとpyproject.tomlを元にパッケージを管理してくれる。

https://dream2nix.dev/guides/pip/

メリデメ

  • 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も色々あるっぽい。

一旦以下のような設定に落ち着いた。

# 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があるんじゃないかと予想