—paste STRING, —paster STRING

https://www.liaoxuefeng.com/wiki/897692888725344/923057027806560 WSGI接口
详解例说Paste模块(PasteDeploy) paste module https://blog.csdn.net/li_101357/article/details/52755367

花了两个星期,我终于把 WSGI 整明白了全面 https://www.sohu.com/a/323444264_671965

https://blog.csdn.net/hzrandd/article/details/10834381

python 中paste.ini文件使用说明

Python.Paste指南之Deploy

http://tumblr.wachang.net/post/38130547044/python-paste-deploy-1
Paste.Deploy主要是用来载入WSGI中的Web App使用,其核心函数是loadapp(),下文中PD就指代Paste.Deploy。

OS:Ubuntu12.04 2012年11月17日 第一版 主要是对官方文档的一个翻译,外加自己的一些理解 本文的Paste.Deploy使用主要是针对WSGI

1 简介及安装

Paste Deployment是一种机制,通过loadapp函数和一个配置文件或者egg包来载入WSGI应用。安装很简单,如下两种方式:

  1. $ sudo pip install PasteDeploy

或者可以从github上进行源码安装

  1. 1. $ hg clone http://bitbucket.org/ianb/pastedeploy
  2. 2. $ cd pastedeploy
  3. 3. $ sudo python setup.py develop

2 配置文件Config Flie

一个配置文件后缀为ini,内容被分为很多段(section),PD只关心带有前缀的段,比如[app:main]或者[filter:errors],总的来说,一个section的标识就是[type:name],不是这种类型的section将会被忽略。
一个section的内容是以键=值来标示的。#是一个注释。在段的定义中,有以下几类:

  • [app:main]:定义WSGI应用,main表示只有一个应用,有多个应用的话main改为应用名字
  • [server:main]:定义WSGI的一个server。
  • [composite:xxx]:表示需要将一个请求调度定向(dispatched)到多个,或者多种应用上。以下是一个简单的例子,例子中,使用了composite,通过urlmap来实现载入多应用。
  • [fliter:]:定义“过滤器”,将应用进行进一步的封装。
  • [DEFAULT]:定义一些默认变量的值。

以下是一个例子:

  1. 1. [composite:main]
  2. 2. use = egg:Paste#urlmap
  3. 3. / = home
  4. 4. /blog = blog
  5. 5. /wiki = wiki
  6. 6. /cms = config:cms.ini
  7. 7.
  8. 8. [app:home]
  9. 9. use = egg:Paste#static
  10. 10. document_root = %(here)s/htdocs
  11. 11.
  12. 12. [filter-app:blog]
  13. 13. use = egg:Authentication#auth
  14. 14. next = blogapp
  15. 15. roles = admin
  16. 16. htpasswd = /home/me/users.htpasswd
  17. 17.
  18. 18. [app:blogapp]
  19. 19. use = egg:BlogApp
  20. 20. database = sqlite:/home/me/blog.db
  21. 21.
  22. 22. [app:wiki]
  23. 23. use = call:mywiki.main:application
  24. 24. database = sqlite:/home/me/wiki.db

下面会进行分段的讲解

2.1 composite

  1. 1. [composite:main]
  2. 2. use = egg:Paste#urlmap
  3. 3. / = home
  4. 4. /blog = blog
  5. 5. /wiki = wiki
  6. 6. /cms = config:cms.ini

这是一个composite段,表示这将会根据一些条件将web请求调度到不同的应用。use = egg:Paste#urlmap表示我们奖使用Pasteegg包中urlmap来实现composite,这一个段(urlmap)可以算是一个通用的composite程序了。根据web请求的path的前缀进行一个到应用的映射(map)。这些被映射的程序就包括blog,home,wiki,config:cms.ini(映射到了另外一个配置文件,PD再根据这个文件进行载入)

2.2 App type1

  1. 1. [app:home]
  2. 2. use = egg:Paste#static
  3. 3. document_root = %(here)s/htdocs

