Nix-direnv with pre-commit installs python

I am new to nix and as part of learning it I am trying to setup my proejcts dependencies through flake.nix in the proejct root and activating it through direnv.

Two packages which are used for development are python312Full and pre-commit. I am now working on a task to upgrade to python313Full but when I change the package from 312 to 313, rebuild and run python --version I am still getting python 3.12. I have noticed that removing the pre-commit package fixes this. So my conclusion is that pre-commit is putting python312 in path. Can I somehow use pre-commit without it putting another python version in the path?

I’m not sure why you are getting this issue, a minimal reproducible example would help but consider installing pre-commit by overriding which pythonPackages it uses like so: pre-commit.override { python3Packages = python313Packages;}

Also, I’d like to note that this exists, but probably is not helpful:

nix-repl> python313Packages.pre-commit-hooks.meta.description
"Some out-of-the-box hooks for pre-commit"

@gytis-ivaskevicius hey. Thanks for your reply. The override suggestion has worked indeed.

Regarding the minimal snippet you can find it below. I have a directory with 3 files. flake.nix, flake.lock, .envrc.

The .envrc has the following

# shellcheck shell=bash
use flake

The flake.nix

{
  description = "example shell of pre-commit getting python 3.12";

  inputs.systems.url = "github:nix-systems/default";
  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
  inputs.flake-utils = {
    url = "github:numtide/flake-utils";
    inputs.systems.follows = "systems";
  };

  outputs = { nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (
      system:
      let
        pkgs = import nixpkgs { inherit system; };
      in
      {
        devShells.default = with pkgs; pkgs.mkShell {
          nativeBuildInputs = [
            pre-commit # python --version prints 3.12
            # (pre-commit.override { python3Packages = python313Packages; }) # python --version prints 3.13
          ];

          shellHook = ''
            echo '--PYTHON VERSION--'
            python --version
            echo '--PYTHON VERSION--'
          '';
        };
      }
    );
}

I created a directory, put these two files in and ran direnv allow. After it compiles I get the python version printed.

Now I am expecting that pre-commit is an executable but python is not, maybe this is the wrong expectation here?

Okay, I figured it out, it loads python from propagated build inputs which is part of the pre-commit. What I suggested is still required even if you used numtide/devshell (which i recommend using as well as flake-parts) since otherwise it would load additional python in the background

Just to clarify. You are talking about the override bit, right?

yes I am

Extra words so I could reply

1 Like