diff --git a/pkgs/development/interpreters/python/python-packages-base.nix b/pkgs/development/interpreters/python/python-packages-base.nix index 19c230a0b94ec..5569606f113aa 100644 --- a/pkgs/development/interpreters/python/python-packages-base.nix +++ b/pkgs/development/interpreters/python/python-packages-base.nix @@ -14,26 +14,40 @@ let # Derivations built with `buildPythonPackage` can already be overridden with `override`, `overrideAttrs`, and `overrideDerivation`. # This function introduces `overridePythonAttrs` and it overrides the call to `buildPythonPackage`. + # + # Overridings specified through `overridePythonAttrs` will always be applied + # before those specified by `overrideAttrs`, even if invoked after them. makeOverridablePythonPackage = f: - lib.mirrorFunctionArgs f ( + let + mirrorArgs = lib.mirrorFunctionArgs f; + in + mirrorArgs ( origArgs: let args = lib.fix ( lib.extends (_: previousAttrs: { passthru = (previousAttrs.passthru or { }) // { - overridePythonAttrs = newArgs: makeOverridablePythonPackage f (overrideWith newArgs); + inherit overridePythonAttrs; }; }) (_: origArgs) ); result = f args; - overrideWith = newArgs: args // (if pkgs.lib.isFunction newArgs then newArgs args else newArgs); + + overrideWith = newArgs: args // lib.toFunction newArgs args; + overridePythonAttrs = mirrorArgs (newArgs: makeOverridablePythonPackage f (overrideWith newArgs)); + + # Change the result of the function call by applying g to it + overrideResult = g: makeOverridablePythonPackage (mirrorArgs (args: g (f args))) origArgs; in if builtins.isAttrs result then result + // lib.optionalAttrs (result ? overrideAttrs) { + overrideAttrs = fdrv: overrideResult (drv: drv.overrideAttrs fdrv); + } else if builtins.isFunction result then { - overridePythonAttrs = newArgs: makeOverridablePythonPackage f (overrideWith newArgs); + inherit overridePythonAttrs; __functor = self: result; } else diff --git a/pkgs/test/overriding.nix b/pkgs/test/overriding.nix index 9ccc84e033560..14b67f44fb7c2 100644 --- a/pkgs/test/overriding.nix +++ b/pkgs/test/overriding.nix @@ -7,6 +7,15 @@ let tests = tests-stdenv // tests-go // tests-python; + # We are testing the overriding result of these packages without building them. + pkgsAllowingBroken = pkgs.extend ( + finalAttrs: previousAttrs: { + config = previousAttrs.config // { + allowBroken = true; + }; + } + ); + tests-stdenv = let addEntangled = @@ -184,13 +193,49 @@ let tests-python = let - p = pkgs.python3Packages.xpybutil.overridePythonAttrs (_: { - dontWrapPythonPrograms = true; - }); + inherit (pkgsAllowingBroken.python3Packages) pip; + applyOverridePythonAttrs = + p: + p.overridePythonAttrs (_: { + dontWrapPythonPrograms = true; + }); + revertOverridePythonAttrs = + p: + p.overridePythonAttrs (_: { + dontWrapPythonPrograms = false; + }); + checkOverridePythonAttrs = p: !lib.hasInfix "wrapPythonPrograms" p.postFixup; + overrideAttrsFooBar = + drv: + drv.overrideAttrs ( + finalAttrs: previousAttrs: { + FOO = "a"; + BAR = finalAttrs.FOO; + } + ); + checkAttrsFooBar = drv: drv.FOO == "a" && drv.BAR == "a"; in { overridePythonAttrs = { - expr = !lib.hasInfix "wrapPythonPrograms" p.postFixup; + expr = checkOverridePythonAttrs (applyOverridePythonAttrs pip); + expected = true; + }; + overridePythonAttrs-nested = { + expr = revertOverridePythonAttrs (applyOverridePythonAttrs pip) == pip; + expected = true; + }; + overrideAttrs-overridePythonAttrs-test-overrideAttrs = { + expr = checkAttrsFooBar (applyOverridePythonAttrs (overrideAttrsFooBar pip)); + expected = true; + }; + overrideAttrs-overridePythonAttrs-test-overridePythonAttrs = { + expr = checkOverridePythonAttrs (applyOverridePythonAttrs (overrideAttrsFooBar pip)); + expected = true; + }; + overrideAttrs-overridePythonAttrs-test-commutation = { + expr = + (applyOverridePythonAttrs (overrideAttrsFooBar pip)) + == (overrideAttrsFooBar (applyOverridePythonAttrs pip)); expected = true; }; };