Robert Brewer avatar Robert Brewer committed 41585da

Promoted namespace dicts to their own class (so they can share docs).

Comments (0)

Files changed (3)

cherrypy/_cpconfig.py

         base.setdefault(section, {}).update(value_map)
 
 
-def _call_namespaces(config, namespaces):
-    """Iterate through config and pass it to each namespace.
+class NamespaceSet(dict):
+    """A dict of config namespace names and handlers.
     
-    'config' should be a flat dict, where keys use dots to separate
-    namespaces, and values are arbitrary.
-    'namespaces' should be a dict whose keys are strings and whose
-    values are namespace handlers.
+    Each config entry should begin with a namespace name; the corresponding
+    namespace handler will be called once for each config entry in that
+    namespace, and will be passed two arguments: the config key (with the
+    namespace removed) and the config value.
     
-    The first name in each config key is used to look up the corresponding
-    namespace handler. For example, a config entry of {'tools.gzip.on': v}
-    will call the 'tools' namespace handler with the args: ('gzip.on', v)
+    Namespace handlers may be any Python callable; they may also be
+    Python 2.5-style 'context managers', in which case their __enter__
+    method should return a callable to be used as the handler.
+    See cherrypy.tools (the Toolbox class) for an example.
+    """
     
-    Each handler may be a bare callable, or it may be a context manager
-    with __enter__ and __exit__ methods, in which case the __enter__
-    method should return the callable.
-    """
-    # Separate the given config into namespaces
-    ns_confs = {}
-    for k in config:
-        if "." in k:
-            ns, name = k.split(".", 1)
-            bucket = ns_confs.setdefault(ns, {})
-            bucket[name] = config[k]
+    def __call__(self, config):
+        """Iterate through config and pass it to each namespace handler.
+        
+        'config' should be a flat dict, where keys use dots to separate
+        namespaces, and values are arbitrary.
+        
+        The first name in each config key is used to look up the corresponding
+        namespace handler. For example, a config entry of {'tools.gzip.on': v}
+        will call the 'tools' namespace handler with the args: ('gzip.on', v)
+        """
+        # Separate the given config into namespaces
+        ns_confs = {}
+        for k in config:
+            if "." in k:
+                ns, name = k.split(".", 1)
+                bucket = ns_confs.setdefault(ns, {})
+                bucket[name] = config[k]
+        
+        # I chose __enter__ and __exit__ so someday this could be
+        # rewritten using Python 2.5's 'with' statement:
+        # for ns, handler in self.iteritems():
+        #     with handler as callable:
+        #         for k, v in ns_confs.get(ns, {}).iteritems():
+        #             callable(k, v)
+        for ns, handler in self.iteritems():
+            exit = getattr(handler, "__exit__", None)
+            if exit:
+                callable = handler.__enter__()
+                no_exc = True
+                try:
+                    try:
+                        for k, v in ns_confs.get(ns, {}).iteritems():
+                            callable(k, v)
+                    except:
+                        # The exceptional case is handled here
+                        no_exc = False
+                        if exit is None:
+                            raise
+                        if not exit(*sys.exc_info()):
+                            raise
+                        # The exception is swallowed if exit() returns true
+                finally:
+                    # The normal and non-local-goto cases are handled here
+                    if no_exc and exit:
+                        exit(None, None, None)
+            else:
+                for k, v in ns_confs.get(ns, {}).iteritems():
+                    handler(k, v)
     
-    # I chose __enter__ and __exit__ so someday this could be
-    # rewritten using Python 2.5's 'with' statement:
-    # for ns, handler in namespaces.iteritems():
-    #     with handler as callable:
-    #         for k, v in ns_confs.get(ns, {}).iteritems():
-    #             callable(k, v)
-    for ns, handler in namespaces.iteritems():
-        exit = getattr(handler, "__exit__", None)
-        if exit:
-            callable = handler.__enter__()
-            no_exc = True
-            try:
-                try:
-                    for k, v in ns_confs.get(ns, {}).iteritems():
-                        callable(k, v)
-                except:
-                    # The exceptional case is handled here
-                    no_exc = False
-                    if exit is None:
-                        raise
-                    if not exit(*sys.exc_info()):
-                        raise
-                    # The exception is swallowed if exit() returns true
-            finally:
-                # The normal and non-local-goto cases are handled here
-                if no_exc and exit:
-                    exit(None, None, None)
-        else:
-            for k, v in ns_confs.get(ns, {}).iteritems():
-                handler(k, v)
+    def __repr__(self):
+        return "%s.%s(%s)" % (self.__module__, self.__class__.__name__,
+                              dict.__repr__(self))
+    
+    def __copy__(self):
+        newobj = self.__class__()
+        newobj.update(self)
+        return newobj
+    copy = __copy__
 
 
 class Config(dict):
         'tools.trailing_slash.on': True,
         }
     
