wsgi调试

其实我之前在:

apache+wsgi+python的web调试

这篇文章中有提到怎么去调试wsgi+python的程序,但是还是非常麻烦,无论通过将想要的查看的内容输出到apache的日志文件还是直接以html方式在浏览器中查看。有时候有些只是简单的语法错误,但是还是要

1. 保存代码

2. 浏览器访问网页

3. 打开错误日志

4. 修改代码

5. 保存代码继续上面的步骤

比如你的某个文件有5个语法错误,那么你就要将上面的步骤执行5次,这个效率实在低下。

今天实在受不了了,上网查了查,也没发现什么好用的方法,于是决定自己写个工具。最后测试一下,很不错,不想独享,奉献出来,与大家共享,当然如果大家有什么意见,可以提出来,一同研究。

优点:

使用方法简单,可以快速找出程序的语法和简单的逻辑错误。

缺点:

需要知道wsgi传过来的参数。

原理其实很简单,就是模拟wsgi调用我们的python程序。下面列出所有的代码:

import sys
from cStringIO import StringIO

if len( sys.argv ) > 1:
    fileimport = sys.argv[1]
    fi = __import__( fileimport, globals(), locals() , ['application'], -1 )
else:
    exit()

class Input:
    body = ''
    def __init__( self, pr ):
        self.body = pr
    def read( self, length ):
        return self.body

en = dict()
body='UserID=test&Password=123456'
ff = Input( body )
en['CONTENT_LENGTH'] = len( body )
en['wsgi.input'] = ff
en['wsgi.errors'] = sys.stdout
def start_response( status, response ):
    print status
    print response
print fi.application( en, start_response )

使用方法:

直接将上面的代码保存成任意文件中,比如是testapp.py。而你要测试的wsgi调用的python脚本是myapp.py,那么可以在终端输入下列命令来测试:

python testapp.py myapp

这样就可以测试你的代码中语法错误和逻辑错误了,注意不要加入文件后缀名。

注意上面被标成红色字体的部分需要根据你的实际情况来做更改,比如说你的myapp.py的就是用来处理用户登录请求的,那么上面的代码你就只需要将 test 和 123456改成你对应的用户名和密码就可以。body其实就模拟wsgi.input的里面的内容而已。如果你处理的是新用户的请求信息,那么上面body的内容可能就要换成用户所填写的用户名,密码,邮箱,电话号码,生日,验证码等信息了。

下面简述了上面的实现和原理

先看看wsgi调用我们程序是怎样调用的:

def application(environ, start_response):
    status = '200 OK'

其实就是把客户端提交的信息填充到envrion变量,然后再定义个回调函数,就调用application,而这个函数是我们自己的写的程序必须的一个函数。我们工具所做的就是做一些假数据,然后调用application。

首先为了让这个工具能够测试不同的wsgi调用的python脚本文件,可以通过参数将所要测试的文件传进来。这里涉及到怎么读出命令行参数的问题,可以使用sys.argv来读取,使用这个需要

import sys

sys.argv[0]是执行程序的路径,这个由系统自动填入,这也意味着sys.argv的长度至少为1,而从第二个参数开始才是我们可以传进去的参数。 我们有了这个参数就可以导入测试的模块了,那就使用import,但是如果我们直接使用

import sys.argv[1]

使用argv[1]我们得看看里面的元素个数如果只有一个说明调用这个工具时没有传进脚本文件,那么直接推出。

就会报错,因为 import只可以接受常量,不可以接受变量。不过python给我们提供了另外一个方法,就是使用内置函数__import__,其实import就是调用这个函数来工作的。

    fileimport = sys.argv[1]
    fi = __import__( fileimport, globals(), locals() , ['application'], -1 )

为什么要使用__import__的返回值,是因为我们在后面实际访问这个模块中的application函数时,需要这个命令空间(其实python并没有命令空间,它相当于这个东西而已)。

接下里定义了一个类:

class Input:
    body = ''
    def __init__( self, pr ):
        self.body = pr
    def read( self, length ):
        return self.body

为什么要定义它,是因为wsgi.input的是一个可以通过read()方法来读取客户端提交过来的数据的一个对象,那么我们创建一个假的这样一个对象,通过构造函数把一个字符串的内容传进去,然后通过read方法就可以把这个字符串读出来。

另外wsgi调用的application函数传进来一个dict类型的变量environ。因此我们就需要假造一个。

en = dict()

然后填充在测试程序中会用到的元素的值,比如说wsgi.input,wsgi.errors,等等。这里wsgi.input就是en,wsgi.errors定义为sys.stdout,这样就可以直接结果将输入到wsgi.errors的重定位到终端,便于我们查看,而真正运行时,信息又可以重定位到apache的日志文件。

还有一个就是模拟application的第二个参数,回调函数:

def start_response( status, response ):
    print status
    print response

其实这个函数就是打印一下status, response 这2个东西,因为在实际中程序中我们会修改这2个东西,这样我们就可以直接查看对应的结果。

最后就是真正让测试程序执行起来的关键,调用测试程序的application函数,并且把执行的结果打印出来。

完。

版权所有,禁止转载. 如需转载,请先征得博主的同意,并且表明文章出处,否则按侵权处理.

    分享到:

留言

你的邮箱是保密的 必填的信息用*表示