次重装完系统以后,我都得折腾好长时间,要更新配置文件,要用新版本的软件,要试用新的工具。毕竟这会儿捣鼓东西是最方便的,折腾得无法挽回时大不了再重装呗……

这次将系统升级到Snow Leopard,折腾了良久,终于轮到捣鼓Python环境了。这回要对Python包进行一下管理了。项目多了,难免会有某些包的依赖关系不一致的情 况,如果还和以前那样全部安装到同一个site目录的话,问题还是满大的。最理想的情况是,在系统的site目录里,只装一些基本常用的包,然后各个项目 使用定制的运行环境。这个需求其实挺好实现的,因为我们有Virtualenv!

好像是去年吧,有段时间Django社区中讲述如何使用Virtualenv和fabric部署Django环境的文章大爆发,我也是在那时知道有 Virtualenv这么个好东西,不过由于人懒,也就是试了试,一直没正式用上。这回赶着重装系统,赶紧地好好调教一下,弄个舒适的开发环境:)

Virtualenv的安装很简单,和一般Python包的安装没啥区别。在安装完成以后,使用:

$ virtualenv <env-name>

来建立一个新的运行环境,然后就可以运行:

$ source <env-path>/bin/activate

就可以进入相应的独立环境了,之后就该干嘛干嘛去吧~

Virtualenv使用非常简单,不过本人既然都开始折腾了,为了使用的方便,还是有一些地方需要微调一下的。

首先是ipython的问题,由于ipython的启动脚本默认使用的是调用ipython安装环境的python来执行的,所以各位童鞋可能会发 现在Virtualenv环境下启动ipython后无法调用当前Virtualenv环境安装的软件包。这个问题改起来很简单,要么把ipython的 启动脚本中的第一行改成

#!/usr/bin/env python

或者将ipython定制成别名

alias ipython="python -c 'import IPython; IPython.Shell.IPShell().mainloop()'"

接下来,开始考虑 PYTHONPATH 的问题。默认情况下,Python使用当前目录和系统目录作为包文件的搜索路径,同时提供了 PYTHONPATH 这个变量来自定义额外的搜索路径。咱都用上Virtualenv了,为了方便,何不在进入Virtualenv的时候就直接把需要的目录加进去呢? 其实还是很惊奇Virtualenv默认没有提供这个功能的,不过,这事也简单,改一下启动脚本就可以了

# <env-dir>/bin/activate
deactivate () {
    # ......
    # Mandatory for every virtualenv to switch between envs correctly
    if [[ ${!_OLD_PYTHONPATH[@]} ]]; then
PYTHONPATH="$_OLD_PYTHONPATH"
        export PYTHONPATH
        unset _OLD_PYTHONPATH
    fi
    # ......
}

# Optional
_OLD_PYTHONPATH="$PYTHONPATH"
echo $_OLD_PYTHONPATH
PYTHONPATH="<any-python-path-you-want>:$PYTHONPATH"
export PYTHONPATH

嗯,这下在进入、退出或者切换Virtualenv的时候就会自动切换 PYTHONPATH 了。

最后一项,纯粹是为了方便管理多个virtualenv了——简化virtualenv的启动命令,并启用bash completion。

基本思路是把所有的env部署在同一个目录下:

~/envs
      
      |- env1
      |- env2
      - env3

这样不同的env之间的只需要通过名称进行区别就可以了。获取了环境名作为特征值,就可以定义如下的bash函数了

ve() {
   if [[ $1 == */* ]]; then
     . $1/bin/activate
   else
     . $VENVS/$1/bin/activate
   fi
}

这个函数可以接受env路径或者是特征值,然后调用相应的启动脚本启动相应环境。当然,如果要用特征值,别忘了定义 VENVS 这个环境变量

export VENVS=~/envs

至于为我们刚刚定义的 ve 函数启用bash completion,做起来也是简单,只需要对 VENVS 目录下的子目录作名称匹配就可以了

_ve()
{
    COMPREPLY=()
    if [[ $COMP_CWORD == 1 ]] ; then
COMPREPLY=( $(compgen -d $VENVS/${COMP_WORDS[COMP_CWORD]} | sed "s//.*///") )
        return 0
    fi
}
complete -F _ve ve

把这段代码存成文件,在 .bashrc 中导入一下,然后就可以开始享受bash completion带来的切换环境的爽快感了。:

$ ve [TAB]
proj1 proj2 env1 env2
$ ve p[TAB]
proj1 proj2

好了,基本捣鼓完了,目前用着还是挺满意的。不知各位童鞋觉得怎么样?还有啥建议不?

 

- EOF -