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

如何在setuptools安装后命令中获取安装包列表并校验版本

单仓库子包版本校验的Post-install脚本实现

问题核心

pkg_resources.working_set在安装阶段无法获取刚安装的子包——因为setuptools还未将新安装的包加入到working_set,直接调用会触发KeyError。

可行解决方案

方案1:解析安装命令参数(适合直接安装场景)

用户执行pip install .或指定子包安装时,sys.argv会包含安装目标信息。结合setuptools_scm的版本获取逻辑,直接校验子包与仓库版本是否一致。

示例代码:

import sys
from setuptools_scm import get_version
from setuptools import setup
from setuptools.command.install import install

def post_install():
    # 筛选安装命令中的子包路径或名称
    install_targets = [
        arg for arg in sys.argv 
        if arg.startswith('.') or '/' in arg or arg in ['subpkg-a', 'subpkg-b']
    ]
    # 获取仓库根版本
    repo_version = get_version(root='..', relative_to=__file__)
    
    # 逐个校验子包版本
    for target in install_targets:
        subpkg_version = get_version(root=target, relative_to=__file__)
        if subpkg_version != repo_version:
            raise RuntimeError(f"子包版本不匹配:{target} 版本{subpkg_version},仓库版本{repo_version}")

class CustomInstall(install):
    def run(self):
        install.run(self)
        post_install()

setup(
    # 其他配置项...
    cmdclass={'install': CustomInstall}
)

方案2:扫描site-packages目录(通用场景)

安装完成后,直接扫描Python的site-packages目录,读取子包的*.dist-info/METADATA文件获取版本信息,再与仓库版本对比。

示例代码:

import os
import glob
import site
from setuptools_scm import get_version
from setuptools import setup
from setuptools.command.install import install

def get_installed_subpkg_versions(subpkg_names):
    # 获取所有site-packages目录
    site_dirs = site.getsitepackages() + [site.getusersitepackages()]
    installed_versions = {}
    
    for pkg_name in subpkg_names:
        # 匹配子包的dist-info目录
        dist_pattern = f"{pkg_name.replace('-', '_')}-*.dist-info"
        for dir_path in site_dirs:
            for dist_dir in glob.glob(os.path.join(dir_path, dist_pattern)):
                with open(os.path.join(dist_dir, 'METADATA'), 'r') as f:
                    for line in f:
                        if line.startswith('Version:'):
                            installed_versions[pkg_name] = line.strip().split(': ')[1]
                            break
    return installed_versions

def post_install():
    repo_version = get_version(root='..', relative_to=__file__)
    target_subpkgs = ['subpkg-a', 'subpkg-b']
    installed_versions = get_installed_subpkg_versions(target_subpkgs)
    
    for pkg, ver in installed_versions.items():
        if ver != repo_version:
            raise RuntimeError(f"子包{pkg}版本不匹配:已安装{ver},仓库版本{repo_version}")

class CustomInstall(install):
    def run(self):
        install.run(self)
        post_install()

setup(
    # 其他配置项...
    cmdclass={'install': CustomInstall}
)

方案3:调用pip命令获取已安装包(简单直接)

在post-install脚本中执行pip list --format=freeze,解析输出结果拿到子包版本,再做一致性校验。

示例代码:

import sys
import subprocess
from setuptools_scm import get_version
from setuptools import setup
from setuptools.command.install import install

def post_install():
    repo_version = get_version(root='..', relative_to=__file__)
    target_subpkgs = ['subpkg-a', 'subpkg-b']
    
    # 调用pip获取已安装包列表
    result = subprocess.run(
        [sys.executable, '-m', 'pip', 'list', '--format=freeze'],
        capture_output=True,
        text=True,
        check=True
    )
    # 解析为包名:版本的字典
    installed_pkgs = {
        line.split('==')[0]: line.split('==')[1] 
        for line in result.stdout.splitlines() if '==' in line
    }
    
    for pkg in target_subpkgs:
        if pkg not in installed_pkgs:
            raise RuntimeError(f"子包{pkg}未完成安装")
        if installed_pkgs[pkg] != repo_version:
            raise RuntimeError(f"子包{pkg}版本不匹配:已安装{installed_pkgs[pkg]},仓库版本{repo_version}")

class CustomInstall(install):
    def run(self):
        install.run(self)
        post_install()

setup(
    # 其他配置项...
    cmdclass={'install': CustomInstall}
)

注意事项

  • 确保校验逻辑在所有子包安装完成后执行:如果是单仓库联合安装,把校验放在顶层包的post-install中,或让所有子包的校验依赖顶层版本。
  • 适配开发模式(pip install -e .):这种场景下site-packages是源码链接,需直接从子包目录用setuptools_scm获取版本,而非扫描site-packages。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 15:36:33