想象一下,您想用 Python 开发一个重要的最终用户桌面(不是 Web)应用程序。构建项目文件夹层次结构的最佳方法是什么?
理想的功能是易于维护、IDE 友好、适合源代码控制分支/合并以及易于生成安装包。
尤其:
- 你把源放在哪里?
- 您将应用程序启动脚本放在哪里?
- 你把 IDE 项目放在哪里?
- 你把单元/验收测试放在哪里?
- 您将非 Python 数据(例如配置文件)放在哪里?
- 对于 pyd/so 二进制扩展模块,您将非 Python 源代码(例如 C++)放在哪里?
想象一下,您想用 Python 开发一个重要的最终用户桌面(不是 Web)应用程序。构建项目文件夹层次结构的最佳方法是什么?
理想的功能是易于维护、IDE 友好、适合源代码控制分支/合并以及易于生成安装包。
尤其:
没有太大关系。任何让你开心的事情都会奏效。没有很多愚蠢的规则,因为 Python 项目可以很简单。
/scripts
或者/bin
对于那种命令行界面的东西/tests
为您的测试/lib
用于您的 C 语言库/doc
对于大多数文档/apidoc
对于 Epydoc 生成的 API 文档。顶级目录可以包含 README、Config 等。
艰难的选择是是否使用/src
树。Python不像 Java 或 C 那样区分/src
、/lib
和。/bin
由于/src
某些人认为顶级目录毫无意义,因此您的顶级目录可以是应用程序的顶级架构。
/foo
/bar
/baz
我建议将所有这些放在“我的产品名称”目录下。因此,如果您正在编写一个名为 的应用程序quux
,则包含所有这些内容的目录名为 /quux
。
PYTHONPATH
然后,另一个项目的可以包含/path/to/quux/foo
以重用该QUUX.foo
模块。
就我而言,因为我使用 Komodo Edit,所以我的 IDE cuft 是单个 .KPF 文件。我实际上将它放在顶级/quux
目录中,并省略了将其添加到 SVN。
根据 Jean-Paul Calderone's Filesystem structure of a Python project:
Project/
|-- bin/
| |-- project
|
|-- project/
| |-- test/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- setup.py
|-- README
Jean-Paul Calderone 的这篇博文通常在 Freenode 上的#python 中作为答案给出。
Python项目的文件系统结构
做:
- 将目录命名为与您的项目相关的名称。例如,如果您的项目名为“Twisted”,请将其源文件的顶级目录命名为
Twisted
。当你发布时,你应该包含一个版本号后缀:Twisted-2.5
.- 创建一个目录
Twisted/bin
并将您的可执行文件放在那里,如果有的话。不要给它们.py
扩展名,即使它们是 Python 源文件。除了导入和调用项目中其他地方定义的主函数外,不要在其中放置任何代码。(轻微的皱纹:因为在 Windows 上,解释器是由文件扩展名选择的,所以你的 Windows 用户确实想要 .py 扩展名。所以,当你为 Windows 打包时,你可能想要添加它。不幸的是,没有简单的 distutils 技巧我知道要自动化这个过程。考虑到在 POSIX 上,.py 扩展名只是一个缺点,而在 Windows 上,缺少的是一个实际的错误,如果您的用户群包括 Windows 用户,您可能希望选择只拥有 .py到处扩展。)- 如果您的项目可以表示为单个 Python 源文件,则将其放入目录中,并将其命名为与您的项目相关的名称。例如,
Twisted/twisted.py
。如果您需要多个源文件,请改为创建一个包(Twisted/twisted/
, 为空Twisted/twisted/__init__.py
)并将源文件放入其中。例如,Twisted/twisted/internet.py
。- 将单元测试放在包的子包中(注意——这意味着上面的单个 Python 源文件选项是一个技巧——你总是需要至少一个其他文件来进行单元测试)。例如,
Twisted/twisted/test/
。当然,将其与Twisted/twisted/test/__init__.py
. 将测试放在像Twisted/twisted/test/test_internet.py
.- 如果您感觉不错,请分别添加
Twisted/README
和来解释和安装您的软件。Twisted/setup.py
不:
- 将您的源代码放在名为
src
or的目录中lib
。这使得不安装就很难运行。- 把你的测试放在你的 Python 包之外。这使得很难针对已安装的版本运行测试。
- 创建一个只有a的包,
__init__.py
然后将所有代码放入__init__.py
. 只需制作一个模块而不是一个包,它更简单。- 尝试想出一些神奇的技巧,让 Python 能够导入您的模块或包,而无需用户将包含它的目录添加到他们的导入路径中(通过 PYTHONPATH 或其他一些机制)。您不会正确处理所有情况,当您的软件在他们的环境中无法运行时,用户会生您的气。
让我摘录那篇优秀文章的项目布局部分:
在设置项目时,布局(或目录结构)对于正确处理很重要。合理的布局意味着潜在的贡献者不必永远花时间寻找一段代码;文件位置很直观。由于我们正在处理现有项目,这意味着您可能需要移动一些东西。
让我们从顶部开始。大多数项目都有许多顶级文件(如 setup.py、README.md、requirements.txt 等)。然后每个项目都应该有三个目录:
- 包含项目文档的 docs 目录
- 以项目名称命名的目录,用于存储实际的 Python 包
- 两个地方之一的测试目录
- 在包含测试代码和资源的包目录下
- 作为一个独立的顶级目录为了更好地了解你的文件应该如何组织,这里是我的一个项目的布局的简化快照,sandman:
$ pwd ~/code/sandman $ tree . |- LICENSE |- README.md |- TODO.md |- docs | |-- conf.py | |-- generated | |-- index.rst | |-- installation.rst | |-- modules.rst | |-- quickstart.rst | |-- sandman.rst |- requirements.txt |- sandman | |-- __init__.py | |-- exception.py | |-- model.py | |-- sandman.py | |-- test | |-- models.py | |-- test_sandman.py |- setup.py
如您所见,有一些顶级文件,一个 docs 目录(生成的是一个空目录,sphinx 将在其中放置生成的文档),一个 sandman 目录,以及 sandman 下的一个 test 目录。
“Python Packaging Authority”有一个示例项目:
https://github.com/pypa/sampleproject
它是一个示例项目,作为 Python 打包用户指南的打包和分发项目教程的辅助工具。
尝试使用python_boilerplate模板启动项目。它在很大程度上遵循最佳实践(例如这里的那些),但更适合您发现自己愿意在某个时候将您的项目拆分为多个鸡蛋(相信我,除了最简单的项目之外,您会的。一个常见的情况是您必须使用其他人的库的本地修改版本)。
你把源放在哪里?
PROJECT_ROOT/src/<egg_name>
.您将应用程序启动脚本放在哪里?
entry_point
其中一个鸡蛋。你把 IDE 项目放在哪里?
PROJECT_ROOT/.<something>
项目的根目录中,这很好。你把单元/验收测试放在哪里?
PROJECT_ROOT/src/<egg_name>/tests
目录中。我个人更喜欢用它py.test
来运行它们。您将非 Python 数据(例如配置文件)放在哪里?
pkg_resources
包使用setuptools
,或者从 Python 3.7 开始通过importlib.resources
标准库中的模块使用。PROJECT_ROOT/config
. 对于部署,可以有多种选择。在 Windows 上可以使用%APP_DATA%/<app-name>/config
、 在 Linux 上/etc/<app-name>
或/opt/<app-name>/config
.PROJECT_ROOT/var
在开发过程中保留它们,并/var
在 Linux 部署期间保留它们。PROJECT_ROOT/src/<egg_name>/native
文档通常会进入PROJECT_ROOT/doc
或PROJECT_ROOT/src/<egg_name>/doc
(这取决于您是否将某些鸡蛋视为单独的大型项目)。一些额外的配置将在文件中,如PROJECT_ROOT/buildout.cfg
和PROJECT_ROOT/setup.cfg
.
根据我的经验,这只是一个迭代的问题。将您的数据和代码放在您认为的任何地方。有可能,无论如何你都会错的。但是,一旦您对事情将如何形成有了更好的了解,您就可以更好地进行这些猜测。
至于扩展源,我们在 trunk 下有一个 Code 目录,其中包含一个用于 python 的目录和一个用于各种其他语言的目录。就个人而言,我更倾向于下次尝试将任何扩展代码放入自己的存储库中。
话虽如此,我回到我最初的观点:不要把它搞得太大。把它放在似乎对你有用的地方。如果您发现某些东西不起作用,则可以(并且应该)对其进行更改。
使用setuptoolspackage_data
中的支持,最好将非 Python 数据捆绑在 Python 模块中。我强烈推荐的一件事是使用命名空间包来创建多个项目可以使用的共享命名空间——很像 Java 将包放入的约定(并且能够拥有一个共享的命名空间)。com.yourcompany.yourproject
com.yourcompany.utils
重新分支和合并,如果你使用足够好的源代码控制系统,它甚至可以通过重命名来处理合并;Bazaar尤其擅长这一点。
与此处的其他一些答案相反,我对拥有src
顶级目录(旁边有doc
和目录)表示 +1。test
文档目录树的特定约定将根据您使用的内容而有所不同;例如, Sphinx有其快速入门工具支持的自己的约定。
请利用 setuptools 和 pkg_resources;这使得其他项目更容易依赖于您的代码的特定版本(如果您使用的是多个版本,则可以使用不同的非代码文件同时安装package_data
)。