app是一个callable object,接受的参数(environ,start_response),这是paste系统交给application的,符合WSGI规范的参数. app需要完成的任务是响应envrion中的请求,准备好响应头和消息体,然后交给start_response处理,并返回响应消息体。egg:Paste#static也是Paste包中的一个简单程序,它只处理静态文件。它需要一个配置文件document_root,后面的值可以是一个变量,形式为%(var)s相应的值应该在[DEFAULT]字段指明以便Paste读取。比如:

  1. 1. [app:test]
  2. 2. use = egg:Paste#static
  3. 3. document_root = %(path)s/htdocs
  4. 4. [DEFAULT]
  5. 5. path = /etc/test

2.3 fliter

filter是一个callable object,其唯一参数是(app),这是WSGI的application对象,filter需要完成的工作是将application包装成另一个application(“过滤”),并返回这个包装后的application。

  1. 1. [filter-app:blog]
  2. 2. use = egg:Authentication#auth
  3. 3. next = blogapp
  4. 4. roles = admin
  5. 5. htpasswd = /home/me/users.htpasswd
  6. 6.
  7. 7. [app:blogapp]
  8. 8. use = egg:BlogApp
  9. 9. database = sqlite:/home/me/blog.db

[filter-app:blog]fliter-app字段表明你希望对某个应用进行包装,需要包装的应用通过next指明(表明在下一个段中),这个字段的意思就是,在正式调用blogapp之前,我会调用egg:Authentication#auth进行一个用户的验证,随后才会调用blogapp进行处理。后面的[app:blogapp]则是定义了blogapp,并指明了需要的database参数。

2.4 App type2

  1. 1. [app:wiki]
  2. 2. use = call:mywiki.main:application
  3. 3. database = sqlite:/home/me/wiki.db

这个段和之前的app段定义类似,不同的是对于wiki这个应用,我们没有使用egg包,而是直接对mywiki.main这个模块中的application对象使用了call方法。python,中一切皆对象,作为WSGI app的可以是一个函数,一个类,或者一个实例,使用call的话,相应的函数,类,实例中必须实现call()方法。此类app的格式用冒号分割: call(表示使用call方法):模块的完成路径名字:应用变量的完整名字

3 基本使用

PD的主要使用就是通过读取配置文件载入WSGI应用。如下:

  1. 1. from paste.deploy import loadapp
  2. 2. wsgi_app = loadapp('config:/path/to/config.ini')

注意,这里需要指明绝对路径。

4 更多关于配置文件

4.1 App

单个配置文件中可以定义多个应用个,每个应用有自己独立的段。应用的定义以[app:name]的格式,[app:main]表示只有一个应用。应用的定义支持以下五种格式:

  1. 1. [app:myapp]
  2. 2. use = config:another_config_file.ini#app_name
  3. 3. #使用另外一个配置文件
  4. 4.
  5. 5. [app:myotherapp]
  6. 6. use = egg:MyApp
  7. 7. #使用egg包中的内容
  8. 8.
  9. 9. [app:mythirdapp]
  10. 10. use = call:my.project:myapplication
  11. 11. #使用模块中的callable对象
  12. 12.
  13. 13. [app:mylastapp]
  14. 14. use = myotherapp
  15. 15. #使用另外一个section
  16. 16.
  17. 17. [app:myfacapp]
  18. 18. paste.app_factory = myapp.modulename:app_factory
  19. 19. #使用工厂函数

其中,最后一种方式,将一个app指向了某些python代码。此模式下,必须执行app协议,以app_factory表示,后面的值需要import的东西,在这个例子中myapp.modulename被载入,并从其中取得了app_factory的实例。
app_factory是一个callable object,其接受的参数是一些关于application的配置信息:(global_conf,**kwargs)global_conf是在ini文件中default section中定义的一系列key-value对,而**kwargs,即一些本地配置,是在ini文件中,app:xxx section中定义的一系列key-value对。app_factory返回值是一个application对象
在app的配置中,use参数以后配置就算结束了。其余的键值参数将会作为参数,传递到factory中,如下:

  1. 1. [app:blog]
  2. 2. use = egg:MyBlog
  3. 3. database = mysql://localhost/blogdb #这是参数
  4. 4. blogname = This Is My Blog! #这是参数

4.2 全局配置

