You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

nixpkgs覆盖Python包未在systemPackages生效的解决方法

问题

当在nixpkgs.config.packageOverrides或nixpkgs.overlays中覆盖python3包时,environment.systemPackages内的Python应用并未使用这些覆盖配置,如何才能让被覆盖的python3包被对应Python3应用正确引用?

以下为使用nixpkgs.overlays的darwin-configuration.nix示例配置,目标为移除pyopenssl依赖,规避darwin-aarch64平台下pyopenssl标记为损坏、无法评估的问题,同时自定义myawscli2包传入覆盖后的python3:

{ config, pkgs, lib, ... }:
{
  environment.systemPackages =
    [
      pkgs.myawscli2
    ];
  nixpkgs.overlays = let overlayRemovePyopenssl = self: super: 
    let removePyopenssl = pythonpkgs:
      lib.filter
        (pythonpkg: !(pythonpkg != null && pythonpkg ? pname && pythonpkg.pname == "pyopenssl"))
        pythonpkgs;
    in {
      python3 = super.python3.override {
        packageOverrides = python-self: python-super: rec {
          # Delete pyopenssl; workaround for broken package on darwin-aarch64
          # “Package ‘python3.10-pyopenssl-22.0.0’ in /nix/store/<hash>-nixpkgs/nixpkgs/pkgs/development/python-modules/pyopenssl/default.nix:73 is marked as broken, refusing to evaluate”
          urllib3 = python-super.urllib3.overridePythonAttrs (origattrs: rec {
            propagatedBuildInputs = removePyopenssl origattrs.propagatedBuildInputs;
          });
          twisted = python-super.twisted.overridePythonAttrs (origattrs: {
            checkInputs = removePyopenssl origattrs.checkInputs;
          });
        };
      };
      myawscli2 = (self.awscli2.override {
        # override the python3 arg of awscli2
        python3 = self.python3;
      });
    }; in
  [
    overlayRemovePyopenssl
  ];
  system.stateVersion = 4;
}

经测试,独立Python包urllib3已正确应用overlay配置:

nix-repl> lib = import <nixpkgs>.lib
nix-repl> :l <darwin>
nix-repl> lib.forEach pkgs.python3.pkgs.urllib3.propagatedBuildInputs (x: x.pname)
[ "brotli" "certifi" "cryptography" "idna" "python3" ]

但使用urllib3的Python应用并未应用该覆盖,awscli2依赖的urllib3传递依赖中仍存在pyopenssl:

nix-repl> lib.forEach (lib.findFirst (x: x.pname == "urllib3") null pkgs.awscli2.propagatedBuildInputs).propagatedBuildInputs (x: x.pname)
[ "brotli" "certifi" "cryptography" "idna" "pyopenssl" "python3" ]

尝试使用nixpkgs.config.packageOverrides实现相同配置,得到了完全一致的结果:

{ config, pkgs, lib, ... }:
{
  environment.systemPackages =
    [
      pkgs.myawscli2
    ];
  nixpkgs.config.packageOverrides = super: 
    let removePyopenssl = pythonpkgs:
      lib.filter
        (pythonpkg: !(pythonpkg != null && lib.hasAttr "pname" pythonpkg && pythonpkg.pname == "pyopenssl"))
        pythonpkgs;
    in {
      python3 = super.python3.override {
        packageOverrides = python-self: python-super: rec {
          # workaround for
          # “Package ‘python3.10-pyopenssl-22.0.0’ in /nix/store/<hash>-nixpkgs/nixpkgs/pkgs/development/python-modules/pyopenssl/default.nix:73 is marked as broken, refusing to evaluate”
          urllib3 = python-super.urllib3.overridePythonAttrs (origattrs: rec {
            propagatedBuildInputs = removePyopenssl origattrs.propagatedBuildInputs;
          });
          twisted = python-super.twisted.overridePythonAttrs (origattrs: {
            checkInputs = removePyopenssl origattrs.checkInputs;
          });
        };
      };
      myawscli2 = (pkgs.awscli2.override {
        python3 = pkgs.python3;
      });
    };
  system.stateVersion = 4;
}

该现象与nixpkgs官方手册描述存在矛盾,手册说明:pythonPackages.twisted现在已被全局覆盖,所有引用twisted的软件包以及NixOS服务(例如services.buildbot-worker)都将使用新的定义。


原因

问题核心是Python包集合的引用闭包没有被完全替换:

  • 通过override创建新的python3实例、修改该实例下的包集合后,nixpkgs中预置的awscli2这类Python应用,在打包时已经把依赖从原始(super层)的Python包集合中固定捕获,单纯给应用传python3 = self.python3参数,只会替换运行时调用的解释器路径,不会自动重写整个Python依赖闭包。
  • 仅覆盖顶层的python3属性,没有同步覆盖顶层的python3Packages属性,很多Python应用实际是直接从顶层python3Packages取依赖,不会主动从传入的python3实例下的pkgs集合拉取修改后的包。
解决方法

正确的overlay写法需要保证所有Python相关属性都引用修改后的包集合,参考如下配置:

{ config, pkgs, lib, ... }:
{
  environment.systemPackages = [
    pkgs.myawscli2
  ];
  nixpkgs.overlays = let
    overlayRemovePyopenssl = self: super:
      let
        removePyopenssl = pythonpkgs:
          lib.filter
            (pythonpkg: !(pythonpkg != null && pythonpkg ? pname && pythonpkg.pname == "pyopenssl"))
            pythonpkgs;
        # 先定义修改后的Python解释器及对应包集合
        customPython3 = super.python3.override {
          packageOverrides = python-self: python-super: rec {
            urllib3 = python-super.urllib3.overridePythonAttrs (origattrs: rec {
              propagatedBuildInputs = removePyopenssl origattrs.propagatedBuildInputs;
            });
            twisted = python-super.twisted.overridePythonAttrs (origattrs: {
              checkInputs = removePyopenssl origattrs.checkInputs;
            });
          };
        };
      in {
        # 同步覆盖顶层python3和python3Packages,保证全局引用一致
        python3 = customPython3;
        python3Packages = customPython3.pkgs;
        # 基于修改后的Python包集合重新构建awscli2,不要只传python3参数
        myawscli2 = customPython3.pkgs.awscli2;
      };
  in [
    overlayRemovePyopenssl
  ];
  system.stateVersion = 4;
}

配置生效后可以重新验证:pkgs.myawscli2依赖的urllib3将不再带有pyopenssl传递依赖,和全局修改的python3.pkgs.urllib3保持一致。

如果是用nixpkgs.config.packageOverrides的场景,逻辑完全相同:同步覆盖python3和python3Packages两个顶层属性,再基于自定义Python的包集合构建目标应用即可。


内容的提问来源于stack exchange,提问作者yonran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 21:48:10