在同一进程中使用不同版本的Python库
我们正在开发一个Python库。在开发过程中,我想在测试这个库的新版本时,使用库中的一些部分。也就是说,我想用稳定的代码来测试开发中的代码。请问在Python中有没有办法做到这一点?
编辑:更具体一点,我们有一个库(LibA),里面有很多有用的功能。同时,我们还有一个测试库,它使用LibA来提供一些测试功能(LibT)。我们想用LibT来测试LibA,但因为LibT依赖于LibA,我们希望在测试LibT时使用LibA的稳定版本(因为我们只会在测试通过后,才会修改LibT以适应更新的LibA)。所以,在运行单元测试时,LibA的开发版本会使用依赖于LibA稳定版本的LibT代码。
我们想到的一个主意是通过RPyC在不同的进程中调用稳定代码,但这样实现起来有点复杂(需要确保它能正常关闭等,并且允许在同一台电脑上同时运行多个实例等)。
谢谢
3 个回答
我不太确定你需要怎样设置你的测试,但你可以试试用 VirtualEnv 来让两个实例同时运行。
我们想用LibT来测试LibA,但因为LibT依赖于LibA,所以我们希望在测试LibT时使用一个稳定版本的LibA。
用T和A来测试A是没有意义的。更合理的做法是这样的。
LibA其实是两个部分合在一起的:A1和A2。
T依赖于A1。
实际上,你是在用T和A1来升级和测试A2。
如果你把LibA拆分成T需要的部分和其他部分,或许就能打破这种循环依赖。
如果你用依赖于稳定版libA的libT来“测试”libA-dev,那么你实际上并没有在测试libA-dev在生产环境中的表现。真正测试libA-dev的唯一方法是让libT依赖于libA-dev。如果这导致你的单元测试失败,那其实是件好事——这说明了哪些地方需要修复。
如果你还没有单元测试,那现在就是开始写它们的时候了(先用稳定版的libA和libT!)。
我建议使用“版本控制系统”(比如bzr、hg、svn、git)。这样你可以为你的项目创建“稳定”和“devA”两个分支。
要在devA分支上工作,你首先需要运行
export PYTHONPATH=/path/to/devA
通过确保PYTHONPATH环境变量不包含其他分支,你可以确保Python只使用你想要的模块。
当你准备将代码从dev合并到stable时,版本控制软件也会提供简单的方法来完成这一步。
版本控制还让你更大胆——尝试重大更改不再那么可怕。如果事情没有按计划进行,恢复到之前的状态非常简单。结合这个和PYTHONPATH的小技巧,你总是可以回到已知的、正常工作的代码。
如果你觉得以上方法对你来说行不通,必须使用依赖于libA的libT来测试libA-dev,那么你需要重命名所有模块,并修改所有导入语句,以清晰区分libA-dev和libA。例如,如果libA有一个模块叫moduleA.py,那么就把它重命名为moduleA_dev.py。
命令
rename -n 's/^(.*)\.py/$1_dev.py/' *.py
会在所有的*.py文件名后加上“_dev”。(使用“-n”选项时,重命名命令只会显示你打算重命名的内容。去掉“-n”才能真正执行重命名。)
要恢复重命名,可以运行
rename -n 's/^(.*)_dev\.py/$1.py/' *.py
接下来,你需要在代码中将所有对moduleA的引用改为moduleA_dev。命令
find /path/to/LibA-dev/ -type f -name '*.py' -exec sed -i 's/moduleA/moduleA_dev/g' {} \;
会在LibA-dev中的每个*.py文件里,将“moduleA”改为“moduleA_dev”。
使用这个命令时要小心。这是个危险的操作,因为如果你有一个变量叫moduleAB,它会被重命名为moduleA_devB,而你真正想要的可能是moduleAB_dev。
要恢复这个更改(注意上面的警告),
find /path/to/LibA-dev/ -type f -name '*.py' -exec sed -i 's/moduleA_dev/moduleA/g' {} \;
一旦你分离了命名空间,就打破了循环依赖。当你确认libA-dev没有问题后,可以将moduleA_dev.py改回moduleA.py,并在你的代码中将所有对moduleA_dev的引用改为moduleA。