Quixote学习笔记(2)

Understanding the mini_demo

Start the mini demo by running the command:
simple_server.py --factory quixote.demo.mini_demo.create_publisher

In a browser, load http://localhost:8080. In your browser, you should see "Welcome ..." page. In your terminal window, you will see a "localhost - - ..." line for each request. These are access log messages from the web server.

Look at the source code in demo/mini_demo.py. Near the bottom you will find the create_publisher() function. The create_publisher() function creates a Publisher instance whose root directory is an instance of the RootDirectory class defined just above. When a request arrives, the Publisher calls the _q_traverse() method on the root directory. In this case, the RootDirectory is using the standard _q_traverse() implementation, inherited from Directory.

Look, preferably in another window, at the source code for _q_traverse() in directory.py. The path argument provided to _q_traverse() is a list of string components of the path part of the URL, obtained by splitting the request location at each '/' and dropping the first element (which is always '') For example, if the path part of the URL is '/', the path argument to _q_traverse() is ['']. If the path part of the URL is '/a', the path argument to _q_traverse() is ['a']. If the path part of the URL is '/a/', the path argument to _q_traverse() is ['a', ''].

Looking at the code of _q_traverse(), observe that it starts by splitting off the first component of the path and calling _q_translate() to see if there is a designated attribute name corresponding to this component. For the '/' page, the component is '', and _q_translate() returns the attribute name '_q_index'. The _q_traverse() function goes on to lookup the _q_index method and return the result of calling it.

Looking back at mini_demo.py, you can see that the RootDirectory class includes a _q_index() method, and this method does return the HTML for http://localhost:8080/

As mentioned above, the _q_translate() identifies a "designated" attribute name for a given component. The default implementation uses self._q_exports to define this designation. In particular, if the component is in self._q_exports, then it is returned as the attribute name, except in the special case of '', which is translated to the special attribute name '_q_index'.

When you click on the link on the top page, you get http://localhost:8080/hello. In this case, the path argument to the _q_traverse() call is ['hello'], and the return value is the result of calling the hello() method.

