Luckylau's Blog

python的pecan框架使用

neutron源码学习基础知识储备之Pecan web框架

什么是Pecan?

​ 创造Pecan是为了填补Python web框架世界的一个空缺——一个提供object-dispatch(对象分发)方式路由的超轻量级的框架。Pecan的目标并不是要成为一个“全栈”框架,因此没有支持一些额外的功能,比如session或是数据库 。相反,Pecan专注于HTTP本身。

功能包括:

Object-dispatch for easy routing
Full support for REST-style controllers
Extensible security framework
Extensible template language support
Extensible JSON support
Easy Python-based configuration

所以对于OpenStack来说,Pecan是一个很好的选择,因为OpenStack项目中统一使用sqlalchemy来实现ORM,API的实现也不需要模板功能,安全控制则基于Keystone体系。使用Pecan来开发REST服务,代码量很少,代码结构也清晰。

创建简单的Pecan应用?

首先在linux新建一个virtualenv环境(本文是在ubantu16.04),我们首先看一下自动生成的工程目录结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
luckylau@luckylau-Ubuntu:~$virtualenv pecan-env
luckylau@luckylau-Ubuntu:~$cd pecan-env/
luckylau@luckylau-Ubuntu:~/pecan-env$ source bin/activate
(pecan-env) luckylau@luckylau-Ubuntu:~/pecan-env$ pip install pecan
(pecan-env) luckylau@luckylau-Ubuntu:~/pecan-env$ pecan create test_project
(pecan-env) luckylau@luckylau-Ubuntu:~/pecan-env$ tree test_project/
test_project/
├── config.py
├── MANIFEST.in
├── public #一些静态文件包括CSS,JS,images,为你的开发服务
│   ├── css
│   │   └── style.css
│   └── images
│   └── logo.png
├── setup.cfg
├── setup.py
└── test_project #基于MVC模型生成的结构
├── app.py #决定应用是如何创造的,这个文件必须包含set_app()并返回WSGI应用对象,一般情况下就用原生的,除非不能满足你定制的应用。
├── controllers #控制层实现
│   ├── __init__.py
│   ├── __init__.pyc
│   ├── root.py
│   └── root.pyc
├── __init__.py
├── __init__.pyc
├── model #模型实现
│   ├── __init__.py #在这里可以加入与database交互,定义表和ORM等
│   └── __init__.pyc
├── templates #模板实现
│   ├── error.html
│   ├── index.html
│   └── layout.html
└── tests #单元测试
├── config.py
├── __init__.py
├── test_functional.py
├── test_units.py
└── test_units.pyc
8 directories, 23 files

实战Demo?

我们通过实际操作中补充pecan相关知识点。项目托管到github:

https://github.com/Luckylau/python-web-frame

该项目用到pecan和wsme(Web Services Made Easy),首先解释一下WSME吧

WSME的全称是Web Service Made Easy,是专门用于实现REST服务的typing库,让你不需要直接操作请求和响应,而且刚好和Pecan结合得非常好,所以,OpenStack的很多项目都使用了Pecan + WSME的组合来实现API。

WSME的理念是:在大部分情况下,Web服务的输入和输出对数据类型的要求都是严格的。所以它就专门解决了这个事情,然后把其他事情都交给其他框架去实现。

WSME会自动帮你检查HTTP请求和响应中的数据是否符合预先设定好的要求。WSME的主要方式是通过装饰器来控制controller方法的输入和输出。WSME中主要使用两个控制器:
● @signature: 这个装饰器用来描述一个函数的输入和输出。
● @wsexpose: 这个装饰器包含@signature的功能,同时会把函数的路由信息暴露给Web框架,效果就像Pecan的expose装饰器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
luckylau@luckylau-Ubuntu:~/github/python-web-frame$ tree webdemo/
webdemo/
├── api
│   ├── app.py
│   ├── config.py
│   ├── controllers
│   │   ├── __init__.py
│   │   └── root.py
│   ├── expose.py
│   ├── hooks.py
│   └── __init__.py
├── cmd
│   ├── api.py
│   └── __init__.py
└── __init__.py

首先参考openstack我们人工的建立如上目录。首先我们实现config.py 代码

https://pecan.readthedocs.io/en/latest/configuration.html#application-configuration

该链接解释配置的含义。

config.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
app = {
'root': 'webdemo.api.controllers.root.RootController',
'modules': ['webdemo.api'],
'debug': True,
}
logging = {
'root': {'level': 'INFO', 'handlers': ['console']},
'loggers': {
'webdemo': {'level': 'INFO', 'handlers': ['console']}
},
'handlers': {
'console': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'simple'
}
},
'formatters': {
'simple': {
'format': ('%(asctime)s %(levelname)-5.5s [%(name)s]'
'[%(threadName)s] %(message)s')
}
}
}

modules

At least one of the listed modules must contain an app.setup_app function which is called to create the WSGI app. In other words, this package should be where your app.py file is located, and this file should contain a setup_app function.

