Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Changeset 1602

Show
Ignore:
Timestamp:
01/20/07 02:03:09
Author:
fumanchu
Message:

First crack at attribute docs on major components. New cherrypy._AttributeDocstrings metaclass to fold magic attribute docs into the class docstring.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/cherrypy/__init__.py

    r1601 r1602  
    55from urlparse import urljoin as _urljoin 
    66 
    7 from cherrypy._cperror import HTTPError, HTTPRedirect, InternalRedirect, NotFound, CherryPyException 
    8 from cherrypy._cperror import TimeoutError 
     7 
     8class _AttributeDocstrings(type): 
     9    """Metaclass for declaring docstrings for class attributes.""" 
     10    # The full docstring for this type is down in the __init__ method so 
     11    # that it doesn't show up in help() for every consumer class. 
     12     
     13    def __init__(cls, name, bases, dct): 
     14        '''Metaclass for declaring docstrings for class attributes. 
     15         
     16        Base Python doesn't provide any syntax for setting docstrings on 
     17        'data attributes' (non-callables). This metaclass allows class 
     18        definitions to follow the declaration of a data attribute with 
     19        a docstring for that attribute; the attribute docstring will be 
     20        popped from the class dict and folded into the class docstring. 
     21         
     22        The naming convention for attribute docstrings is: <attrname> + "__doc". 
     23        For example: 
     24         
     25            class Thing(object): 
     26                """A thing and its properties.""" 
     27                 
     28                __metaclass__ = cherrypy._AttributeDocstrings 
     29                 
     30                height = 50 
     31                height__doc = """The height of the Thing in inches.""" 
     32         
     33        In which case, help(Thing) starts like this: 
     34         
     35            >>> help(mod.Thing) 
     36            Help on class Thing in module pkg.mod: 
     37             
     38            class Thing(__builtin__.object) 
     39             |  A thing and its properties. 
     40             |   
     41             |  height [= 50]: 
     42             |      The height of the Thing in inches. 
     43             |  
     44         
     45        The benefits of this approach over hand-edited class docstrings: 
     46            1. Places the docstring nearer to the attribute declaration. 
     47            2. Makes attribute docs more uniform ("name (default): doc"). 
     48            3. Reduces mismatches of attribute _names_ between 
     49               the declaration and the documentation. 
     50            4. Reduces mismatches of attribute default _values_ between 
     51               the declaration and the documentation. 
     52         
     53        The benefits of a metaclass approach over other approaches: 
     54            1. Simpler ("less magic") than interface-based solutions. 
     55            2. __metaclass__ can be specified at the module global level 
     56               for classic classes. 
     57         
     58        The type of the attribute is intentionally not included, because 
     59        that's not How Python Works. Quack. 
     60        ''' 
     61         
     62        newdoc = [cls.__doc__ or ""] 
     63         
     64        dctnames = dct.keys() 
     65        dctnames.sort() 
     66         
     67        for name in dctnames: 
     68            if name.endswith("__doc"): 
     69                # Remove the magic doc attribute. 
     70                if hasattr(cls, name): 
     71                    delattr(cls, name) 
     72                 
     73                # Get an inspect-style docstring if possible (usually so). 
     74                val = dct[name] 
     75                try: 
     76                    import inspect 
     77                    val = inspect.getdoc(property(doc=val)).strip() 
     78                except: 
     79                    pass 
     80                 
     81                # Indent the docstring. 
     82                val = '\n'.join(['    ' + line.rstrip() 
     83                                 for line in val.split('\n')]) 
     84                 
     85                # Get the default value. 
     86                attrname = name[:-5] 
     87                try: 
     88                    attrval = getattr(cls, attrname) 
     89                except AttributeError: 
     90                    attrval = "missing" 
     91                 
     92                # Add the complete attribute docstring to our list. 
     93                newdoc.append("%s [= %r]:\n%s" % (attrname, attrval, val)) 
     94         
     95        # Add our list of new docstrings to the class docstring. 
     96        cls.__doc__ = "\n\n".join(newdoc) 
     97 
     98 
     99from cherrypy._cperror import HTTPError, HTTPRedirect, InternalRedirect 
     100from cherrypy._cperror import NotFound, CherryPyException, TimeoutError 
    9101 
    10102from cherrypy import _cpdispatch as dispatch 
  • trunk/cherrypy/_cprequest.py

    r1592 r1602  
    1414 
    1515class Hook(object): 
    16     """A callback and its metadata: failsafe, priority, and kwargs. 
    17      
    18     failsafe: If True, the callback is guaranteed to run even if other 
    19         callbacks from the same call point raise exceptions. 
    20     priority: Defines the order of execution for a list of Hooks. 
    21         Defaults to 50. Priority numbers should be limited to the 
    22         closed interval [0, 100], but values outside this range are 
    23         acceptable, as are fractional values. 
    24     """ 
     16    """A callback and its metadata: failsafe, priority, and kwargs.""" 
     17     
     18    __metaclass__ = cherrypy._AttributeDocstrings 
     19     
     20    callback = None 
     21    callback__doc = """The bare callable that this Hook object is wrapping. 
     22    This will be called when the Hook is called.""" 
     23     
     24    failsafe = False 
     25    failsafe__doc = """If True, the callback is guaranteed to run even if 
     26    other callbacks from the same call point raise exceptions.""" 
     27     
     28    priority = 50 
     29    priority__doc = """Defines the order of execution for a list of Hooks. 
     30    Priority numbers should be limited to the closed interval [0, 100], but 
     31    values outside this range are acceptable, as are fractional values.""" 
     32     
     33    kwargs = {} 
     34    kwargs__doc = """A set of keyword arguments that will be passed 
     35    to the callable on each call.""" 
    2536     
    2637    def __init__(self, callback, failsafe=None, priority=None, **kwargs): 
     
    142153    """ 
    143154     
     155    __metaclass__ = cherrypy._AttributeDocstrings 
     156     
    144157    prev = None 
     158    prev__doc = """ 
     159    The previous Request object (if any). This should be None 
     160    unless we are processing an InternalRedirect.""" 
    145161     
    146162    # Conversation/connection attributes 
    147163    local = http.Host("localhost", 80) 
     164    local__doc = \ 
     165        "An http.Host(ip, port, hostname) object for the server socket." 
     166     
    148167    remote = http.Host("localhost", 1111) 
     168    remote__doc = \ 
     169        "An http.Host(ip, port, hostname) object for the client socket." 
     170     
    149171    scheme = "http" 
     172    scheme__doc = """ 
     173    The protocol used between client and server. In most cases, 
     174    this will be either 'http' or 'https'.""" 
     175     
    150176    server_protocol = "HTTP/1.1" 
     177    server_protocol__doc = """ 
     178    The HTTP version for which the HTTP server is at least 
     179    conditionally compliant.""" 
     180     
    151181    base = "" 
     182    base__doc = """The 'base' (scheme + host) portion of the requested URL.""" 
    152183     
    153184    # Request-Line attributes 
    154185    request_line = "" 
     186    request_line__doc = """ 
     187    The complete Request Line received from the client. This is a 
     188    single string consisting of the request method, URI, and protocol 
     189    version (joined by spaces). Any final CRLF is removed.""" 
     190     
    155191    method = "GET" 
     192    method__doc = """ 
     193    Indicates the HTTP method to be performed on the resource identified 
     194    by the Request-URI. Common methods include GET, HEAD, POST, PUT, and 
     195    DELETE. CherryPy allows any extension method; however, various HTTP 
     196    servers and gateways may restrict the set of allowable methods. 
     197    CherryPy applications SHOULD restrict the set (on a per-URI basis).""" 
     198     
    156199    query_string = "" 
     200    query_string__doc = """ 
     201    The query component of the Request-URI, a string of information to be 
     202    interpreted by the resource. The query portion of a URI follows the 
     203    path component, and is spearated by a '?'. For example, the URI 
     204    'http://www.cherrypy.org/wiki?a=3&b=4' has the query component, 
     205    'a=3&b=4'.""" 
     206     
    157207    protocol = (1, 1) 
     208    protocol__doc = """The HTTP protocol version corresponding to the set 
     209        of features which should be allowed in the response. If BOTH 
     210        the client's request message AND the server's level of HTTP 
     211        compliance is HTTP/1.1, this attribute will be the tuple (1, 1). 
     212        If either is 1.0, this attribute will be the tuple (1, 0). 
     213        Lower HTTP protocol versions are not explicitly supported.""" 
     214     
    158215    params = {} 
     216    params__doc = """ 
     217    A dict which combines query string (GET) and request entity (POST) 
     218    variables. This is populated in two stages: GET params are added 
     219    before the 'on_start_resource' hook, and POST params are added 
     220    between the 'before_request_body' and 'before_handler' hooks.""" 
    159221     
    160222    # Message attributes 
    161223    header_list = [] 
     224    header_list__doc = """ 
     225    A list of the HTTP request headers as (name, value) tuples. 
     226    In general, you should use request.headers (a dict) instead.""" 
     227     
    162228    headers = http.HeaderMap() 
    163229    cookie = Cookie.SimpleCookie() 
     230     
    164231    rfile = None 
     232    rfile__doc = """ 
     233    If the request included an entity (body), it will be available 
     234    as a stream in this attribute. However, the rfile will normally 
     235    be read for you between the 'before_request_body' hook and the 
     236    'before_handler' hook, and the resulting string is placed into 
     237    either request.params or the request.body attribute. 
     238     
     239    You may disable the automatic consumption of the rfile by setting 
     240    request.process_request_body to False, either in config for the desired 
     241    path, or in an 'on_start_resource' or 'before_request_body' hook. 
     242     
     243    WARNING: In almost every case, you should not attempt to read from the 
     244    rfile stream after CherryPy's automatic mechanism has read it. If you 
     245    turn off the automatic parsing of rfile, you should read exactly the 
     246    number of bytes specified in request.headers['Content-Length']. 
     247    Ignoring either of these warnings may result in a hung request thread 
     248    or in corruption of the next (pipelined) request. 
     249    """ 
     250     
    165251    process_request_body = True 
     252    process_request_body__doc = """ 
     253    If True, the rfile (if any) is automatically read and parsed, 
     254    and the result placed into request.params or request.body.""" 
     255     
    166256    methods_with_bodies = ("POST", "PUT") 
     257    methods_with_bodies__doc = """ 
     258    A sequence of HTTP methods for which CherryPy will automatically 
     259    attempt to read a body from the rfile.""" 
     260     
    167261    body = None 
     262    body__doc = """ 
     263    If the request Content-Type is 'application/x-www-form-urlencoded' 
     264    or multipart, this will be None. Otherwise, this will contain the 
     265    request entity body as a string; this value is set between the 
     266    'before_request_body' and 'before_handler' hooks (assuming that 
     267    process_request_body is True).""" 
    168268     
    169269    # Dispatch attributes 
    170270    dispatch = cherrypy.dispatch.Dispatcher() 
     271     
    171272    script_name = "" 
     273    script_name__doc = """ 
     274    The 'mount point' of the application which is handling this request.""" 
     275     
    172276    path_info = "/" 
     277    path_info__doc = """ 
     278    The 'relative path' portion of the Request-URI. This is relative 
     279    to the script_name ('mount point') of the application which is 
     280    handling this request.""" 
     281     
    173282    app = None 
     283    app__doc = """The Application object which is handling this request.""" 
     284     
    174285    handler = None 
     286    handler__doc = """ 
     287    The function, method, or other callable which CherryPy will call to 
     288    produce the response. The discovery of the handler and the arguments 
     289    it will receive are determined by the request.dispatch object. 
     290    By default, the handler is discovered by walking a tree of objects 
     291    starting at request.app.root, and is then passed all HTTP params 
     292    (from the query string and POST body) as keyword arguments.""" 
     293     
    175294    toolmaps = {} 
     295    toolmaps__doc = """ 
     296    A nested dict of all Toolboxes and Tools in effect for this request, 
     297    of the form: {Toolbox.namespace: {Tool.name: config dict}}.""" 
     298     
    176299    config = None 
     300    config__doc = """ 
     301    A flat dict of all configuration entries which apply to the 
     302    current request. These entries are collected from global config, 
     303    application config (based on request.path_info), and from handler 
     304    config (exactly how is governed by the request.dispatch object in 
     305    effect for this request; by default, handler config can be attached 
     306    anywhere in the tree between request.app.root and the final handler, 
     307    and inherits downward).""" 
     308     
    177309    is_index = None 
     310    is_index__doc = """ 
     311    This will be True if the current request is mapped to an 'index' 
     312    resource handler (or a 'default' handler if path_info ends with 
     313    a slash). The value may be used to automatically redirect the 
     314    user-agent to a 'more canonical' URL which either adds or removes 
     315    the trailing slash. See cherrypy.tools.trailing_slash.""" 
    178316     
    179317    hooks = HookMap(hookpoints) 
    180318     
    181319    error_response = cherrypy.HTTPError(500).set_response 
     320    error_response__doc = """ 
     321    The callable which will handle unexpected errors during request 
     322    processing. By default, it uses HTTPError(500) to return an error 
     323    response to the user-agent.""" 
     324     
    182325    error_page = {} 
     326    error_page__doc = """ 
     327    A dict of {error code: response filename} pairs. The named response 
     328    files should be Python string-formatting templates, and can expect by 
     329    default to receive the keyword-formatted values 'status', 'message', 
     330    'traceback', and 'version'. The set of keyword values can be extended 
     331    by overriding HTTPError.set_response.""" 
     332     
    183333    show_tracebacks = True 
     334    show_tracebacks__doc = """ 
     335    If True, unexpected errors encountered during request processing will 
     336    include a traceback in the response body.""" 
     337     
    184338    throws = (KeyboardInterrupt, SystemExit, cherrypy.InternalRedirect) 
     339    throws__doc = """The sequence of exceptions which Request.run does not trap.""" 
     340     
    185341    throw_errors = False 
     342    throw_errors__doc = """ 
     343    If True, Request.run will not trap any errors (except HTTPRedirect and 
     344    HTTPError, which are more properly called 'exceptions', not errors).""" 
    186345     
    187346    namespaces = {"hooks": hooks_namespace, 
     
    191350                  # "tools": See _cptools.Toolbox 
    192351                  } 
     352    namespaces__doc = """ 
     353    A dict of config namespace names and handlers. Each config entry must 
     354    begin with a namespace name; the corresponding namespace handler will 
     355    be called once for each config entry in that namespace, and will be 
     356    passed two arguments: the config key (with the namespace removed) 
     357    and the config value. 
     358     
     359    Namespace handlers may be any Python callable; they may also be 
     360    Python 2.5-style 'context managers', in which case their __enter__ 
     361    method should return a callable to be used as the handler. 
     362    See cherrypy.tools (the Toolbox class) for an example. 
     363     
     364    Namespaces may be added at the class level and will be inherited 
     365    by all Request instances. 
     366    """ 
    193367     
    194368    def __init__(self, local_host, remote_host, scheme="http", 
  • trunk/cherrypy/lib/http.py

    r1533 r1602  
    449449            name = ip 
    450450        self.name = name 
     451     
     452    def __repr__(self): 
     453        return "http.Host(%r, %r, %r)" % (self.ip, self.port, self.name) 

Hosted by WebFaction

Log in as guest/cpguest to create tickets