Feeling bold? (Just kidding, this won't hurt at all.) Try opening http://localhost:8080/bogus. This is what happens when _q_traverse() raises a TraversalError. A TraversalError is no big deal, but how does quixote handle more exceptional exceptions? To see, you can introduce one by editing mini_demo.py. Try inserting the line "raise 'ouch'" into the hello() method. Kill the demo server (Control-c) and start a new one with the same command as before. Now load the http://localhost:8080/hello page. You should see a plain text python traceback followed by some information extracted from the HTTP request. This information is always printed to the error log on an exception. Here, it is also displayed in the browser because the create_publisher() function made a publisher using the 'plain' value for the display_exceptions keyword argument. If you omit that keyword argument from the Publisher constructor, the browser will get an "Internal Server Error" message instead of the full traceback. If you provide the value 'html', the browser displays a prettier version of the traceback.

One more thing to try here. Replace your 'raise "ouch"' line in the hello() method with 'print "ouch"'. If you restart the server and load the /hello page, you will see that print statements go the the error log (in this case, your terminal window). This can be useful.



今天继续看Quixote安装目录doc下的 demo.html文件,Understanding the mini_demo部分。

在命令行解释器里输入:

simple_server.py --factory quixote.demo.mini_demo.create_publisher

启动mini_demo的server程序。

在浏览器里输入 http://localhost:8080,这时可以看到mini_demo的页面:

Welcome to the Quixote demo. Here is a link .

点击link,打开新的页面:

Hello world!

命令行解释器里也有两条日志:

localhost - - [13/Aug/2007 17:20:40] "GET / HTTP/1.1" 200 -
localhost - - [13/Aug/2007 17:22:43] "GET /hello HTTP/1.1" 200 -

下面就是读mini_demo.py,publish.py和directory.py三个源代码的内容了,从mini_demo.py开始:

from  quixote.publish  import  Publisher
from  quixote.directory  import  Directory

class  RootDirectory(Directory):

    _q_exports 
=  [ '' ' hello ' ]

    
def  _q_index(self):
        
return   ''' <html>
                    <body>Welcome to the Quixote demo.  Here is a
                    <a href="hello">link</a>.                   
                    </body>
                  </html>
                
'''

    
def  hello(self):
        
return   ' <html><body>Hello world!</body></html> '
       


def create_publisher():
    
return Publisher(RootDirectory(),
                     display_exceptions
='html')


if __name__ == '__main__':
    
from quixote.server.simple_server import run
    
print 'creating demo listening on http://localhost:8080/'
    run(create_publisher, host
='localhost', port=8080)

demo.html上这样描述:

The create_publisher() function creates a Publisher instance whose root directory is an instance of the RootDirectory class defined just above. When a request arrives, the Publisher calls the _q_traverse() method on the root directory.

这时我们再打开publish.py文件,首先看一下Publisher类的注释:

     """
    The core of Quixote and of any Quixote application.  This class is
    responsible for converting each HTTP request into a traversal of the
    application's directory tree and, ultimately, a call of a Python
    function/method/callable object.

    Each invocation of a driver script should have one Publisher
    instance that lives for as long as the driver script itself.  Eg. if
    your driver script is plain CGI, each Publisher instance will handle
    exactly one HTTP request; if you have a FastCGI driver, then each
    Publisher will handle every HTTP request handed to that driver
    script process.
    
"""

_q_traverse()方法调用次序如下:

__main__——create_publisher——?——process——process_request——try_publish——_q_traverse

process:
         """ (stdin : stream, env : dict) -> HTTPResponse
        
        Process a single request, given a stream, stdin, containing the 
        incoming request and a dictionary, env, containing the web server's 
        environment.
        
        An HTTPRequest object is created and the process_request() method is 
        called and passed the request object.
        
"""

process_request:
         """ (request : HTTPRequest) -> HTTPResponse

        Process a single request, given an HTTPRequest object.  The
        try_publish() method will be called to do the work and
        exceptions will be handled here.
        
"""

try_publish:
         """ (request : HTTPRequest) -> object

        The master method that does all the work for a single request.
        Exceptions are handled by the caller.
        
"""

而_q_traverse方法是Directory类的方法,directory.py里相关代码:

     def  _q_traverse(self, path):
        
""" (path: [string]) -> object

        Traverse a path and return the result.
        
"""
        
assert  len(path)  >  0
        component 
=  path[0]
        path 
=  path[ 1 :]
        name 
=  self._q_translate(component)
        
if  name  is   not  None:
            obj 
=  getattr(self, name)
        
else :
            obj 
=  self._q_lookup(component)
        
if  obj  is  None:
            
raise  TraversalError(private_msg = ( ' directory %r has no component  '
                                              
' %r '   %  (self, component)))
        
if  path:
            
if  hasattr(obj,  ' _q_traverse ' ):
                
return  obj._q_traverse(path)
            
else :
                
raise  TraversalError
        
elif  callable(obj):
            
return  obj()
        
else :
            
return  obj

上面我们点击link的时候,传到_q_traverse()里的path大概是这样的:/hello
这时候_q_traverse()把'/hello'分离出来,调用 _q_translate()去看是否有对应的组件,在这里就是hello。directory.py里相关代码:

     def  _q_translate(self, component):
        
""" (component : string) -> string | None

        Translate a path component into a Python identifier.  Returning
        None signifies that the component does not exist.
        
"""
        
if  component  in  self._q_exports:
            
if  component  ==   '' :
                
return   ' _q_index '   #  implicit mapping
             else :
                
return  component
        
else :
            
#  check for an explicit external to internal mapping
             for  value  in  self._q_exports:
                
if  isinstance(value, tuple):
                    
if  value[0]  ==  component:
                        
return  value[ 1 ]
            
else :
                
return  None

_q_translate()是Directory类的一个方法,在_q_exports(mini_demo.py里定义的)里查找path的组件,这里是hello。
如果是'/',组件就是空字符串'', _q_translate()返回'_q_index‘。_q_traverse()函数根据_q_translate返回值继续搜索对应名字的方法并返回它的调用结果。

如果我们要添加一个页面,和访问它的链接,需要改动三个地方:

class  RootDirectory(Directory):

    _q_exports 
=  [ '' ' hello ' , 'who' ]

    
def  _q_index(self):
        
return   ''' <html>
                    <body>Welcome to the Quixote demo.  Here is a
                    <a href="hello">link</a>.<br>
                    <a href="who">who</a>
                    </body>
                  </html>
                
'''

    
def  hello(self):
        
return   ' <html><body>Hello world!</body></html> '
       
    
def  who(self):
         return   '<html><body>I'm Jasmine!</body></html>'

这时再打开http://localhost:8080/,可以看到多了一个who的链接:

Welcome to the Quixote demo. Here is a link .
who

点击后,打开一个新的页面:

I'm Jasmine!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值