简单来说,modules是app.py(同时包含setup_pp功能)所在的包,pecan会扫描的。

root

The root controller of your application. Remember to provide a string representing a Python path to some callable (e.g.”yourapp.controllers.root.RootController”).

简单来说,RootController所在路径

debug
Enables the ability to display tracebacks in the browser and interactively debug during development.

简单来说,是否开启debug模式

app.py

1
2
3
4
5
6
7
8
9
10
11
12
import pecan
from webdemo.api import config as api_config
def get_pecan_config():
filename=api_config.__file__.replace('.pyc','.py')
return pecan.configuration.conf_from_file(filename)
def setup_app():
config=get_pecan_config()
app_conf=dict(config.app)
app=pecan.make_app(app_conf.pop('root'),
logging=getattr(config,'logging',{}),
**app_conf)
return app

expose.py

1
2
3
4
5
6
#让API返回JSON格式的数据
import wsmeext.pecan as wsme_pecan
def expose(*args, **kwargs):
if 'rest_content_types' not in kwargs:
kwargs['rest_content_types'] = ('json',)
return wsme_pecan.wsexpose(*args, **kwargs)

root.py

1
2
3
4
5
6
7
8
9
10
from pecan import rest
from wsme import types as wtypes
from webdemo.api import expose
import logging
logger = logging.getLogger(__name__)
class RootController(rest.RestController):
@expose.expose(wtypes.text)
def get(self):
logger.info("Method is called ...")
return "python-web-frame: pecan & wsme "

api.py

1
2
3
4
5
6
7
8
9
from wsgiref import simple_server
from webdemo.api import app
def main():
application = app.setup_app()
httpd = simple_server.make_server('', 8080, application)
print ("Server on port 8080 ,listening ...")
httpd.serve_forever()
if __name__ == '__main__':
main()

我们进一步扩展该Demo,源码更新看日志:

https://github.com/Luckylau/python-web-frame/commits/master

需求:设计一个管理用户的API,实现如下

GET /v1/users 获取所有用户的列表。
POST /v1/users 创建一个用户。
GET /v1/users/ 获取一个特定用户的详细信息。
PUT /v1/users/ 修改一个用户的详细信息。
DELETE /v1/users/ 删除一个用户。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
luckylau@luckylau-Ubuntu:~/github/python-web-frame$ tree webdemo/
webdemo/
├── api
│   ├── app.py
│   ├── app.pyc
│   ├── config.py
│   ├── config.pyc
│   ├── controllers
│   │   ├── __init__.py
│   │   ├── __init__.pyc
│   │   ├── root.py
│   │   ├── root.pyc
│   │   └── v1
│   │   ├── __init__.py
│   │   ├── controller.py #用户管理控制器
│   │   └── users.py #用户模型
│   ├── expose.py
│   ├── expose.pyc
│   ├── hooks.py
│   ├── __init__.py
│   └── __init__.pyc
├── cmd
│   ├── api.py
│   └── __init__.py
├── __init__.py
└── __init__.pyc

然后我们在加入sqlalchemy库来实现数据库操作

我们可以看一个脚本预热一下

https://github.com/Luckylau/oslo.modules.sample/blob/lucky-branch/sqlalchemy.orm/db_query_ports.py

然后开始我们这个Demo的扩展

由于OpenStack项目在单元测试中使用的是sqlite的内存数据库,这样开发者运行单元测试的时候不需要安装和配置复杂的MySQL数据库,只要安装好sqlite3就可以了。而且,数据库是保存在内存中的,会提高单元测试的速度,我们的Demo也是用sqlite,sqlalchemy库的使用参考:

https://luckylau.github.io/2017/03/02/Python%E7%9A%84sqlalchemy%E5%BA%93%E7%90%86%E8%A7%A3/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
webdemo/
├── api
│   ├── app.py
│   ├── app.pyc
│   ├── config.py
│   ├── config.pyc
│   ├── controllers
│   │   ├── __init__.py
│   │   ├── __init__.pyc
│   │   ├── root.py
│   │   ├── root.pyc
│   │   └── v1
│   │   ├── controller.py
│   │   ├── controller.pyc
│   │   ├── __init__.py
│   │   ├── __init__.pyc
│   │   ├── users.py
│   │   └── users.pyc
│   ├── expose.py
│   ├── expose.pyc
│   ├── hooks.py
│   ├── __init__.py
│   └── __init__.pyc
├── cmd
│   ├── api.py
│   └── __init__.py
├── db
│   ├── api.py #sqlalchemy 增删改查功能
│   ├── __init__.py #
│   └── models.py # sqlalchemy ORM的定义
├── __init__.py
└── __init__.pyc
5 directories, 26 files

具体的分析在源码有标注。

参考:

https://pecan.readthedocs.io/en/latest/

http://www.infoq.com/cn/articles/OpenStack-demo-API3

https://pythonhosted.org/WSME/

http://www.sqlalchemy.org/

Luckylau wechat
如果对您有价值,看官可以打赏的!