2019独角兽企业重金招聘Python工程师标准>>>
环境
为了正确地跑起来,你的应用需要依赖许多不同的软件。 就算是再怎么否认这一点的人,也无法否认至少需要依赖Flask本身。 你的应用的运行环境,在当你想要让它跑起来时,是至关重要的。 幸运的是,我们有许多工具可以减低管理环境的复杂度。
使用virtualenv来管理环境
virtualenv是一个能把你的应用隔离在一个虚拟环境中的工具。 一个虚拟环境是一个包含了你的应用依赖的软件的文件夹。一个虚拟环境同时也封存了你在开发时的环境变量。 与其把依赖包,比如Flask,下载到你的系统包管理文件夹,或用户包管理文件夹,我们可以把它下载到对应当前应用的一个隔离的文件夹之下。 这使得你可以指定一个特定的Python二进制版本,取决于当前开发的项目。
virtualenv也可以让你给不同的项目指定同样的依赖包的不同版本。 当你在一个老旧的包含众多不同项目的平台上开发时,这种灵活性十分重要。
用了virtualenv,你将只会把少数几个Python模块安装到系统的全局空间中。其中一个会是virtualenv本身:
# 使用pip安装virtualenv
$ pip install virtualenv
安装完virtualenv,就可以开始创建虚拟环境。切换到你的项目文件夹,运行virtualenv
命令。这个命令接受一个参数,作为虚拟环境的名字(同样也是它的位置,在当前文件夹ls
下你就知道了)。
$ virtualenv venv
New python executable in venv/bin/python
Installing setuptools, pip...done.
这将创建一个包含所有依赖的文件夹。
一旦新的virtual environment已经准备就绪,你需要给对应的virtual environment下的bin/activate
脚本执行source
,来激活它。
$ source venv/bin/activate
你可以通过运行which python
看到:“python”现在指向的是virtual environment中的二进制版本。
$ which python
/usr/local/bin/python
$ source venv/bin/activate
(venv)$ which python
/Users/robert/Code/myapp/venv/bin/python
当一个virtual environment被激活了,依赖包会被pip安装到virtual environment中而不是全局系统环境。
你也许注意到了,你的shell提示符发生了改变。 virtualenv在它前面添加了当前被激活的virtual environment,所以你能意识到你并不存在于全局系统环境中。
运行deactivate
命令,你就能离开你的virtual environment。
(venv)$ deactivate
$
使用virtualenvwrapper管理你的virtual environment
我想要让你了解到virtualenvwrapper对于前面的工作做了什么改进,这样你就知道为什么你应该使用它。
虚拟环境文件夹现在已经位于你的项目文件夹之下。 但是你仅仅是在激活了虚拟环境后才会跟它交互。它甚至不应该被放入版本控制中。所以它呆在项目文件夹中也是挺碍眼的。 解决这个问题的一个方法就是使用virtualenvwrapper。这个包把你所有的virtual environment整理到单独的文件夹下,通常是~/.virtualenvs/
。
要安装virtualenvwrapper,遵循这个文档中的步骤。
注意 确保你在安装virtualenvwrapper时不在任何一个virtual environment中。你需要把它安装在全局空间,而不是一个已存在的virtual environment中
现在,你不再需要运行virtualenv
来创建一个环境,只需运行mkvirtualenv
:
$ mkvirtualenv rocket
New python executable in rocket/bin/python
Installing setuptools, pip...done.
在你的virtual environment目录之下,比如在~/.virtualenv
之下,mkvirtualenv
创建了一个文件夹,并替你激活了它。 就像普通的virtualenv
,python
和pip
现在指向的是virtual environment而不是全局系统。 为了激活想要的环境,运行这个命令:workon [environment name]
,而deactivate
依然会关闭环境。
记录依赖变动
随着项目增长,你会发现它的依赖列表也一并随着增长。在你能运行一个Flask应用之前,即使已经需要数以十记的依赖包也毫不奇怪。 管理依赖的最简单的方法就是使用一个简单的文本文件。 pip可以生成一个文本文件,列出所有已经安装的包。它也可以解析这个文件,并在新的系统(或者新的环境)下安装每一个包。
pip freeze
requirements.txt是一个常常被许多Flask应用用于列出它所依赖的包的文本文件。它是通过pip freeze > requirements.txt
生成的。 使用pip install -r requirements.txt
,你就能安装所有的包。
注意 在freeze或install依赖包时,确保你正为于正确的virtual environment之中。
手动记录依赖变动
随着项目增长,你可能会发现pip freeze
中列出的每一个包并不再是运行应用所必须的了。 也许有些包只是在开发时用得上。pip freeze
没有判断力;它只是列出了当前安装的所有的包。所以你只能手动记录依赖的变动了。 你可以把运行应用所需的包和开发应用所需的包分别放入对应的require_run.txt和require_dev.txt。
版本控制
选择一个版本控制系统并使用它。 我推荐Git。如我所知,Git是当下最大众的版本控制系统。 在删除代码的时候无需担忧潜在的巨大灾难是无价的。 你现在可以对过去那种把不要的代码注释掉的行为说拜拜了,因为你可以直接删掉它们,即使将来突然需要,也可以通过git revert
来恢复。 另外,你将会有整个项目的备份,存在Github,Bitbucket或你自己的Git server。
什么不应该在版本控制里
我通常不把一个文件放在版本控制里,如果它满足以下两个原因中的一个。
- 它是不必要的
- 它是不公开的。
编译的产物,比如.pyc
,和virtual environment(如果你因为某些原因没有使用virtualenvwrapper)正是前者的例子。 它们不需要加入到版本控制中,因为它们可以通过.py
或requirements.txt
生成出来。
接口密钥(调用接口时必须传入的参数),应用密钥,以及数据库证书则是后者的例子。 它们不应该在版本控制中,因为一旦泄密,将造成严重的安全隐患。
注意 在做安全相关的决定时,我会假设稳定版本库将会在一定程度上被公开。这意味着要清除所有的隐私,并且永不假设一个安全漏洞不会被发现, 因为“谁能想到他们会干出什么事情?”
在使用Git时,你可以在版本库中创建一个特别的文件名为.gitignore。 在里面,能使用正则表达式来列出对应的文件。任何匹配的文件将被Git所忽略。 我建议你至少在其中加入*.pyc
和/instance
。instance文件夹中存放着跟你的应用相关的不便公开的配置。
.gitignore:
*.pyc
instance/
参见
- 在这里你可以了解什么是.gitignore : http://git-scm.com/docs/gitignore
- Flask文档中对instance目录的一段介绍 : http://flask.pocoo.org/docs/config/#instance-folders
调试
调试模式
Flask有一个便利的特性叫做“debug mode”。在你的应用配置中设置debug = True
就能启动它。 当它被启动后,服务器会在代码变动之后重新加载,并且一旦发生错误,错误会打印成一个带交互式命令行的调用栈。
注意 不要在生产环境中开启debug mode。交互式命令行运行任意的代码输入,如果是在运行中的网站上,这将导致安全上的灾难性后果。
另见
- 阅读一下quickstart页面的debug mode部分 : http://docs.jinkan.org/docs/flask/quickstart.html#debug-mode
- 这里有一些关于错误处理,日志记录和使用其他调试工具的信息 : http://docs.jinkan.org/docs/flask/errorhandling.html
Flask-DebugToolbar
Flask-DebugToolbar 是用来调试你的应用的另一个得力工具。在debug mode中,它在你的应用中添加了一个侧边条。 这个侧边条会给你提供有关SQL查询,日志,版本,模板,配置和其他有趣的信息。
总结
- 使用virtualenv来打包你的应用的依赖包。
- 使用virtualenvwrapper来打包你的virtual environment。
- 使用一个或多个文本文件来记录依赖变化。
- 使用一个版本控制系统。我推荐Git。
- 使用.gitignore来排除不必要的或不能公开的东西混进版本控制。
- debug mode会在开发时给你有关bug的信息。
- Flaks-DebugToolbar拓展将给你有关bug更多的信息。
原文:http://colesmith.space/2015/05/19/revise-virtualenv-and-virtualenvwrapper.html
官方文档
- virtualenv
- virtualenvwrapper
一 virtualenv
What
:- virtualenv 是一个隔离Python环境的工具.
Why
:- virtualenv 可以让你在同一个操作系统上建立多个不同的Python环境.
- 如一个Python2, 另一个Python3, 还有Django1.2 和 Django1.5
- 项目Python环境互不相同,互不干涉.
How
: (So Easy)Install
:- sudo pip install virtualenv
Use
: (Recommend)创建环境
:virtualenv -p PYTHON_VERSION VIRTUAL_ENVIRONMENT_NAME
- 解释:
- -p PYTHON_EXE, –python=PYTHON_EXE : 指定Python版本, Python2, Python2.5, Python3等
- 注意: 这个Python版本必须存在于系统内部
- –no-site-packages : 废弃了,因为默认没有权限访问全局包
- 栗子:
virtualenv -p python3 django1.8
进入环境
:- source path/to/VIRTUAL_ENVIRONMENT_NAME/bin/activate
- 栗子:
- source django1.8/bin/activate
- 或者 cd django1.8; source bin/activate
有明显标志(VIRTUAL_ENVIRONMENT_NAME),说明成功进入环境
退出环境
:- deactivate
删除环境
:- 只要删除创建的虚拟环境目录即可: rm -rf path/to/VIRTUAL_ENVIRONMENT_NAME
- rm -rf django1.8
- 只要删除创建的虚拟环境目录即可: rm -rf path/to/VIRTUAL_ENVIRONMENT_NAME
二 virtualenvwrapper
what
:- virtualenvwrapper 是 virtaulenv 的扩展的集合.
Why
:- 便于使用和管理 virtualenv
How
:Install
:- sudo pip install virtualenvwrapper
Use
:每次使用前必须先source环境
: 才有mkvirtualev, lssitepackages等命令source /usr/local/bin/virtualenvwrapper.sh
或者将/etc/profile 或者 ~/.bashrc 或者 ~/.zshrc
启动终端时自动载入source
创建环境
:- Syntax:
mkvirtualenv [-a project_path] [-i package] [-r requirements_file] [virtualenv options] VIRTUAL_ENVIRONMENT_NAME
注意: 项目默认创建一律在 ~/.virtualenvs 目录下
- 栗子:
- 默认:
- mkvirtualenv django1.8 # (ls ~/.virtualenvs 可见)
- 指定Python版本:
- mkvirtualenv -p python3 django1.8
- 指定Python版本和依赖的包:
- mkvirtualenv -r requirements.txt -p python3 django1.8
- 指定项目地址, 只要载入环境,自动切换到项目目录:
- mkvirtualenv -a . django1.8
注意: 环境创建完成后,会自动载入环境
- Syntax:
打开或切换工作环境
:- Syntax:
workon [(-c|--cd)|(-n|--no-cd)] [environment_name|"."]
- 栗子:
- 默认:
- workon django1.8
注意: 默认进入 mkvirtualenv 选项 -a 指定的目录,如果没有,则在当前目录
- 切换, 即已经在一个虚拟环境, 但要切换另一个环境:
- workon django1.5
- 不进入 -a 指定的目录:
- workon -n django1.8
- Syntax:
退出环境,使用系统环境
:- deactivate
删除环境
:- rmvirtualenv VIRTUAL_ENVIRONMENT_NAME
- 或 rm -rf ~/.virtualenvs/VIRTUAL_ENVIRONMENT_NAME
- 栗子:
- rmvirtualenv django1.8 (推荐)
- rm -rf ~/.virtualenvs/django1.8
让所有创建的环境都执行某个命令,比如安装某个包等
:- Syntax:
allvirtualenv command with arguments
- 栗子:
- allvirtualenv pip install ipython
- Syntax:
切换当前环境能否访问系统的Python包, 建议关闭(disable)
:- Syntax:
toggleglobalsitepackages [-p]
- -p : 不输出日志
- 栗子:
- toggleglobalsitepackages
- Syntax:
删除第三方包
: (注意: 必须已经在虚拟环境中)- Syntax:
wipeenv
- Syntax:
创建项目+环境
:- Create a new virtualenv in the WORKON_HOME and project directory in PROJECT_HOME.
- Syntax:
mkproject [-f|--force] [-t template] [virtualenv_options] ENVNAME
注意设置 WORKON_HOME 和 PROJECT_HOME
- 其他命令:
- 显示安装的包: lssitepackages (建议用 pip list 更清楚)
- 复制一份虚拟环境: cpvirtualenv [sorce] [dest]
- cp django1.8 django
- 临时环境,deactivate后删除:
-
mktmpenv [(-c –cd) (-n –no-cd)] [VIRTUALENV_OPTIONS] - 栗子: mktmpenv -p python3
-
- 列出所有创建的虚拟环境: 即~/.virtualenvs目录下的
-
lsvirtualenv [-b -l -h] - -b 简短形式, 建议
- -l 默认的详细信息输出
- -h help
-
绑定项目目录
:- Syntax:
setvirtualenvproject [virtualenv_path project_path]
- Syntax:
原文:http://virtualenv-chinese-docs.readthedocs.io/en/latest/#id3
Contents
- virtualenv
- 安装
- 用处
- 命令
- 环境变量和配置文件
- Windows下注意事项
- PyPy支持
- 创建自己的启动脚本
- 启动脚本范例
- 激活脚本
--system-site-packages
参数- 不使用Virtualenv下的
bin/python
- 重定位隔离环境
--extra-search-dir
参数
- 与可替代品的比较
- 贡献力量
- 运行测试
- 相关文档和链接
- 现状和许可
- Wrongway的补充:常用见法
- 1.创建隔离环境并安装最新的django
- 2.创建隔离环境并安装django1.3以及一系列开发用组件
- 3.创建Python2.7隔离环境并安装tornado
- Wrongway的补充:中译版致谢
- Changes & News
安装
运行 pip install virtualenv
即可安装virtualenv,想用 最新开发版就运行 pip installvirtualenv==dev
。
还可以用 easy_install
安装,即使是没有安装任何Python包管理器,也可以直接获取 virtualenv.py并运行 python virtualenv.py
,效果一样。
用处
virtualenv
用来创建隔离的Python环境。
处理python环境的多版本和模块依赖,以及相应的权限是一个很常见的问题。比如,你有个应用使用的是LibFoo V1.0,但另一个应用却要用到LibFoo V2.0。如何处理呢?如果把所有模块都安装到/usr/lib/python2.7/site-packages
(或是你本机python默认的模块安装目录),那你极有可能无意中升级一些不该升级的模块。
更普遍的是,就算你成功安装了某个应用,那么接下来又会怎样?只要它开始运行了,那么只要其所依赖的模块发生任何改动,亦或升级,都可能打断该应用。
这还没完,要是你无法在 site-packages
目录下安装模块呢?比如共享主机。
上述这几种场合都适用 virtualenv
。它会创建一个拥有独立安装目录的python环境,该隔离环境不会与其他virtualenv环境共享模块(可选择是否访问全局库目录)。
一般用法是:
$ python virtualenv.py ENV
在已安装virtualenv的情况下,可以直接运行 virtualenv ENV
。
该操作会创建 ENV/lib/pythonX.X/site-packages
目录 和 ENV/bin/python
,前者用来存放要安装的模块,后者就是隔离环境的Python解释器。在virtualenv环境下使用此解释器(包括以#!/path/to/ENV/bin/python
开头的脚本)时,使用的都是隔离环境下的模块。
该操作还在隔离环境下安装了 Setuptools 或 distribute 。要用Distribue取代setuptools的话,只要运行:
$ python virtualenv.py --distribute ENV
设置环境变量 VIRTUALENV_USE_DISTRIBUTE 也能达到同样目的。
新的virtualenv还包含了 pip 包管理器,可以直接用 ENV/bin/pip
安装第三方模块。
命令
用法:
$ virtualenv [OPTIONS] DEST_DIR
选项:
--version
显示当前版本号。
-h, --help
显示帮助信息。
-v, --verbose
显示详细信息。
-q, --quiet
不显示详细信息。
-p PYTHON_EXE, --python=PYTHON_EXE
指定所用的python解析器的版本,比如
--python=python2.5
就使用2.5版本的解析器创建新的隔离环境。默认使用的是当前系统安装(/usr/bin/python)的python解析器
--clear
清空非root用户的安装,并重头开始创建隔离环境。
--no-site-packages
令隔离环境不能访问系统全局的site-packages目录。
--system-site-packages
令隔离环境可以访问系统全局的site-packages目录。
--unzip-setuptools
安装时解压Setuptools或Distribute
--relocatable
重定位某个已存在的隔离环境。使用该选项将修正脚本并令所有.pth文件使用相当路径。
--distribute
使用Distribute代替Setuptools,也可设置环境变量VIRTUALENV_DISTRIBUTE达到同样效要。
--extra-search-dir=SEARCH_DIRS
用于查找setuptools/distribute/pip发布包的目录。可以添加任意数量的–extra-search-dir路径。
--never-download
禁止从网上下载任何数据。此时,如果在本地搜索发布包失败,virtualenv就会报错。
--prompt==PROMPT
定义隔离环境的命令行前缀。
环境变量和配置文件
virtualenv既可以通过命令行配置,比如 --distribute
,也可以用下面两种方式配置:
-
环境变量
命令行的每个参数都以
VIRTUALENV_
的格式对应一个环境变量。转换变量名过程中,除了将命令行参数大写外,还要把 ('-'
) 替换为 ('_'
) 。举个例子,要自动安装Distribute取代默认的setuptools,可以这样设置环境变量:
$ export VIRTUALENV_USE_DISTRIBUTE=true $ python virtualenv.py ENV
等同于在命令行直接使用参数:
$ python virtualenv.py --distribute ENV
有时要重复输入多个命令行参数,比如
--extra-search-dir
。变成环境变量时,要用空格隔开多个参数值,例如:$ export VIRTUALENV_EXTRA_SEARCH_DIR="/path/to/dists /path/to/other/dists" $ virtualenv ENV
等同于:
$ python virtualenv.py --extra-search-dir=/path/to/dists --extra-search-dir=/path/to/other/dists ENV
-
配置文件
virtualenv还能通过标准ini文件进行配置。在Unix和Mac OS X中是
$HOME/.virtualenv/virtualenv.ini
,在Windows下是%HOME%\\virtualenv\\virtualenv.ini
。配置项名称就是命令行参数的名称。例如,参数
--distribute
在ini文件如下:[virtualenv] distribute = true
象
--extra-search-dir
这样的多值命令行参数,在ini文件中要用断行将多个值隔开:[virtualenv] extra-search-dir = /path/to/dists /path/to/other/dists
virtualenv --help
可以查看完整的参数列表。
Windows下注意事项
在Windows下路径会与*nix下略有不同:脚本和可执行文件在Windows下位于 ENV\Scripts\
下,而非ENV/bin/
,模块也会安装在 ENV\Lib\
下,而非 ENV/lib/
。
要在某个含有空格的目录下面创建virtualenv环境,就要安装 win32api 。
PyPy支持
从1.5版开始,virtualenv开始支持 PyPy 。>=1.5版的virtualenv支持PyPy1.4和1.4.1,>=1.6.1版的virtualenv支持PyPy1,5。
创建自己的启动脚本
Wrongway提示:该段一般情况下初学者用不到,所以刚接触virtualenv的朋友不要在此节投放过多精力。Virtualenv的文档讲解顺序是有点问题。
创建隔离环境时,virtualenv不会执行额外操作。但开发者有时会想在安装隔离环境后运行某个脚本。例如用脚本安装某个web应用。
要创建上述脚本,需要调用virtualenv.create_bootstrap_script(extra_text)
,将后续操作写入到生成的启动脚本,以下是从docstring中生成的文档:
启动脚本与一般脚本无异,只是多了三个extend_parser, adjust_options, after_install三个钩子方法。
create_bootstrap_script返回一个可定制的,能做为启动脚本的字符串(当然,该字符串后面要写回到磁盘文件中)。这个字符串是一个标准的virtualenv.py脚本,用户可以自行添加内容(所加内容必须是python代码)。
如果定义了下列方法,运行脚本时就会被调用:
extend_parser(optparse_parser)
:
可以在解析器optparse_parser中添加或删除参数。
adjust_options(options, args)
:
调整options,或改变args(如果要接收各种不同的参数,一定要在最后将 args
修改为 [DEST_DIR]
)
after_install(options, home_dir)
:
在所有代码和模块安装完之后,就会调用该方法。这可能是用户最喜欢的方法,例如下:
def after_install(options, home_dir): if sys.platform == 'win32': bin = 'Scripts' else: bin = 'bin' subprocess.call([join(home_dir, bin, 'easy_install'), 'MyPackage']) subprocess.call([join(home_dir, bin, 'my-package-script'), 'setup', home_dir])
上述例子会安装一个包,并运行包内的setup脚本
wrongway在这里强调:上述三个方法并不是独立方法,而是一段代码字符串!!也就是extra_text的内容。有点象javascript下的eval(‘......代码字符串......’)
启动脚本范例
这有个具体的例子:
import virtualenv, textwrap output = virtualenv.create_bootstrap_script(textwrap.dedent(""" import os, subprocess def after_install(options, home_dir): etc = join(home_dir, 'etc') if not os.path.exists(etc): os.makedirs(etc) subprocess.call([join(home_dir, 'bin', 'easy_install'), 'BlogApplication']) subprocess.call([join(home_dir, 'bin', 'paster'), 'make-config', 'BlogApplication', join(etc, 'blog.ini')]) subprocess.call([join(home_dir, 'bin', 'paster'), 'setup-app', join(etc, 'blog.ini')]) """)) f = open('blog-bootstrap.py', 'w').write(output)
这还有一个例子 点击 。
激活脚本
刚创建的隔离环境下会有一个 bin/activate
命令行脚本。在Windows下,激活脚本要在CMD.exe或Powershell.exe中使用。
在Posix系统(*nix/BSD)中,用法如下:
$ source bin/activate
该操作会将当前 $PATH
指向隔离环境下的 bin/
目录。之所以要用source是因为它要改变当前shell环境。仅仅就是一行命令,就这么简单。如果直接运行隔离环境下的脚本或是python解释器(比如path/to/env/bin/pip
or/path/to/env/bin/python script.py
),那都没必要使用激活脚本。
输入 deactivate
就能退出已激活的隔离环境,也就是取消对当前 $PATH
所做的修改。
activate
脚本会修改当前shell命令行提示符,以提示当前激活的是哪个隔离环境。这是挺有用的,不过要是想自定义的提示符,只要在运行 activate
前将 VIRTUAL_ENV_DISABLE_PROMPT
设为你想要的提示(不能为空字符串)。
在Windows下只须如此(*nix用户此处就不用看了,包括下面的注意也不用看了):
> \path\to\env\Scripts\activate
输入 deactivate 就能退出隔离环境。
视你用的shell不同(CMD.exe或Powershell.exe),Windows会使用activate.bat或activate.ps1来激活隔离环境。如果使用的是Powershell,那么以下几点值得注意。
注意(说真的,开发python还是在*nix下好,真的真的真的!):
使用Powershell时,运行 ``activate`` 脚本取决于`执行策略`_ 。但在Windows7下,默认情况下执行策略被设为严格, 这就意味着象 ``activate`` 这样的脚本是不能直接运行的。但稍微设置一下即可。 降低执行策略,改为 ``AllSigned``, 这就意味着本机所有已通过数字签名的脚本都获许运行。 由于virtualenv作者之一Jannis Leidel的数字签名已被核准,允许运行。那么只要以管理员权限运行:: PS C:\> Set-ExecutionPolicy AllSigned 接下来运行脚本时会提示是否信任该签名:: PS C:\> virtualenv .\foo New python executable in C:\foo\Scripts\python.exe Installing setuptools................done. Installing pip...................done. PS C:\> .\foo\scripts\activate Do you want to run software from this untrusted publisher? File C:\foo\scripts\activate.ps1 is published by [email protected], CN=Jannis Leidel, L=Berlin, S=Berlin, C=DE, Description=581796-Gh7xfJxkxQSIO4E0 and is not trusted on your system. Only run scripts from trusted publishers. [V] Never run [D] Do not run [R] Run once [A] Always run [?] Help (default is "D"):A (foo) PS C:\> 如果选择了 ``[A] Always Run``, 该证书就会添加到当前帐户下的受信任发布者名单中,而且此后一直被该用户所信任。 如果选择了 ``[R] Run Once``, 该脚本会立即运行,但之后每次使用都会重新出现信任提示并选择。 高级用户可以将该证书添加到当前计算机的受信任发布者名单中,这样所有用户都可以使用该脚本了(不过这部分内容已经超过了本文档范畴了)。 此外,还可以进一步降低执行策略,允行未验证的本地脚本运行:: PS C:\> Set-ExecutionPolicy RemoteSigned 因为对任何一个virtualenv环境而言, ``activate.ps1`` 都是一个本地脚本而非远程脚本,因为可以获准运行。
--system-site-packages
参数
virtualenv --system-site-packages ENV
创建的隔离环境能直接引用 /usr/lib/python2.7/site-packages
(即是本机全局site-packages路径)中的模块。
只在拥有全局site-packages目录的读写权限,并且你的应用要依赖其中的模块的情况下,该参数会很有用。其他情况下没必要使用该参数。
不使用Virtualenv下的 bin/python
某些情况下,我们无法或是不想使用由virtualenv创建的Python解释器。比如,在 mod_python 或 mod_wsgi下,只能用唯一一个Python解释器。(wrongway补充,不过uwsgi是可以使用多个python解释器的)
幸运的是,这相当简单。只要用指定的Python解释器来 安装 应用包即可。但要使用这些模块,就得更正路径。有一个脚本可以用来更正路径,如下这般设置环境:
activate_this = '/path/to/env/bin/activate_this.py' execfile(activate_this, dict(__file__=activate_this))
上述操作会更改 sys.path
和 sys.prefix
,但使用的仍是当前Python解释器。在隔离环境中会先寻找sys.path
下的内容再寻找全局路径。不过全局路径始终是可以访问的(无论隔离环境是否是由 --system-site-packages
创建的)。而且,上述操作不会影响其他隔离环境,也不会更正在此之前已经引用的模块。所以,在处理web请求时才激活环境往往是无效的,应该尽可能早的激活环境和更正路径,而不是在处理请求时才开始处理。
重定位隔离环境
注意: –relocatable参数带有一定的实验性,可能还有一些尚未发现的问题。而且该参数也不能在Windows下使用。
一般情况下,隔离环境都绑定在某个特定路径下。这也就意味着不能通过仅仅是移动或拷贝目录到另一台计算机上而迁移隔离环境。这时可以使用–relocatable来重定位隔离环境:
$ virtualenv --relocatable ENV
该参数会根据相对路径生成某些setuptools或distribute文件,然后再运行 activate_this.py
更改所有的脚本,而不是通过改变python解释器软链接的指向来重置环境。
注意: 安装 任何 包之后,都要再次重定位环境。只要你将某个隔离环境迁移了,那么每安装一个新的包之后,都要再运行一遍 virtualenv --relocatable
。
要认识到,该参数 不能做到真正的跨平台 。虽然我们可以移动相关目录,但仅仅能用于类似的计算机之间。一些已知的环境差异,仍会导致不兼容:
- 不同版本的Python
- 不同平台使用不同的内部编码,比如一台用UCS2,另一台用UCS4
- Linux和Windows
- Intel和ARM
- 某些包依赖系统的C库,而C库在不同平台下有所差异(不同的版本或不同的文件系统下的所在位置)。
使用重定位参数创建新隔离环境时,会默认使用 --system-site-packages
参数。
--extra-search-dir
参数
创建新的隔离环境时,virtualenv会安装setuptools,distribute或是pip包管理器。一般情况下,它们都会从 Python Package Index (PyPI) 中寻找并安装最新的包。但在一些特定情况下,我们并不希望如此。例如,你在部署virtualenv时既不想从网上下载,也不想从PyPI中获取包。
做为替代方案,可以让setuptools,distribute或是pip搜寻文件系统,让virtualenv使用本地发行包而不是从网上下载。只要象下面这样传入一个或多个 --extra-search-dir
参数就能使用该特性:
$ virtualenv --extra-search-dir=/path/to/distributions ENV
/path/to/distributions
路径指向某个包含setuptools/distribute/pip发行包的目录。Setuptools发行包必须是 .egg
文件,distribute和pip发行包则是 .tar.gz 原代码压缩包。
如果本地路径没有找到相应的发布包,virtualenv还是会从网上下载。
要想确保不会从网上下载任何发行包,就使用 --never-download
参数,如下:
$ virtualenv --extra-search-dir=/path/to/distributions --never-download ENV
这样,virtualenv不会从网上下载任何发行包。而只搜索本地发行包,如果没有找到要安装的包,就返回状态码1。virtualenv会按照如下顺序搜索发行包位置:
- 当前目录
- virtualenv.py所在目录
- virtualenv.py所在目录下的
virtualenv_support
目录- 如果实际运行的脚本名并不是virtualenv.py (换句话说,就是你的自定义启动脚本),会搜索实际安装的virtualenv.py所在目录下的``virtualenv_support`` 目录。
与可替代品的比较
下面几个替代品也可以创建隔离环境:
-
workingenv
(建议不考虑workingenv) 是virtualenv的前身。它使用全局环境的Python解释器,但要靠设置$PYTHONPATH
来激活环境。因此在运行隔离环境以外的Python脚本时,出现很多问题(比如,象全局环境下的hg
或bzr
)。而且它与Setuptools也有很多冲突。 -
virtual-python也是virtualenv的前身。它只使用软链接,因此不能在Windows上工作。而且它的链接会覆盖标准模块和全局环境的
site-packages
,因此无法使用安装在全局环境下的site-packages
的第三方模块因为virtual-python的软链接只是覆盖了全局环境下的标准模块的一部分,因此在windows上,可以用拷贝模块文件的方式来使用virtual-python。同时,它会创建一个空的
site-packages
,并把全局环境的site-packages
指向该目录,因此更新是分别跟踪记录的(这块wrongway也不理解是什么意思,或许作者是想说要两个目录都注意要更新吧)。virtual-python也会自动安装Setuptools,从而省去了从网上手动安装这一步。 -
zc.buildout 不会以上述方式创建隔离的Python环境,但它通过定义配置文件,使用非常特殊的模块,配置脚本达到了相似的效果。做为一个可定义的系统,它是非常容易复制和管理的,但是比较难以改写。
zc.buildout
可以安装非Python的系统(比如数据库服务器或是Apache实例)
我 强烈 建议任何人开发或部署应用时都应该上述工具中的某一款
贡献力量
参照 contributing to pip (参与PIP贡献)这篇文章,里面提及的内容同样适用于virtualenv。
Virtualenv与pip同步发行,每有新的pip发布,就意味着该捆绑新版本pip的virtualenv也发布了。
运行测试
Virtualenv 的测试案例很小,也不完整,但我们后面会完善的。
运行测试的最简单方法就是(自动处理测试依赖):
$ python setup.py test
可以使用nose运行测试的某一部分。创建一个virtualenv环境,然后安装必要的包:
$ pip install nose mock
运行nosetests:
$ nosetests
或是只测试某个文件:
$ nosetests tests.test_virtualenv
相关文档和链接
- James Gardner 编写了教程, 在virtualenv下使用Pylons 。
- 博文 workingenv已死,virtualenv当立 。
- Doug Hellmann 介绍了 virtualenv(virtualenvwrapper)命令行下流水线运行 ,通过几个自写的脚本,让运行多个环境变得更加容易。他还写了 在virtualenv下运行IPython 。
- Chris Perkins 在showmedo创作了视频 使用virtualenv 。
- 在mod_wsgi下使用virtualenv 。
- 更多virtualenv周边工具 。
现状和许可
virtualenv
是 workingenv 的升级, 也是 virtual-python 的扩展。
virtualenv
由 Ian Bicking 编写,接受 Open PlanningProject 赞助,由开发小组 负责维护。该开源遵循 MIT 协议。
Wrongway的补充:常用见法
1.创建隔离环境并安装最新的django
使用当前系统默认Python解释器安装最新的django(当前是1.4),以及django用到的mysql驱动:
$ mkdir myproject1 $ cd myproject1 $ virtualenv env --no-site-packages $ source env/bin/active $(env) pip install django $(env) pip install mysql-python $(env) deactive $
2.创建隔离环境并安装django1.3以及一系列开发用组件
首先编辑一个.pip文件,假定为requirement.pip文件,将要用到的第三方模块名称写入:
Django==1.3 PIL South sorl-thumbnail pylibmc mysql-python django-debug-toolbar再在命令行运行:
$ mkdir myproject2 $ cd myproject2 $ virtualenv environ --no-site-packages $ source environ/bin/active $(environ) pip install -r requirement.pip $(environ) deactive $
3.创建Python2.7隔离环境并安装tornado
我当前环境的默认Python解析器版本是2.6,我已经安装了python2.7,现在两个python共存,但默认使用还是2.6:
$ mkdir myproject3 $ cd myproject3 $ virtualenv huanjing --no-site-packages --python=python2.7 $ source huanjing/bin/active $(huanjing) pip install tornado $(huanjing) deactive $要注意的,python2.7应该是被已设为全局可访问的,在当前命令行输入python2.7是可运行的,否则–python就要设为python2.7解释器的完整路径。
Flask博客源码公开在Github
博客欢迎界面
博客主页
缘起
最近想读读python方向的源码, 想Pythonic一点, 左右看去, 最后决定读Flask源码.
既然决定读源码, 我认为首先要简单的了解:
- 框架的功能
- 具体接口
- 实现一个简单的轮子.
Flask
我就不多介绍了, 网上一搜一大把, python几大著名Web框架之一, 以其轻量级, 高可扩展性
而著名.
那么我们开始造轮子之旅吧
环境相关:
Mac OS X 10.10.3
Sublime Text 3
FLask 0.10.1
Python 3.4.1 # 请放手Python2.7.8, 拥抱Python3
下文主要内容:
- 介绍Flask搭建博客依赖(随着文章的圆满, 会逐渐添加)
- 搭建博客欢迎页面
- 搭建博客基本框架
Flask安装及相关插件
框架及插件:
- Flask
- Flask-Script
- Flask-WTF
- flask-mongoengine
- Flask-markdown
- virtualenv(版本控制) Virtualenv简明教程
数据库:
- mongo(
了解并会使用一种NoSQL会有很大的好处
)
环境配置
$ pip install virtualenv
$ virtualenv -p /usr/local/bin/python3.4 Flask
$ source Flask/bin/activate
$ pip install Flask, Flask-Script, Flask-WTF, flask-mongoengine
项目骨架
请根据下面的Tree文件结构建立文件夹和文件
$ tree ./
./
├── README.md
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── static/
│ ├── templates/
│ └── views.py
├── config.py
├── manage.py
├── requirements.txt
app
为项目核心源码static
为项目静态文件templates
为项目HTML模板
Hello World
国际惯例, 编程第一步...
$ vim app/__init__.py
# -*- coding: utf-8 -*-
#!/usr/bin/env python
from flask import Flask
app = Flask(__name__) #创建Flask类的实例
app.config.from_object("config") #从config.py读入配置
#这个import语句放在这里, 防止views, models import发生循环import
from app import views, models
views.py用于便携Blog的主逻辑, 和Django中views.py功能相同
$ vim app/views.py
# -*- coding: utf-8 -*-
#!/usr/bin/env python
from app import app
from flask import render_template
@app.route('/')
def index():
return "Hello World!"
运用Flask-Script为Flask编写服务器脚本, 产生类似Django的运行方式
$vim manage.py
# -*- coding: utf-8 -*-
#!/usr/bin/env python
from flask.ext.script import Manager, Server
from app import app
manager = Manager(app)
manager.add_command("runserver",
Server(host="127.0.0.1", port=5000, use_debugger=True))
if __name__ == '__main__':
manager.run()
运行服务器
$ python manage.py flask
浏览器打开http://127.0.0.1:5000/, 正式踏出第一步...
博客搭建框架
编写欢迎页面及样式
$ vim app/templates/welcome.html
{% if title %}
{{ title }} - 雪忆
{% else %}
雪忆
{% endif %}
Andrew Liu 雪 忆
雪忆, 如雪般单纯, 冷静思考.
$ vim app/static/welcome.css
/* reset */
* {
margin: 0;
padding: 0;
}
#wrapper {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
}
label {
cursor: pointer;
}
label:focus {
outline: none;
}
/* for show */
html, body {
height: 100%;
}
body {
background: url(http://37.media.tumblr.com/f6c67ec2821a91051e4175f8a102e1e2/tumblr_n6rzpcsMk41st5lhmo1_1280.jpg) 50% 50%/cover;
}
p {
margin-bottom: 15px;
}
#info {
display: table;
background: rgba(0, 0, 0, 0.4);
height: 100%;
width: 100%;
}
#info #info-content {
display: table-cell;
vertical-align: middle;
text-align: center;
text-transform: uppercase;
color: #fff;
font-size: 12px;
}
#info #info-content h1 {
color: #fff;
border: 3px solid #fff;
text-align: center;
background: rgba(0, 0, 0, 0.1);
font-size: 22px;
font-weight: normal;
padding: 20px;
margin: 10px;
display: inline-block;
}
#info #info-content h1 strong {
display: block;
font-size: 26px;
}
现在更改views.py
# -*- coding: utf-8 -*-
#!/usr/bin/env python
from app import app
from flask import render_template, url_for
@app.route('/')
def index():
return render_template('welcome.html', title="Welcome")
到现在为止我们已经完成了欢迎页面的搭建
编写博客主页框架和样式
$ vim app/templates/base.html
{% if title %}
{{ title }} - 雪忆
{% else %}
雪忆
{% endif %}
{% block content %}{% endblock %}
$vim app/static/base.css
@import url(http://fonts.googleapis.com/css?family=Open+Sans:400,800,700,600,300);
body {
margin:0;
font-family: 'Open Sans', sans-serif;
background: #eee;
}
hr {
background:#dedede;
border:0;
height:1px;
}
.header {
overflow: hidden;
display:block;
position:fixed;
top:0;
margin:0;
width:100%;
height:4px;
text-align:center;
}
.header ul {
margin:0;
padding:0;
}
.header ul li {
overflow:hidden;
display:block;
float:left;
width:20%;
height:4px;
}
.header .cor-1 {
background:#f1c40f;
}
.header .cor-2 {
background:#e67e22;
}
.header .cor-3 {
background:#e74c3c;
}
.header .cor-4 {
background:#9b59b6;
}
.header .cor-5 {
background-color: hsla(10,40%,50%,1);
}
.wrap {
width: 950px;
margin:25px auto;
}
nav.menu ul {
overflow:hidden;
float:left;
width: 650px;
padding:0;
margin:0 0 0;
list-style: none;
color:#fff;
background: #1abc9c;
-webkit-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55);
-moz-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55);
box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55);
}
nav.menu ul li {
float:left;
margin:0;
}
nav.menu ul a {
display:block;
padding:25px;
font-size: 16px;
font-weight:600;
text-transform: uppercase;
color:#fff;
text-decoration: none;
transition: all 0.5s ease;
}
nav.menu ul a:hover {
background:#16a085;
text-decoration: underline;
}
.sidebar {
width:275px;
float:right;
}
.sidebar .widget {
margin:0 0 25px;
padding:25px;
background:#fff;
transition: all 0.5s ease;
border-bottom: 2px solid #fff;
}
.sidebar .widget:hover {
border-bottom: 2px solid #3498db;
}
.sidebar .widget h2 {
margin:0 0 15px;
padding:0;
text-transform: uppercase;
font-size: 18px;
font-weight:800;
color:#3498db;
}
.sidebar .widget p {
font-size: 14px;
}
.sidebar .widget p:last-child {
margin:0;
}
.blog {
float:left;
}
.conteudo {
width:600px;
margin:25px auto;
padding:25px;
background: #fff;
border:1px solid #dedede;
-webkit-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35);
-moz-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35);
box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35);
}
.conteudo img {
margin:0 0 25px -25px;
max-width: 650px;
min-width: 650px;
}
.conteudo h1 {
margin:0 0 15px;
padding:0;
font-family: Georgia;
font-weight: normal;
color: #666;
}
.conteudo p:last-child {
margin: 0;
}
.conteudo .continue-lendo {
color:#000;
font-weight: 700;
text-decoration: none;
transition: all 0.5s ease;
}
.conteudo .continue-lendo:hover {
margin-left:10px;
}
.post-info {
float: right;
margin: -10px 0 15px;
font-size: 12px;
text-transform: uppercase;
}
@media screen and (max-width: 960px) {
.header {
position:inherit;
}
.wrap {
width: 90%;
margin:25px auto;
}
.sidebar {
width:100%;
float:right;
margin:25px 0 0;
}
.sidebar .widget {
padding:5%;
}
nav.menu ul {
width: 100%;
}
nav.menu ul {
float:inherit;
}
nav.menu ul li {
float:inherit;
margin:0;
}
nav.menu ul a {
padding:15px;
font-size: 16px;
border-bottom:1px solid #16a085;
border-top:1px solid #1abf9f;
}
.blog {
width:90%;
}
.conteudo {
float:inherit;
width:101%;
padding:5%;
margin:0 auto 25px;
background: #fff;
border:1px solid #dedede;
}
.conteudo img {
margin:0 0 25px -5%;
max-width: 110%;
min-width: 110%;
}
.conteudo .continue-lendo:hover {
margin-left:0;
}
}
@media screen and (max-width: 460px) {
nav.menu ul a {
padding:15px;
font-size: 14px;
}
.sidebar {
display:none
}
.post-info {
display:none;
}
.conteudo {
margin:25px auto;
}
.conteudo img {
margin:-5% 0 25px -5%;
}
}
在views.py编写主页测试代码
# -*- coding: utf-8 -*-
#!/usr/bin/env python
from app import app
from flask import render_template, url_for
@app.route('/')
def index():
return render_template('welcome.html', title="Welcome")
@app.route('/home')
def home():
return render_template('base.html', title="Home")
打开浏览器, 访问http://127.0.0.1:5000/home, 你会看到精美小清新的主页框架