PasteDeploy

PasteDeploy
简介
  PasteDeploy全称是Paste Deployment,原先是Python Paste的一个子项目,现在已经独立出来了。
  PasteDeploy的官网文档位于:Paste Deployment
  PasteDeploy是用来寻找和配置WSGI应用和服务的系统。PasteDeploy给开发者提供了一个简单的函数loadapp。通过这个函数,可以从一个配置文件或者Python egg中加载一个WSGI应用。
  使用PasteDeploy的其中一个重要意义在于,系统管理员可以安装和管理WSGI应用,而无需掌握与Python和WSGI相关知识。

安装和卸载
  可以使用pip工具方便的进行安装和卸载。
  安装:
    # pip install pastedeploy
  卸载:
  pip uninstall pastedeploy
  由于PasteDeploy原来是属于Paste的,现在独立出来了,但是安装的时候还是会安装到paste目录(site-packages\paste\deploy)下。

PasteDeploy的使用
  使用PasteDeploy主要包括下面三步:
    一、配置PasteDeploy使用的ini文件;
    二、定义WSGI应用;
    三、通过loadapp函数加载WSGI应用;

配置PasteDeploy使用的ini文件
  PasteDeploy使用ini格式的文件作为配置文件。
  PasteDeploy的配置文件可以包括多个section。每个section包含一个section name和多个键值对。section name包含两部分:type和name,使用冒号:将两者分隔开来。每个键值对占一行,键名和值使用等号=分隔开,为了便于阅读,等号=前后可以添加空格。
  比较常用的type有两个:
    composite:
      composite的type指的是用来分发请求到其它应用去。其下的键值对use = egg:Paste#urlmap表示使用Paste中的urlmap应用。urlmap是使用路径的前缀来将请求映射到不同的应用去。
    app:
      app的type指的是基本的WSGI应用。通常的用法是paste.app_factory = <模块名>:<类名>.<类方法>。
  以下是一个简单的例子:
[composite:main]
use = egg:Paste#urlmap
/ = home
/blog = blog
/wiki = wiki

[app:home]
paste.app_factory = example:Home.factory

[app:blog]
paste.app_factory = example:Blog.factory

[app:wiki]
paste.app_factory = example:Wiki.factory


定义WSGI应用
实质就是提供符合WSGI规范的可执行对象。
以下是一个简单的例子:
import os
from paste.deploy import loadapp
from wsgiref.simple_server import make_server


class Home(object):
    def __init__(self):
        print("Init Home.")

    def __call__(self, environ, start_response):
        status_code = "200 OK"
        response_headers = [("Content-Type", "text/plain")]
        response_body = "This is Home's response body.".encode('utf-8')

        start_response(status_code, response_headers)
        return [response_body]

    @classmethod
    def factory(cls, global_conf, **kwargs):
        print("Home factory.")
        return Home()

通过loadapp函数加载WSGI应用
  通过loadapp函数可以从配置文件加载相应的WSGI应用。loadapp()函数可以接收两个实参:
    URI:"config:<配置文件的全路径>"
    name:WSGI应用的名称
  以下是一个简单的例子:
configfile = "paste.ini"
application_name = "main"
applications = loadapp("config:%s" % os.path.abspath(configfile), application_name)

完整的例子
文件paste.ini的内容
[composite:main]
use = egg:Paste#urlmap
/ = home
/blog = blog
/wiki = wiki

[app:home]
paste.app_factory = example:Home.factory

[app:blog]
paste.app_factory = example:Blog.factory

[app:wiki]
paste.app_factory = example:Wiki.factory

文件example.py的内容
import os
from paste.deploy import loadapp
from wsgiref.simple_server import make_server


class Home(object):
    def __init__(self):
        print("Init Home.")

    def __call__(self, environ, start_response):
        status_code = "200 OK"
        response_headers = [("Content-Type", "text/plain")]
        response_body = "This is Home's response body.".encode('utf-8')

        start_response(status_code, response_headers)
        return [response_body]

    @classmethod
    def factory(cls, global_conf, **kwargs):
        print("Home factory.")
        return Home()


class Blog(object):
    def __init__(self):
        print("Init Blog.")

    def __call__(self, environ, start_response):
        status_code = "200 OK"
        response_headers = [("Content-Type", "text/plain")]
        response_body = "This is Blog's response body.".encode('utf-8')

        start_response(status_code, response_headers)
        return [response_body]

    @classmethod
    def factory(cls, global_conf, **kwargs):
        print("Blog factory.")
        return Blog()


class Wiki(object):
    def __init__(self):
        print("Init Wiki.")

    def __call__(self, environ, start_response):
        status_code = "200 OK"
        response_headers = [("Content-Type", "text/plain")]
        response_body = "This is Wiki's response body.".encode('utf-8')

        start_response(status_code, response_headers)
        return [response_body]

    @classmethod
    def factory(cls, global_conf, **kwargs):
        print("Wiki factory.")
        return Wiki()


if __name__ == "__main__":
    configfile = "paste.ini"
    application_name = "main"
    port = 8000
    applications = loadapp("config:%s" % os.path.abspath(configfile), application_name)
    server = make_server("localhost", port, applications)
    print('Started web server at port {}'.format(port))
    server.serve_forever()

运行
通过以下命令启动web server:
# python example.py
如果一切正常,那么打开浏览器,访问http://127.0.0.1:8000/,应该显示:This is Home's response body.;访问http://127.0.0.1:8000/blog,应该显示:This is Blog's response body.;访问http://127.0.0.1:8000/wiki,应该显示:This is Wiki's response body.。
注意:urlmap对url的大小写是敏感的,例如如果访问http://127.0.0.1:8000/BLOG,在url映射中未能找到大写的BLOG,会使用/映射,最终会显示home页面,即显示:This is Home's response body.。

PasteDeploy配置文件中的type
  除了composite和app这个常用的type外,还有几个非常有用的type。下面是对type的完整介绍。
  type的值和对应的意义如下:
    composite:
      composite的type指的是用来分发请求到其它应用去。其下的键值对use = egg:Paste#urlmap表示使用Paste中的urlmap应用。urlmap是使用路径的前缀来将请求映射到不同的应用去。urlmap对路径的前缀的大小写是敏感的。例如:
[composite:main]
use = egg:Paste#urlmap
/ = home
/blog = blog
/wiki = wiki
    app:
      app的type指的是基本的WSGI应用。通常的用法是paste.app_factory = <模块名>:<类名>.<类方法>。例如:
[app:home]
paste.app_factory = example:Home.factory

      filter-app的type指的是过滤器应用,意思请求通过此过滤器后,最后会到达一个通常的WSGI应用。通过键值next可以指定需要将请求传递给谁。next指定的可以是一个普通的WSGI应用,也可以是另一个过滤器。虽然名称上是过滤器,但是功能上不局限于过滤功能,可以是其它功能,例如日志功能,即将认为重要的请求数据记录下来。例如:
[app-filter:filter_name]
use = egg:...
next = next_app

[app:next_app]
...
      filter的type指的是过滤器,与filter-app比较类似,只是用法上不同。定义了filter之后,在其它应用中可以使用filter-with指定使用此filter。
[app:app_name]
use = egg:...
filter-with = filtert_name

[filter:filtert_name]
...
      pipeline的type指的是管道,当需要多个filter一起工作时,可以使用pipeline将多个filter和最后一个WSGI应用串联起来。例如:
[pipeline:main]
pipeline = filter1 filter2 filter3 myapp

[filter:filter1]
...

[filter:filter2]
...

[app:myapp]
...