如何让pip本地安装时自动安装build-system依赖setuptools_scm?
我们的项目Locust使用setuptools_scm进行版本管理,本地目录安装时必须依赖该工具。此前在setup.py中通过setup_requires=["setuptools_scm>=6.2"]指定依赖,现在已升级为使用setup.cfg和pyproject.toml,并在pyproject.toml的[build-system]段配置:
[build-system] requires = ["setuptools_scm>=6.2", ...]
多数场景下该配置能正常工作,但执行pip install -e .(pip install .也存在相同问题,但优先级较低)时,pip不会自动安装setuptools_scm,导致本地安装的版本被设为0.0.0,示例执行输出如下:
~/git/locust pip install -e . Looking in indexes: https://pypi.org/simple ... Running setup.py develop for locust Successfully installed locust-0.0.0
我们需要找到合适的方法,让pip从源码安装时自动安装setuptools_scm,同时避免将其添加为setup.cfg中的常规依赖(否则会让数千PyPI用户下载不必要的依赖)。以下是几种可行方案:
方案1:完善pyproject.toml配置并升级pip
首先确保pyproject.toml的build-system配置完整,包含指定的构建后端,示例:
[build-system] requires = ["setuptools>=61.0", "setuptools_scm>=6.2"] build-backend = "setuptools.build_meta"
同时要求本地开发者使用pip 21.0及以上版本,旧版pip对PEP 517/518的支持存在缺陷,无法正确安装构建阶段的依赖。
方案2:添加条件化依赖
在setup.cfg中使用环境标记(environment markers),仅在源码安装场景下引入setuptools_scm依赖。在setup.cfg的[options]段添加:
[options] install_requires = setuptools_scm>=6.2; (exists(".git") or exists("PKG-INFO"))
这种配置会在检测到本地存在.git目录或PKG-INFO文件(源码安装特征)时,才安装setuptools_scm,PyPI用户下载的预构建轮子不会触发该依赖。注意部分旧版setuptools可能对这类标记的支持有限,需要测试兼容性。
方案3:保留极简setup.py做兼容处理
虽然已迁移到setup.cfg和pyproject.toml,但可以保留一个极简的setup.py,用来检测并自动安装setuptools_scm:
from setuptools import setup try: import setuptools_scm except ImportError: from setuptools.command.install import install from setuptools.command.develop import develop class InstallWithSCM(install): def run(self): self.distribution.install_requires.append("setuptools_scm>=6.2") install.run(self) class DevelopWithSCM(develop): def run(self): self.distribution.install_requires.append("setuptools_scm>=6.2") develop.run(self) setup(cmdclass={"install": InstallWithSCM, "develop": DevelopWithSCM}) else: setup(use_scm_version=True)
该脚本会在检测到setuptools_scm未安装时,临时将其加入安装依赖列表,仅在本地源码安装时生效;PyPI用户下载的是已生成版本号的轮子,不会触发这段逻辑。
方案4:临时 workaround:使用--no-build-isolation参数
告知本地开发者在安装时添加参数:
pip install -e . --no-build-isolation
但该方案要求用户本地已预先安装setuptools_scm,仅适合临时应急使用。
内容的提问来源于stack exchange,提问作者Cyberwiz

