Successive withPackages calls

I want to use something like this to install multiple python packages:

(python.withPackages(ps: [
  ps.numpy
])).withPackages(ps: [
  ps.bottle
]);

Of course, in this example it would be far easier to just put both packages in the same list, but sometimes that’s not feasible. If I have a certain python package installed system-wide, I want it to be available all the time but using withPackages in this way overwrites the previous invocation.
Right now, I’m working on a python project which uses cadquery, along with some other libraries. The flake for this project looks something like this:

{
  description = "cadquery project";

  inputs = {
    cadquery.url = "github:marcus7070/cq-flake";
    flake-utils.url = "github:numtide/flake-utils";
  };
  outputs = { self, cadquery, flake-utils }: 
    flake-utils.lib.eachSystem [ "x86_64-linux" ]( system: {
      packages.defaultShell = 
        cadquery.packages.${system}.cadquery-env.withPackages(ps: [
          numpy-stl
          bottle
        ]);
    });
}

Where cadquery-env is a python environment with all the cadquery libraries I need. I was quite surprised when this didn’t work as I had come to expect this sort of cumulative behavior from Nix. Am I missing something simple? Should I be using overlays instead? Or is this whole way of thinking just wrong?

1 Like

You’re not missing anything, the Python withPackages wrapper just doesn’t support anything of the sort. Not that it wouldn’t be possible — just no one has implemented that feature. I think it would mostly be a matter of figuring out a good overriding scheme for this (which is tricky since what nixpkgs has a confusingly high amount of is overriding schemes).

Not sure if multiple withPackages applications is a good idea to have for the API, as the python and python.withPackages (p: …) derivations are fundamentally different, so having them expose the same attribute function may give the wrong impression.

the withPackages uses buildenv to construct a psuedo-package which contains symlinks to all of the packages specified. So, after the first usage, it’s no longer a python interpreter

1 Like

…buildenv…
…no longer a python interpreter

Wow! I’ve never figured out these details! Just wish we had static types to express that

There should be a way to expose a passthru.withPackages for the result buildenv, which will union all of the successive calls. I tried do so but then my mind melted from how to express that in a fixed point… :confused:

2 Likes

php supports this. — Well, you get access to the previously enabled extensions as a function argument. — And yes, it sends my head spinning every time I need to modify it. Especially when we wanted it to compose with overrideAttrs.

3 Likes