-    namespaces = {"server": lambda k, v: setattr(cherrypy.server, k, v),
-                  "engine": lambda k, v: setattr(cherrypy.engine, k, v),
-                  "log": lambda k, v: setattr(cherrypy.log, k, v),
-                  "checker": lambda k, v: setattr(cherrypy.checker, k, v),
-                  }
+    namespaces = NamespaceSet(
+        **{"server": lambda k, v: setattr(cherrypy.server, k, v),
+           "engine": lambda k, v: setattr(cherrypy.engine, k, v),
+           "log": lambda k, v: setattr(cherrypy.log, k, v),
+           "checker": lambda k, v: setattr(cherrypy.checker, k, v),
+           })
     
     def __init__(self):
         self.reset()
             config['tools.staticdir.section'] = "global"
         
         dict.update(self, config)
-        _call_namespaces(config, self.namespaces)
+        self.namespaces(config)
     
     def __setitem__(self, k, v):
         dict.__setitem__(self, k, v)
-        _call_namespaces({k: v}, self.namespaces)
+        self.namespaces({k: v})
 
 
 

cherrypy/_cprequest.py

 import types
 
 import cherrypy
-from cherrypy import _cpcgifs
+from cherrypy import _cpcgifs, _cpconfig
 from cherrypy._cperror import format_exc, bare_error
 from cherrypy.lib import http
 
     If True, Request.run will not trap any errors (except HTTPRedirect and
     HTTPError, which are more properly called 'exceptions', not errors)."""
     
-    namespaces = {"hooks": hooks_namespace,
-                  "request": request_namespace,
-                  "response": response_namespace,
-                  "error_page": error_page_namespace,
-                  # "tools": See _cptools.Toolbox
-                  }
-    namespaces__doc = """
-    A dict of config namespace names and handlers. Each config entry should
-    begin with a namespace name; the corresponding namespace handler will
-    be called once for each config entry in that namespace, and will be
-    passed two arguments: the config key (with the namespace removed)
-    and the config value.
-    
-    Namespace handlers may be any Python callable; they may also be
-    Python 2.5-style 'context managers', in which case their __enter__
-    method should return a callable to be used as the handler.
-    See cherrypy.tools (the Toolbox class) for an example.
-    
-    Namespaces may be added at the class level and will be inherited
-    by all Request instances.
-    """
+    namespaces = _cpconfig.NamespaceSet(
+        **{"hooks": hooks_namespace,
+           "request": request_namespace,
+           "response": response_namespace,
+           "error_page": error_page_namespace,
+           # "tools": See _cptools.Toolbox
+           })
     
     def __init__(self, local_host, remote_host, scheme="http",
                  server_protocol="HTTP/1.1"):
                     self.hooks = self.__class__.hooks.copy()
                     self.toolmaps = {}
                     self.get_resource(path_info)
-                    cherrypy._cpconfig._call_namespaces(self.config,
-                                                        self.namespaces)
+                    self.namespaces(self.config)
                     
                     self.hooks.run('on_start_resource')
                     
     (key, value) tuples.
     """
     
+    __metaclass__ = cherrypy._AttributeDocstrings
+    
     # Class attributes for dev-time introspection.
     status = ""
     status__doc = """The HTTP Status-Code and Reason-Phrase."""

cherrypy/_cptree.py

     A dict of {path: pathconf} pairs, where 'pathconf' is itself a dict
     of {key: value} pairs."""
     
-    namespaces = {}
-    namespaces__doc = """
-    A dict of config namespace names and handlers. Each config entry should
-    begin with a namespace name; the corresponding namespace handler will
-    be called once for each config entry in that namespace, and will be
-    passed two arguments: the config key (with the namespace removed)
-    and the config value.
-    
-    Namespace handlers may be any Python callable; they may also be
-    Python 2.5-style 'context managers', in which case their __enter__
-    method should return a callable to be used as the handler.
-    See cherrypy.tools (the Toolbox class) for an example.
-    """
+    namespaces = _cpconfig.NamespaceSet()
     
     log = None
     log__doc = """A LogManager instance. See _cplogging."""
         _cpconfig.merge(self.config, config)
         
         # Handle namespaces specified in config.
-        _cpconfig._call_namespaces(self.config.get("/", {}), self.namespaces)
+        self.namespaces(self.config.get("/", {}))
     
     def __call__(self, environ, start_response):
         return self.wsgiapp(environ, start_response)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.