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

Python setup.py导入包版本引发pip安装依赖缺失报错

问题根因

pip安装源码分发包的执行顺序是固定的:

  1. 解压tar.gz包,先执行setup.py收集包元数据(也就是报错日志里的egg_info阶段)
  2. 解析setup.py里install_requires声明的依赖,下载并安装这些依赖
  3. 再执行实际的包安装逻辑

报错本质原因是:元数据收集阶段发生在依赖安装之前。你在setup.py中写from mypackage.version import VERSION时,Python的包导入机制会先执行mypackage/__init__.py,而这个文件里直接导入了依赖第三方库的some_code模块,some_code.py顶层又导入了尚未安装的jsonpickle、pyzmq,自然触发ModuleNotFoundError。
你本来只是想读取版本常量,结果连带触发了整个包的初始化逻辑,把还没安装的依赖提前加载了。

修复方案

按推荐优先级从高到低排列:

  • 方案1:直接解析version.py文件读取版本号,完全不触发包导入
    这是Python打包的通用最佳实践,完全绕开包的初始化逻辑,不会有任何依赖导入问题。把setup.py中原来导入VERSION的代码替换为如下内容即可:
    import os
    import re
    
    ROOT_DIR = os.path.dirname(__file__)
    VERSION_FILE = os.path.join(ROOT_DIR, "mypackage", "version.py")
    
    with open(VERSION_FILE, encoding="utf-8") as f:
        # 正则匹配VERSION常量的赋值
        VERSION = re.search(
            r'^VERSION\s*=\s*["\']([^"\']+)["\']',
            f.read(),
            re.MULTILINE
        ).group(1)
    
  • 方案2:直接加载version模块,跳过包的__init__.py
    如果不想用正则解析,可以用importlib直接加载单独的version.py文件,不会触发mypackage包的初始化流程,注意要保证version.py本身只存版本常量,不导入任何依赖第三方库的模块:
    import os
    import importlib.util
    
    ROOT_DIR = os.path.dirname(__file__)
    VERSION_FILE = os.path.join(ROOT_DIR, "mypackage", "version.py")
    
    spec = importlib.util.spec_from_file_location("pkg_version", VERSION_FILE)
    version_mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(version_mod)
    VERSION = version_mod.VERSION
    
  • 方案3:调整包初始化逻辑(不推荐)
    可以修改__init__.py,不在顶层导入依赖第三方库的业务模块,改成懒加载或者按需导入,但这种方式治标不治本,后续修改业务代码时很容易再次引入同类问题。

核心原则:setup.py本身的执行不能依赖install_requires里声明的任何第三方包,也尽量不要导入自己包内带业务逻辑的模块,避免触发不必要的依赖加载。

内容的提问来源于stack exchange,提问作者Wör Du Schnaffzig

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 18:39:28