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

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

特别是:

你把源头放在哪里? 应用程序启动脚本放在哪里? 你把IDE项目的cruft放在哪里? 你把单元/验收测试放在哪里? 你把非python数据放在哪里,比如配置文件? 你把非python源代码放在哪里,比如pyd/二进制扩展模块的c++ ?


当前回答

这篇由Jean-Paul Calderone撰写的博客文章通常是Freenode上#python的答案。

Filesystem structure of a Python project Do: name the directory something related to your project. For example, if your project is named "Twisted", name the top-level directory for its source files Twisted. When you do releases, you should include a version number suffix: Twisted-2.5. create a directory Twisted/bin and put your executables there, if you have any. Don't give them a .py extension, even if they are Python source files. Don't put any code in them except an import of and call to a main function defined somewhere else in your projects. (Slight wrinkle: since on Windows, the interpreter is selected by the file extension, your Windows users actually do want the .py extension. So, when you package for Windows, you may want to add it. Unfortunately there's no easy distutils trick that I know of to automate this process. Considering that on POSIX the .py extension is a only a wart, whereas on Windows the lack is an actual bug, if your userbase includes Windows users, you may want to opt to just have the .py extension everywhere.) If your project is expressable as a single Python source file, then put it into the directory and name it something related to your project. For example, Twisted/twisted.py. If you need multiple source files, create a package instead (Twisted/twisted/, with an empty Twisted/twisted/__init__.py) and place your source files in it. For example, Twisted/twisted/internet.py. put your unit tests in a sub-package of your package (note - this means that the single Python source file option above was a trick - you always need at least one other file for your unit tests). For example, Twisted/twisted/test/. Of course, make it a package with Twisted/twisted/test/__init__.py. Place tests in files like Twisted/twisted/test/test_internet.py. add Twisted/README and Twisted/setup.py to explain and install your software, respectively, if you're feeling nice. Don't: put your source in a directory called src or lib. This makes it hard to run without installing. put your tests outside of your Python package. This makes it hard to run the tests against an installed version. create a package that only has a __init__.py and then put all your code into __init__.py. Just make a module instead of a package, it's simpler. try to come up with magical hacks to make Python able to import your module or package without having the user add the directory containing it to their import path (either via PYTHONPATH or some other mechanism). You will not correctly handle all cases and users will get angry at you when your software doesn't work in their environment.

其他回答

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

Where do you put the source? For decently large projects it makes sense to split the source into several eggs. Each egg would go as a separate setuptools-layout under PROJECT_ROOT/src/<egg_name>. Where do you put application startup scripts? The ideal option is to have application startup script registered as an entry_point in one of the eggs. Where do you put the IDE project cruft? Depends on the IDE. Many of them keep their stuff in PROJECT_ROOT/.<something> in the root of the project, and this is fine. Where do you put the unit/acceptance tests? Each egg has a separate set of tests, kept in its PROJECT_ROOT/src/<egg_name>/tests directory. I personally prefer to use py.test to run them. Where do you put non-Python data such as config files? It depends. There can be different types of non-Python data. "Resources", i.e. data that must be packaged within an egg. This data goes into the corresponding egg directory, somewhere within package namespace. It can be used via the pkg_resources package from setuptools, or since Python 3.7 via the importlib.resources module from the standard library. "Config-files", i.e. non-Python files that are to be regarded as external to the project source files, but have to be initialized with some values when application starts running. During development I prefer to keep such files in PROJECT_ROOT/config. For deployment there can be various options. On Windows one can use %APP_DATA%/<app-name>/config, on Linux, /etc/<app-name> or /opt/<app-name>/config. Generated files, i.e. files that may be created or modified by the application during execution. I would prefer to keep them in PROJECT_ROOT/var during development, and under /var during Linux deployment. Where do you put non-Python sources such as C++ for pyd/so binary extension modules? Into PROJECT_ROOT/src/<egg_name>/native

文档通常会进入PROJECT_ROOT/doc或PROJECT_ROOT/src/<egg_name>/doc(这取决于您是否将某些eggs视为单独的大型项目)。一些额外的配置将在PROJECT_ROOT/build - out.cfg和PROJECT_ROOT/setup.cfg这样的文件中。

这篇由Jean-Paul Calderone撰写的博客文章通常是Freenode上#python的答案。

Filesystem structure of a Python project Do: name the directory something related to your project. For example, if your project is named "Twisted", name the top-level directory for its source files Twisted. When you do releases, you should include a version number suffix: Twisted-2.5. create a directory Twisted/bin and put your executables there, if you have any. Don't give them a .py extension, even if they are Python source files. Don't put any code in them except an import of and call to a main function defined somewhere else in your projects. (Slight wrinkle: since on Windows, the interpreter is selected by the file extension, your Windows users actually do want the .py extension. So, when you package for Windows, you may want to add it. Unfortunately there's no easy distutils trick that I know of to automate this process. Considering that on POSIX the .py extension is a only a wart, whereas on Windows the lack is an actual bug, if your userbase includes Windows users, you may want to opt to just have the .py extension everywhere.) If your project is expressable as a single Python source file, then put it into the directory and name it something related to your project. For example, Twisted/twisted.py. If you need multiple source files, create a package instead (Twisted/twisted/, with an empty Twisted/twisted/__init__.py) and place your source files in it. For example, Twisted/twisted/internet.py. put your unit tests in a sub-package of your package (note - this means that the single Python source file option above was a trick - you always need at least one other file for your unit tests). For example, Twisted/twisted/test/. Of course, make it a package with Twisted/twisted/test/__init__.py. Place tests in files like Twisted/twisted/test/test_internet.py. add Twisted/README and Twisted/setup.py to explain and install your software, respectively, if you're feeling nice. Don't: put your source in a directory called src or lib. This makes it hard to run without installing. put your tests outside of your Python package. This makes it hard to run the tests against an installed version. create a package that only has a __init__.py and then put all your code into __init__.py. Just make a module instead of a package, it's simpler. try to come up with magical hacks to make Python able to import your module or package without having the user add the directory containing it to their import path (either via PYTHONPATH or some other mechanism). You will not correctly handle all cases and users will get angry at you when your software doesn't work in their environment.

根据我的经验,这只是一个迭代的问题。把你的数据和代码放在你认为它们应该去的地方。不管怎样,你都有可能是错的。但一旦你对事情会如何发展有了更好的了解,你就能更好地做出这些猜测。

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

说了这么多,我回到我最初的观点:不要把它看得太大。把它放在对你有用的地方。如果你发现某些东西不起作用,它可以(也应该)被改变。

“Python打包权威”有一个样本项目:

https://github.com/pypa/sampleproject

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

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

再分支和合并,如果你使用一个足够好的源代码控制系统,它甚至可以通过重命名来处理合并;芭莎在这方面尤其在行。

与这里的其他一些答案相反,我赞成将src目录作为顶级目录(附带doc和test目录)。文档目录树的特定约定将根据您使用的内容而有所不同;例如,Sphinx有自己的快速入门工具支持的约定。

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