Making variables available to callPackage

How do I define a variable so that callPackage will see it and pass automatically it as an argument like it does with packages and functions defined in nixpkgs?

For example, if I have a package derivation in a file like this,

{ lib
, buildPythonPackage
, myCustomFetch
}:

buildPythonPackage rec {
  pname = "my-packag";
  version = "0.0.1";

  src = myCustomFetch {
    inherit pname version;
    foo = "blah";
    # etc.
  };
}

And I go to use it in an overlay like this,

final: prev:
let
  myCustomFetch = prev.callPackage ./pkgs/my-custom-fetch.nix { };
  callPythonPackage = prev.python3.pkgs.callPackage;
in
{
  python3 = prev.python3.override {
    packageOverrides = py-final: py-prev: {
      my-package = callPythonPackage ./pkgs/my-package { };
    };
  };
}

I get the error,

error: Function called without required argument "myCustomFetch" at /nix/store/aaaa...-source/pkgs/my-package/default.nix:3

I have looked through the nixpkgs source, and I see that there are multiple callPackage functions for different package scopes, and I read up a bit on nix scopes, but I have only been able to find examples of overriding packages in scopes, but nothing about modifying the scope’s callPackage function itself. I also found callPackageWith, but that appears to be a reimplementation of callPackage, so I could not use that to extend an existing scope.

I do think you want to create your own callPackage with callpackageWith. Look for that function in the nixpkgs repo, it’s got a few good examples.

Oh, I use it too: dotfiles/default.nix at ba2512ac8858dbc04991cfbe17870a09ca96d22f · TLATER/dotfiles · GitHub

1 Like

For one, you can pass the arguments through the second argument of callPackage:

final: prev:
let
  myCustomFetch = prev.callPackage ./pkgs/my-custom-fetch.nix { };
  callPythonPackage = prev.python3.pkgs.callPackage;
in
{
  python3 = prev.python3.override {
    packageOverrides = py-final: py-prev: {
      my-package = callPythonPackage ./pkgs/my-package {
        inherit myCustomFetch;
      };
    };
  };
}

But depending on the specifics, it might also make sense to add the fetch function to the package set and let its callPackage inject it for you (you will need callPackage from the final package set since the one from prev would not see myCustomFetch defined on the current “level”):

final: prev:
{
  python3 = prev.python3.override {
    packageOverrides = py-final: py-prev: {
      myCustomFetch = py-final.callPackage ./pkgs/my-custom-fetch.nix { };
      my-package = py-final.callPackage ./pkgs/my-package { };
    };
  };
}

Also, when you have nested overlays like here, you generally want to use the values from a package set through the arguments of the relevant overlay, rather than getting it from an outer overlay (py-final.callPackage instead of final.python3.pkgs.callPackage). Otherwise it will become a tangled mess that is difficult to reason about.

3 Likes