全局配置主要是用于多个应用共用一些变量,这些变量我们规定放在段[DEFAULT]中,如果需要覆盖,可以在自己的app中重新定义,如下:

  1. 1. [DEFAULT]
  2. 2. admin_email = webmaster@example.com
  3. 3. [app:main]
  4. 4. use = ...
  5. 5. set admin_email = bob@example.com

4.3 composite app

composite是一个运行着像是app,但是实际上是由多个应用组成的。urlmap就是composite app的一个例子,url不同的path对应了不同的应用。如下:

  1. 1. [composite:main]
  2. 2. use = egg:Paste#urlmap
  3. 3. / = mainapp
  4. 4. /files = staticapp
  5. 5.
  6. 6. [app:mainapp]
  7. 7. use = egg:MyApp
  8. 8.
  9. 9. [app:staticapp]
  10. 10. use = egg:Paste#static
  11. 11. document_root = /path/to/docroot

在loadapp函数的执行中,composite app被实例化,它同时还会访问配置文件中定义的其他应用。

4.4 app定义高级用法

在app段中,你可以定义fliters和servers,通过fliter:server: PD通过loadserver和loadfilter函数进行调用,工作机制都一样,返回不同的对象。

4.4.1 filter composition

应用filter的方式很多,重要的是看你filter的数量和组织形式。下面会一一介绍应用fliter的几种方式:
1.使用filter-with

  1. 1. [app:main]
  2. 2. use = egg:MyEgg
  3. 3. filter-with = printdebug
  4. 4.
  5. 5. [filter:printdebug]
  6. 6. use = egg:Paste#printdebug
  7. 7. # and you could have another filter-with here, and so on...

2.使用fliter-app

  1. 1. [fliter-app:printdebug]
  2. 2. use = egg:Paste
  3. 3. next = main
  4. 4.
  5. 5. [app:main]
  6. 6. use = egg:MyEgg

3.使用pipeline
当使用多个filter的时候需要使用pipeline的方式,它需要提供一个key参数pipeline,后面的值是一个列表,最后以应用结尾。如下:

  1. 1. [pipeline:main]
  2. 2. pipeline = filter1 egg:FilterEgg#filter2 filter3 app
  3. 3.
  4. 4. [filter:filter1]
  5. 5. ...

假设在ini文件中, 某条pipeline的顺序是filter1, filter2, filter3,app, 那么,最终运行的appreal是这样组织的: appreal = filter1(filter2(filter3(app)))
在app真正被调用的过程中,filter1.call(environ,startresponse)被首先调用,若某种检查未通过,filter1做出反应;否则交给filter2.call(environ,startresponse)进一步处理,若某种检查未通过,filter2做出反应,中断链条,否则交给filter3.__call(environ,start_response)处理,若filter3的某种检查都通过了,最后交给app.__call
(environ,start_response)进行处理。

4.5 读取配置文件

如果希望在不创建应用的情况下得到配置文件,可以使用appconfig(uri)函数,将会以字典形式返回使用的配置。这个字典包括了全局很本地的配置信息,所以可以通过属性方法获得相应的attributes (.local_conf and .global_conf)

5 其他

5.1 如何引用Egg包

egg是python的一个包,pip easy_install等都是安装egg包的方式。关注egg包要注意: +某一egg包是有标准说明的
python setup.py name +有entry point,不用太在意,这个只是说明调用程序的参数。

5.2 定义factory函数

工厂函数的定义还是遵循之前提到的应用的协议。目前,用于工厂函数的协议有以下:
paste.app_factory
paste.compositefactory
paste.filter_factory
paste.serverfactory
所有的这些都希望有一个含有__call
方法的(函数,方法,类)。
1.paste.app_factory

  1. 1. def app_factory(global_config, **local_conf):
  2. 2. return wsgi_app

