咨询:无src结构下将setup.py置于包根目录构建Python包的方法
关于setuptools包结构与构建方案的疑问
我正在学习setuptools,现有一个Python包结构如下:
package1 ├──setup.py ├── __init__.py ├── module1.py └── submodule1 └── __init__.py
我希望将setup.py放在package1目录(即GitHub仓库根目录)内,构建分发版时将package1的文件打包为名为package1的包,同时排除setup.py文件。目前我使用的是带src的结构:
production ├──setup.py └──src └──package1 ├── __init__.py ├── module1.py └── submodule1 └── __init__.py
这样设置是为了让克隆仓库的用户可直接执行python -m build进行构建,请问该方案是否可行?有无其他实现方式?
方案可行性分析
你采用的带src的结构完全可行,而且这是Python打包社区推荐的最佳实践之一。这种结构的优势很明确:
- 彻底避免本地开发时的包导入混淆(不会出现直接导入当前目录下的
package1而非已安装版本的问题) - 克隆仓库的用户确实可以直接在根目录执行
python -m build,build工具能自动识别src目录下的包并正确打包,且setup.py不会被包含到最终的分发包里,完全符合你的需求。
其他实现方式
如果不想用src结构,也有两种常用方案:
1. 直接在根目录放置setup.py,通过配置排除setup.py
保持你最初的目录结构(setup.py和package1同属根目录),然后通过以下两种方式排除setup.py:
- 在setup.py中配置:
调用setup()时,通过参数控制排除文件,示例:from setuptools import setup, find_packages setup( name="package1", packages=find_packages(), exclude_package_data={"": ["setup.py"]} ) - 使用MANIFEST.in文件:
在根目录创建MANIFEST.in,写入:
这个文件会告诉setuptools构建分发版时排除指定文件。exclude setup.py
不过这种方式有个潜在问题:本地开发时,如果你在根目录运行脚本,可能会直接导入当前目录的package1,而非已安装的版本,容易引发调试混乱。
2. 使用pyproject.toml替代setup.py(现代打包方式)
现在Python打包更推荐使用pyproject.toml来声明构建依赖和配置,配合setup.cfg或者直接在pyproject.toml里写包配置,不管是src结构还是非src结构都适用。
比如src结构下的pyproject.toml示例:
[build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] name = "package1" version = "0.1.0" packages = ["package1"] package-dir = {"": "src"}
这种方式更简洁,也能自动排除根目录的配置文件,用户同样可以直接执行python -m build构建。
内容的提问来源于stack exchange,提问作者grexor
相关产品推荐
相关产品推荐

