`Nix-shell -p 'python37.pkgs.pytest'` fails

Hi all,

When I try to install pytest for python37 it fails

nix-shell -p 'python37.withPackages(ps: with ps; [pytest])'
...
ERROR: Could not find a version that satisfies the requirement importlib-metadata; python_version < "3.8" (from setuptools-scm) (from versions: none)
ERROR: No matching distribution found for importlib-metadata; python_version < "3.8"

Do you have any idea why it is not the python37 pytest that is used?

My machine is running

nix-shell -p nix-info --run "nix-info -m"

 - system: `"x86_64-linux"`
 - host os: `Linux 6.0.0, NixOS, 22.11 (Raccoon), 22.11.20221005.37bd398`
 - multi-user?: `yes`
 - sandbox: `yes`
 - version: `nix-env (Nix) 2.11.0`
 - nixpkgs: `/nix/store/7xlnfnx4pc3bv0kp719jr1r8jbsxkv54-source`

Best regards,

I feel like I remember something about setuptools and importlib-metadata

python 3.7 is no longer maintainer in nixpkgs. Currently we only support 3.9 and 3.10.

Ok, thanks a lot. Is there a way I should have known that? As a new user I thought that all packages available in <nixpkgs> are maintained until removed.

But your answer let me to this find nixpkgs commit-id for a package.

So searching for python3, shows that I can do

nix-shell -p 'python37.withPackages(ps: with ps; [pytest])' -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/20dd1e678299aae83735f1af5d1dcd80de22da5f.tar.gz

Btw, what is the equivalent nix ... command? Is it correct that I should get familiar with nix shell ... -c $SHELL instead of nix-shell -p?

Not sure if that is written somewhere, I just know it. Sadly not, there are always a good amount of unmaintained packages like in any other distro.

If you are not using flakes then you can continue to use nix-shell.

You could try something along the lines of

nix shell --impure --expr 'with builtins.getFlake "nixpkgs"; with legacyPackages.${builtins.currentSystem}; python37.withPackages (ps: with ps; [ pytest ])'

Ok, thanks for the replies.
I am using flakes. I want to learn the “new” way to do things.

Can you explain the command you posted? Is it equivalent to

nix shell --impure --expr 'with import <nixpkgs> {}; python38.withPackages (ps: with ps; [ pytest ])'  

How can I avoid --impure? The command is using the current commit <nixpkgs> points to. How can I point to a previous commit, à la

nix-shell -p ... -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/20dd1e678299aae83735f1af5d1dcd80de22da5f.tar.gz

You still can use builtins.getFlake "github:NixOS/nixpkgs/20dd1e678299aae83735f1af5d1dcd80de22da5f" in the call I posted.

Should work also w/o --impure.

ok, but sorry for continuing with the questions. I would like to understand what I can shorten your command to.

I know I can do

nix shell github:NixOS/nixpkgs/20dd1e678299aae83735f1af5d1dcd80de22da5f#hello -c hello
#and
nix shell --impure --expr 'with import <nixpkgs> {}; python38.withPackages (ps: with ps; [ pytest ])'  

and yours[1]

nix shell --impure --expr 'with builtins.getFlake "github:NixOS/nixpkgs/20dd1e678299aae83735f1af5d1dcd80de22da5f"; with legacyPackages.${builtins.currentSystem}; python37.withPackages (ps: with ps; [ pytest ])'

Is there a way I can condense your expression so I don’t need to remember with legacyPackages.${builtins.currentSystem}?
Ideally I would just write

nix shell <something> --expr 'python37.withPackages (ps: with ps; [ pytest ])'

[1]
without --impure it fails with

error: attribute 'currentSystem' missing
  at «string»:1:111:
    1| with builtins.getFlake "github:NixOS/nixpkgs/20dd1e678299aae83735f1af5d1dcd80de22da5f"; with legacyPackages.${builtins.currentSystem}; python37.withPackages (ps: with ps; [ pytest ])

Right, replacing with x86_64-linux or what your current system is should get you there.

Regarding yr other question the path syntax (<...>) should also apply to relative paths i. e. the tgz of the commit, doesn’t it ?

Also <something> just needs to be on NIX_PATH, channel or registry for this to work as well I guess.

Thanks, you’re right. Stupid of me. Now I know that

nix shell nixpkgs/20dd1e678299aae83735f1af5d1dcd80de22da5f#hello -c hello
nix shell --expr 'with builtins.getFlake "github:NixOS/nixpkgs/20dd1e678299aae83735f1af5d1dcd80de22da5f"; with legacyPackages.x86_64-linux; python37.withPackages (ps: with ps; [ pytest ])'

works.

Two questions

  • Is it correct, that there is no way to shorten the last command?
  • running
$ nix registry list
system flake:nixpkgs path:/nix/store/7xlnfnx4pc3bv0kp719jr1r8jbsxkv54-source?lastModified=1664989420&narHash=sha256-Q8IxomUjjmewsoJgO3htkXLfCckQ7HkDJ%2fZhdYVf%2ffA=&rev=37bd39839acf99c5b738319f42478296f827f274
global flake:nixpkgs github:NixOS/nixpkgs/nixpkgs-unstable

How do nix know that nix shell nixpkgs/20dd1e6 should be interpreted as the global flake? In NIX_PATH, nixpkgs points to /nix/store/7x...

I’m not seeing where you were being stupid and I’m sorry if I made you feel that way.

I’m also just learning the concept of flakes and from what I have so far I can only say I would pin the commit you have:

user   flake:nixpkgs-mypin github:NixOS/nixpkgs/nixpkgs-unstable
user   github:NixOS/nixpkgs/nixpkgs-unstable github:NixOS/nixpkgs/20dd1e678299aae83735f1af5d1dcd80de22da5f

The expression with getFlake would condense into (for x86_64-linux): nix shell --expr 'with builtins.getFlake "nixpkgs-mypin"; with legacyPackages.x86_64-linux; python38.withPackages (ps: with ps; [ pytest ])'.

On the other hand if you’re already in the process of declaring a pin via registry the concise contains-all-info-needed command line call might not have that much importance anyway and you would be better off writing a nix expression in a file ?

Regarding the <something> approach from what I know you need -I at some point as you said yourself, can test it via nix repl -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/20dd1e678299aae83735f1af5d1dcd80de22da5f.tar.gz and nix-repl> <nixpkgs>. This so answer explains that.
You sure could then nix shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/20dd1e678299aae83735f1af5d1dcd80de22da5f.tar.gz --expr 'with import <nixpkgs> {}; python38.withPackages (ps: with ps; [ pytest ])'.

1 Like