global_config是一个字典,而local_conf则是关键字参数。返回一个wsgi_app(含有call方法。)
2.paste.composite_factory`

  1. 1. def composite_factory(loader, global_config, **local_conf):
  2. 2. return wsgi_app

loader是一个对象,有几个有趣的方法,get_app(name_or_uri, global_conf=None)根据name返回一个wsgi应用,get_filter()和get_server()也是一样。看一个更加复杂的例子,举例一个pipeline应用:

  1. 1. def pipeline_factory(loader, global_config, pipeline):
  2. 2. # space-separated list of filter and app names:
  3. 3. pipeline = pipeline.split()
  4. 4. filters = [loader.get_filter(n) for n in pipeline[:-1]]
  5. 5. app = loader.get_app(pipeline[-1])
  6. 6. filters.reverse() # apply in reverse order!
  7. 7. for filter in filters:
  8. 8. app = filter(app)
  9. 9. return app

相应的配置文件如下:

  1. 1. [composite:main]
  2. 2. use = <pipeline_factory_uri>
  3. 3. pipeline = egg:Paste#printdebug session myapp
  4. 4.
  5. 5. [filter:session]
  6. 6. use = egg:Paste#session
  7. 7. store = memory
  8. 8.
  9. 9. [app:myapp]
  10. 10. use = egg:MyApp

3.paste.filter_factory fliter的工厂函数和app的共产函数类似,除了它返回的是一个filter,fliter是一个仅仅把一个wsgi应用作为唯一参数的callable对象,返回一个被filter了的应用。 以下是一个例子,这个filter会检查CGI中REMOTE_USER变量是否存在,并创建一个简单的认证过滤器。

  1. 1. def auth_filter_factory(global_conf, req_usernames):
  2. 2. # space-separated list of usernames:
  3. 3. req_usernames = req_usernames.split()
  4. 4. def filter(app):
  5. 5. return AuthFilter(app, req_usernames)
  6. 6. return filter
  7. 7.
  8. 8. class AuthFilter(object):
  9. 9. def __init__(self, app, req_usernames):
  10. 10. self.app = app
  11. 11. self.req_usernames = req_usernames
  12. 12.
  13. 13. def __call__(self, environ, start_response):
  14. 14. if environ.get('REMOTE_USER') in self.req_usernames:
  15. 15. return self.app(environ, start_response)
  16. 16. start_response(
  17. 17. '403 Forbidden', [('Content-type', 'text/html')])
  18. 18. return ['You are forbidden to view this resource']

4.paste.filter_app_factory 和paste.filter_factory类似,接受一个wsgi应用参数,返回一个WSGI应用,所以如果改变以上代码的:

  1. 1. class AuthFilter(object):
  2. 2. def __init__(self, app, global_conf, req_usernames):
  3. 3. ....

那么,类 AuthFilter就会作为一个filter_app_factory函数使用。
5.paste.server_factory
与以上不同的是,函数返回的是一个server,一个server也是一个callable对象,以一个WSGI应用作为参数,而后为这个应用服务。

  1. 1. def server_factory(global_conf, host, port):
  2. 2. port = int(port)
  3. 3. def serve(app):
  4. 4. s = Server(app, host=host, port=port)
  5. 5. s.serve_forever()
  6. 6. return serve

Server的实现用户可以自定义,可以参考python包wsgiref
6.paste.server_runner 与 paste.server_factory类似,不同的是参数格式。

6 其他一些值得讨论的问题

ConfigParser(PD底层用到这个来解析ini文件)解析ini文件不是很有效率,是否需要更改?
在配置文件中的对象是否需要是python风格的,而不是字符串的形式?

Paste Deployment currently does not require other parts of Paste, and is distributed as a separate package.

上一节中梳理了Python Paste中Deploy机制的概念,这一节就做一点小小的实践。首先,我们举一个使用了Deploy的例子,这个就是OpenStack的Quantum组件的WSGI部分。我们先来看关于WSGI部分的配置文件,以ini后缀,那么就是api-paste.ini文件,决定了API的处理流程。我加入了适当的注释。

1 OpenStack Quantum配置文件api-paste.ini

  1. 1. [composite:quantum]
  2. 2. use = egg:Paste#urlmap
  3. 3. /: quantumversions
  4. 4. /v2.0: quantumapi_v2_0
  5. 5. #使用composite分解机制,composite使用了usrlmap,xxxxx/xxx的API交给quantumversions处理。xxxx/v2.0/xxxx的API交给quantumapi_v2_0处理。
  6. 6.
  7. 7. [composite:quantumapi_v2_0]
  8. 8. use = call:quantum.auth:pipeline_factory
  9. 9. noauth = extensions quantumapiapp_v2_0
  10. 10. keystone = authtoken keystonecontext extensions quantumapiapp_v2_0
  11. 11. #quantumapi_v2_0依然是一个分解组件,使用了quantum.auth模块下的pipeline_factory,对于这个factory,传递了两个参数,一个是noauth,一个是keystone。
  12. 12.
  13. 13. [filter:keystonecontext]
  14. 14. paste.filter_factory = quantum.auth:QuantumKeystoneContext.factory
  15. 15. #对于keystonecontext,实际上是一个过滤器,使用了quantum.auth模块下的类的QuantumKeystoneContext的factory函数
  16. 16.
  17. 17. [filter:authtoken]
  18. 18. paste.filter_factory = keystone.middleware.auth_token:filter_factory
  19. 19. auth_host = 127.0.0.1
  20. 20. auth_port = 35357
  21. 21. auth_protocol = http
  22. 22. admin_tenant_name = %SERVICE_TENANT_NAME%
  23. 23. admin_user = %SERVICE_USER%
  24. 24. admin_password = %SERVICE_PASSWORD%
  25. 25. #定义了另外一个filter
  26. 26.
  27. 27. [filter:extensions]
  28. 28. paste.filter_factory = quantum.extensions.extensions:plugin_aware_extension_middleware_factory
  29. 29. #定义了另外一个filter,这个filter是为了支持扩展quantum api的
  30. 30.
  31. 31. [app:quantumversions]
  32. 32. paste.app_factory = quantum.api.versions:Versions.factory
  33. 33. #核心的app部分,使用工厂函数,将app指向python代码。app_factory表明这个函数接收一系列参数,[DEFAULET]以及[app:]下面的,本部分本section没有参数,并返回一个函数对象。
  34. 34.
  35. 35. [app:quantumapiapp_v2_0]
  36. 36. paste.app_factory = quantum.api.v2.router:APIRouter.factory
  37. 37. #同上

我们来总结一下,整个Quantum处理api的流程如下,其中,强调的部分为函数代码,其他为配置文件中的section部分。 对于路径为/类的API——quantumversions处理——调用quantum.api.versions:Version类的factory函数处理。 对于路径为/2.0类的API——quantumapi_v2_0处理——调用quantum.auth中的pipeline_factory处理,同时传递了两个参数noauth和keystone,类型为字典。 这个pipeline_factory中会读取另外一个变量CONF.auth(来自另外一个配置文件,不考虑),选择采用的认证方式,然后选择noauth或者keystone,并读取参数的值。 那么,就有两种情况: noauth: 应用将会先经过extensions这个filter处理——调用了quantum.extensions.extensions:plugin_aware_extension_middleware_factory,用来处理扩展api请求,这是第一次包装——quantumapiapp_v2_0,这才是实际的WSGI应用,调用了quantum.api.v2.router:APIRouter.factory,并处理返回结果。 keystone:和上面类似,不同的是多了几个filter,authtoken keystonecontext extensions quantumapiapp_v2_0,并且在每个filter中可能还会有参数传递给这个fliter。 总的来说,通过pipeline装载多个filter,将最基本的app—APIRouter,层层包装,使其变为一个具有处理认证,扩展API等的应用(逻辑上看),filter的好处就是可以自定义,比如可以不要认证功能,这比写一个囊括全部功能的应用明显要好的多。

2 代码实践

2.1 配置文件

  1. 1. [DEFAULT]
  2. 2. company = UESTC
  3. 3. school = Commuication and Information
  4. 4.
  5. 5. [composite:common]
  6. 6. use = egg:Paste#urlmap
  7. 7. /:showversion
  8. 8. /detail:showdetail
  9. 9.
  10. 10. [pipeline:showdetail]
  11. 11. pipeline = filter1 filter2 showstudetail
  12. 12.
  13. 13. [filter:filter1]
  14. 14. #filter1 deal with auth,read args below
  15. 15. paste.filter_factory = python_paste:AuthFilter.factory
  16. 16. user = admin
  17. 17. passwd = admin
  18. 18.
  19. 19. [filter:filter2]
  20. 20. #filter2 deal with time,read args below
  21. 21. paste.filter_factory = python_paste:LogFilter.factory
  22. 22. #all value is string
  23. 23. date = 20121120
  24. 24.
  25. 25. [app:showstudetail]
  26. 26. name = wangchang
  27. 27. age = 23
  28. 28. paste.app_factory = python_paste:ShowStuDetail.factory
  29. 29.
  30. 30. [app:showversion]
  31. 31. version = 1.0.0

从配置文件可以看出,这个程序会有如下操作: *对于http://localhost/的访问,会调用showversion这个应用,应用读取ini文件中的version值并返回。__注意,在ini中的所有值都是字符串。 对于http://localhost/detail的访问,会先经过filter1以及filter2,这两个filter分别处理认证和LOG信息,他们会读取ini配置中的用户信息以及时间。最后才是交给showstudetail处理,showstudetail会读取ini中的用户信息并返回。__注意,使用多个filter的时候需要使用pipeline方式。

2.2 代码

  1. 1. import sys
  2. 2. import os
  3. 3. import webob
  4. 4. from webob import Request
  5. 5. from webob import Response
  6. 6. #from webob import environ
  7. 7. from paste.deploy import loadapp
  8. 8. from wsgiref.simple_server import make_server
  9. 9. from pprint import pprint
  10. 10.
  11. 11.
  12. 12. class AuthFilter(object):
  13. 13. '''filter1,auth
  14. 14. 1.factory read args and print,return self instance
  15. 15. 2.call method return app
  16. 16. 3.AuthFilter(app)
  17. 17. '''
  18. 18. def __init__(self,app):
  19. 19. self.app = app
  20. 20.
  21. 21. def __call__(self,environ,start_response):
  22. 22. print 'this is Auth call filter1'
  23. 23. #pass environ and start_response to app
  24. 24. return self.app(environ,start_response)
  25. 25. @classmethod
  26. 26. def factory(cls,global_conf,**kwargs):
  27. 27. '''global_conf and kwargs are dict'''
  28. 28. print '######filter1##########'
  29. 29. print 'global_conf type:',type(global_conf)
  30. 30. print '[DEFAULT]',global_conf
  31. 31. print 'kwargs type:',type(kwargs)
  32. 32. print 'Auth Info',kwargs
  33. 33. return AuthFilter
  34. 34.
  35. 35. class LogFilter(object):
  36. 36. '''
  37. 37. filter2,Log
  38. 38. '''
  39. 39. def __init__(self,app):
  40. 40. self.app = app
  41. 41. def __call__(self,environ,start_response):
  42. 42. print 'This is call LogFilter filter2'
  43. 43. return self.app(environ,start_response)
  44. 44. @classmethod
  45. 45. def factory(cls,global_conf,**kwargs):
  46. 46. #print type(global_conf)
  47. 47. #print type(kwargs)
  48. 48. print '######filter2###########'
  49. 49. print '[DEFAULT]',global_conf
  50. 50. print 'Log Info',kwargs
  51. 51. return LogFilter
  52. 52.
  53. 53. class ShowStuDetail(object):
  54. 54. '''
  55. 55. app
  56. 56. '''
  57. 57. def __init__(self,name,age):
  58. 58. self.name = name
  59. 59. self.age = age
  60. 60. def __call__(self,environ,start_response):
  61. 61. print 'this is call ShowStuDetail'
  62. 62. #pprint(environ)
  63. 63. #pprint environ
  64. 64. start_response("200 OK",[("Content-type","text/plain")])
  65. 65. content = []
  66. 66. content.append("name: %s age:%s\n" % (self.name,self.age))
  67. 67. content.append("**********WSGI INFO***********\n")
  68. 68. for k,v in environ.iteritems():
  69. 69. content.append('%s:%s \n' % (k,v))
  70. 70. return ['\n'.join(content)] #return a list
  71. 71.
  72. 72. @classmethod
  73. 73. def factory(cls,global_conf,**kwargs):
  74. 74. #self.name = kwargs['name']
  75. 75. #self.age = kwargs['age']
  76. 76. return ShowStuDetail(kwargs['name'],kwargs['age'])
  77. 77.
  78. 78. class ShowVersion(object):
  79. 79. '''
  80. 80. app
  81. 81. '''
  82. 82. def __init__(self,version):
  83. 83. self.version = version
  84. 84. def __call__(self,environ,start_response):
  85. 85. print 'this is call ShowVersion'
  86. 86. req = Request(environ)
  87. 87. res = Response()
  88. 88. res.status = '200 OK'
  89. 89. res.content_type = "text/plain"
  90. 90. content = []
  91. 91. #pprint(req.environ)
  92. 92. content.append("%s\n" % self.version)
  93. 93. content.append("*********WSGI INFO*********")
  94. 94. for k,v in environ.iteritems():
  95. 95. content.append('%s:%s\n' % (k,v))
  96. 96. res.body = '\n'.join(content)
  97. 97. return res(environ,start_response)
  98. 98. @classmethod
  99. 99. def factory(cls,global_conf,**kwargs):
  100. 100. #self.version = kwargs['version']
  101. 101. return ShowVersion(kwargs['version'])
  102. 102.
  103. 103. if __name__ == '__main__':
  104. 104. config = "python_paste.ini"
  105. 105. appname = "common"
  106. 106. wsgi_app = loadapp("config:%s" % os.path.abspath(config), appname)
  107. 107. server = make_server('localhost',7070,wsgi_app)
  108. 108. server.serve_forever()
  109. 109. pass

在程序中,对于web请求的处理,我分别采用了webob和普通WSGI定义的方式,后续我会补上webob的使用。

2.3 结果

先从服务端结果分析一下调用流程:

  1. 1. Ubuntu:~/python$ python python_paste.py
  2. 2. ######filter1##########
  3. 3. global_conf type: <type 'dict'>
  4. 4. [DEFAULT] {'school': 'Commuication and Information', 'company': 'UESTC', 'here': '/home/wachang/python', '__file__': '/home/wachang/python/python_paste.ini'}
  5. 5. kwargs type: <type 'dict'>
  6. 6. Auth Info {'passwd': 'admin', 'user': 'admin'}
  7. 7. ######filter2###########
  8. 8. [DEFAULT] {'school': 'Commuication and Information', 'company': 'UESTC', 'here': '/home/wachang/python', '__file__': '/home/wachang/python/python_paste.ini'}
  9. 9. Log Info {'date': '20121120'}
  10. 10. 以上是PD载入应用时,调用filterfactory方法输出的结果,可以看到,此读出了相关的变量信息。
  11. 11.
  12. 12.
  13. 13. this is call ShowVersion
  14. 14. localhost - - [21/Nov/2012 13:23:40] "GET / HTTP/1.1" 200 2938
  15. 15. this is call ShowVersion
  16. 16. localhost - - [21/Nov/2012 13:23:40] "GET /favicon.ico HTTP/1.1" 200 2889
  17. 17. 以上是接收/请求,因为没有使用filter,直接交予showversion应用处理,并返回。
  18. 18.
  19. 19. this is Auth call filter1
  20. 20. This is call LogFilter filter2
  21. 21. this is call ShowStuDetail
  22. 22. localhost - - [21/Nov/2012 13:24:23] "GET /detail HTTP/1.1" 200 3016
  23. 23. this is call ShowVersion
  24. 24. localhost - - [21/Nov/2012 13:24:24] "GET /favicon.ico HTTP/1.1" 200 2889
  25. 25. filter的调用时重点啊,可以看到,调用的顺序和pipeline中一样。最后才调用应用。

需要继续折腾的话,就看看webob:do-it-yourselfrself

http://pythonpaste.org/deploy/#defining-factorieshttp://pythonpaste.org/deploy/ http://pythonpaste.org/script/#paster-servehttp://kevinzheng.sinaapp.com/?p=104http://blog.csdn.net/icycolawater/article/details/7045287