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

如何基于setuptools与pyproject.toml分发Python包关联的Shell脚本?

解决pyproject.toml项目中分发Shell脚本的问题

我完全懂你的困扰——想用纯pyproject.toml构建项目,还要绑定一个Shell脚本一起分发,官方的[project.scripts]又只能配置Python函数,直接调用的话加载整个项目太慢,拆成两个项目又破坏了二者的强耦合性。这里有两个可行的方案,帮你搞定这个问题:

方案一:用setuptools的data_files直接安装Shell脚本

这个方案最直接,不需要额外的Python包装层,直接把Shell脚本安装到系统可执行路径。在你的pyproject.toml里添加:

[tool.setuptools.data_files]
# 目标安装路径,类Unix系统一般用/usr/local/bin,Windows可根据需求调整为Scripts目录
"/usr/local/bin" = ["path/to/your/my_script.sh"]

注意事项:

  • 打包前记得给Shell脚本加可执行权限:chmod +x path/to/your/my_script.sh,这样安装后用户直接就能在终端调用my_script.sh
  • 跨平台场景下,Windows需要额外编写对应的.bat脚本,再分平台配置data_files路径

方案二:轻量Python包装器(推荐,跨平台友好)

如果担心data_files的路径兼容性问题,或者需要一点灵活度,可以写一个完全不依赖项目核心代码的极简Python包装器,这样既符合[project.scripts]的规范,又不会加载整个项目导致耗时。

步骤如下:

  1. 把Shell脚本放到你的Python包目录下(比如my_project/my_script.sh),确保它有可执行权限
  2. 在包内创建一个轻量的包装模块,比如my_project/scripts/script_wrapper.py,内容如下:
#!/usr/bin/env python3
import subprocess
import sys
from importlib.resources import files

def main():
    # 定位打包后Shell脚本的实际路径
    script_path = files("my_project").joinpath("my_script.sh")
    # 把命令行参数传递给Shell脚本
    subprocess.run([str(script_path)] + sys.argv[1:], check=True)

if __name__ == "__main__":
    main()
  1. 在pyproject.toml里配置两项:
    • 把Shell脚本作为包数据包含进去:
      [tool.setuptools.package_data]
      my_project = ["my_script.sh"]
      
    • 配置project.scripts指向这个包装器:
      [project.scripts]
      my_script = "my_project.scripts.script_wrapper:main"
      

这样,用户执行my_script时,只会加载这个几行代码的包装器,不会触发项目核心代码的加载,完美解决耗时问题,而且Shell脚本和项目完全绑定,不需要拆分。

另外补充一点:关于setup.py的scripts参数,虽然现在官方文档提及较少,但它是setuptools的传统特性,短期内不会被移除,但既然你用纯pyproject.toml,优先用上面的方案更符合现代Python打包规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 19:04:06