src 布局与扁平布局

“扁平布局”是指在一个文件夹或仓库中组织项目文件,使得各种配置文件和可导入包都位于顶级目录中。

.
├── README.md
├── noxfile.py
├── pyproject.toml
├── setup.py
├── awesome_package/
│   ├── __init__.py
│   └── module.py
└── tools/
    ├── generate_awesomeness.py
    └── decrease_world_suck.py

“src 布局”通过将旨在可导入的代码(即 import awesome_package,也称为可导入包)移动到子目录中,从而偏离了扁平布局。此子目录通常命名为 src/,因此称为“src 布局”。

.
├── README.md
├── noxfile.py
├── pyproject.toml
├── setup.py
├── src/
│    └── awesome_package/
│       ├── __init__.py
│       └── module.py
└── tools/
    ├── generate_awesomeness.py
    └── decrease_world_suck.py

以下是 src 布局和扁平布局之间重要行为差异的细分:

  • src 布局需要安装项目才能运行其代码,而扁平布局则不需要。

    这意味着 src 布局在项目开发工作流程中涉及一个额外的步骤(通常,可编辑安装用于开发,常规安装用于测试)。

  • src 布局有助于防止意外使用正在开发中的代码副本。

    这一点很重要,因为 Python 解释器会将当前工作目录作为导入路径中的第一项。这意味着如果当前工作目录中存在与已安装的导入包同名的导入包,则将使用当前工作目录中的变体。这可能导致项目打包工具的微妙配置错误,从而可能导致文件未包含在分发中。

    src 布局通过将导入包保存在与项目根目录分开的目录中来帮助避免这种情况,从而确保使用已安装的副本。

  • src 布局有助于强制执行可编辑安装只能导入旨在可导入的文件。

    当通过路径配置文件实现可编辑安装时,这一点尤为重要,该文件将目录添加到导入路径中。

    扁平布局会将其他项目文件(例如:README.mdtox.ini)和打包/工具配置文件(例如:setup.pynoxfile.py)添加到导入路径中。这将使某些导入在可编辑安装中有效,但在常规安装中无效。

使用 src 布局从源代码运行命令行界面

由于 src 布局首先提到的特殊性,命令行界面无法直接从源树运行,而是需要以开发模式安装包以进行测试。由于这在某些情况下可能不切实际,因此一种解决方法是在通过其 __main__.py 文件调用时,将包文件夹预加到 Python 的 sys.path

import os
import sys

if not __package__:
    # Make CLI runnable from source tree with
    #    python src/package
    package_source_path = os.path.dirname(os.path.dirname(__file__))
    sys.path.insert(0, package_source_path)