pecan源码目录
创建pecan工程
pecan create test
创建pecan工程用到了bin下的pecan脚本
// bin/pecan
#!/usr/bin/env python
if __name__ == '__main__':
from pecan.commands import CommandRunner
CommandRunner.handle_command_line()
调用了pecan/commands/base.py下的CommandRunner类中的handle_command_line()方法
//具体处理命令
def run(self, args):
ns = self.parser.parse_args(args)//解析参数
self.commands[ns.command_name]().run(ns)//执行命令,相当于执行commands下相应模块中的run方法
@classmethod
def handle_command_line(cls):
runner = CommandRunner()//实例化该对象时,加载commands文件夹下定义的名命令
runner.run(sys.argv[1:])
// pecan/commands/base.py
//加载command的方法,entry point在setup.py里面注册了
def load_commands(self):
for ep in pkg_resources.iter_entry_points('pecan.command'):
log.debug('%s loading plugin %s', self.__class__.__name__, ep)
if ep.name in self.commands:
warn(
"Duplicate entry points found on `%s` - ignoring %s" % (
ep.name,
ep
),
RuntimeWarning
)
continue
try:
//该方法是去加载模块中含有run方法的类
cmd = ep.load()
cmd.run //确保加载的类有run方法
except Exception as e: # pragma: nocover
warn("Unable to load plugin %s: %s" % (ep, e), RuntimeWarning)
continue
self.add({ep.name: cmd})//添加到self.commands字典里面,上面的run运行时,从字典中取出类,实例化,然后调用run方法
可以看到,pecan创建工程的过程和django类似(其实基本所有的python web框架都是一样的)
下面来看看创建工程具体做了什么工作
// pecan/commands/create.py
class ScaffoldManager(object):
def __init__(self):
self.scaffolds = {}
self.load_scaffolds()
def load_scaffolds(self):
//加载在setup.py文件中注册了的类
for ep in pkg_resources.iter_entry_points('pecan.scaffold'):
log.debug('%s loading scaffold %s', self.__class__.__name__, ep)
try:
cmd = ep.load()
cmd.copy_to //确保有copy_to方法
except Exception as e: # pragma: nocover
warn(
"Unable to load scaffold %s: %s" % (ep, e), RuntimeWarning
)
continue
self.add({ep.name: cmd})
def add(self, cmd):
self.scaffolds.update(cmd)
class CreateCommand(BaseCommand):
//通过实例化该对象,加载pecan/scaffolds下的BaseScaffold和RestAPIScaffold类,加载方法和加载command方法一样
manager = ScaffoldManager()
arguments = ({
'name': 'project_name',
'help': 'the (package) name of the new project'
}, {
'name': 'template_name',
'metavar': 'template_name',
'help': 'a registered Pecan template',
'nargs': '?',
'default': DEFAULT_SCAFFOLD,//值为base,会调用BaseScaffold的实例
'choices': manager.scaffolds.keys()
})
//该方法会首先执行
def run(self, args):
super(CreateCommand, self).run(args)
// self.manager.scaffolds为{'rest-api': <class 'pecan.scaffolds.RestAPIScaffold'>, 'base': <class 'pecan.scaffolds.BaseScaffold'>}
//具体由RestAPIScaffold和BaseScaffold去创建工程
self.manager.scaffolds[args.template_name]().copy_to(
args.project_name //项目名:test
)
注:通过上面的代码可以知道,默认创建工程时使用的是BaseScaffold类,创建的是一般的pecan工程,而要创建restful的pecan工程,则需要使用下面的方式创建
pecan create test rest-api
BaseScaffold和RestAPIScaffold调用copy_to(project_name)方法去创建工程,主要工作就是根据传入的项目名创建目录,拷贝文件等,pecan/scaffolds模块中放置了相关的模板文件
至此,一个pecan工程就创建完毕。
运行pecan工程
运行方式:
pecan serve config.py
和创建工程一样,运行时调用了pecan/commands/create.py模块的方法。
def run(self, args):
super(ServeCommand, self).run(args)
app = self.load_app() // 创建一个app
self.serve(app, app.config) // 部署app
众所周知,要运行一个python的web服务,需要两个条件:
1.application
2.wsgi server
上面的load_app()方法创建了一个application(会调用到core.py里面的load_app()方法)
// pecan/core.py
def load_app(config, **kwargs):
from .configuration import _runtime_conf, set_config
//根据配置文件初始化配置
set_config(config, overwrite=True)
for package_name in getattr(_runtime_conf.app, 'modules', []):
module = __import__(package_name, fromlist=['app'])
//项目工程创建好后,有个test/test/app.py文件,里面的setup_app(config)具体来创建app
if hasattr(module, 'app') and hasattr(module.app, 'setup_app'):
//这里开始创建一个app
app = module.app.setup_app(_runtime_conf, **kwargs)
app.config = _runtime_conf
return app
raise RuntimeError(
'No app.setup_app found in any of the configured app.modules'
)
// test/test/app.py
def setup_app(config):
model.init_model() //创建app时,初始化model,一般在这实现orm映射
app_conf = dict(config.app)
// test/conifg.py文件中有app配置项,定义了app的重要内容
return make_app(
app_conf.pop('root'),
logging=getattr(config, 'logging', {}),
**app_conf
)
// pecan/__init__.py
def make_app(root, **kw):
...
// root是test/config.py中app项里面配置的,作为路由的入口
app = Pecan(root, **kw)
...
return app
app其实就是一个Pecan实例。
对于wsgi server,下面的代码可以看出,pecan使用了python内置的simple_server
// pecan/commands/serve.py
def serve(self, app, conf):
if self.args.reload:
try:
//使用了watchdog,用于修改文件后自动部署(暂不做讲解)
self.watch_and_spawn(conf)
except ImportError:
print('The `--reload` option requires `watchdog` to be '
'installed.')
print(' $ pip install watchdog')
else:
//这里就是具体部署app的方法
self._serve(app, conf)
def _serve(self, app, conf):
// 引入python内置simple_server
from wsgiref.simple_server import make_server
host, port = conf.server.host, int(conf.server.port)
srv = make_server(
host,
port,
app, //创建的app
handler_class=PecanWSGIRequestHandler,//处理器
)
print('Starting server in PID %s' % os.getpid())
if host == '0.0.0.0':
print(
'serving on 0.0.0.0:%s, view at http://127.0.0.1:%s' %
(port, port)
)
else:
print("serving on http://%s:%s" % (host, port))
try:
// 运行web服务
srv.serve_forever()
except KeyboardInterrupt:
# allow CTRL+C to shutdown
pass
至此,一个python web服务就运行起来了。
下一篇将介绍pecan工程配置文件和路由。