今天将分析 Python 里的一个开源项目:Paste Deployment(后面简写为 PasteDeploy),它是一套框架,可以用于发现并配置 WSGI 应用程序和 WSGI Servers。对于 WSGI 应用程序的使用者而言,它可以提供单一的入口(loadpp)来从配置文件或者 Python Egg
中加载 WSGI 应用程序,而对于 WSGI 应用程序的开发者而言,只需要按照 PasteDeploy
的 协议
,为应用程序提供相应的 entry_points,PasteDeploy 即可发现这些 WSGI 应用程序,WSGI 应用程序的实现细节里也无需感知应用程序的用户。
PasteDeploy 最核心的一点,就是它预先定义好了接口(可调用的 Python 对象),只要应用程序开发者提供了这些接口(即遵守 PasteDeploy的协议),就能被 PasteDeploy 识别。
PasteDeploy 目前并不依赖 Paste,它可以作为一个独立的包进行发布。
基本使用方法
PasteDeploy 最主要的用途就是加载 WSGI 应用程序,可以通过如下方式加载应用程序:
1 | from paste.deploy import loadapp |
loadapp 函数从指定的 URI 中加载应用程序,目前支持两种 URI 格式:config:
以及 egg:
。如果配置文件中定义了多个 app,可以通过 name
关键字参数来指定要加载的 app。如果没有指定 app 的 name,同时 loadapp 中的 URI 参数不包含也 #
,则默认加载的 app 为 main
。
PasteDeploy 中共有 3 种类型的对象,分别是 application
、filter
、和 server
。因此除了使用 loadapp 来加载app 外,还可以使用 loadfilter 来加载 filter、使用 loadserver 来加载 server。
PasteDeploy 配置文件
可以通过配置文件来使用 PasteDeploy。PasteDeploy
的配置文件采用 INI 文件格式,包含不同的 sections,每一个 section 都有一个前缀,例如 app:main
、filter:errors
。前缀的格式为:type:name
。
典型的配置文件如下所示:
1 | [composite:main] |
application object
可以在配置文件中定义多个 application 对象,每个应用程序都在自己的 section 中。application
也可以根据他们的功能,划分为不同的种类。
Applications
最基本的 application 对象,section 前缀以 app:
为开头,后面是该应用程序的名称(如果没有指定则为 main)。有两种方式来指定该应用程序的 Python 代码:
- 通过 URI 或名称指定
1 | [app:myapp] |
- 显示指定 Python 代码,此时配置项采用
协议
作为键
1 | [app:myapp] |
section 下除了 use 关键字之外的其他配置,都会作为关键字参数传给工厂代码。另外 [DEFAULT]
section 下的配置是全局配置,全局配置会传递给所有 application
,而且可以在 section 下通过 set key=value
来覆盖全局配置。
Composite Applications
Composite Applications
组合应用程序由一系列应用程序构成,最典型的例子是 URL mapper
,这样根据 URL 挂载不同的应用程序:
1 | [composite:main] |
这里就是定义了一个名为的 main 的 composite 应用,它使用的是 Paste 包中的 urlmap 应用。urlmap 是 Paste 提供的一套通用 composite 应用,根据根据 URL 将请求分发到不同的 WSGI 应用,这里访问 /
将被映射到 mainapp,访问 /files 将映射到 staticapp。
同样也可以通过协议来指定 Composite Applications
,协议名称为 paste.composite_factory
。
Filter Composition
Filter Composition
可以对于 application
可以应用 filter
,然后再执行 application
。有多种方式来创建 Filter Composition application
。
- 使用
filter-with
1 | [app:main] |
- 使用
[filter-app:...]
section:在该 section 中通过use
定义了一个 filter,同时通过next
指定该filter
应用的app
1 | [filter-app:blog] |
- 使用
[pipeline:...]
section:通过 pipeline 可以定义一系列的filter
,以及这些filter
最终应用的app
1 | [pipeline:main] |
可以通过协议 paste.filter_app_factory
来指定 Filter Composition
。
filter object
接下来介绍 filter
,filter
是过滤器,它接受应用程序作为参数,然后返回一个新的应用程序,新的应用程序包含了 filter 的过滤逻辑。使用 [filter:...]
section 可以创建 filter
:
1 | [filter:printdebug] |
也可以通过协议 paste.filter_factory
来指定 filter
。
server object
server
是指 WSGI 服务器,可以为 WSGI 应用程序提供服务。使用 [server:...]
可以指定 server
对象。另外通过协议 paste.server_factory
和 paste.server_runner
也可以指定 server。
加载对象
如上所述,有两种方式来加载对象,一种是通过 egg
URI 的方式,另外一种就是通过 protocol
的方式。
egg: URIs
通过 setuptools 安装的软件包,都可以指定 entry_points。如果我们编写的 WSGI 软件包,想被 PasteDeploy 识别,可以按照如下方式编写 setup()
:
1 | setup( |
这里通过 paste.app_factory
entry_points 组定义了 2 个 app_factory,这样就可以被 PasteDeploy 识别,然后可以在 PasteDeploy 的配置文件中可以通过 egg:MyApp#main
和 egg:MyApp#ob2
来加载这两个 application。如果想提供其他的 object,只需要将 entry_points 的 group 设置为相应的 protocol
名称即可。
Defining Factories
除了 entry_points
的方式,还可以直接指定应用程序工厂的代码,即采用类似于 paste.app_factory = myapp.modulename:app_factory
的形式。应用程序工厂的代码需要遵循 PasteDeploy 的协议,即工厂代码需要是可调用对象(参数和返回值需要符合预期)。PasteDeploy 定义了如下协议:
- paste.app_factory:它接受全局配置、本地配置作为参数,返回一个 WSGI 应用
例如:
1 | def app_factory(global_config, **local_conf): |
- paste.composite_factory:接受三个参数:loader、全局配置、本地配置。loader 对象提供一系列方法:get_app(name_or_uri, global_conf=None) 根据名称返回 WSGI 应用程序、get_filter 和 get_server 也是类似。
例如:
1 | def composite_factory(loader, global_config, **local_conf): |
如下是一个更复杂的例子,它实现了一个 pipeline
application:
1 | def pipeline_factory(loader, global_config, pipeline): |
通过如下方式来使用这个 pipeline:
1 | [composite:main] |
- paste.filter_factory:类似于
app_facotry
,但是返回的是 filters。Filter 也是可调用对象,但是接受一个 WSGI 应用程序作为参数,返回一个包含过滤逻辑的 app。
例如:
1 | def auth_filter_factory(global_conf, req_usernames): |
paste.filter_app_factory:类似于
paste.filter_factory
,但是还接受wsgi_app
作为参数,并返回一个 WSGI 应用程序paste.server_factory:接受的参数和
app_factory
相同,但是返回一个 server。该 server 接受一个 WSGI application 作为参数,提供相应的服务
例如:
1 | def server_factory(global_conf, host, port): |
- paste.server_runner:类似于 paste.server_factory,除了第一个参数是
wsgi_app
,同时 server 也会立即运行