本节内容基本译自Pyramid官方网站,添加了一些自己的标注。
本节基本就是router.py这个模块的一一对应,需要加深理解最好打开源代码一边看代码一边看说明(本文针对Pyramid 1.3b2代码)。
上一篇说了Pyramid项目里main函数使用make_wsgi_app生成了一个名字叫Router的app,并将这个app传给了WSGI服务器。那么,显而易见,Pyramid处理Request请求就是跟这个Router类息息相关了。
1. WSGI服务器一旦接受到用户请求,即按照规范要求构造WSGI环境变量,然后将这些变量传递给router对象(app)的__call__方法。(参见paste deploy)
2. router使用request_factory创建一个request对象,并将WSGI环境变量传递给request对象。从这种处理方式可以看出,我们甚至可以自定义一个定制化的request_factory,以便生成特有的request。(参加router.py 179行)
3. 将request、registry对象放入到thread local栈中,以使每次请求之间的数据不会有冲突。今后可以用get_current_request()、get_current_registry()来得到这两个对象,不过在view中建议采用直接采用request、request.registry。(参加router.py 180-183行)
4. 触发一个NewRequest事件。(参加router.py 75行)
5. 如果在之前的应用配置处(main函数)配置了route配置项,Pyramid会调用routes_mapper函数进行URL分发。该函数检查预定义的route中(main函数)是否有与request包含的当前WSGI变量相匹配的项。(参加router.py 79行)
6. 如果找到匹配项,route_mapper函数会在request中加入两个属性:matchdict、matched_route。matchdict是一个针对具体PATH_INFO与预定义route项匹配之后形成的动态参数。比如定义了add_route(’idea’, ’site/{id}’),那么/site/1请求就会形成一个值为{’id’:’1’}的matchdict。matched_route则是指对应的那条route对象(参加router.py 94-95行)。随后,生成该route对应的root对象(参加router.py 120行)。如果这条route中配置了factory,则采用该factory生成root对象,否则采用默认的root_factory。(参见48、77、118行)
7. 如果没有找到相匹配的route,而且在创建Configurator对象时指定了root_factory参数,则使用该root_factory创建root对象。如果没有指定root_factory参数,则使用DefaultRootFactory来创建root对象。(参见48、77、118行)
8. Pyramid通过root、request参数漫游(traverser),traverser从root对象开始漫游(__getitem__方法)以寻找合适的context,如果root对象没有__getitem__方法,则将root对象赋给context。traverser返回一个带context、view名字等信息的字典。(参加router.py124-136行)
9. 将上一步取得的参数添加到request对象中,因此在view代码中,可以用request.context这种方式来访问他们。(参见router.py 138行)
10. 触发contextFound事件(参见router.py 139行)
11. 使用context、request、view名字等信息查找view,如果找不到,则抛出HTTPNotFound 异常(参见router.py 141-162行)
12. 如果找到了合适的view,Pyramid查看是否已经定义了认证策略,且这个view配置了访问权限。如是,则Pyramid将request中的访问者凭证与context附带的安全信息进行匹配,如果匹配通过,Pyramid则调用该view并且获得response对象。否则抛出HTTPForbidden异常。
13. 如果在上述过程中(root factory、traversal、view)抛出了异常,如HTTPNotFound、 HTTPForbidden,router将捕获这些异常,并赋给request.exception属性。然后寻找一个合适该异常的view,如果有这样的view,就调用它,产生response对象。如果找不到,就抛出该异常。
14. 触发NewResponse事件(参见router.py 188行)
15. 当一个response对象通过view或exception view生成之后,Pyramid将会遍历执行所有通过add_response_callback方法加进来的方法、对象。(参加 router.py 190-192 行)
16. 遍历执行通过add_finished_callback加入进来的方法、对象。(参见router.py 196-197 行)
17. 将threadlocal从栈中弹出。(参见 router.py 200 行)
Friday, March 23, 2012
Thursday, March 22, 2012
Pyramid启动时都能干些啥?
Pyramid找到我们项目的main函数之后,一切就相对简单了。
一、项目参数的传递
我们打开项目中的__init__.py文件,找到自动生成的main函数如下:
我们可以看到,main函数带了两个参数,global_config和setting。这是由Paste deploy传递过来的解析自development.ini的参数项。
其中global_config是development.ini中[DEFAULT]这一节中的参数定义,在我们自动生成的例子中,我们没有使用default节,所以也就没有传入自定义的参数,系统默认在global_config这个字典对象中加了两个参数项定义:
here: 表示development.ini文件所在目录的绝对路径
__file__: 表示development.ini文件的绝对路径
setting字典则包含了所有定义在[app:main]中的参数项(除了use),在我们的例子中,就包含了pyramid.reload_templates、pyramid.debug_authorization、sqlalchemy.url等的参数项。这些参数项都可以直接在我们的程序中使用。我们也可以在[app:main]中定义自定义的参数项,如mytest=testconfig。那么我们在view中就可以用如下程序取得定义的值。
settings = request.registry.settings
mytest = settings[’mytest’]
这里注意一下,放在其他section中的参数是传不进来的,如果一定要这样用,需要在程序中取到ini文件路径(global_config中的__file__),然后自行使用ConfigParser读取解析。
二、Configurator的配置
就如上面的程序,main函数做的最主要的工作就是做整合项目的配置,形成注册表。在Pyramid中可以配置的东西很多,我们可以简单看下几个常用的配置:
1. 静态资源
通过config.add_static_view('static', 'static', cache_max_age=3600)加入一个静态资源目录,一般写成config.add_static_view(name=’static’, path=’/var/www/static’) 或 config.add_static_view(name=’static’, path=’mypackage:a/b/c/static’) 这样的方式更清晰。
在add_static_view中,name代表了静态文件URL的前缀,如果我们使用了上面前一个例子,那么URL /static/foo.css 就会取指向文件/var/www/static/foo.css。后一个例子是相对与项目包结构的相对路径。
不过现在很多程序都是用外部资源来做静态资源的,也可以用config.add_static_view(name=’http://example.com/images’, path=’mypackage:static’)这种方式将静态文件指向外部服务器。
在程序中,就可以用static_url('pyramidkoans:static/favicon.ico') 或 static_path('pyramidkoans:static/favicon.ico') 这样的方式来引用静态资源。按照之前不同的定义,这里会解析出不同的结果。
2. add_route、add_view、view_config、scan
这几个函数定义了从URL到view的映射关系,add_route只在Route模式才会使用,traversal模式下不用。
view的配置可以使用add_view手工加入,也可以使用view_config标注+scan函数合作完成。
3. 权限
pyramid整合了一套ACL权限管理体系,也需要在configurtor中进行配置才能生效。pyramid权限管理划分了认证、授权两个部分,需要分别配置。
authn_policy = AuthTktAuthenticationPolicy('sosecret', callback=groupfinder)
authz_policy = ACLAuthorizationPolicy()
config.set_authentication_policy(authn_policy)
config.set_authorization_policy(authz_policy)
4. 用include包含子模块
项目大了之后,可以划分成多个子模块,然后用include包含子模块。
5.subscriber
Pyramid定义了一套简单的事件系统,开发者可以通过订阅一些特定的事件来改变框架的一些默认行为。
三、app的生成
完成了configurator的配置之后,pyramid就调用make_wsgi_app来生成一个符合WSGI规范的app,以便提供服务。
不过这个app是一个叫Router的类的实例,很奇怪吧。
好了,接下来就等待访问链接的来临吧
一、项目参数的传递
我们打开项目中的__init__.py文件,找到自动生成的main函数如下:
我们可以看到,main函数带了两个参数,global_config和setting。这是由Paste deploy传递过来的解析自development.ini的参数项。
其中global_config是development.ini中[DEFAULT]这一节中的参数定义,在我们自动生成的例子中,我们没有使用default节,所以也就没有传入自定义的参数,系统默认在global_config这个字典对象中加了两个参数项定义:
here: 表示development.ini文件所在目录的绝对路径
__file__: 表示development.ini文件的绝对路径
setting字典则包含了所有定义在[app:main]中的参数项(除了use),在我们的例子中,就包含了pyramid.reload_templates、pyramid.debug_authorization、sqlalchemy.url等的参数项。这些参数项都可以直接在我们的程序中使用。我们也可以在[app:main]中定义自定义的参数项,如mytest=testconfig。那么我们在view中就可以用如下程序取得定义的值。
settings = request.registry.settings
mytest = settings[’mytest’]
这里注意一下,放在其他section中的参数是传不进来的,如果一定要这样用,需要在程序中取到ini文件路径(global_config中的__file__),然后自行使用ConfigParser读取解析。
二、Configurator的配置
就如上面的程序,main函数做的最主要的工作就是做整合项目的配置,形成注册表。在Pyramid中可以配置的东西很多,我们可以简单看下几个常用的配置:
1. 静态资源
通过config.add_static_view('static', 'static', cache_max_age=3600)加入一个静态资源目录,一般写成config.add_static_view(name=’static’, path=’/var/www/static’) 或 config.add_static_view(name=’static’, path=’mypackage:a/b/c/static’) 这样的方式更清晰。
在add_static_view中,name代表了静态文件URL的前缀,如果我们使用了上面前一个例子,那么URL /static/foo.css 就会取指向文件/var/www/static/foo.css。后一个例子是相对与项目包结构的相对路径。
不过现在很多程序都是用外部资源来做静态资源的,也可以用config.add_static_view(name=’http://example.com/images’, path=’mypackage:static’)这种方式将静态文件指向外部服务器。
在程序中,就可以用static_url('pyramidkoans:static/favicon.ico') 或 static_path('pyramidkoans:static/favicon.ico') 这样的方式来引用静态资源。按照之前不同的定义,这里会解析出不同的结果。
2. add_route、add_view、view_config、scan
这几个函数定义了从URL到view的映射关系,add_route只在Route模式才会使用,traversal模式下不用。
view的配置可以使用add_view手工加入,也可以使用view_config标注+scan函数合作完成。
3. 权限
pyramid整合了一套ACL权限管理体系,也需要在configurtor中进行配置才能生效。pyramid权限管理划分了认证、授权两个部分,需要分别配置。
authn_policy = AuthTktAuthenticationPolicy('sosecret', callback=groupfinder)
authz_policy = ACLAuthorizationPolicy()
config.set_authentication_policy(authn_policy)
config.set_authorization_policy(authz_policy)
4. 用include包含子模块
项目大了之后,可以划分成多个子模块,然后用include包含子模块。
5.subscriber
Pyramid定义了一套简单的事件系统,开发者可以通过订阅一些特定的事件来改变框架的一些默认行为。
三、app的生成
完成了configurator的配置之后,pyramid就调用make_wsgi_app来生成一个符合WSGI规范的app,以便提供服务。
不过这个app是一个叫Router的类的实例,很奇怪吧。
好了,接下来就等待访问链接的来临吧
Wednesday, March 21, 2012
利用Amazon SES为应用构建简单的邮件服务
Amazon SES是AWS推出的一项邮件发送服务,类似于sendgrid等专业的邮件发送服务商。不过因AWS众多其他服务的捆绑支持,对于AWS平台上的应用还是具有不小的吸引力的。
一. 为啥使用SES呢
1. 对于发送量不稳定的应用,价格还是便宜的,发多少,算多少($0.10/1000条),没有套餐限制,附带流量也会产生费用。
2. 对于AWS EC2上的应用,有每天2000封的免费额度,基本足够大部分人使用了。
当然,也要牢记,amazon不是专业的mail发送公司,涉及到更专业的送达服务、垃圾邮件等方面还不那么健全,普通用用是完全没问题的,毕竟大家都知道邮件是怎么回事,有点小问题也都能谅解,顶多勤快点,多泡泡amazon服务论坛。
二. SES接入模式
amazon提供了多种接入支持以满足各种不同的需要:
1. smtp发送服务,提供了STARTTLS、TLS Wrapper两种不同方式,端口不同,可以用于编程或安装应用软件配置
2. api发送服务,可以通过amazon的api发送邮件,这里提供了一个封装。https://github.com/pankratiev/python-amazon-ses-api/blob/master/amazon_ses.py3. 与 Postfix 整合,配置其relayhost参数,使已有的应用能方便的使用SES服务能力。
三. smtp接入案例
1. 发件人认证
SES需要对每一个发件人邮箱进行认证,不存在的发件人不能够发送邮件。只需要再verify a new sender里面输入邮件地址,SES会往这个邮箱发送一个验证URL,在浏览器打开该URL即可完成验证。
SES 工作在sanbox状态下,需要同时将收信人也进行同样的认证。如果需要在生产环境使用,需要事先申请,24小时开通。
2. 生成SMTP 用户密码对
在发信之前,还需要生成一个smtp用户密码对,只需要点击SMTP Settings 中的Create My SMTP Credentials按钮即可在IAM中生成一个账号,同时显示其名字、密码,记录下来保存好需要在发送邮件时使用。
3. 小程序
mailServer = smtplib.SMTP_SSL('email-smtp.us-east-1.amazonaws.com', 465)
mailServer.set_debuglevel(1)
mailServer.login(IAM用户名, IAM用户密码)
mailServer.sendmail('发件人', ['收件人'], msg.as_string())
mailServer.close()
一. 为啥使用SES呢
1. 对于发送量不稳定的应用,价格还是便宜的,发多少,算多少($0.10/1000条),没有套餐限制,附带流量也会产生费用。
2. 对于AWS EC2上的应用,有每天2000封的免费额度,基本足够大部分人使用了。
当然,也要牢记,amazon不是专业的mail发送公司,涉及到更专业的送达服务、垃圾邮件等方面还不那么健全,普通用用是完全没问题的,毕竟大家都知道邮件是怎么回事,有点小问题也都能谅解,顶多勤快点,多泡泡amazon服务论坛。
二. SES接入模式
amazon提供了多种接入支持以满足各种不同的需要:
1. smtp发送服务,提供了STARTTLS、TLS Wrapper两种不同方式,端口不同,可以用于编程或安装应用软件配置
2. api发送服务,可以通过amazon的api发送邮件,这里提供了一个封装。https://github.com/pankratiev/python-amazon-ses-api/blob/master/amazon_ses.py3. 与 Postfix 整合,配置其relayhost参数,使已有的应用能方便的使用SES服务能力。
三. smtp接入案例
1. 发件人认证
SES需要对每一个发件人邮箱进行认证,不存在的发件人不能够发送邮件。只需要再verify a new sender里面输入邮件地址,SES会往这个邮箱发送一个验证URL,在浏览器打开该URL即可完成验证。
SES 工作在sanbox状态下,需要同时将收信人也进行同样的认证。如果需要在生产环境使用,需要事先申请,24小时开通。
2. 生成SMTP 用户密码对
在发信之前,还需要生成一个smtp用户密码对,只需要点击SMTP Settings 中的Create My SMTP Credentials按钮即可在IAM中生成一个账号,同时显示其名字、密码,记录下来保存好需要在发送邮件时使用。
3. 小程序
mailServer = smtplib.SMTP_SSL('email-smtp.us-east-1.amazonaws.com', 465)
mailServer.set_debuglevel(1)
mailServer.login(IAM用户名, IAM用户密码)
mailServer.sendmail('发件人', ['收件人'], msg.as_string())
mailServer.close()
Tuesday, March 20, 2012
Pyramid项目是怎么启动起来的?
Pyramid 官方文档上专门有一个章节解释了Pyramid项目的启动过程,不过因为整个启动过程还涉及到一些非pyramid模块,光看那个说明未必能很好理解清楚整个启动过程。下面,我们通过一个小例子简单看看一个Pyramid项目是怎么一步一步启动起来的。
一、创建好项目,配置好开发环境。
按照pyramid的介绍,我们用如下命令很快就可以创建一个演示项目。
pcreate -s alchemy PyramidKoans
python setup.py develop
Ok,现在就可以用
pserve development.ini来启动这个项目了。
二、pserve是啥?
问题来了,为什么是用pserve来启动?pserve又是怎么启动载入的呢?
我们知道,pyramid安装的时候会在/bin目录下(如果你用virtualenv的话)生成一堆的执行文件,pserve就是其中一个,我们打开看看先:
这堆文件基本都是这个样子,只是里面参数有差异而已,其实这些都是easy_install根据egg包中的egg_info自动生成的,所以当然都差不多啦。
下面我们再打开pyramid EGG_INFO中的entry_points.txt文件对比一下:
可以看到在/bin下生成的执行文件跟上面console_scripts是一一对应的。
所以,我们就可以很好理解 load_entry_point('pyramid==1.3b2', 'console_scripts', 'pserve')() 这语句了,它就是来pyramid 1.3b2这个egg包中来找'console_scripts', 'pserve'这个入口,然后载入其对应的程序,这里就是pyramid.scripts.pserve:main。
再打开pyramid包script目录下,找到pserve.py找到main函数,刚才的pserve命令就是启动了这个main函数而已。(其实这个script就是原来的paste script内容,基本原封不动的转到这里来了。)
二、paste deploy来了
既然用了paste script,那当然就要用到paste deploy啦。
找到PServeCommand类的run方法,很容易就可以找到
这就是用了paste deploy中的loadserver,loadapp方法。
paste deploy是一个很常用定位、配置WSGI应用/服务器的工具包,它可以从一个定制的配置文件里面载入你所定义的app和server。这里这个配置文件就是上面启动命令里面提到的development.ini。加载了app和server之后,马上可以看到
因为这里的server跟app都是符合WSGI标准的,所有将app丢给server即可启动啦。
三、development.ini
上面已经找到了server和app的载入,那么又是怎么找到你所需要的那个server跟app呢?要理解这点,就需要看development.ini这个配置文件了。
这是一个基本上算标准的ini配置文件,不过paste deploy还是在上面做了一些定制。比如server:main、app:main、use这些定义。
server:main
这里的server是一个固定用法,表示下面的配置用于启动一个WSGI server。
server:main这一配置块定义了WSGI server启动方式以及它的启动参数,如host、port。
这里的第一行use = egg:waitress#main就是定义了如何启动WSGI server。这里use也是个固定用法,egg:waitress#main表示找到waitress这个egg包,找到里面的entry_points中main定义项:
然后查看waitress这个包中的serve_paste这个方法即可,这个方法就是将waitress这个WSGI server启动起来。具体的waitress内容这里就不详细讨论了。
在定义waitressa参数的时候要注意下,我们经常还需要定义一个threads参数,它表示需要启动多少线程来提供服务,默认是4个,如果需要在正式环境用的话是不够的。
当然,我们也可以通过修改配置重新使用paste来替换waitress提供服务。
app:main
这里app也是固定用法,表示app_factory,表示由这里的信息来生成WSGI app。main是配置块名字,在使用pipeline的时候用得到。
app:main块定义了app中所能使用的参数(除了use),如pyramid.reload_templates、pyramid.debug_templates、sqlalchemy.url…这些都是pyramid本身或app程序中需要使用的配置,如果app需要定义自己的配置,也可以放在这里。
这里我们要着重看一下的是use = egg:PyramidKoans这句。egg:PyramidKoans表示从PyramidKoans这个egg包找到app的入口,这里省略了#main(默认就是它啦)。所以,又要找entry point啦,打开PyramidKoans项目中的setup.py文件(没打包发行之前,entry_points存在这里面。),
我们在这里也找到了entry_points,看[paste.app_factory]这里的定义,paste deploy就是来找这一段配置,再看main = pyramidkoans:main,这里第一个main就是我们刚才说的省略了的那个main,然后它指向了 pyramidkoans:main,表示需要到paramidkoans这个包里去找main这个方法。
终于走到我的程序了!
一、创建好项目,配置好开发环境。
按照pyramid的介绍,我们用如下命令很快就可以创建一个演示项目。
pcreate -s alchemy PyramidKoans
python setup.py develop
Ok,现在就可以用
pserve development.ini来启动这个项目了。
二、pserve是啥?
问题来了,为什么是用pserve来启动?pserve又是怎么启动载入的呢?
我们知道,pyramid安装的时候会在
这堆文件基本都是这个样子,只是里面参数有差异而已,其实这些都是easy_install根据egg包中的egg_info自动生成的,所以当然都差不多啦。
下面我们再打开pyramid EGG_INFO中的entry_points.txt文件对比一下:
可以看到在
所以,我们就可以很好理解 load_entry_point('pyramid==1.3b2', 'console_scripts', 'pserve')() 这语句了,它就是来pyramid 1.3b2这个egg包中来找'console_scripts', 'pserve'这个入口,然后载入其对应的程序,这里就是pyramid.scripts.pserve:main。
再打开pyramid包script目录下,找到pserve.py找到main函数,刚才的pserve命令就是启动了这个main函数而已。(其实这个script就是原来的paste script内容,基本原封不动的转到这里来了。)
二、paste deploy来了
既然用了paste script,那当然就要用到paste deploy啦。
找到PServeCommand类的run方法,很容易就可以找到
这就是用了paste deploy中的loadserver,loadapp方法。
paste deploy是一个很常用定位、配置WSGI应用/服务器的工具包,它可以从一个定制的配置文件里面载入你所定义的app和server。这里这个配置文件就是上面启动命令里面提到的development.ini。加载了app和server之后,马上可以看到
因为这里的server跟app都是符合WSGI标准的,所有将app丢给server即可启动啦。
三、development.ini
上面已经找到了server和app的载入,那么又是怎么找到你所需要的那个server跟app呢?要理解这点,就需要看development.ini这个配置文件了。
这是一个基本上算标准的ini配置文件,不过paste deploy还是在上面做了一些定制。比如server:main、app:main、use这些定义。
server:main
这里的server是一个固定用法,表示下面的配置用于启动一个WSGI server。
server:main这一配置块定义了WSGI server启动方式以及它的启动参数,如host、port。
这里的第一行use = egg:waitress#main就是定义了如何启动WSGI server。这里use也是个固定用法,egg:waitress#main表示找到waitress这个egg包,找到里面的entry_points中main定义项:
然后查看waitress这个包中的serve_paste这个方法即可,这个方法就是将waitress这个WSGI server启动起来。具体的waitress内容这里就不详细讨论了。
在定义waitressa参数的时候要注意下,我们经常还需要定义一个threads参数,它表示需要启动多少线程来提供服务,默认是4个,如果需要在正式环境用的话是不够的。
当然,我们也可以通过修改配置重新使用paste来替换waitress提供服务。
app:main
这里app也是固定用法,表示app_factory,表示由这里的信息来生成WSGI app。main是配置块名字,在使用pipeline的时候用得到。
app:main块定义了app中所能使用的参数(除了use),如pyramid.reload_templates、pyramid.debug_templates、sqlalchemy.url…这些都是pyramid本身或app程序中需要使用的配置,如果app需要定义自己的配置,也可以放在这里。
这里我们要着重看一下的是use = egg:PyramidKoans这句。egg:PyramidKoans表示从PyramidKoans这个egg包找到app的入口,这里省略了#main(默认就是它啦)。所以,又要找entry point啦,打开PyramidKoans项目中的setup.py文件(没打包发行之前,entry_points存在这里面。),
我们在这里也找到了entry_points,看[paste.app_factory]这里的定义,paste deploy就是来找这一段配置,再看main = pyramidkoans:main,这里第一个main就是我们刚才说的省略了的那个main,然后它指向了 pyramidkoans:main,表示需要到paramidkoans这个包里去找main这个方法。
终于走到我的程序了!
Wednesday, August 10, 2011
快速建立Pylons CI环境
因目前业务还跑在Pylons上,因此就拿Pylons来做这个例子吧。其他Python环境应该也是大同小异的。
CI系统环境:
OS: Ubuntu
CI 工具: Hudson 1.396
单元测试工具: nosetests
Hudson 本身的安装使用就不细写了,网上现在已经有很多了。直接下载war包,用java -jar运行即可。
启动之后,在管理界面中安装 Hudson Cobertura plugin、Python Plugin、Hudson Violations plugin、Subversion Plugin等插件即可。
一、建立虚拟环境
为了使Hudson同时支持多个python项目的持续集成,建议为每一个项目建立独立的虚拟环境,以便更清楚与项目相关联的包的情况,方便今后的部署。
下面几个步骤即可建立一个基本的虚拟环境。
1. 找到virtualenv包,取出其中的virtualenv.py
2. 运行python virtualenv.py --no-site-packages pylons-0.9.7 建立一个名字叫pylons-0.9.7的虚拟环境。这里 --no-site-packages参数是为了排除linux系统自带的python包对项目的影响,加了这个参数即可建立比较干净的Python虚拟环境。
3. 启动刚才建立的虚拟环境 source pylons-0.9.7/bin/activate
4. 运行easy_install nose 安装nosetests单元测试工具
5. 运行easy_install fudge 安装fudge Mock工具
6. 运行easy_install nosexcover 安装覆盖率生成工具,这个工具可以生成hudson中需要的xml格式的报表。仅仅安装coverage包不能生成类似报表。
二、建立项目运行环境
现在一个基本的环境已经基本建立完成了。下面在安装一些该项目特定的包
1. 安装mysql python包、sqlalchemy包
sudo apt-get install libmysqlclient-dev (MySQL-python编译安装需要mysql client开发环境)
easy_install MySQL-python
easy_install "sqlalchemy==0.5.8"
2. 安装pylons
easy_install -Z "pylons==0.9.7"
在pylons-0.9.7/lib/python26/site-packages/WebOb-1.1beta1-py2.6.egg/webob/__init__.py中加入一行from webob.multidict import UnicodeMultiDict
(pylons下载了最新的webob,里面有些改动,pylons 0.9.7不支持,需要改下)
3. 再按装写杂七杂八的项目用到的包
easy_install pycrypto
easy_install recaptcha_client
easy_install python-memcached
好了,一个pylons虚拟环境基本完成了,可以先直接下载项目代码运行nosetests看看有没有什么问题,如果运行都正常,即可进行以下步骤
三、建立Hudsong项目
1. 在Hudson中新建一个任务,选择“构建一个自由风格的软件项目“
2. 输入代码地址(SVN/CVS...)
3. 按照crontab规则建立build规律
4. 选择shell脚本作为build命令,在里面输入如下内容:
. /home/mm/pylons-0.9.7/bin/activate
cd ${WORKSPACE}
nosetests --cover-package=包名 --cover-tests --with-xcoverage --with-xunit --verbose
注:这里报名替换成需要测试覆盖率的包名
5. 设置输出报表
Publish JUnit test result report
xml文件直接输入 nosetests.xml
Publish Cobertura Coverage Report
xml文件直接输入 coverage.xml
CI系统环境:
OS: Ubuntu
CI 工具: Hudson 1.396
单元测试工具: nosetests
Hudson 本身的安装使用就不细写了,网上现在已经有很多了。直接下载war包,用java -jar运行即可。
启动之后,在管理界面中安装 Hudson Cobertura plugin、Python Plugin、Hudson Violations plugin、Subversion Plugin等插件即可。
一、建立虚拟环境
为了使Hudson同时支持多个python项目的持续集成,建议为每一个项目建立独立的虚拟环境,以便更清楚与项目相关联的包的情况,方便今后的部署。
下面几个步骤即可建立一个基本的虚拟环境。
1. 找到virtualenv包,取出其中的virtualenv.py
2. 运行python virtualenv.py --no-site-packages pylons-0.9.7 建立一个名字叫pylons-0.9.7的虚拟环境。这里 --no-site-packages参数是为了排除linux系统自带的python包对项目的影响,加了这个参数即可建立比较干净的Python虚拟环境。
3. 启动刚才建立的虚拟环境 source pylons-0.9.7/bin/activate
4. 运行easy_install nose 安装nosetests单元测试工具
5. 运行easy_install fudge 安装fudge Mock工具
6. 运行easy_install nosexcover 安装覆盖率生成工具,这个工具可以生成hudson中需要的xml格式的报表。仅仅安装coverage包不能生成类似报表。
二、建立项目运行环境
现在一个基本的环境已经基本建立完成了。下面在安装一些该项目特定的包
1. 安装mysql python包、sqlalchemy包
sudo apt-get install libmysqlclient-dev (MySQL-python编译安装需要mysql client开发环境)
easy_install MySQL-python
easy_install "sqlalchemy==0.5.8"
2. 安装pylons
easy_install -Z "pylons==0.9.7"
在pylons-0.9.7/lib/python26/site-packages/WebOb-1.1beta1-py2.6.egg/webob/__init__.py中加入一行from webob.multidict import UnicodeMultiDict
(pylons下载了最新的webob,里面有些改动,pylons 0.9.7不支持,需要改下)
3. 再按装写杂七杂八的项目用到的包
easy_install pycrypto
easy_install recaptcha_client
easy_install python-memcached
好了,一个pylons虚拟环境基本完成了,可以先直接下载项目代码运行nosetests看看有没有什么问题,如果运行都正常,即可进行以下步骤
三、建立Hudsong项目
1. 在Hudson中新建一个任务,选择“构建一个自由风格的软件项目“
2. 输入代码地址(SVN/CVS...)
3. 按照crontab规则建立build规律
4. 选择shell脚本作为build命令,在里面输入如下内容:
. /home/mm/pylons-0.9.7/bin/activate
cd ${WORKSPACE}
nosetests --cover-package=包名 --cover-tests --with-xcoverage --with-xunit --verbose
注:这里报名替换成需要测试覆盖率的包名
5. 设置输出报表
Publish JUnit test result report
xml文件直接输入 nosetests.xml
Publish Cobertura Coverage Report
xml文件直接输入 coverage.xml
Sunday, August 7, 2011
code review 之我见
近期code review的讨论貌似很多,也来凑下热闹,说说自己的一些认识和想法。
一、常见误区
1. 在我经历过的很多团队中,貌似不少人员都认为code review是一种上级的管理手段。毕竟翻译成中文叫“代码评审
”,这又评又审的,很多人就已经开始心里打鼓了,这嘴上不说,心底里早就开始抵触上了。这种情绪下还能指望即时
的review么?
2. code review不能算是考核工具,很多管理者都会有review出一个问题,扣多少多少类似的想法,把review简简单单
的当成了抓虫子,从而造成了更多的开发人员的抵触。一review就变味成了给开发挑刺,然后升级成双方攻防战,搞得
面红耳赤,你死我活的,最后一拍两散。
3. code review也不是个人技术挑战赛,这在很多年轻气盛的开发人员中很常见,“凭什么给他看”,“他又看不懂”
是这类人经常会说的话。其实从来没有人规定过review一定要找更厉害的人,一定要找出问题来的。
4. review是每一个团队成员的事,而不仅仅是经理或者架构师的事。这在传统的开发团队里面很常见,代码开发完了
一丢,就没自己啥事了。在敏捷开发中,review应该是每一个成员自发的行为。
二、一点想法
1. 整个团队必须保持一个开放的心态,能够虚心听取他人意见,战斗的团队是指对外战斗,不是内斗。
2. 必须建立一个前提认识:代码共享,团队中每个人都能随时浏览他人最新代码。代码不是私人物品,不能敝帚自珍。
3. 明确一个观点:任何review都不是挑错,是一种相互探讨,追求更高质量,更优代码的过程,是团队共同进步的一种手段。
4. review中每个人都是平等的,没有谁服从谁的概念。每个参与review的人要有包容的心态,不是只有你的解决办法是最优的
5. 得有一个公认的代码标准,最好能持续维护一个知识库,将一些优秀的代码、历史的review经验积累起来。
6. review要经常化,每次review的量要小,最好完成一个功能就review它。一次review一整个项目任谁都会烦。
7. 提交代码的时候要写清楚,也要有点必要的注释或文档,不要让别人去猜,浪费大家时间。
一、常见误区
1. 在我经历过的很多团队中,貌似不少人员都认为code review是一种上级的管理手段。毕竟翻译成中文叫“代码评审
”,这又评又审的,很多人就已经开始心里打鼓了,这嘴上不说,心底里早就开始抵触上了。这种情绪下还能指望即时
的review么?
2. code review不能算是考核工具,很多管理者都会有review出一个问题,扣多少多少类似的想法,把review简简单单
的当成了抓虫子,从而造成了更多的开发人员的抵触。一review就变味成了给开发挑刺,然后升级成双方攻防战,搞得
面红耳赤,你死我活的,最后一拍两散。
3. code review也不是个人技术挑战赛,这在很多年轻气盛的开发人员中很常见,“凭什么给他看”,“他又看不懂”
是这类人经常会说的话。其实从来没有人规定过review一定要找更厉害的人,一定要找出问题来的。
4. review是每一个团队成员的事,而不仅仅是经理或者架构师的事。这在传统的开发团队里面很常见,代码开发完了
一丢,就没自己啥事了。在敏捷开发中,review应该是每一个成员自发的行为。
二、一点想法
1. 整个团队必须保持一个开放的心态,能够虚心听取他人意见,战斗的团队是指对外战斗,不是内斗。
2. 必须建立一个前提认识:代码共享,团队中每个人都能随时浏览他人最新代码。代码不是私人物品,不能敝帚自珍。
3. 明确一个观点:任何review都不是挑错,是一种相互探讨,追求更高质量,更优代码的过程,是团队共同进步的一种手段。
4. review中每个人都是平等的,没有谁服从谁的概念。每个参与review的人要有包容的心态,不是只有你的解决办法是最优的
5. 得有一个公认的代码标准,最好能持续维护一个知识库,将一些优秀的代码、历史的review经验积累起来。
6. review要经常化,每次review的量要小,最好完成一个功能就review它。一次review一整个项目任谁都会烦。
7. 提交代码的时候要写清楚,也要有点必要的注释或文档,不要让别人去猜,浪费大家时间。
Tuesday, August 2, 2011
Pyramid 学习笔记:创建Pyramid项目(下)
除了在项目根目录生成了一系列项目配置性文件之外,Pyramid还生成了一个简单的项目框架结构以方便开发人员编写代码。这些文件统一放在了myproject这个目录下面。
一、__init__.py文件
该文件主要定义了项目入口方法。主要代码如下:
这个main函数是Pyramid自动生成的本项目的入口,这里global_config, settings两个参数分别对应于development.ini(或production.ini)中的DEFAULT段和app:myproject段的内容。本函数主要功能就是完成了使用traversal机制进行URL映射的配置过程。traversal机制是受zope启发而来的一种URL映射机制,可以构建比较复杂的URL结构。如果URL结构比较简单的化,可以使用ROUTE机制,比较直观一点。
该函数最后返回一个WSGI应用以启动本应用。
二、view.py文件
Pyramid应用中的大部分实现都是在view中实现的,这个可以看作pylons中的controller。在我们生成的项目中,view.py只有一个简单的函数:
def my_view(request):
return {'project':'myproject'}
在前面提到的__init__.py中,我们通过add_view函数注册到了系统中。因此运行这个应用之后,直接浏览 / 看到的就是调用了这个函数而返回的结果(经模板渲染之后)。
三、resources.py文件
这个文件就是用于traversal机制来映射URL时提供站点结构等资源的文件。我们通常用一个Root类来表示这些资源的根。每次接到WEB请求的时候,Pyramid Router通过这个类来找到本项目资源树的根。
四、静态文件目录
主要包含CSS、图片等静态文件
五、模板目录
存放项目开发用的模板文件。这也是在__init__.py中被add_view注册到系统中,并且与一个view关联。
六、test.py
这就是单元测试文件。
Pyramid生成的这个项目框架其实是很简单的一个结构,基本上是无法满足我们项目开发的需要的,一般我们都会修修改改再在项目中使用,也可以修改后生成一套scaffold以便今后重复利用。
一般情况下,我们都会做如下修改:
* view包,以及多层的包结构,如果应用比较复杂的话。
* 单元测试包结构
* URL映射如果复杂的化最好也能独立出来
* lib包,如果需要的话
* model包,如果有数据库支持的话
总体感觉,Pyramid生成的代码在项目代码结构的指导意义上不如pylons,也没Pylons那么严谨周全,要动的东西很多,需要抽个时间好好整理一个能用的东西出来。
本文提到的示例材料均源于Pyramid官方网站
一、__init__.py文件
该文件主要定义了项目入口方法。主要代码如下:
def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ config = Configurator(root_factory=Root, settings=settings) config.add_view(’myproject.views.my_view’, context=’myproject.resources.Root’, renderer=’myproject:templates/mytemplate.pt’) config.add_static_view(’static’, ’myproject:static’) return config.make_wsgi_app()
这个main函数是Pyramid自动生成的本项目的入口,这里global_config, settings两个参数分别对应于development.ini(或production.ini)中的DEFAULT段和app:myproject段的内容。本函数主要功能就是完成了使用traversal机制进行URL映射的配置过程。traversal机制是受zope启发而来的一种URL映射机制,可以构建比较复杂的URL结构。如果URL结构比较简单的化,可以使用ROUTE机制,比较直观一点。
该函数最后返回一个WSGI应用以启动本应用。
二、view.py文件
Pyramid应用中的大部分实现都是在view中实现的,这个可以看作pylons中的controller。在我们生成的项目中,view.py只有一个简单的函数:
def my_view(request):
return {'project':'myproject'}
在前面提到的__init__.py中,我们通过add_view函数注册到了系统中。因此运行这个应用之后,直接浏览 / 看到的就是调用了这个函数而返回的结果(经模板渲染之后)。
三、resources.py文件
这个文件就是用于traversal机制来映射URL时提供站点结构等资源的文件。我们通常用一个Root类来表示这些资源的根。每次接到WEB请求的时候,Pyramid Router通过这个类来找到本项目资源树的根。
四、静态文件目录
主要包含CSS、图片等静态文件
五、模板目录
存放项目开发用的模板文件。这也是在__init__.py中被add_view注册到系统中,并且与一个view关联。
六、test.py
这就是单元测试文件。
Pyramid生成的这个项目框架其实是很简单的一个结构,基本上是无法满足我们项目开发的需要的,一般我们都会修修改改再在项目中使用,也可以修改后生成一套scaffold以便今后重复利用。
一般情况下,我们都会做如下修改:
* view包,以及多层的包结构,如果应用比较复杂的话。
* 单元测试包结构
* URL映射如果复杂的化最好也能独立出来
* lib包,如果需要的话
* model包,如果有数据库支持的话
总体感觉,Pyramid生成的代码在项目代码结构的指导意义上不如pylons,也没Pylons那么严谨周全,要动的东西很多,需要抽个时间好好整理一个能用的东西出来。
本文提到的示例材料均源于Pyramid官方网站
Subscribe to:
Posts (Atom)