Use multiple instances of `prev.python.override'

First, you need to pass a function to override to get access to the previous overridden values.

Then, you can drop old //, since packageOverrides are already plopped over the previous package set.

Finally, you can use lib.composeExtensions to merge the overlay with the previous layer, if present.

overlays =
  let
    emptyOverlay = final: prev: {};
  in
  {
    autoslot = final: prev: {
      python310 = prev.python310.override (prevArgs: {
        packageOverrides =
          let
            ourOverlay = new: old: {
              autoslot = new.callPackage ./autoslot.nix {};
            };
          in
          prev.lib.composeExtensions
            prevArgs.packageOverrides or emptyOverlay
            ourOverlay;
      });
    };
    backtrace = final: prev: {
      python310 = prev.python310.override (prevArgs: {
        packageOverrides =
          let
            ourOverlay = new: old: {
              backtrace = new.callPackage ./backtrace.nix {};
            };
          in
          prev.lib.composeExtensions
            prevArgs.packageOverrides or emptyOverlay
            ourOverlay;
      });
    };
  }

Also, I would still go with the new.callPackage. Overlays are complicated enough when they are self-contained – no need to make them even more headache-inducing by mixing the layers.

3 Likes