Install python packages for specific python

I have below setup on replit.nix

{ pkgs }: {
	deps = [
		pkgs.neovim
	];
}

Neovim’s python gets installed separate from the system installation. I want to install a python package for that python. Something like pkgs.python39Packages.cryptography but for neovim’s python executable. How can I accomplish it with minimal changes in above setup?

Normally you can use python39.withPackages(ps: with ps; [ cryptography ]) to create a python39 derivation that has python39.pkgs.cryptography installed as a package (i.e. you can import modules from it).

neovim derivation function takes python3 parameter, so it is possible to override it. But there are two problems:

the first problem

pkgs.neovim is not the derivation returned by calling the function at (pkgs/applications/editors/neovim/default.nix), instead it is a wrapper around that function.

neovim = wrapNeovim neovim-unwrapped { }

This means we need to override the unwrapped derivation and then wrap it again

# doesn't work, see problem #2
{ pkgs }:

let
  inherit (pkgs)
    neovim
    python3
    wrapNeovim
  ;

  customNeovim = neovim.unwrapped.override {
    python3 = python3.withPackages(ps: with ps; [ cryptography ]);
  }
in
{
  deps = [
    (wrapNeovim customNeovim)
  ];
}

the second problem

neovim derivation also calls withPackages on the given python3 argument and chaining multiple withPackages seem to overwrite the effect of the previous one.

While I am not suggesting it is the prettiest solution, something like this seem to be working:

let
  inherit (pkgs)
    neovim
    python3
    wrapNeovim
  ;

  pythonWithPackages = python: packageNames: {
    withPackages = packagesFor:
      python.withPackages(_: (packagesFor python.pkgs) ++ (map (p: python.pkgs.${p}) packageNames));
  };

  customNeovim = neovim.unwrapped.override {
    python3 = pythonWithPackages python3 [ "cryptography" ];
  }
in
{
  deps = [
    (wrapNeovim customNeovim)
  ];
}