Packages split to external file, syntax help

Hi, so I split my python310 packages into another file and it works well. It’s basically


pkgs: with pkgs; [
  python310
  python310Packages.item1
  python310Packages.item2
 ...
]

But what I really want to do is more like

pkgs: with pkgs; [ python310 ]
pkgs: with pkgs.python310Packages; [
  item1
  item2
  ...
]

But I have an error there of course. Any suggestion how to fix?

The pkgs: part creates an anonymous function with pkgs as an argument name and the stuff after : as the returned value. It does not really make sense to put one function after another – you should have a single function and then join the arrays with ++ operator inside. In order to do that you will also need to wrap each with ...; ... statement inside parentheses to make them clear.

It is also possible to nest with statements but I would advise against it since it makes it hard to tell where does each thing come from.

Also you should either use python310 with python310.pkgs, or python310Packages.python with python310Packages. Mixing them together can lead to a confusing mismatch if you override a wrong one using overlay.

Using ++ I can live with this:

pkgs: with pkgs; [ python310 ] ++
  [
  python310Packages.item1
  python310Packages.item2
  ]

but I was hoping to strip out repetition of “python310Packages” and just enter it once.

You can do with pkgs; [ ... ] ++ (with pythonPackages; [ ... ]).

Though I am really not a friend of with and would probably spell that out here.

Alternatively if lists get to big, I’d do this instead:

builtins.attrValues {
  inherit (pkgs) python;
  inherit (pkgs.pythonPackages) a b c;
}

Right you can omit the parentheses around the first with statement, since even though the expression is interpreted as follows, the bindings (i.e. what we call “variables” in some other languages) brought into the scope by inner with statements actually take precedence over the ones from outer withs – the oposite of explicit bindings.

(with pkgs;
    ([  ]
     ++
     (with python3Packages;
        [ ... ]
     )))

But I would still recommend against nesting with statements, since doing so can lead to further confusing behaviours. For example,with pkgs; [ ... ] ++ (with python3Packages; [ pkg-config ]) will actually bring in pkgs.pkg-config instead of the expected pkgs.python3Packages.pkgconfig when one accidentally include a dash in the package name.

The builtins.attrValues is probably the nicest syntax until https://github.com/NixOS/rfcs/pull/110 is implemented.

1 Like

Thank you for the ideas. I need to rewrite the question to be more fundamental:

How do I split

environment.systemPackages

so that system-specific programs are listed in configuration.nix and generic programs in other_file.nix?

It would work like:

environment.systemPackages = [ load the programs in /this/generic/file ] ++ [ and also these: prog3 prog4 ];

and

this/generic/file would contain [ prog1 prog2 ]

Sorry if I’m missing something obvious.

Amusingly, I just answered that exact same question here, if I understand yours correctly: A module (or config file) that adds config options, system packages and python packages - #2 by TLATER

And also amusingly, the other user also struggled with specifically python, because python always needs its own special cookie.

But in a nutshell, you just define environment.systemPackages in both files, and the NixOS module system figures it out for you.

For python, because it keeps its own special list, you basically need to make your own custom NixOS option to get this behavior.

That’s getting close, but I’m confused about the syntax in the external file.

If I place environment.systemPackages = pkgs; [prog1 prog2] in the external file, and reference that file in configuration.nix like this

imports = 
  [
    ./hardware-configuration.nix
    /path/to/ext/file
  ];

I get a syntax error about the external file:

error: syntax error, unexpected '=', expecting end of file

What is the full content of that external file?

For testing purposes it has this:

environment.systemPackages = with pkgs; [
  python39Full 
  python39Packages.jupyter_core
  python39Packages.ipykernel
  python39Packages.numpy
  python39Packages.pandas
]

You need to wrap that in {} to make it valid nix.

You can not simply “assign”.

You either need to open a let or do it in a set.

As you want to obviously change some options in the module system, you have to use a set.

PS: for code blocks you want to use at least 3 backticks:

```nix
{
  foo.bar = "";
}
```
1 Like