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

Changeset 1134

Show
Ignore:
Timestamp:
06/11/06 22:57:21
Author:
fumanchu
Message:

Separated tool construction from default toolbox by renaming cherrypy.tools module to _cptools, and binding cherrypy tools to a new _cptools.default_toolbox object. Also cleaned up the top-level cherrypy namespace quite a bit, and moved some user code out of lib.cptools.

Files:

Legend:

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

    r1120 r1134  
    33__version__ = '3.0.0alpha' 
    44 
    5 import cgi 
    6 import datetime 
    7 import sys 
    8 import traceback 
    9 import types 
    105 
    116from _cperror import * 
    127import config 
    13 import tools 
     8 
     9import _cptools 
     10tools = _cptools.default_toolbox 
    1411 
    1512import _cptree 
    1613tree = _cptree.Tree() 
    17  
    1814import _cpengine 
    1915engine = _cpengine.Engine() 
     
    2117server = _cpserver.Server() 
    2218 
     19def quickstart(root, script_name="", conf=None): 
     20    """Mount the given app, start the engine and builtin server, then block.""" 
     21    tree.mount(root, script_name, conf) 
     22    server.start() 
     23    engine.start() 
     24 
    2325codecoverage = False 
    2426 
    2527try: 
    26     from threading import local 
     28    from threading import local as _local 
    2729except ImportError: 
    28     from cherrypy._cpthreadinglocal import local 
     30    from cherrypy._cpthreadinglocal import local as _local 
    2931 
    3032# Create a threadlocal object to hold the request, response, and other 
     
    3234# a new HTTP conversation, yet still refer to them as module-level globals 
    3335# in a thread-safe way. 
    34 serving = local() 
     36serving = _local() 
    3537 
    3638class _ThreadLocalProxy: 
     
    7072 
    7173# Create thread_data object as a thread-specific all-purpose storage 
    72 thread_data = local() 
    73  
    74 def expose(func=None, alias=None): 
    75     """Expose the function, optionally providing an alias or set of aliases.""" 
    76      
    77     def expose_(func): 
    78         func.exposed = True 
    79         if alias is not None: 
    80             if isinstance(alias, basestring): 
    81                 parents[alias.replace(".", "_")] = func 
    82             else: 
    83                 for a in alias: 
    84                     parents[a.replace(".", "_")] = func 
    85         return func 
    86      
    87     parents = sys._getframe(1).f_locals 
    88     if isinstance(func, (types.FunctionType, types.MethodType)): 
    89         # expose is being called directly, before the method has been bound 
    90         return expose_(func) 
    91     else: 
    92         # expose is being called as a decorator 
    93         if alias is None: 
    94             alias = func 
    95         return expose_ 
    96  
    97 def set_config(**kwargs): 
    98     """Decorator to set _cp_config using the given kwargs.""" 
    99     def wrapper(f): 
    100         if not hasattr(f, "_cp_config"): 
    101             f._cp_config = {} 
    102         f._cp_config.update(kwargs) 
    103         return f 
    104     return wrapper 
     74thread_data = _local() 
     75 
     76 
     77 
     78#                                 Logging                                 # 
    10579 
    10680 
    10781def logtime(): 
     82    import datetime 
    10883    now = datetime.datetime.now() 
    10984    from cherrypy.lib import httptools 
     
    172147 
    173148 
    174 def quickstart(root, script_name="", conf=None): 
    175     """Mount the given app, start the engine and builtin server, then block.""" 
    176     tree.mount(root, script_name, conf) 
    177     server.start() 
    178     engine.start() 
    179  
     149 
     150#                       Helper functions for CP apps                       # 
     151 
     152 
     153def decorate(func, decorator): 
     154    """ 
     155    Return the decorated func. This will automatically copy all 
     156    non-standard attributes (like exposed) to the newly decorated function. 
     157    """ 
     158    import inspect 
     159    newfunc = decorator(func) 
     160    for (k,v) in inspect.getmembers(func): 
     161        if not hasattr(newfunc, k): 
     162            setattr(newfunc, k, v) 
     163    return newfunc 
     164 
     165def decorateAll(obj, decorator): 
     166    """ 
     167    Recursively decorate all exposed functions of obj and all of its children, 
     168    grandchildren, etc. If you used to use aspects, you might want to look 
     169    into these. This function modifies obj; there is no return value. 
     170    """ 
     171    import inspect 
     172    obj_type = type(obj) 
     173    for (k,v) in inspect.getmembers(obj): 
     174        if hasattr(obj_type, k): # only deal with user-defined attributes 
     175            continue 
     176        if callable(v) and getattr(v, "exposed", False): 
     177            setattr(obj, k, decorate(v, decorator)) 
     178        decorateAll(v, decorator) 
     179 
     180 
     181class ExposeItems: 
     182    """ 
     183    Utility class that exposes a getitem-aware object. It does not provide 
     184    index() or default() methods, and it does not expose the individual item 
     185    objects - just the list or dict that contains them. User-specific index() 
     186    and default() methods can be implemented by inheriting from this class. 
     187     
     188    Use case: 
     189     
     190    from cherrypy import ExposeItems 
     191    ... 
     192    root.foo = ExposeItems(mylist) 
     193    root.bar = ExposeItems(mydict) 
     194    """ 
     195    exposed = True 
     196    def __init__(self, items): 
     197        self.items = items 
     198    def __getattr__(self, key): 
     199        return self.items[key] 
     200 
     201 
     202def expose(func=None, alias=None): 
     203    """Expose the function, optionally providing an alias or set of aliases.""" 
     204     
     205    def expose_(func): 
     206        func.exposed = True 
     207        if alias is not None: 
     208            if isinstance(alias, basestring): 
     209                parents[alias.replace(".", "_")] = func 
     210            else: 
     211                for a in alias: 
     212                    parents[a.replace(".", "_")] = func 
     213        return func 
     214     
     215    import sys, types 
     216    parents = sys._getframe(1).f_locals 
     217    if isinstance(func, (types.FunctionType, types.MethodType)): 
     218        # expose is being called directly, before the method has been bound 
     219        return expose_(func) 
     220    else: 
     221        # expose is being called as a decorator 
     222        if alias is None: 
     223            alias = func 
     224        return expose_ 
     225 
     226def set_config(**kwargs): 
     227    """Decorator to set _cp_config using the given kwargs.""" 
     228    def wrapper(f): 
     229        if not hasattr(f, "_cp_config"): 
     230            f._cp_config = {} 
     231        f._cp_config.update(kwargs) 
     232        return f 
     233    return wrapper 
     234 
  • trunk/cherrypy/_cperror.py

    r1130 r1134  
    11"""Error classes for CherryPy.""" 
    22 
    3 import cgi 
    4 import sys 
    5 import traceback 
    6 import urlparse 
    7  
    8 from cherrypy.lib import httptools 
     3# cherrypy imports this module as *, so hide nonessentials. 
     4from cgi import escape as _escape 
     5from sys import exc_info as _exc_info 
     6from urlparse import urljoin as _urljoin 
     7from cherrypy.lib import httptools as _httptools 
    98 
    109 
     
    3231            path, pm = path.split("?", 1) 
    3332            request.query_string = pm 
    34             request.params = httptools.parseQueryString(pm) 
     33            request.params = _httptools.parseQueryString(pm) 
    3534         
    3635        # Note that urljoin will "do the right thing" whether url is: 
     
    3837        #  2. a URL relative to the current path 
    3938        # Note that any querystring will be discarded. 
    40         path = urlparse.urljoin(cherrypy.request.path_info, path) 
     39        path = _urljoin(cherrypy.request.path_info, path) 
    4140         
    4241        # Set a 'path' member attribute so that code which traps this 
     
    7069            #  3. a URL relative to the current path 
    7170            # Note that any querystring in browser_url will be discarded. 
    72             url = urlparse.urljoin(cherrypy.request.browser_url, url) 
     71            url = _urljoin(cherrypy.request.browser_url, url) 
    7372            abs_urls.append(url) 
    7473        self.urls = abs_urls 
     
    179178        response.headers['Content-Type'] = "text/html" 
    180179         
    181         be_ie_unfriendly(self.status) 
     180        _be_ie_unfriendly(self.status) 
    182181 
    183182 
     
    230229     
    231230    try: 
    232         code, reason, message = httptools.validStatus(status) 
     231        code, reason, message = _httptools.validStatus(status) 
    233232    except ValueError, x: 
    234233        raise cherrypy.HTTPError(500, x.args[0]) 
     
    248247            kwargs[k] = "" 
    249248        else: 
    250             kwargs[k] = cgi.escape(kwargs[k]) 
     249            kwargs[k] = _escape(kwargs[k]) 
    251250     
    252251    template = _HTTPErrorTemplate 
     
    260259                m += "<br />" 
    261260            m += ("In addition, the custom error page " 
    262                   "failed:\n<br />%s" % (sys.exc_info()[1])) 
     261                  "failed:\n<br />%s" % (_exc_info()[1])) 
    263262            kwargs['message'] = m 
    264263     
     
    273272 
    274273 
    275 def be_ie_unfriendly(status): 
     274def _be_ie_unfriendly(status): 
    276275    import cherrypy 
    277276    response = cherrypy.response 
     
    300299    """format_exc(exc=None) -> exc (or sys.exc_info if None), formatted.""" 
    301300    if exc is None: 
    302         exc = sys.exc_info() 
     301        exc = _exc_info() 
    303302    if exc == (None, None, None): 
    304303        return "" 
     304    import traceback 
    305305    return "".join(traceback.format_exception(*exc)) 
    306306 
  • trunk/cherrypy/_cptools.py

    r1129 r1134  
    3434        self.point = point 
    3535        self.callable = callable 
    36         if name is None: 
    37             name = callable.__name__ 
    3836        self.name = name 
    3937        # TODO: add an attribute to self for each arg 
     
    172170 
    173171 
    174  
    175172#                              Builtin tools                              # 
    176173 
    177 from cherrypy.lib import cptools 
    178 session_auth = MainTool(cptools.session_auth) 
    179 base_url = Tool('before_request_body', cptools.base_url) 
    180 response_headers = Tool('before_finalize', cptools.response_headers) 
    181 # We can't call virtual_host in on_start_resource, 
    182 # because it's failsafe and the redirect would be swallowed. 
    183 virtual_host = Tool('before_request_body', cptools.virtual_host) 
    184 log_tracebacks = Tool('before_error_response', cptools.log_traceback, 'log_tracebacks') 
    185 log_headers = Tool('before_error_response', cptools.log_request_headers, 'log_headers') 
    186 err_redirect = ErrorTool(cptools.redirect, 'err_redirect') 
    187 etags = Tool('before_finalize', cptools.validate_etags, 'etags') 
    188 del cptools 
    189  
    190 from cherrypy.lib import encodings 
    191 decode = Tool('before_main', encodings.decode) 
    192 encode = Tool('before_finalize', encodings.encode) 
    193 gzip = Tool('before_finalize', encodings.gzip) 
    194 del encodings 
    195  
    196 from cherrypy.lib import static 
    197 class _StaticDirTool(MainTool): 
     174from cherrypy.lib import cptools, encodings, static 
     175from cherrypy.lib import sessions as _sessions, xmlrpc as _xmlrpc 
     176from cherrypy.lib import caching as _caching, wsgiapp as _wsgiapp 
     177 
     178 
     179class StaticDirTool(MainTool): 
    198180    def setup(self): 
    199181        """Hook this tool into cherrypy.request using the given conf.""" 
     
    204186        # Don't pass conf (or our wrapper will get wrapped!) 
    205187        cherrypy.request.hooks.attach(self.point, wrapper) 
    206 staticdir = _StaticDirTool(static.staticdir) 
    207 staticfile = MainTool(static.staticfile) 
    208 del static 
    209  
    210 from cherrypy.lib import sessions as _sessions 
    211 class _SessionTool(Tool): 
     188 
     189 
     190class SessionTool(Tool): 
    212191    def __init__(self): 
    213192        self.point = "before_finalize" 
     
    256235        cherrypy.request.hooks.attach('before_finalize', _sessions.save) 
    257236        cherrypy.request.hooks.attach('on_end_request', _sessions.cleanup) 
    258 sessions = _SessionTool() 
    259  
    260 from cherrypy.lib import xmlrpc as _xmlrpc 
     237 
     238 
    261239class XMLRPCController(object): 
    262240     
     
    284262    index = __call__ 
    285263 
    286 class _XMLRPCTool(object): 
     264 
     265class XMLRPCTool(object): 
    287266    """Tool for using XMLRPC over HTTP. 
    288267     
     
    302281        if ppath != path_info: 
    303282            raise cherrypy.InternalRedirect(ppath) 
    304 xmlrpc = _XMLRPCTool() 
    305  
    306 from cherrypy.lib import wsgiapp as _wsgiapp 
    307 class _WSGIAppTool(MainTool): 
     283 
     284 
     285class WSGIAppTool(MainTool): 
    308286    """A tool for running any WSGI middleware/application within CP. 
    309287     
     
    327305        cherrypy.request.process_request_body = False 
    328306        MainTool.setup(self) 
    329 wsgiapp = _WSGIAppTool(_wsgiapp.run, "wsgiapp") 
    330 del _wsgiapp 
    331  
    332  
    333 # These modules are themselves Tools 
    334 from cherrypy.lib import caching 
     307 
     308 
     309class Toolbox(object): 
     310    """A collection of Tools.""" 
     311     
     312    def __setattr__(self, name, value): 
     313        # If the Tool.name is None, supply it from the attribute name. 
     314        if isinstance(value, Tool): 
     315            if value.name is None: 
     316                value.name = name 
     317        object.__setattr__(self, name, value) 
     318 
     319 
     320default_toolbox = Toolbox() 
     321default_toolbox.session_auth = MainTool(cptools.session_auth) 
     322default_toolbox.base_url = Tool('before_request_body', cptools.base_url) 
     323default_toolbox.response_headers = Tool('before_finalize', cptools.response_headers) 
     324# We can't call virtual_host in on_start_resource, 
     325# because it's failsafe and the redirect would be swallowed. 
     326default_toolbox.virtual_host = Tool('before_request_body', cptools.virtual_host) 
     327default_toolbox.log_tracebacks = Tool('before_error_response', cptools.log_traceback) 
     328default_toolbox.log_headers = Tool('before_error_response', cptools.log_request_headers) 
     329default_toolbox.err_redirect = ErrorTool(cptools.redirect) 
     330default_toolbox.etags = Tool('before_finalize', cptools.validate_etags) 
     331default_toolbox.decode = Tool('before_main', encodings.decode) 
     332default_toolbox.encode = Tool('before_finalize', encodings.encode) 
     333default_toolbox.gzip = Tool('before_finalize', encodings.gzip) 
     334default_toolbox.staticdir = StaticDirTool(static.staticdir) 
     335default_toolbox.staticfile = MainTool(static.staticfile) 
     336default_toolbox.sessions = SessionTool() 
     337default_toolbox.xmlrpc = XMLRPCTool() 
     338default_toolbox.wsgiapp = WSGIAppTool(_wsgiapp.run) 
     339default_toolbox.caching = _caching 
     340 
     341 
     342del cptools, encodings, static 
  • trunk/cherrypy/lib/cptools.py

    r1118 r1134  
    1 """Tools which both CherryPy and application developers may invoke.""" 
    2  
    3 import inspect 
     1"""Tools which CherryPy may invoke.""" 
     2 
    43import md5 
    5 import os 
    64import sys 
    7 import time 
    85 
    96import cherrypy 
    107import httptools 
    11  
    12  
    13 def decorate(func, decorator): 
    14     """ 
    15     Return the decorated func. This will automatically copy all 
    16     non-standard attributes (like exposed) to the newly decorated function. 
    17     """ 
    18     newfunc = decorator(func) 
    19     for (k,v) in inspect.getmembers(func): 
    20         if not hasattr(newfunc, k): 
    21             setattr(newfunc, k, v) 
    22     return newfunc 
    23  
    24 def decorateAll(obj, decorator): 
    25     """ 
    26     Recursively decorate all exposed functions of obj and all of its children, 
    27     grandchildren, etc. If you used to use aspects, you might want to look 
    28     into these. This function modifies obj; there is no return value. 
    29     """ 
    30     obj_type = type(obj) 
    31     for (k,v) in inspect.getmembers(obj): 
    32         if hasattr(obj_type, k): # only deal with user-defined attributes 
    33             continue 
    34         if callable(v) and getattr(v, "exposed", False): 
    35             setattr(obj, k, decorate(v, decorator)) 
    36         decorateAll(v, decorator) 
    37  
    38  
    39 class ExposeItems: 
    40     """ 
    41     Utility class that exposes a getitem-aware object. It does not provide 
    42     index() or default() methods, and it does not expose the individual item 
    43     objects - just the list or dict that contains them. User-specific index() 
    44     and default() methods can be implemented by inheriting from this class. 
    45      
    46     Use case: 
    47      
    48     from cherrypy.lib.cptools import ExposeItems 
    49     ... 
    50     root.foo = ExposeItems(mylist) 
    51     root.bar = ExposeItems(mydict) 
    52     """ 
    53     exposed = True 
    54     def __init__(self, items): 
    55         self.items = items 
    56     def __getattr__(self, key): 
    57         return self.items[key] 
    588 
    599 
  • trunk/cherrypy/test/test_core.py

    r1131 r1134  
    55 
    66import cherrypy 
    7 from cherrypy import tools 
     7from cherrypy import _cptools, tools 
    88from cherrypy.lib import httptools, static 
    99import types 
     
    138138        if not getattr(cherrypy.request, "login", None): 
    139139            raise cherrypy.InternalRedirect("/internalredirect/login") 
    140     tools.login_redir = tools.Tool('before_main', login_redir) 
     140    tools.login_redir = _cptools.Tool('before_main', login_redir) 
    141141     
    142142    class InternalRedirect(Test): 
  • trunk/cherrypy/test/test_response_headers.py

    r1114 r1134  
    33 
    44import cherrypy 
    5 from cherrypy.tools import response_header
    6 headers = response_headers.wrap 
     5from cherrypy import tool
     6headers = tools.response_headers.wrap 
    77 
    88 
  • trunk/cherrypy/test/test_tools.py

    r1115 r1134  
    77 
    88import cherrypy 
    9 from cherrypy import tools 
     9from cherrypy import _cptools, tools 
    1010 
    1111 
     
    1717        if not getattr(cherrypy.request, "login", None): 
    1818            raise cherrypy.HTTPError(401) 
    19     tools.check_access = tools.Tool('before_request_body', check_access) 
     19    tools.check_access = _cptools.Tool('before_request_body', check_access) 
    2020     
    2121    def numerify(): 
     
    2727        cherrypy.response.body = number_it(cherrypy.response.body) 
    2828     
    29     class NumTool(tools.Tool): 
     29    class NumTool(_cptools.Tool): 
    3030        def setup(self): 
    3131            def makemap(): 
     
    3636    tools.numerify = NumTool('before_finalize', numerify) 
    3737     
    38     # It's not mandatory to inherit from tools.Tool. 
     38    # It's not mandatory to inherit from _cptools.Tool. 
    3939    class NadsatTool: 
    4040         
  • trunk/cherrypy/test/test_xmlrpc.py

    r1114 r1134  
    66def setup_server(): 
    77    import cherrypy 
    8     from cherrypy import tools 
     8    from cherrypy import _cptools 
    99     
    1010    class Root: 
     
    1414 
    1515 
    16     class XmlRpc(tools.XMLRPCController): 
     16    class XmlRpc(_cptools.XMLRPCController): 
    1717         
    1818        def return_single_item_list(self): 

Hosted by WebFaction

Log in as guest/cpguest to create tickets