关闭。这个问题需要更加集中。它目前不接受答案。想改进这个问题?更新问题,使其仅通过编辑此帖子专注于一个问题。 5年前关闭。改进这个问题
想象一下,您想用 Python 开发一个重要的最终用户桌面(不是 Web)应用程序。构建项目文件夹层次结构的最佳方法是什么?
理想的功能是易于维护、IDE 友好、适合源代码控制分支/合并以及易于生成安装包。
尤其是:
你把源放在哪里?您将应用程序启动脚本放在哪里?你把 IDE 项目放在哪里?你把单元/验收测试放在哪里?您将非 Python 数据(例如配置文件)放在哪里?对于 pyd/so 二进制扩展模块,您将非 Python 源代码(例如 C++)放在哪里?
没有太大关系。任何让你开心的事情都会奏效。没有很多愚蠢的规则,因为 Python 项目可以很简单。
/scripts 或 /bin 用于那种命令行界面的东西
/tests 为您的测试
/lib 用于您的 C 语言库
/doc 用于大多数文档
/apidoc 用于 Epydoc 生成的 API 文档。
顶级目录可以包含 README、Config 等。
艰难的选择是是否使用 /src
树。 Python 不像 Java 或 C 那样区分 /src
、/lib
和 /bin
。
由于某些人认为顶级 /src
目录毫无意义,因此您的顶级目录可以是应用程序的顶级架构。
/foo
/酒吧
/baz
我建议将所有这些放在“我的产品名称”目录下。因此,如果您正在编写一个名为 quux
的应用程序,则包含所有这些内容的目录名为 /quux
。
然后,另一个项目的 PYTHONPATH
可以包含 /path/to/quux/foo
以重用 QUUX.foo
模块。
就我而言,因为我使用 Komodo Edit,所以我的 IDE cuft 是单个 .KPF 文件。我实际上将它放在顶级 /quux
目录中,并省略了将其添加到 SVN。
根据 Jean-Paul Calderone 的Filesystem structure of a Python project:
Project/
|-- bin/
| |-- project
|
|-- project/
| |-- test/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- setup.py
|-- README
../
)
bin
文件夹和 Project
顶级文件夹中都有一个 __init__.py
文件。
pip install -e /path/to/Project
)
-e
标志,它将包安装为可编辑包,即将其安装为指向实际项目文件夹的链接。然后可执行文件只需 import project
即可访问该模块。
这个 blog post by 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 或其他一些机制)。您不会正确处理所有情况,当您的软件在他们的环境中无法运行时,用户会生您的气。
Twisted
作为项目名称具有讽刺意味,因为官方 Twisted
library 现在使用 src
布局,这与第一个“不要”建议相矛盾:“将您的源代码放在一个名为 src 的目录中或lib。这使得不安装就很难运行。”这就是重点(见Ionel Cristian Mărieș's article)。
查看Open Sourcing a Python Project the Right Way。
让我摘录那篇优秀文章的项目布局部分:
在设置项目时,布局(或目录结构)对于正确处理很重要。合理的布局意味着潜在的贡献者不必永远花时间寻找一段代码;文件位置很直观。由于我们正在处理现有项目,这意味着您可能需要移动一些东西。让我们从顶部开始。大多数项目都有许多顶级文件(如 setup.py、README.md、requirements.txt 等)。然后每个项目都应该有三个目录: 包含项目文档的 docs 目录 以项目名称命名的目录,用于存储实际的 Python 包 两个位置之一的测试目录 包含测试代码和资源的包目录下 作为一个支架-alone 顶级目录 为了更好地了解文件的组织方式,这是我的一个项目 sandman 的布局的简化快照: $ pwd ~/code/sandman $ tree 。 |- 许可证 |- README.md |- TODO.md |- 文档 | |-- conf.py | |-- 生成 | |-- 索引.rst | |-- 安装.rst | |-- 模块.rst | |-- 快速入门.rst | |-- sandman.rst |- requirements.txt |- 沙子 | |-- __init__.py | |-- 异常.py | |-- 模型.py | |-- 沙子.py | |-- 测试 | |-- 模型.py | |-- test_sandman.py |- setup.py 如你所见,有一些顶级文件,一个docs目录(生成的是一个空目录,sphinx将放置生成的文档),一个sandman目录,下面还有一个test目录沙人。
Makefile
置于与 setup.py
相同的级别吗?因此,如果我对您的理解正确,make env
会自动创建一个新的 venv
并将软件包安装到其中...?
/code/sandman/sandman/
中的任何文件如何在 /code/sandman/docs/
中导入某些内容?比如说,我想从 sandman.py
导入 config.py
。我该怎么做?
“Python Packaging Authority”有一个示例项目:
https://github.com/pypa/sampleproject
它是一个示例项目,作为 Python 打包用户指南的打包和分发项目教程的辅助工具。
root/src/*
结构的趋势:github.com/pypa/sampleproject/commit/…
尝试使用 python_boilerplate 模板启动项目。它在很大程度上遵循最佳实践(例如 those here),但更适合您发现自己愿意在某个时候将您的项目拆分为多个鸡蛋的情况(相信我,除了最简单的项目之外,您会的。一种常见的情况是您必须使用其他人的库的本地修改版本)。
你把源放在哪里?对于相当大的项目,将源分成几个鸡蛋是有意义的。每个鸡蛋都将作为一个单独的 setuptools-layout 在 PROJECT_ROOT/src/
对于相当大的项目,将源分成几个鸡蛋是有意义的。每个鸡蛋都将作为一个单独的 setuptools-layout 在 PROJECT_ROOT/src/
您将应用程序启动脚本放在哪里?理想的选择是将应用程序启动脚本注册为其中一个鸡蛋中的 entry_point。
理想的选择是将应用程序启动脚本注册为其中一个鸡蛋中的 entry_point。
你把 IDE 项目放在哪里?取决于IDE。他们中的许多人将他们的东西保存在项目根目录的 PROJECT_ROOT/.
取决于IDE。他们中的许多人将他们的东西保存在项目根目录的 PROJECT_ROOT/.
你把单元/验收测试放在哪里?每个 egg 都有一组单独的测试,保存在其 PROJECT_ROOT/src/
每个 egg 都有一组单独的测试,保存在其 PROJECT_ROOT/src/
您将非 Python 数据(例如配置文件)放在哪里?这取决于。可以有不同类型的非 Python 数据。 “资源”,即必须打包在鸡蛋中的数据。该数据进入相应的 egg 目录,位于包命名空间中的某处。它可以通过 setuptools 中的 pkg_resources 包使用,或者从 Python 3.7 开始通过标准库中的 importlib.resources 模块使用。 “配置文件”,即非 Python 文件,它们被视为项目源文件的外部文件,但在应用程序开始运行时必须使用一些值进行初始化。在开发过程中,我更喜欢将这些文件保存在 PROJECT_ROOT/config 中。对于部署,可以有多种选择。在 Windows 上可以使用 %APP_DATA%/
这取决于。可以有不同类型的非 Python 数据。 “资源”,即必须打包在鸡蛋中的数据。该数据进入相应的 egg 目录,位于包命名空间中的某处。它可以通过 setuptools 中的 pkg_resources 包使用,或者从 Python 3.7 开始通过标准库中的 importlib.resources 模块使用。 “配置文件”,即非 Python 文件,它们被视为项目源文件的外部文件,但在应用程序开始运行时必须使用一些值进行初始化。在开发过程中,我更喜欢将这些文件保存在 PROJECT_ROOT/config 中。对于部署,可以有多种选择。在 Windows 上可以使用 %APP_DATA%/
“资源”,即必须打包在鸡蛋中的数据。该数据进入相应的 egg 目录,位于包命名空间中的某处。它可以通过 setuptools 中的 pkg_resources 包使用,或者从 Python 3.7 开始通过标准库中的 importlib.resources 模块使用。
“配置文件”,即非 Python 文件,它们被视为项目源文件的外部文件,但在应用程序开始运行时必须使用一些值进行初始化。在开发过程中,我更喜欢将这些文件保存在 PROJECT_ROOT/config 中。对于部署,可以有多种选择。在 Windows 上可以使用 %APP_DATA%/
生成的文件,即可以由应用程序在执行期间创建或修改的文件。我希望在开发期间将它们保留在 PROJECT_ROOT/var 中,并在 Linux 部署期间将它们保留在 /var 下。
对于 pyd/so 二进制扩展模块,您将非 Python 源代码(例如 C++)放在哪里?进入 PROJECT_ROOT/src/
进入 PROJECT_ROOT/src/
文档通常会进入 PROJECT_ROOT/doc
或 PROJECT_ROOT/src/<egg_name>/doc
(这取决于您是否将某些鸡蛋视为单独的大型项目)。一些附加配置将位于 PROJECT_ROOT/buildout.cfg
和 PROJECT_ROOT/setup.cfg
等文件中。
base_data_location
变量,但你如何适当地设置它?
根据我的经验,这只是一个迭代的问题。将您的数据和代码放在您认为的任何地方。有可能,无论如何你都会错的。但是,一旦您对事情将如何形成有了更好的了解,您就可以更好地进行这些猜测。
至于扩展源,我们在 trunk 下有一个 Code 目录,其中包含一个用于 python 的目录和一个用于各种其他语言的目录。就个人而言,我更倾向于下次尝试将任何扩展代码放入自己的存储库中。
话虽如此,我回到我最初的观点:不要把它搞得太大。把它放在似乎对你有用的地方。如果您发现某些东西不起作用,则可以(并且应该)对其进行更改。
使用 setuptools 中的 package_data
支持最好将非 Python 数据捆绑在 Python 模块中。我强烈推荐的一件事是使用名称空间包来创建多个项目可以使用的共享名称空间——很像将包放在 com.yourcompany.yourproject
中的 Java 约定(并且能够拥有一个共享的 com.yourcompany.utils
名称空间)。
重新分支和合并,如果你使用足够好的源代码控制系统,它甚至可以通过重命名来处理合并; Bazaar 在这方面特别擅长。
与此处的其他一些答案相反,我对拥有 src
顶级目录(旁边有 doc
和 test
目录)表示 +1。文档目录树的特定约定将根据您使用的内容而有所不同;例如,Sphinx 有其快速入门工具支持的自己的约定。
请利用 setuptools 和 pkg_resources;这使得其他项目更容易依赖于您的代码的特定版本(如果您使用 package_data
,则可以使用不同的非代码文件同时安装多个版本)。