Python.org使用了Django框架,基于Python3.3开发,是在生产环境应用Python3+Django的好例子,所以clone了它的源代码来学习,使用的是868d254版,整理如下。
Deploy
搭建Python环境自然先想到virtualenv,但Python.org源代码根目录里有Vagrantfile文件,支持用vagrant来搭建环境。虽然之前做ROR的环境时都配好了,但Python.org的配置用vagrant 1.0.1版本运行会出错,升级成最新的vagrant 1.5.1就正常了,执行vagrant up命令会自动下载Ubuntu 12.04 64bit来部署:
==> default: Successfully added box ‘hashicorp/precise64’ (v1.1.0) for ‘virtualbox’!
==> default: Setting the name of the VM: pythondotorg_default_1396007711925_54940
default: Adapter 1: nat
==> default: Forwarding ports…
default: 8000 => 8000 (adapter 1)
==> default: Booting VM
==> default: Running provisioner: chef_solo
Generating chef JSON and uploading
Running chef-solo
[2014-03-29T03:28:59+00:00] INFO: *** Chef 10.14.2 ***
如果宿主机是32位的,通常需要在VirtualBox配置文件或者图形界面中取消勾选Enable PAE/NX,否则可能会报VT-x is not available. (VERR_VMX_NO_VMX).的错误。网速很差的情况下可以先把box文件下载到本地,再修改配置文件config.vm.box = “box文件名”,重新执行vagrant up会直接使用指定的box文件。
输出的最后一行显示vagrant运行了chef-sole,用Chef来做配置管理,配置文件和命令都在源代码的chef/目录下, 会根据这些配置自动安装数据库(postgresql)、对应的Python/Pip版本、依赖的Python包。该项目的Django版本是1.5.4,Django1.5开始支持Python3。从commit记录来看,Python.org的开发者们最初是使用1.5a1,升级到1.5.4就没有再升级过版本。
Chef执行结束后运行vagrant ssh连到虚拟机,会自动切换到virtualenv中。migrate数据库后,启动Django测试服务器就能访问网站了。
我clone的这个版本漏掉了susy,需要手动gem install 装上;数据库密码可以在chef/roles/python-dev-box.json里清掉,如果用dj-database-url要设置export DATABASE_URL=”postgres://postgres:pydotorg@localhost/python.org”
Testing
Python.org的测试代码有用Django的TestCase,也有用Python自带的unittest,用coverage测试覆盖率得到的报告结果是87%:
Name | Stmts | Miss | Branch | BrMiss | Cover |
TOTAL | 3007 | 310 | 296 | 107 | 87% |
测试代码用到了ddt,实现在一个测试用例中使用多个测试数据,比如这段代码(正则部分很有意思所以一起复制了):
import ddt
import unittest
import re
PAGE_PATH_RE = re.compile(r"""
^
/? # We can optionally start with a /
([a-z0-9-\.]+) # Then at least one path segment...
(/[a-z0-9-\.]+)* # And then possibly more "/whatever" segments
/? # Possibly ending with a slash
$
""",
re.X
)
@ddt.ddt
class PagePathReTests(unittest.TestCase):
good_paths = {
"path" : 1,
"path/2" : 2,
"yet/another/path/wow": 3,
"/initial-slash" : 4,
"trailing/slash/" : 5,
}
bad_paths = (
"Path",
"",
"no_underscores",
"no/special!/chars?",
)
@ddt.data(*good_paths)
def test_good_path(self, p):
self.assertTrue(PAGE_PATH_RE.match(p), "'%s' didn't match (it shoulld)" % p)
@ddt.data(*bad_paths)
def test_bad_path(self, p):
self.assertFalse(PAGE_PATH_RE.match(p), "'%s' matched (it shouldn't)" % p)
引入dtt,在名为ddt.data的decorator中传入一个可iterate的对象作为参数,也支持直接读取json文件,执行测试时就自动遍历了。
Others
就架构来说,其实我最关心的是API部分,结果Python.org的API还是用tastypie实现的,非常规范的实现方式,目前没什么可借鉴的。tastypie我虽然11年就写文章分享过,但至今为止只在两个项目中用过,其他项目要不就是直接nodejs+restify来做,要不就自己手写。
另一个小发现是整个项目用了不少的models.Manager,确实简化了models.py的代码,也让结构更清晰了,看来以后这部分还是不能偷懒。以及,forms仍然没人用…
Afterword
Python3发布也五六年了,一直没有取代Python2。不用Python3的理由很多,它不向下兼容,性能也没大的提升,看了Python.org的源代码,发现其实没用到多少Python3的语言特征。可能跟Web开发的特性有关:合作开发(代码不能写得太复杂让别人都看不懂)强调服务稳定(不能随便引入新特性避免兼容问题)。但我还是建议各位升级到Python3,比如:虽然对于大部分开发者来说,Python3解决的坑,各位在Python2里基本都踩过了,但至少是为了不继续坑其它人,咱们还是往Python3上转吧。