孤独750 发表于 2015-12-1 14:53:57

Python Paste.deploy 笔记

  首先python paste是一个WSGI工具包,在WSGI的基础上包装了几层,让应用管理和实现变得方便。说实话,Python Paste的文档做的真差劲!加之python代码可读性本来就不怎么滴,真费劲。
  
  paste.deploy关键部分留个抓印:
  1)python paste.deploy不能只装个paste.deploy包就可以工作了,还需要paste.script包
  2)python paste.deploy中loadapp给的路径可用os.path.abspath(配置文件相对路径)得到配置文件的绝对路径,否则报找不到relative_to path...没搞明白怎么回事,目前不重要,放过。
  3)python paste.deploy中filter,filter_factory,app,app_factory的规范在文档中都没怎么写清楚,我来给你补上吧:
  - app是一个callable object,接受的参数(environ,start_response),这是paste系统交给application的,符合
  WSGI规范的参数. app需要完成的任务是响应envrion中的请求,准备好响应头和消息体,然后交给start_response处理,并返回响应消息体。
  - filter是一个callable object,其唯一参数是(app),这是WSGI的application对象,见(1),filter需要完成的工作是将application包 装成另一个application(“过滤”),并返回这个包装后的application。
  - 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对象
  - filter_factory是一个callable object,其接受的参数是一系列关于filter的配置信息:(global_conf,**kwargs),global_conf是在ini文件 中default section中定义的一系列key-value对,而**kwargs,即一些本地配置,是在ini文件中,filter:xxx section中定 义的一系列key-value对。filter_factory返回一个filter对象
  
  给个例子:
  pastedeploylab.ini:



1   
2   key1=value1
3   key2=value2
4   key3=values
5   
6   use=egg:Paste#urlmap
7   /:root
8   /calc:calc
9   
10   pipeline = logrequest showversion
11   
12   pipeline = logrequest calculator
13   
14   username = root
15   password = root123
16   paste.filter_factory = pastedeploylab:LogFilter.factory
17   
18   version = 1.0.0
19   paste.app_factory = pastedeploylab:ShowVersion.factory
20   
21   description = This is an "+-*/" Calculator   
22   paste.app_factory = pastedeploylab:Calculator.factory
  
  pastedeploylab.py



1 Created on 2011-6-12
2 @author: Sonic
3 '''
4 import os
5 import webob
6 from webob import Request
7 from webob import Response
8 from paste.deploy import loadapp
9 from wsgiref.simple_server import make_server
10 #Filter
11 class LogFilter():
12   def __init__(self,app):
13         self.app = app
14         pass
15   def __call__(self,environ,start_response):
16         print "filter:LogFilter is called."
17         return self.app(environ,start_response)
18   @classmethod
19   def factory(cls, global_conf, **kwargs):
20         print "in LogFilter.factory", global_conf, kwargs
21         return LogFilter
22 class ShowVersion():
23   def __init__(self):
24         pass
25   def __call__(self,environ,start_response):
26         start_response("200 OK",[("Content-type", "text/plain")])
27         return ["Paste Deploy LAB: Version = 1.0.0",]
28   @classmethod
29   def factory(cls,global_conf,**kwargs):
30         print "in ShowVersion.factory", global_conf, kwargs
31         return ShowVersion()
32 class Calculator():
33   def __init__(self):
34         pass
35      
36   def __call__(self,environ,start_response):
37         req = Request(environ)
38         res = Response()
39         res.status = "200 OK"
40         res.content_type = "text/plain"
41         # get operands
42         operator = req.GET.get("operator", None)
43         operand1 = req.GET.get("operand1", None)
44         operand2 = req.GET.get("operand2", None)
45         print req.GET
46         opnd1 = int(operand1)
47         opnd2 = int(operand2)
48         if operator == u'plus':
49             opnd1 = opnd1 + opnd2
50         elif operator == u'minus':
51             opnd1 = opnd1 - opnd2
52         elif operator == u'star':
53             opnd1 = opnd1 * opnd2
54         elif operator == u'slash':
55             opnd1 = opnd1 / opnd2
56         res.body = "%s /nRESULT= %d" % (str(req.GET) , opnd1)
57         return res(environ,start_response)
58   @classmethod
59   def factory(cls,global_conf,**kwargs):
60         print "in Calculator.factory", global_conf, kwargs
61         return Calculator()
62 if __name__ == '__main__':
63   configfile="pastedeploylab.ini"
64   appname="pdl"
65   wsgi_app = loadapp("config:%s" % os.path.abspath(configfile), appname)
66   server = make_server('localhost',8080,wsgi_app)
67   server.serve_forever()
68   pass
  
  使用:
  http://127.0.0.1:8080/
  输出:

Paste Deploy LAB: Version = 1.0.0
  http://127.0.0.1:8080/calc?operator=plus&operand1=12&operand2=23
  输出:
  UnicodeMultiDict([('operator', u'plus'), ('operand1', u'12'), ('operand2', u'23')])

RESULT= 35

====================================================

进一步猜测filter的使用过程:在paste deploy库中应该有类似这样的一段代码对application进行重组包装:

#

# 假设在ini文件中, 某条pipeline的顺序是filter1, filter2, filter3

# app, 那么,最终运行的app_real是这样组织的:

#

app_real = filter1(filter2(filter3(app)))
# 在app真正被调用的过程中,filter1.__call__(environ,start_response)被首先调用,若某种检查未通过,filter1做出反应;否则交给filter2__call__(environ,start_response)
进一步处理,若某种检查未通过,filter2做出反应,中断链条,否则交给filter3.__call__(environ,start_response)处理,若filter3的某种检查都通过了,最后交给
app.__call__(environ,start_response)进行处理。
页: [1]
查看完整版本: Python Paste.deploy 笔记