Python应用程序的最佳项目结构是什么?

假设您想用Python开发一个重要的最终用户桌面(而不是Web)应用程序。构建项目文件夹层次结构的最佳方法是什么?

理想的特性是易于维护、IDE友好、适合源代码控制分支/合并以及易于生成安装包。

特别是:

  1. 你把源头放在哪里?
  2. 你把应用程序启动脚本放在哪里?
  3. 你把IDE项目的垃圾放在哪里?
  4. 你把单元/验收测试放在哪里?
  5. 您将配置文件等非Python数据放在哪里?
  6. 在哪里放置非Python源,例如pyd/so二进制扩展模块的C++?
602526 次浏览

没什么大不了的。任何让你高兴的事情都会奏效。没有很多愚蠢的规则,因为Python项目可以很简单。

  • /scripts/bin对于那种命令行界面的东西
  • /tests为您的测试
  • /lib为您的C语言库
  • /doc留档
  • /apidoc用于Epydoc生成的API文档。

顶级目录可以包含README、Config等。

困难的选择是是否使用/src树。Python不像Java或C那样区分/src/lib/bin

由于顶层/src目录被某些人视为毫无意义,因此您的顶层目录可以成为您的应用程序的顶层架构。

  • /foo
  • /bar
  • /baz

我建议将所有这些都放在“name-of-my-Products”目录下。因此,如果您正在编写名为quux的应用程序,则包含所有这些内容的目录名为/quux

然后,另一个项目的PYTHONPATH可以包含/path/to/quux/foo以重用QUUX.foo模块。

在我的情况下,由于我使用Komodo Edit,我的IDE cuft是一个单一的。KPF文件。我实际上把它放在顶级/quux目录中,并省略了将其添加到SVN。

非python数据最好使用setup工具中的package_data支持捆绑在Python模块中。我强烈推荐的一件事是使用命名空间包来创建多个项目可以使用的共享命名空间-就像将包放在com.yourcompany.yourproject中的Java约定(并且能够拥有共享的com.yourcompany.utils命名空间)。

重新分支和合并,如果您使用足够好的源代码控制系统,它甚至可以通过重命名来处理合并;芭莎特别擅长这一点。

与这里的其他一些答案相反,我对拥有src目录顶层(旁边有doctest目录)感到高兴。留档目录树的特定约定将因您使用的内容而异;例如,狮身人面像有其快速入门工具支持的自己的约定。

请利用setupols和pkg_resources;这使得其他项目更容易依赖您的代码的特定版本(如果您使用的是package_data,则可以同时安装多个版本的不同非代码文件)。

根据我的经验,这只是一个迭代的问题。把你的数据和代码放在你认为它们去的任何地方。无论如何,你都有可能错了。但是一旦你对事情将如何发展有了更好的了解,你就可以更好地做出这种猜测。

至于扩展源,我们在主干下有一个Code目录,其中包含一个python目录和一个其他各种语言的目录。就个人而言,我更倾向于下次尝试将任何扩展代码放入自己的存储库中。

话虽如此,我还是回到我最初的观点:不要小题大做。把它放在一个似乎对你有用的地方。如果你发现一些不起作用的东西,它可以(也应该)被改变。

这个作者:Jean-Paul Calderone通常作为Freenode上的#python中的答案给出。

Python项目的文件系统结构

做:

  • 将目录命名为与您的项目相关的内容。例如,如果您的项目名为“Twisted”,请将其源文件的顶级目录命名为Twisted。当您发布版本时,您应该包含版本号后缀:Twisted-2.5
  • 创建一个目录Twisted/bin并将您的可执行文件放在那里,如果您有的话。不要给它们.py扩展名,即使它们是Python源文件。除了导入和调用项目中其他地方定义的main函数外,不要在其中放置任何代码。(轻微皱纹:由于在Windows上,解释器是由文件扩展名选择的,因此您的Windows用户实际上需要. py扩展名。所以,当您为Windows打包时,您可能想要添加它。不幸的是,据我所知,没有简单的distutils技巧来自动化此过程。考虑到在POSIX上. py扩展名只是一个疣,而在Windows上缺乏是一个实际的bug,如果您的用户群包括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/READMETwisted/setup.py来解释和安装您的软件。

不要:

  • 将您的源代码放在名为srclib的目录中。这使得不安装就很难运行。
  • 将测试放在Python包之外。这使得很难针对已安装的版本运行测试。
  • 创建一个包只有有一个__init__.py,然后将所有代码放入__init__.py。只需制作一个模块而不是包,它更简单。
  • 尝试想出神奇的黑客方法,使Python能够导入您的模块或包,而无需用户将包含它的目录添加到他们的导入路径(通过PYTHONPATH或其他机制)。您将没有正确处理所有情况,当您的软件在他们的环境中不起作用时,用户会对您生气。

根据Jean-Paul Calderone的Python项目的文件系统结构

Project/|-- bin/|   |-- project||-- project/|   |-- test/|   |   |-- __init__.py|   |   |-- test_main.py|   ||   |-- __init__.py|   |-- main.py||-- setup.py|-- README

检查以正确的方式开源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下的test目录。

尝试使用python_boilerplate模板启动项目。它在很大程度上遵循了最佳实践(例如这里的人),但更适合你发现自己愿意在某个时候将项目拆分为多个鸡蛋的情况(相信我,除了最简单的项目,你会的。一种常见的情况是,你必须使用他人库的本地修改版本)。

  • 你把源头放在哪里?

    • 对于相当大的项目,将源代码拆分为几个鸡蛋是有意义的。每个鸡蛋将作为PROJECT_ROOT/src/<egg_name>下的单独setup工具布局。
  • 你把应用程序启动脚本放在哪里?

    • 理想的选择是让应用程序启动脚本在其中一个鸡蛋中注册为entry_point
  • 你把IDE项目的垃圾放在哪里?

    • 取决于IDE。他们中的许多人将他们的东西保存在项目根目录的PROJECT_ROOT/.<something>中,这很好。
  • 你把单元/验收测试放在哪里?

    • 每个鸡蛋都有一组单独的测试,保存在其PROJECT_ROOT/src/<egg_name>/tests目录中。我个人更喜欢使用py.test来运行它们。
  • 您将配置文件等非Python数据放在哪里?

    • 这取决于。可以有不同类型的非Python数据。
      • "资源",即必须打包在蛋中的数据。该数据进入相应的蛋目录,在包命名空间的某个地方。它可以通过setuptoolspkg_resources包使用,也可以从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中,在部署期间将它们保存在/varLinux。
  • 你在哪里放置非Python源,例如pyd/so二进制扩展模块的C++?
    • 进入PROJECT_ROOT/src/<egg_name>/native

文档通常会进入PROJECT_ROOT/docPROJECT_ROOT/src/<egg_name>/doc(这取决于您是否将一些鸡蛋视为单独的大型项目)。一些额外的配置将在PROJECT_ROOT/buildout.cfgPROJECT_ROOT/setup.cfg等文件中。

“Python打包机构”有一个示例项目:

https://github.com/pypa/sampleproject

它是一个示例项目,作为Python打包用户指南的打包和分发项目教程的辅助工具而存在。