[Repoze-dev] Repoze CVS: publisher.py

Tres Seaver tseaver at agendaless.com
Wed Sep 12 20:20:27 UTC 2007


Update of /home/repoze/cvs/repoze.obob/repoze/obob
In directory laguna.palladion.com:/tmp/cvs-serv16762/repoze/obob

Modified Files:
	publisher.py 
Log Message:
 - Break multiple plugpoints out into a separate helper class, configured
   through new 'helper_factory' plugpoing on ObobPublisher.

 - Remove use of 'request' anywhere (the helper is responsible for all that).

 - Move old default plugpoint implementations out into DefaultHelper class.


Index: publisher.py
===================================================================
RCS file: /home/repoze/cvs/repoze.obob/repoze/obob/publisher.py,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- publisher.py	12 Sep 2007 18:23:35 -0000	1.5
+++ publisher.py	12 Sep 2007 20:20:25 -0000	1.6
@@ -1,136 +1,105 @@
-PLUGPOINTS = ('request_factory',
-              'get_root',
-              'before_traverse',
-              'traverse',
-              'before_invoke',
-              'invoke',
-              'map_result',
-             )
+""" repoze.obob publisher:  perform policy-driven graph traversal.
+"""
 
-class ObobPublisher:
+class DefaultHelper:
+    """ Default traversal policy helper.
 
-    def __init__(self,
-                 get_root=None,
-                 request_factory=None,
-                 before_traverse=None,
-                 traverse=None,
-                 before_invoke=None,
-                 invoke=None,
-                 map_result=None,
-                 dispatchable=None,
-                 extras=None,
-                ):
+    Simple applications may just use this class directly.  More complex
+    apps can either subclass it, or else supply a different 'helper_factory'
+    to the ObobPublisher constructor, implementing all the same methods
+    on the returned object.
+    """
+    def __init__(self, environ):
+        self.environ = environ
 
-        if dispatchable is None:
-            dispatchable = {}
+    def path_elements(self):
+        return [x for x in self.environ['PATH_INFO'].split('/') if x.strip()]
 
-        if extras is None:
-            extras = {}
+    def before_traverse(self, current, name):
+        pass
 
-        self._default_root = _DefaultRoot(dispatchable)
-        self.extras = extras
+    def traverse(self, current, name):
+        return current[name]
 
-        if get_root is not None:
-            if not callable(get_root):
-                raise ValueError("'get_root' not callable!")
+    def before_invoke(self, published):
+        pass
 
-            self.get_root = get_root
+    def invoke(self, published):
+        return published()
 
-        if request_factory is not None:
-            if not callable(request_factory):
-                raise ValueError("'request_factory' not callable!")
-            self.request_factory = request_factory
+    def map_result(self, result):
+        if isinstance(result, basestring):
+            result = [result]
+        return '200 OK', {}, result
 
-        if before_traverse is not None:
-            if not callable(before_traverse):
-                raise ValueError("'before_traverse' not callable!")
-            self.before_traverse = before_traverse
 
-        if traverse is not None:
-            if not callable(traverse):
-                raise ValueError("'traverse' not callable!")
-            self.traverse = traverse
+class ObobPublisher:
+    """
+    """
+    def __init__(self,
+                 get_root=None,
+                 helper_factory=None,
+                 dispatchable=None,
+                 extras=None,
+                ):
 
-        if before_invoke is not None:
-            if not callable(before_invoke):
-                raise ValueError("'before_invoke' not callable!")
-            self.before_invoke = before_invoke
+        if get_root is not None:
+            self.get_root = get_root
+        else:
+            if dispatchable is None:
+                dispatchable = {}
+            self._default_root = _DefaultRoot(dispatchable)
 
-        if invoke is not None:
-            if not callable(invoke):
-                raise ValueError("'invoke' not callable!")
-            self.invoke = invoke
+        if helper_factory is not None:
+            self.helper_factory = helper_factory
 
-        if map_result is not None:
-            if not callable(map_result):
-                raise ValueError("'map_result' not callable!")
-            self.map_result = map_result
+        if extras is None:
+            extras = {}
+
+        self.extras = extras
 
     def __call__(self, environ, start_response):
         """ Application dispatch via graph traversal.
-        
-        1. Convert WSGI environ into a request object.
 
-        2. Get traversal root via self.get_root().
+        1. Get traversal root via self.get_root().
 
-        3. Iterate over items in request's path:
+        2. Iterate over items in request's path:
 
            a. Notify 'self.before_traverse' if not None.
 
            b. Get next object via 'self.traverse'.
 
-        4. Notify 'self.before_invoke', if not None.
+        3. Notify 'self.before_invoke', if not None.
 
-        5. Call the terminal ("published") object, applying request
+        4. Call the terminal ("published") object, applying request
            parameters.
 
-        6. Map result + request onto WSGI 'start_response' + iteration.
+        5. Map result onto WSGI 'start_response' + iteration.
         """
-        request = self.request_factory(environ)
-        root = current = self.get_root(request)
+        helper = self.helper_factory(environ)
+        root = current = self.get_root(environ)
 
-        elements = request['PATH_INFO'].split('/') # XXX, contract?
-        for name in elements:
-            if name.strip() == '':
-                continue
-            self.before_traverse(current, name, request)
-            current = self.traverse(current, name)
+        for name in helper.path_elements():
+            helper.before_traverse(current, name)
+            current = helper.traverse(current, name)
 
-        published = request['PUBLISHED'] = current # XXX, contract?
+        published = current
 
-        self.before_invoke(published, request)
-        result = self.invoke(published, request)
+        helper.before_invoke(published)
+        result = helper.invoke(published)
 
-        status, headers, body_iter = self.map_result(request, result)
+        status, headers, body_iter = helper.map_result(result)
 
         start_response(status, headers)
 
         for chunk in body_iter:
             yield chunk
 
-    # Default implementations for plug points.
-    def request_factory(self, environ):
-        return environ
-
-    def get_root(self, request):
+    def get_root(self, environ):
         return self._default_root
 
-    def before_traverse(self, current, name, request):
-        pass
-
-    def traverse(self, current, name):
-        return current[name]
-
-    def before_invoke(self, published, request):
-        pass
-
-    def invoke(self, published, request):
-        return published()
-
-    def map_result(self, request, result):
-        if isinstance(result, basestring):
-            result = [result]
-        return '200 OK', {}, result
+    def helper_factory(self, environ):
+        return DefaultHelper(environ)
 
 class _DefaultRoot:
 
@@ -158,6 +127,11 @@
                      ])
         return lines
 
+
+_PLUGPOINTS = ('get_root',
+               'helper_factory',
+              )
+
 def _resolve(dotted_or_ep):
     from pkg_resources import EntryPoint
     return EntryPoint.parse('x=%s' % dotted_or_ep).load(False)
@@ -171,7 +145,7 @@
         if k.startswith(PREFIX):
             trimmed = k[len(PREFIX):]
             callable = _resolve(v)
-            if trimmed in PLUGPOINTS:
+            if trimmed in _PLUGPOINTS:
                 new_kw[trimmed] = callable
             else:
                 dispatchable[trimmed] = callable

_______________________________________________
Repoze-dev mailing list
Repoze-dev at lists.repoze.org
http://lists.repoze.org/mailman/listinfo/repoze-dev



More information about the Repoze-dev mailing list