Python代码组织问题:Eggs + 包 + Buildout + 单元测试 + SVN

8 投票
4 回答
2450 浏览
提问于 2025-04-11 09:26

我有几个Python项目,它们都用到了相同的模块。到现在为止,我一直在...嗯...手动维护这些公共代码的多个副本,真是麻烦。不过,我显然希望能有更好的办法。

现在看来,zc.Buildout可能正是我需要的。我想我应该把系统中每个可重用的部分放到一个单独的“蛋”(egg)里,然后用buildout把它们组合成项目。

我还在想,对于某个特定的模块,我应该把单元测试放到一个单独的包或蛋里,这样我就不需要在每个项目中都安装这个模块的单元测试。我只想在开发库的地方进行单元测试,而不是在仅仅使用它的地方。

所以我可能想要这样的结构:

projects
  lib1
    tests
    code
  lib2
    tests
    code
  app1
    tests 
    appcode
  app2
    tests
    appcode

等等。

在这个结构中,app1和app2是独立的应用程序,各自有自己的代码和测试,但它们也会包含和使用lib1和lib2。而lib1/test、lib1/code、lib2/test、lib2/code、app1和app2都是独立的蛋。这样说对吗?

不过,我现在有点困惑。我假设当我开发app1时,我希望buildout把lib1、lib2和app1的副本拉到一个单独的工作目录,而不是直接把这些库放在app1下面。但这和我的SVN源代码管理是怎么结合起来的呢?如果工作目录是用buildout动态构建的,那它就不能是一个可以实时更新的SVN目录,我也不能把更改提交回去吗?

我是不是误解了buildout的使用方式?我是不是应该考虑完全不同的方法?在项目之间如何混合源代码管理和模块重用呢?

更新:感谢目前回答这个问题的两位朋友。我正在进一步实验这个。

4 个回答

2

这就是为什么你需要用到 site 模块的原因。它会设置内部的 sys.path,让所有的包和模块都能被找到,具体包括:

  • lib/site-packages -- 这里面包括了文件夹、egg 文件和 .pth 文件。
  • PYTHONPATH

这样的话,你的库就只有一个有效的副本。

利用这个方法有很多种方式。这里介绍两种。

  1. 在每个库里写一个 setup.py 文件,确保你的库能够正确部署。当你做了修改后,运行 svn up 来获取最新的更改,然后用 python setup.py install 来部署每个应用共享的那个有效副本。

  2. 在每个应用中,可以依赖于 PYTHONPATH 环境变量中的内容。确保 projects/lib1projects/lib2 都在 PYTHONPATH 里。这样每个应用就可以共享这些库的一个有效副本。

2

我在SVN中使用了以下结构,效果很好。

Lib1/
   branches/
   tags/
   trunk/
     lib1/
     tests/
     setup.py
Lib2
   branches/
   tags/
   trunk/
     lib2/
     tests/
     setup.py
App1
   branches/
   tags/
   trunk/
     app1/
     tests/
     setup.py
App2
   branches/
   tags/
   trunk/
     app2/
     tests/
     setup.py

接下来,我会创建我的开发工作区(我用的是eclipse/pydev),可以从主干或某个分支上检出代码。

Lib1/
   lib1/
   tests/
   setup.py
Lib2/
   lib2/
   tests/
   setup.py
App1/
   app1/
   tests/
   setup.py
App2/
   app2/
   tests/
   setup.py

然后,我会使用eclipse的项目依赖设置来配置Python路径,这样可以很好地支持eclipse的代码补全功能。虽然setup.py也能用,但对多个工作区的支持不太好。

在部署时,我会创建一个包含以下结构的压缩包。

App1/
   lib1-1.1.0-py2.5.egg/
   lib2-1.1.0-py2.5.egg/
   app1/
   sitecustomize.py

App2/
   lib1-1.2.0-py2.5.egg/
   lib2-1.2.0-py2.5.egg/
   app2/
   sitecustomize.py

我不使用setup install,因为我想支持多个版本的应用程序。此外,我对运行环境有一些控制,所以在部署时不把Python打包进去,但如果需要的话,添加Python到部署包里应该很简单。

5

不要把测试和你的代码分开,最好把它们放在一起。测试占用的磁盘空间和内存其实并不多!而且,测试对使用你库的用户来说非常有帮助。

对于库包,最好在你的包里包含一个 buildout.cfg 文件和一个 bootstrap.py 文件,这样可以方便地运行测试。比如,你可以看看 plone.reload 包,它是如何使用 zc.recipe.testrunner 的部分来创建一个自动发现并运行测试的脚本。这样,你就能确保你的库包始终经过测试!

然后,你的应用包只需要测试集成和特定于应用的代码。同样,测试也要和包放在一起,这样在写代码时就不会忘记测试。可以在你的 buildout 中使用 zc.recipe.testrunner 的部分来发现和运行这些测试。

最后,使用 mr.developer 来管理你的包。通过 mr.developer,你可以在开发时检出包,或者如果不需要修改代码,可以依赖发布的版本。大项目通常会有很多依赖,其中很多不需要你去修改代码。使用 mr.developer,你可以随意拉取源代码,并将其转化为开发版本,直到你发布了这些代码,然后可以不再需要检出了。

想看看这样的项目构建实例,可以参考 Plone 核心开发构建

sources.cfg 文件里列出了各种包的很多 SCM 位置,但通常使用的是发布版本的包,直到你明确激活你打算工作的包。checkouts.cfg 列出了默认检出的所有包;这些包有一些改动,将会成为 Plone 下一个版本的一部分,但还没有发布。如果你在做 Plone 的工作,这些包是很重要的,因为你不能忽视这些改动。而 testing.cfg 列出了如果你想测试 Plone 需要的所有包,数量可不少。

需要注意的是,Plone 的源代码来自很多不同的地方。一旦你开始使用 buildout 和 mr.developer 来管理你的包,你就可以自由地从任何地方拉取源代码。

撰写回答