Python: possible to override `packageOverrides`?

Similar / related:

Trying to make an overlay to work around nixos/healthchecks: migration fails due to pydantic schema · Issue #401010 · NixOS/nixpkgs · GitHub, I find that my overlay doesn’t seem to work:

(
  _: prev: {
    healthchecks =
      let
        py = prev.python3.override {
          self = py;
          packageOverrides = _: pyprev: {
            pydantic-core = pyprev.pydantic-core.overridePythonAttrs {
              version = "2.34.1";
              src = prev.fetchFromGitHub {
                owner = "pydantic";
                repo = "pydantic-core";
                tag = "v2.34.1";
                hash = "";
              };
            };
          };
        };
      in
      prev.healthchecks.override {
        python3 = py;
      };
  }
)

Messing around in nix repl, I think it’s because the package is already overriding python and packageOverrides: nixpkgs/pkgs/by-name/he/healthchecks/package.nix at 24a5a710e5a0d8cce237edc444c095960b1a86bb · NixOS/nixpkgs · GitHub

If I edit a local checkout to remove this overriding in the healthchecks package, then I’m prompted to fix my empty hash; if I leave this content in, evaluation doesn’t seem to even notice the empty hash.

pythonPackagesExtensions seems to work, but it breaks a bunch of other packages; I’d prefer to only override in the scope of healthchecks if possible.

Reading the links at the top, it seems like it may be hopeless – that there is no way to merge packageOverrides like this, and I can’t fixup a python dependency if the parent package is accepting python3 and overriding it in the derivation.

Is this correct? Is this still the case in 2025?

It has nothing to do with 2025, they just wrote the code in a way that will ignore yours. Yes, packageOverrides don’t compose and this is why they’ve been deprecated at the top-level in favor of overlays for the last 8 years.

One option would be for upstream to extract python3 = python3.override {...} into all-packages.nix, that way it’s not squirrelled away in a let binding that no one can override. Another option would be to do what mailman does (but actually make it part of the public api unlike mailman).

1 Like

We could try to fix them like this draft PR:

If it works and people agree with such fixes, we could apply it to the other 70 packages.

If you really cannot modify the Nix source, here’s a bloody hack:

let
  # Hadouken monkey patch of `<python application>.override`
  # to preserve `python3.override { packageOverrides = ...; }`
  preservePython3PackageOverrides = p: p // {
    override = lib.mirrorFunctionArgs p.override (fdrv:
      preservePython3PackageOverrides (p.override (previous:
        let
          fdrv' = lib.toFunction fdrv previous;
        in
        fdrv' // lib.optionalAttrs (fdrv' ? python3) {
          python3 = fdrv'.python3 // {
            override = lib.mirrorFunctionArgs fdrv'.python3.override (fdrv:
              fdrv'.python3.override (previous:
                let
                  fdrv' = lib.toFunction fdrv previous;
                in
                fdrv' // {
                  packageOverrides = lib.composeExtensions previous.packageOverrides or (_: _: { }) fdrv'.packageOverrides or (_: _: { });
                }
              )
            );
          };
        }
      ))
    );
  };
in
preservePython3PackageOverrides healthchecks
1 Like

That’s a new one to me, thanks for sharing!

1 Like

lib.mirrorFunctionArgs is essentially a shorthand of f: g: lib.setFunctionArgs g (lib.functionArgs f) to save developers’ lives (i.e., my life) dealing with overriding implementations.

All lib.mirrorFunctionArgs f can be stripped and the function will still preserve packageOverrides. Still, __functionArgs is useful for callPakage, so I preserve them as I could.

1 Like

Thanks for your input. I was actually looking at this part of mailman an hour or two before posting (just grepping through instanrces of override and packageOverrides in python packages).

This is what I was thinking – isn’t this one of the reasons the callPackage pattern is encouraged?

Sorry, if you have a minute, can you elaborate on this? I thought the healthchecks example was an overlay? Just one that uses packageOverrides (as spelled out in the lua docs). Just a name or link to a package that “does it right” would be great.

Full implementation in context here: nixos/healthchecks: migration fails due to pydantic schema · Issue #401010 · NixOS/nixpkgs · GitHub

Thank you! I definitely would not have figured that one out myself.