Python 应用程序的最佳项目结构是什么?[关闭]
- 2024-12-27 08:47:00
- admin 原创
- 121
问题描述:
假设您想用 Python 开发一个非平凡的最终用户桌面(而非 Web)应用程序。构建项目文件夹层次结构的最佳方法是什么?
理想的特性是易于维护、IDE 友好、适合源代码控制分支/合并、以及易于生成安装包。
尤其:
您将源放在哪里?
您将应用程序启动脚本放在哪里?
您将 IDE 项目杂物放在哪里?
您将单元测试/验收测试放在哪里?
您将非 Python 数据(例如配置文件)放在哪里?
您将 pyd/so 二进制扩展模块的非 Python 源代码(例如 C++)放在哪里?
解决方案 1:
没什么大不了的。只要你开心就行。没有太多愚蠢的规则,因为 Python 项目可以很简单。
/scripts
或者/bin
类似命令行界面的东西/tests
为您的测试/lib
适用于您的 C 语言库/doc
对于大多数文档/apidoc
用于 Epydoc 生成的 API 文档。
并且顶级目录可以包含 README、Config 等等。
是否使用树是一个艰难的选择。Python不像 Java 或 C 那样/src
区分/src
、/lib
和。/bin
由于有些人认为顶级/src
目录毫无意义,因此您的顶级目录可以是应用程序的顶级架构。
/foo
/bar
/baz
我建议将所有这些内容放在“name-of-my-product”目录下。因此,如果您正在编写一个名为的应用程序quux
,则包含所有这些内容的目录名为 /quux
。
PYTHONPATH
然后,另一个项目可以包括/path/to/quux/foo
以重用该QUUX.foo
模块。
就我而言,由于我使用 Komodo Edit,所以我的 IDE 库是一个 .KPF 文件。我实际上将其放在顶级/quux
目录中,并省略将其添加到 SVN。
解决方案 2:
根据 Jean-Paul Calderone 的Python 项目的文件系统结构:
Project/
|-- bin/
| |-- project
|
|-- project/
| |-- test/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- setup.py
|-- README
解决方案 3:
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
将您的源代码放在名为或 的目录中lib
。这使得在未安装的情况下难以运行。将测试放在 Python 包之外。这使得针对已安装的版本运行测试变得困难。
创建一个只有的包
__init__.py
,然后将所有代码放入__init__.py
。只需创建一个模块而不是包,这样更简单。尝试想出神奇的技巧,让 Python 能够导入您的模块或包,而无需用户将包含它的目录添加到他们的导入路径(通过 PYTHONPATH 或其他机制)。您无法正确处理所有情况,当您的软件无法在他们的环境中运行时,用户会对您生气。
解决方案 4:
查看以正确的方式开源 Python 项目。
让我摘录一下那篇优秀文章的项目布局部分:
在设置项目时,布局(或目录结构)非常重要。合理的布局意味着潜在的贡献者不必花很长时间寻找一段代码;文件位置很直观。由于我们处理的是现有项目,这意味着您可能需要移动一些内容。
我们从最顶层开始。大多数项目都有许多顶层文件(如 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 下的一个测试目录。
解决方案 5:
“Python 包装管理局”有一个示例项目:
https://github.com/pypa/sampleproject
它是一个示例项目,作为《Python 打包用户指南》中有关打包和分发项目的教程的辅助而存在。
解决方案 6:
尝试使用python_boilerplate模板启动项目。它在很大程度上遵循最佳实践(例如此处的最佳实践),但更适合于您愿意在某个时候将项目拆分成多个 egg(相信我,除了最简单的项目之外,您都会这样做。一种常见的情况是您必须使用其他人的库的本地修改版本)。
您将源放在哪里?
+ 对于相当大的项目,将源代码拆分成几个 egg 是有意义的。每个 egg 都作为单独的 setuptools-layout 放在 下`PROJECT_ROOT/src/<egg_name>`。
您将应用程序启动脚本放在哪里?
+ 理想的选择是将应用程序启动脚本注册为`entry_point`其中一个eggs。
您将 IDE 项目杂物放在哪里?
+ 取决于 IDE。许多 IDE 将其内容保存在`PROJECT_ROOT/.<something>`项目的根目录中,这很好。
您将单元测试/验收测试放在哪里?
+ 每个 egg 都有一组单独的测试,保存在其`PROJECT_ROOT/src/<egg_name>/tests`目录中。我个人更喜欢使用`py.test`来运行它们。
您将非 Python 数据(例如配置文件)放在哪里?
+ 视情况而定。非 Python 数据可以有多种类型。
- *“资源”*,即必须打包在 egg 中的数据。此数据进入相应的 egg 目录,位于包命名空间内的某个位置。它可以通过`pkg_resources`中的包使用`setuptools`,或者从 Python 3.7 开始通过`importlib.resources`标准库中的模块使用。
- *“配置文件”*,即非 Python 文件,它们被视为项目源文件的外部文件,但在应用程序开始运行时必须用一些值进行初始化。在开发过程中,我更喜欢将此类文件保存在 中`PROJECT_ROOT/config`。对于部署,可以有多种选择。在 Windows 上,可以使用`%APP_DATA%/<app-name>/config`,在 Linux 上,`/etc/<app-name>`或者`/opt/<app-name>/config`。
- *生成的文件*,即应用程序在执行期间可能创建或修改的文件。我更愿意在`PROJECT_ROOT/var`开发期间和`/var`Linux 部署期间保留它们。
您将 pyd/so 二进制扩展模块的非 Python 源代码(例如 C++)放在哪里?
进入
PROJECT_ROOT/src/<egg_name>/native
文档通常会放在PROJECT_ROOT/doc
或中PROJECT_ROOT/src/<egg_name>/doc
(这取决于您是否将其中一些视为单独的大型项目)。一些其他配置将放在像PROJECT_ROOT/buildout.cfg
和这样的文件中PROJECT_ROOT/setup.cfg
。
解决方案 7:
根据我的经验,这只是一个迭代问题。将数据和代码放在您认为应该放的位置。很有可能,您无论如何都会出错。但是,一旦您更好地了解事情将如何发展,您就更有能力做出此类猜测。
至于扩展源,我们在 trunk 下有一个 Code 目录,其中包含一个用于 Python 的目录和一个用于其他各种语言的目录。就我个人而言,我更倾向于下次尝试将任何扩展代码放入其自己的存储库中。
话虽如此,我还是回到最初的观点:不要太在意。把它放在对你有用的地方。如果你发现某些东西不起作用,它可以(也应该)被改变。
解决方案 8:
最好使用setuptoolspackage_data
中的支持将非 Python 数据捆绑到 Python 模块中。我强烈建议使用命名空间包来创建多个项目可以使用的共享命名空间 - 就像 Java 中放入包的约定(并且能够拥有共享命名空间)。com.yourcompany.yourproject
`com.yourcompany.utils`
重新分支和合并,如果您使用足够好的源代码控制系统,它甚至可以通过重命名来处理合并;Bazaar在这方面特别擅长。
与此处的其他一些答案相反,我赞成在src
顶层设置目录(旁边有doc
和test
目录)。文档目录树的具体约定将根据您使用的内容而有所不同;例如, Sphinx有自己的约定,其快速启动工具支持该约定。
请利用 setuptools 和 pkg_resources;这使得其他项目更容易依赖您代码的特定版本(如果您使用的话,还可以同时安装具有不同非代码文件的多个版本package_data
)。