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

Changeset 1275

Show
Ignore:
Timestamp:
08/24/06 02:02:42
Author:
fumanchu
Message:

Overhaul of config system:

  1. New docstring for config module!
  2. Put all entries into a config namespace. New deadlock, log, request and response namespaces.
  3. Request and response entries now directly modify attributes of cherrypy.request and .response, and consumer code looks up those attributes, not config. This also allows interactive inspection of defaults.
  4. Removed 'log_config' config entry. Use engine.on_start_engine_list.append(config.log_config) instead.
  5. Old 'dispatch' entry is now 'request.dispatch'.
  6. New log entries: log.error.file, log.error.function, log.access.file, log.access.function, log.screen.
  7. 'server.max_request_body_size' is now 'request.max_body_size'.
  8. environments now only apply to globalconf.
  9. The 'development' environment has been removed, since its settings were all the default anyway.
  10. The 'embedded' environment has been removed, since it duplicates the 'production' environment now.
  11. There's a new 'test_suite' environment.
  12. Removed log_file_not_found (from static.py).

Something still needs to be done to config.wrap, so it can take dotted names as kwarg keys.

Files:

Legend:

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

    r1274 r1275  
    150150        from cherrypy import _cperror 
    151151        msg += _cperror.format_exc() 
    152     logfunc = config.get('log_function', _log_message) 
     152    logfunc = config.get('log.error.function', _log_message) 
    153153    logfunc(msg, context, severity) 
    154154 
  • trunk/cherrypy/_cpengine.py

    r1263 r1275  
    6969        conf = cherrypy.config.get 
    7070         
    71         # Output config options to log 
    72         if conf("log_config", True): 
    73             cherrypy.config.log_config() 
    74          
    7571        for func in self.on_start_engine_list: 
    7672            func() 
     
    7874        self.state = STARTED 
    7975         
    80         freq = float(cherrypy.config.get('deadlock_poll_freq', 60)) 
     76        freq = float(conf('deadlock.poll_freq', 60)) 
    8177        if freq > 0: 
    8278            self.monitor_thread = threading.Timer(freq, self.monitor) 
     
    223219            for req, resp in self.servings: 
    224220                resp.check_timeout() 
    225             freq = float(cherrypy.config.get('deadlock_poll_freq', 60)) 
     221            freq = float(cherrypy.config.get('deadlock.poll_freq', 60)) 
    226222            self.monitor_thread = threading.Timer(freq, self.monitor) 
    227223            self.monitor_thread.start() 
  • trunk/cherrypy/_cperror.py

    r1243 r1275  
    178178        response.status = self.status 
    179179        tb = None 
    180         if cherrypy.config.get('show_tracebacks', False)
     180        if cherrypy.request.show_tracebacks
    181181            tb = format_exc() 
    182182        content = get_error_page(self.status, traceback=tb, 
  • trunk/cherrypy/_cpmodpy.py

    r1260 r1275  
    1919        func() 
    2020     
    21     cherrypy.config.update({'global' : {'log_to_screen' : False}}) 
     21    cherrypy.config.update({'log.screen': False}) 
    2222     
    2323    if cherrypy.engine.state == cherrypy._cpengine.STOPPED: 
  • trunk/cherrypy/_cprequest.py

    r1271 r1275  
    7878 
    7979 
     80class PageHandler(object): 
     81    """Callable which sets response.body.""" 
     82     
     83    def __init__(self, callable, *args, **kwargs): 
     84        self.callable = callable 
     85        self.args = args 
     86        self.kwargs = kwargs 
     87     
     88    def __call__(self): 
     89        cherrypy.response.body = self.callable(*self.args, **self.kwargs) 
     90 
     91 
     92class LateParamPageHandler(PageHandler): 
     93    """When passing cherrypy.request.params to the page handler, we don't 
     94    want to capture that dict too early; we want to give tools like the 
     95    decoding tool a chance to modify the params dict in-between the lookup 
     96    of the handler and the actual calling of the handler. This subclass 
     97    takes that into account, and allows request.params to be 'bound late' 
     98    (it's more complicated than that, but that's the effect). 
     99    """ 
     100     
     101    def _get_kwargs(self): 
     102        kwargs = cherrypy.request.params.copy() 
     103        if self._kwargs: 
     104            kwargs.update(self._kwargs) 
     105        return kwargs 
     106     
     107    def _set_kwargs(self, kwargs): 
     108        self._kwargs = kwargs 
     109     
     110    kwargs = property(_get_kwargs, _set_kwargs, 
     111                      doc='page handler kwargs (with ' 
     112                      'cherrypy.request.params copied in)') 
     113 
     114 
     115class Dispatcher(object): 
     116     
     117    def __call__(self, path_info): 
     118        """Set handler and config for the current request.""" 
     119        request = cherrypy.request 
     120        func, vpath = self.find_handler(path_info) 
     121         
     122        if func: 
     123            # Decode any leftover %2F in the virtual_path atoms. 
     124            vpath = [x.replace("%2F", "/") for x in vpath] 
     125            request.handler = LateParamPageHandler(func, *vpath) 
     126        else: 
     127            request.handler = cherrypy.NotFound() 
     128     
     129    def find_handler(self, path): 
     130        """Find the appropriate page handler for the given path.""" 
     131        request = cherrypy.request 
     132        app = request.app 
     133        root = app.root 
     134         
     135        # Get config for the root object/path. 
     136        curpath = "" 
     137        nodeconf = {} 
     138        if hasattr(root, "_cp_config"): 
     139            nodeconf.update(root._cp_config) 
     140        if "/" in app.conf: 
     141            nodeconf.update(app.conf["/"]) 
     142        object_trail = [('root', root, nodeconf, curpath)] 
     143         
     144        node = root 
     145        names = [x for x in path.strip('/').split('/') if x] + ['index'] 
     146        for name in names: 
     147            # map to legal Python identifiers (replace '.' with '_') 
     148            objname = name.replace('.', '_') 
     149             
     150            nodeconf = {} 
     151            node = getattr(node, objname, None) 
     152            if node is not None: 
     153                # Get _cp_config attached to this node. 
     154                if hasattr(node, "_cp_config"): 
     155                    nodeconf.update(node._cp_config) 
     156             
     157            # Mix in values from app.conf for this path. 
     158            curpath = "/".join((curpath, name)) 
     159            if curpath in app.conf: 
     160                nodeconf.update(app.conf[curpath]) 
     161             
     162            object_trail.append((objname, node, nodeconf, curpath)) 
     163         
     164        def set_conf(): 
     165            """Set cherrypy.request.config.""" 
     166            base = cherrypy.config.globalconf.copy() 
     167            # Note that we merge the config from each node 
     168            # even if that node was None. 
     169            for name, obj, conf, curpath in object_trail: 
     170                base.update(conf) 
     171                if 'tools.staticdir.dir' in conf: 
     172                    base['tools.staticdir.section'] = curpath 
     173            return base 
     174         
     175        # Try successive objects (reverse order) 
     176        for i in xrange(len(object_trail) - 1, -1, -1): 
     177             
     178            name, candidate, nodeconf, curpath = object_trail[i] 
     179            if candidate is None: 
     180                continue 
     181             
     182            # Try a "default" method on the current leaf. 
     183            if hasattr(candidate, "default"): 
     184                defhandler = candidate.default 
     185                if getattr(defhandler, 'exposed', False): 
     186                    # Insert any extra _cp_config from the default handler. 
     187                    conf = getattr(defhandler, "_cp_config", {}) 
     188                    object_trail.insert(i+1, ("default", defhandler, conf, curpath)) 
     189                    request.config = set_conf() 
     190                    return defhandler, names[i:-1] 
     191             
     192            # Uncomment the next line to restrict positional params to "default". 
     193            # if i < len(object_trail) - 2: continue 
     194             
     195            # Try the current leaf. 
     196            if getattr(candidate, 'exposed', False): 
     197                request.config = set_conf() 
     198                if i == len(object_trail) - 1: 
     199                    # We found the extra ".index". Check if the original path 
     200                    # had a trailing slash (otherwise, do a redirect). 
     201                    if path[-1:] != '/': 
     202                        atoms = request.browser_url.split("?", 1) 
     203                        new_url = atoms.pop(0) + '/' 
     204                        if atoms: 
     205                            new_url += "?" + atoms[0] 
     206                        raise cherrypy.HTTPRedirect(new_url) 
     207                return candidate, names[i:-1] 
     208         
     209        # We didn't find anything 
     210        request.config = set_conf() 
     211        return None, [] 
     212 
     213 
     214class MethodDispatcher(Dispatcher): 
     215    """Additional dispatch based on cherrypy.request.method.upper(). 
     216     
     217    Methods named GET, POST, etc will be called on an exposed class. 
     218    The method names must be all caps; the appropriate Allow header 
     219    will be output showing all capitalized method names as allowable 
     220    HTTP verbs. 
     221     
     222    Note that the containing class must be exposed, not the methods. 
     223    """ 
     224     
     225    def __call__(self, path_info): 
     226        """Set handler and config for the current request.""" 
     227        request = cherrypy.request 
     228        resource, vpath = self.find_handler(path_info) 
     229         
     230        # Decode any leftover %2F in the virtual_path atoms. 
     231        vpath = [x.replace("%2F", "/") for x in vpath] 
     232         
     233        if resource: 
     234            # Set Allow header 
     235            avail = [m for m in dir(resource) if m.isupper()] 
     236            if "GET" in avail and "HEAD" not in avail: 
     237                avail.append("HEAD") 
     238            avail.sort() 
     239            cherrypy.response.headers['Allow'] = ", ".join(avail) 
     240             
     241            # Find the subhandler 
     242            meth = cherrypy.request.method.upper() 
     243            func = getattr(resource, meth, None) 
     244            if func is None and meth == "HEAD": 
     245                func = getattr(resource, "GET", None) 
     246            if func: 
     247                request.handler = LateParamPageHandler(func, *vpath) 
     248            else: 
     249                request.handler = cherrypy.HTTPError(405) 
     250        else: 
     251            request.handler = cherrypy.NotFound() 
     252 
     253 
    80254class Request(object): 
    81255    """An HTTP request.""" 
     
    105279    body = None 
    106280    body_read = False 
     281    max_body_size = 100 * 1024 * 1024 
    107282     
    108283    # Dispatch attributes 
     284    dispatch = Dispatcher() 
    109285    script_name = "" 
    110286    path_info = "/" 
     
    113289    toolmap = {} 
    114290    config = None 
    115     error_response = cherrypy.HTTPError(500).set_response 
     291    recursive_redirect = False 
     292     
    116293    hookpoints = ['on_start_resource', 'before_request_body', 
    117294                  'before_main', 'before_finalize', 
     
    119296                  'before_error_response', 'after_error_response'] 
    120297    hooks = HookMap(hookpoints) 
     298     
     299    error_response = cherrypy.HTTPError(500).set_response 
     300    show_tracebacks = True 
     301    throw_errors = False 
     302     
    121303     
    122304    def __init__(self, local_host, remote_host, scheme="http", 
     
    219401                except cherrypy.InternalRedirect, ir: 
    220402                    pi = ir.path 
    221                     if (pi in self.redirections and 
    222                         not cherrypy.config.get("recursive_redirect")): 
     403                    if pi in self.redirections and not self.recursive_redirect: 
    223404                        raise RuntimeError("InternalRedirect visited the " 
    224405                                           "same URL twice: %s" % repr(pi)) 
     
    229410            raise 
    230411        except: 
    231             if cherrypy.config.get("throw_errors", False)
     412            if self.throw_errors
    232413                raise 
    233414            self.handle_error(sys.exc_info()) 
     
    237418            cherrypy.response.body = [] 
    238419         
    239         log_access = cherrypy.config.get("log_access", cherrypy.log_access) 
     420        log_access = cherrypy.config.get("log.access.function", cherrypy.log_access) 
    240421        if log_access: 
    241422            log_access() 
     
    265446                    if self.process_request_body: 
    266447                        # Prepare the SizeCheckWrapper for the request body 
    267                         mbs = int(self.config.get('server.max_request_body_size', 
    268                                                   100 * 1024 * 1024)) 
     448                        mbs = self.max_body_size 
    269449                        if mbs > 0: 
    270450                            self.rfile = http.SizeCheckWrapper(self.rfile, mbs) 
     
    324504    def get_resource(self, path): 
    325505        """Find and call a dispatcher (which sets self.handler and .config).""" 
    326         dispatch = default_dispatch 
     506        dispatch = self.dispatch 
    327507        # First, see if there is a custom dispatch at this URI. Custom 
    328508        # dispatchers can only be specified in app.conf, not in _cp_config 
     
    331511        while trail: 
    332512            nodeconf = self.app.conf.get(trail, {}) 
    333             d = nodeconf.get("dispatch") 
     513            d = nodeconf.get("request.dispatch") 
    334514            if d: 
    335515                dispatch = d 
     
    348528     
    349529    def tool_up(self): 
    350         """Populate self.toolmap and set up each tool.""" 
     530        """Process self.config, populate self.toolmap and set up each tool.""" 
    351531        # Get all 'tools.*' config entries as a {toolname: {k: v}} dict. 
    352532        self.toolmap = tm = {} 
     
    366546                    v = cherrypy.lib.attributes(v) 
    367547                self.hooks.attach(hookpoint, v) 
     548            elif namespace == "request": 
     549                # Override properties of this request object. 
     550                setattr(self, atoms[1], reqconf[k]) 
     551            elif namespace == "response": 
     552                # Override properties of the current response object. 
     553                setattr(cherrypy.response, atoms[1], reqconf[k]) 
    368554         
    369555        # Run tool._setup(conf) for each tool in the new toolmap. 
     
    432618         
    433619        # Failure in error handler or finalize. Bypass them. 
    434         if cherrypy.config.get('show_tracebacks', False)
     620        if self.show_tracebacks
    435621            dbltrace = ("\n===First Error===\n\n%s" 
    436622                        "\n\n===Second Error===\n\n%s\n\n") 
     
    440626        r = bare_error(body) 
    441627        response.status, response.header_list, response.body = r 
    442  
    443  
    444 class PageHandler(object): 
    445     """Callable which sets response.body.""" 
    446      
    447     def __init__(self, callable, *args, **kwargs): 
    448         self.callable = callable 
    449         self.args = args 
    450         self.kwargs = kwargs 
    451      
    452     def __call__(self): 
    453         cherrypy.response.body = self.callable(*self.args, **self.kwargs) 
    454  
    455  
    456 class LateParamPageHandler(PageHandler): 
    457     """When passing cherrypy.request.params to the page handler, we don't 
    458     want to capture that dict too early; we want to give tools like the 
    459     decoding tool a chance to modify the params dict in-between the lookup 
    460     of the handler and the actual calling of the handler. This subclass 
    461     takes that into account, and allows request.params to be 'bound late' 
    462     (it's more complicated than that, but that's the effect). 
    463     """ 
    464      
    465     def _get_kwargs(self): 
    466         kwargs = cherrypy.request.params.copy() 
    467         if self._kwargs: 
    468             kwargs.update(self._kwargs) 
    469         return kwargs 
    470      
    471     def _set_kwargs(self, kwargs): 
    472         self._kwargs = kwargs 
    473      
    474     kwargs = property(_get_kwargs, _set_kwargs, 
    475                       doc='page handler kwargs (with ' 
    476                       'cherrypy.request.params copied in)') 
    477  
    478  
    479 class Dispatcher(object): 
    480      
    481     def __call__(self, path_info): 
    482         """Set handler and config for the current request.""" 
    483         request = cherrypy.request 
    484         func, vpath = self.find_handler(path_info) 
    485          
    486         if func: 
    487             # Decode any leftover %2F in the virtual_path atoms. 
    488             vpath = [x.replace("%2F", "/") for x in vpath] 
    489             request.handler = LateParamPageHandler(func, *vpath) 
    490         else: 
    491             request.handler = cherrypy.NotFound() 
    492      
    493     def find_handler(self, path): 
    494         """Find the appropriate page handler for the given path.""" 
    495         request = cherrypy.request 
    496         app = request.app 
    497         root = app.root 
    498          
    499         # Get config for the root object/path. 
    500         environments = cherrypy.config.environments 
    501         curpath = "" 
    502         nodeconf = {} 
    503         if hasattr(root, "_cp_config"): 
    504             nodeconf.update(root._cp_config) 
    505         if 'environment' in nodeconf: 
    506             env = environments[nodeconf['environment']] 
    507             for k in env: 
    508                 if k not in nodeconf: 
    509                     nodeconf[k] = env[k] 
    510         if "/" in app.conf: 
    511             nodeconf.update(app.conf["/"]) 
    512         object_trail = [('root', root, nodeconf, curpath)] 
    513          
    514         node = root 
    515         names = [x for x in path.strip('/').split('/') if x] + ['index'] 
    516         for name in names: 
    517             # map to legal Python identifiers (replace '.' with '_') 
    518             objname = name.replace('.', '_') 
    519              
    520             nodeconf = {} 
    521             node = getattr(node, objname, None) 
    522             if node is not None: 
    523                 # Get _cp_config attached to this node. 
    524                 if hasattr(node, "_cp_config"): 
    525                     nodeconf.update(node._cp_config) 
    526                      
    527                     # Resolve "environment" entries. This must be done node-by-node 
    528                     # so that a child's "environment" can override concrete settings 
    529                     # of a parent. However, concrete settings in this node will 
    530                     # override "environment" settings in the same node. 
    531                     if 'environment' in nodeconf: 
    532                         env = environments[nodeconf['environment']] 
    533                         for k in env: 
    534                             if k not in nodeconf: 
    535                                 nodeconf[k] = env[k] 
    536              
    537             # Mix in values from app.conf for this path. 
    538             curpath = "/".join((curpath, name)) 
    539             if curpath in app.conf: 
    540                 nodeconf.update(app.conf[curpath]) 
    541              
    542             object_trail.append((objname, node, nodeconf, curpath)) 
    543          
    544         def set_conf(): 
    545             """Set cherrypy.request.config.""" 
    546             base = cherrypy.config.globalconf.copy() 
    547             # Note that we merge the config from each node 
    548             # even if that node was None. 
    549             for name, obj, conf, curpath in object_trail: 
    550                 base.update(conf) 
    551                 if 'tools.staticdir.dir' in conf: 
    552                     base['tools.staticdir.section'] = curpath 
    553             return base 
    554          
    555         # Try successive objects (reverse order) 
    556         for i in xrange(len(object_trail) - 1, -1, -1): 
    557              
    558             name, candidate, nodeconf, curpath = object_trail[i] 
    559             if candidate is None: 
    560                 continue 
    561              
    562             # Try a "default" method on the current leaf. 
    563             if hasattr(candidate, "default"): 
    564                 defhandler = candidate.default 
    565                 if getattr(defhandler, 'exposed', False): 
    566                     # Insert any extra _cp_config from the default handler. 
    567                     conf = getattr(defhandler, "_cp_config", {}) 
    568                     object_trail.insert(i+1, ("default", defhandler, conf, curpath)) 
    569                     request.config = set_conf() 
    570                     return defhandler, names[i:-1] 
    571              
    572             # Uncomment the next line to restrict positional params to "default". 
    573             # if i < len(object_trail) - 2: continue 
    574              
    575             # Try the current leaf. 
    576             if getattr(candidate, 'exposed', False): 
    577                 request.config = set_conf() 
    578                 if i == len(object_trail) - 1: 
    579                     # We found the extra ".index". Check if the original path 
    580                     # had a trailing slash (otherwise, do a redirect). 
    581                     if path[-1:] != '/': 
    582                         atoms = request.browser_url.split("?", 1) 
    583                         new_url = atoms.pop(0) + '/' 
    584                         if atoms: 
    585                             new_url += "?" + atoms[0] 
    586                         raise cherrypy.HTTPRedirect(new_url) 
    587                 return candidate, names[i:-1] 
    588          
    589         # We didn't find anything 
    590         request.config = set_conf() 
    591         return None, [] 
    592  
    593 default_dispatch = Dispatcher() 
    594  
    595  
    596 class MethodDispatcher(Dispatcher): 
    597     """Additional dispatch based on cherrypy.request.method.upper(). 
    598      
    599     Methods named GET, POST, etc will be called on an exposed class. 
    600     The method names must be all caps; the appropriate Allow header 
    601     will be output showing all capitalized method names as allowable 
    602     HTTP verbs. 
    603      
    604     Note that the containing class must be exposed, not the methods. 
    605     """ 
    606      
    607     def __call__(self, path_info): 
    608         """Set handler and config for the current request.""" 
    609         request = cherrypy.request 
    610         resource, vpath = self.find_handler(path_info) 
    611          
    612         # Decode any leftover %2F in the virtual_path atoms. 
    613         vpath = [x.replace("%2F", "/") for x in vpath] 
    614          
    615         if resource: 
    616             # Set Allow header 
    617             avail = [m for m in dir(resource) if m.isupper()] 
    618             if "GET" in avail and "HEAD" not in avail: 
    619                 avail.append("HEAD") 
    620             avail.sort() 
    621             cherrypy.response.headers['Allow'] = ", ".join(avail) 
    622              
    623             # Find the subhandler 
    624             meth = cherrypy.request.method.upper() 
    625             func = getattr(resource, meth, None) 
    626             if func is None and meth == "HEAD": 
    627                 func = getattr(resource, "GET", None) 
    628             if func: 
    629                 request.handler = LateParamPageHandler(func, *vpath) 
    630             else: 
    631                 request.handler = cherrypy.HTTPError(405) 
    632         else: 
    633             request.handler = cherrypy.NotFound() 
    634628 
    635629 
     
    692686    time = None 
    693687    timed_out = False 
     688    stream = False 
    694689     
    695690    def __init__(self): 
     
    726721        self.status = "%s %s" % (code, reason) 
    727722         
    728         stream = cherrypy.config.get("stream_response", False) 
    729         # OPTIONS requests MUST include a Content-Length of 0 if no body. 
    730         # Just punt and figure Content-Length for all OPTIONS requests. 
    731         if cherrypy.request.method == "OPTIONS": 
    732             stream = False 
    733          
    734723        headers = self.headers 
    735         if stream: 
     724        if self.stream: 
    736725            headers.pop('Content-Length', None) 
    737726        else: 
     
    758747        so that a monitor thread can interrupt the Response thread. 
    759748        """ 
    760         timeout = float(cherrypy.config.get('deadlock_timeout', 300)) 
     749        timeout = float(cherrypy.config.get('deadlock.timeout', 300)) 
    761750        if time.time() > self.time + timeout: 
    762751            self.timed_out = True 
  • trunk/cherrypy/_cptools.py

    r1261 r1275  
    235235    wsgi_app - any wsgi application callable 
    236236    env_update - a dictionary with arbitrary keys and values to be 
    237                  merged with the WSGI environment dictionary. 
     237                 merged with the WSGI environ dictionary. 
    238238     
    239239    Example: 
  • trunk/cherrypy/_cptree.py

    r1260 r1275  
    5050        # Create log handlers as specified in config. 
    5151        rootconf = self.conf.get("/", {}) 
    52         config._configure_builtin_logging(rootconf, self.access_log, "log_access_file") 
     52        config._configure_builtin_logging(rootconf, self.access_log, "log.access.file") 
    5353        config._configure_builtin_logging(rootconf, self.error_log) 
    5454     
  • trunk/cherrypy/_cpwsgi.py

    r1269 r1275  
    6868        raise ex 
    6969    except: 
    70         if cherrypy.config.get("throw_errors", False)
     70        if request and request.throw_errors
    7171            raise 
    7272        tb = format_exc() 
    7373        cherrypy.log(tb) 
    74         if not cherrypy.config.get("show_tracebacks", False)
     74        if request and not request.show_tracebacks
    7575            tb = "" 
    7676        s, h, b = bare_error(tb) 
     
    136136        if isinstance(self.rfile, http.SizeCheckWrapper): 
    137137            self.rfile = self.rfile.rfile 
    138         mbs = int(cherrypy.config.get('server.max_request_body_size', 
    139                                       100 * 1024 * 1024)) 
     138        mbs = int(cherrypy.config.get('request.max_body_size', 100 * 1024 * 1024)) 
    140139        if mbs > 0: 
    141140            self.rfile = http.SizeCheckWrapper(self.rfile, mbs) 
  • trunk/cherrypy/config.py

    r1253 r1275  
    1 """Configuration system for CherryPy.""" 
     1"""Configuration system for CherryPy. 
     2 
     3Configuration in CherryPy is implemented via dictionaries. Keys are strings 
     4which name the mapped value, which may be of any type. 
     5 
     6 
     7Architecture 
     8------------ 
     9 
     10CherryPy Requests are part of an Application, which runs in a global context, 
     11and configuration data may apply to any of those three scopes: 
     12 
     13    Global: configuration entries which apply everywhere are stored in 
     14    cherrypy.config.globalconf. Use the top-level function 'config.update' 
     15    to modify it. 
     16     
     17    Application: entries which apply to each mounted application are stored 
     18    on the Application object itself, as 'app.conf'. This is a two-level 
     19    dict where each key is a path, or "relative URL" (for example, "/" or 
     20    "/path/to/my/page"), and each value is a config dict. Usually, this 
     21    data is provided in the call to cherrypy.tree.mount(root(), conf=conf), 
     22    although you may also use app.merge(conf). 
     23     
     24    Request: each Request object possesses a single 'Request.config' dict. 
     25    Early in the request process, this dict is populated by merging global 
     26    config entries, Application entries (whose path equals or is a parent 
     27    of Request.path_info), and any config acquired while looking up the 
     28    page handler (see next). 
     29 
     30 
     31Usage 
     32----- 
     33 
     34Configuration data may be supplied as a Python dictionary, as a filename, 
     35or as an open file object. When you supply a filename or file, CherryPy 
     36uses Python's builtin ConfigParser; you declare Application config by 
     37writing each path as a section header: 
     38 
     39    [/path/to/my/page] 
     40    request.stream = True 
     41 
     42To declare global configuration entries, place them in a [global] section. 
     43 
     44You may also declare config entries directly on the classes and methods 
     45(page handlers) that make up your CherryPy application via the '_cp_config' 
     46attribute. For example: 
     47 
     48    class Demo: 
     49        _cp_config = {'tools.gzip.on': True} 
     50         
     51        def index(self): 
     52            raise cherrypy.InternalRedirect("/cuba") 
     53        index.exposed = True 
     54        index._cp_config = {'request.recursive_redirect': True} 
     55 
     56 
     57Namespaces 
     58---------- 
     59 
     60Configuration keys are separated into namespaces by the first "." in the key. 
     61Current namespaces: 
     62 
     63    autoreload: Controls the autoreload mechanism in cherrypy.engine. 
     64                These can only be declared in the global config. 
     65    deadlock:   Controls the deadlock monitoring system in cherrypy.engine. 
     66                These can only be declared in the global config. 
     67    hooks:      Declares additional request-processing functions. 
     68    log:        Configures the logging for each application. 
     69    request:    Adds attributes to each Request during the tool_up phase. 
     70    response:   Adds attributes to each Response during the tool_up phase. 
     71    server:     Controls the default HTTP server via cherrypy.server. 
     72                These can only be declared in the global config. 
     73    tools:      Runs and configures additional request-processing packages. 
     74 
     75The only key that does not exist in a namespace is the "environment" entry. 
     76This special entry 'imports' other config entries from a template stored in 
     77cherrypy.config.environments[environment]. It only applies to globalconf, 
     78and only when you use "update" to modify globalconf. 
     79""" 
    280 
    381import ConfigParser 
     
    583_logfmt = _logging.Formatter("%(message)s") 
    684import os as _os 
     85_localdir = _os.path.dirname(__file__) 
    786 
    887import cherrypy 
     
    1089 
    1190environments = { 
    12     "development": { 
    13         'autoreload.on': True, 
    14         'log_file_not_found': True, 
    15         'show_tracebacks': True, 
    16         'log_request_headers': True, 
    17         }, 
    1891    "staging": { 
    1992        'autoreload.on': False, 
    20         'log_file_not_found': False, 
    21         'show_tracebacks': False, 
    22         'log_request_headers': False, 
     93        'tools.log_headers.on': False, 
     94        'request.show_tracebacks': False, 
    2395        }, 
    2496    "production": { 
    2597        'autoreload.on': False, 
    26         'log_file_not_found': False, 
    27         'show_tracebacks': False, 
    28         'log_request_headers': False, 
     98        'tools.log_headers.on': False, 
     99        'request.show_tracebacks': False, 
     100        'log.screen': False, 
    29101        }, 
    30     "embedded": { 
     102    "test_suite": { 
    31103        'autoreload.on': False, 
    32         'log_to_screen': False, 
    33         'server.class': None, 
     104        'tools.log_headers.on': False, 
     105        'request.show_tracebacks': True, 
     106        'log.screen': False, 
    34107        }, 
    35108    } 
     
    40113        if other not in cherrypy.engine.reload_files: 
    41114            cherrypy.engine.reload_files.append(other) 
    42         other = Parser().dict_from_file(other) 
     115        other = _Parser().dict_from_file(other) 
    43116    elif hasattr(other, 'read'): 
    44         other = Parser().dict_from_file(other) 
     117        other = _Parser().dict_from_file(other) 
    45118     
    46119    # Load other into base 
    47120    for section, value_map in other.iteritems(): 
    48         # Resolve "environment" entries 
    49         if 'environment' in value_map: 
    50             env = environments[value_map['environment']] 
    51             for k in env: 
    52                 if k not in value_map: 
    53                     value_map[k] = env[k] 
    54             del value_map['environment'] 
    55          
    56121        base.setdefault(section, {}).update(value_map) 
    57122 
     123 
    58124default_conf = { 
     125    # Server config 
    59126    'server.socket_port': 8080, 
    60127    'server.socket_host': '', 
     
    65132    'server.reverse_dns': False, 
    66133    'server.thread_pool': 10, 
    67     'log_to_screen': True, 
    68     'log_file': _os.path.join(_os.getcwd(), _os.path.dirname(__file__), 
    69                               "error.log"), 
     134    'server.max_request_header_size': 500 * 1024, 
     135    'server.instance': None, 
     136     
     137    # Log config 
     138    'log.to_screen': True, 
     139##    'log.error.function': cherrypy._log_message, 
     140    'log.error.file': _os.path.join(_os.getcwd(), _localdir, "error.log"), 
     141    # Using an access file makes CP about 10% slower. 
     142##    'log.access.function': cherrypy.log_access, 
     143##    'log.access.file': _os.path.join(_os.getcwd(), _localdir, "access.log"), 
     144     
     145    # Process management 
     146    'autoreload.on': True, 
     147    'autoreload.frequency': 1, 
     148    'deadlock.timeout': 300, 
     149    'deadlock.poll_freq': 60, 
     150     
     151    'error_page.404': '', 
     152     
    70153    'tools.log_tracebacks.on': True, 
    71     'environment': "development"
     154    'tools.log_headers.on': True
    72155    } 
     156 
    73157 
    74158globalconf = default_conf.copy() 
     
    83167        if conf not in cherrypy.engine.reload_files: 
    84168            cherrypy.engine.reload_files.append(conf) 
    85         conf = Parser().dict_from_file(conf) 
     169        conf = _Parser().dict_from_file(conf) 
    86170    elif hasattr(conf, 'read'): 
    87         conf = Parser().dict_from_file(conf) 
     171        conf = _Parser().dict_from_file(conf) 
    88172     
    89173    if isinstance(conf.get("global", None), dict): 
     
    102186     
    103187    _configure_builtin_logging(globalconf, cherrypy._error_log) 
    104     _configure_builtin_logging(globalconf, cherrypy._access_log, "log_access_file") 
     188    _configure_builtin_logging(globalconf, cherrypy._access_log, "log.access.file") 
    105189 
    106190def _add_builtin_screen_handler(log): 
     
    119203    log.addHandler(h) 
    120204 
    121 def _configure_builtin_logging(conf, log, filekey="log_file"): 
     205def _configure_builtin_logging(conf, log, filekey="log.error.file"): 
    122206    """Create/destroy builtin log handlers as needed from conf.""" 
    123207     
     
    125209                     for x in log.handlers]) 
    126210    h = existing.get("screen") 
    127     screen = conf.get('log_to_screen') 
     211    screen = conf.get('log.screen') 
    128212    if screen: 
    129213        if not h: 
     
    170254 
    171255 
    172 class Parser(ConfigParser.ConfigParser): 
     256class _Parser(ConfigParser.ConfigParser): 
    173257    """Sub-class of ConfigParser that keeps the case of options and that raises 
    174258    an exception if the file cannot be read. 
     
    227311    server_vars = [ 
    228312                  'environment', 
    229                   'log_to_screen', 
    230                   'log_file', 
     313                  'log.screen', 
     314                  'log.error.file', 
    231315                  'server.protocol_version', 
    232316                  'server.socket_host', 
  • trunk/cherrypy/lib/encoding.py

    r1243