[Checkins] SVN: grok/branches/faassen-martian/martian/src/martian/ Add prepare and finalize functions that can be run around module

Martijn Faassen faassen at infrae.com
Sun May 6 14:12:37 EDT 2007


Log message for revision 75579:
  Add prepare and finalize functions that can be run around module
  grokking. 
  
  Add some sanity checking code to make sure grokking returns True or
  False.
  

Changed:
  U   grok/branches/faassen-martian/martian/src/martian/README.txt
  U   grok/branches/faassen-martian/martian/src/martian/__init__.py
  U   grok/branches/faassen-martian/martian/src/martian/core.py

-=-
Modified: grok/branches/faassen-martian/martian/src/martian/README.txt
===================================================================
--- grok/branches/faassen-martian/martian/src/martian/README.txt	2007-05-06 17:41:06 UTC (rev 75578)
+++ grok/branches/faassen-martian/martian/src/martian/README.txt	2007-05-06 18:12:36 UTC (rev 75579)
@@ -207,12 +207,6 @@
   >>> module_grokker = ModuleGrokker()
   >>> module_grokker.register(filetype_grokker)
 
-Note that directly putting a grokker into a ``ModuleGrokker`` is
-typically not recommended - normally you would put in a multi grokker
-(see the examples for multi grokkers). We can do it here as the only
-thing we want to grok are functions and other objects are rejected on
-a name basis.
-
 We now define a module that defines a few filetype handlers to be
 grokked::
 
@@ -405,7 +399,7 @@
 Let's put our ``multi_grokker`` in a ``ModuleGrokker``. We can do
 this by passing it explicitly to the ``ModuleGrokker`` factory::
 
-  >>> module_grokker = ModuleGrokker(multi_grokker)
+  >>> module_grokker = ModuleGrokker(grokker=multi_grokker)
 
 We can now grok a module for both ``Color`` and ``Sound`` instances::
 
@@ -493,7 +487,7 @@
 
 Now let's wrap it into a ``ModuleGrokker`` and grok the module::
 
-  >>> grokker = ModuleGrokker(multi_grokker)
+  >>> grokker = ModuleGrokker(grokker=multi_grokker)
   >>> grokker.grok('animals', animals)
   True
 
@@ -638,7 +632,7 @@
 
 Let's construct a ``ModuleGrokker`` that can grok this module::
 
-  >>> mix_grokker = ModuleGrokker(multi)
+  >>> mix_grokker = ModuleGrokker(grokker=multi)
 
 Note that this is actually equivalent to calling ``ModuleGrokker``
 without arguments and then calling ``register`` for the individual
@@ -779,6 +773,86 @@
   >>> sorted(all_animals.keys())
   ['Animal', 'Bear', 'Dragon', 'Lizard', 'Python', 'SpermWhale', 'Whale']
 
+Preparation and finalization
+----------------------------
 
-  
+Before grokking a module, it may be that we need to do some
+preparation. This preparation can include setting up some parameters
+to pass along to the grokking process, for instance. We can pass
+a ``prepare`` function a the ModuleGrokker::
 
+  >>> class Number(object):
+  ...   def __init__(self, nr):
+  ...     self.nr = nr
+  >>> all_numbers = {}
+  >>> class NumberGrokker(InstanceGrokker):
+  ...  component_class = Number
+  ...  def grok(self, name, obj, multiplier):
+  ...    all_numbers[obj.nr] = obj.nr * multiplier
+  ...    return True
+  >>> def prepare(name, module, kw):
+  ...   kw['multiplier'] = 3
+  >>> module_grokker = ModuleGrokker(prepare=prepare)
+  >>> module_grokker.register(NumberGrokker())
+ 
+We have created a ``prepare`` function that does one thing: create a
+``multiplier`` parameter that is passed along the grokking
+process. The ``NumberGrokker`` makes use of this to prepare the
+``all_numbers`` dictionary values.
+
+Let's try this with a module::
+
+  >>> class numbers(FakeModule):
+  ...   one = Number(1)
+  ...   two = Number(2)
+  ...   four = Number(4)
+  >>> numbers = fake_import(numbers)
+  >>> module_grokker.grok('numbers', numbers)
+  True
+  >>> sorted(all_numbers.items())
+  [(1, 3), (2, 6), (4, 12)]
+
+You can also optionally register a finalization function, which will
+be run at the end of a module grok::
+
+  >>> def finalize(name, module, kw):
+  ...     all_numbers['finalized'] = True
+  >>> module_grokker = ModuleGrokker(prepare=prepare, finalize=finalize)
+  >>> module_grokker.register(NumberGrokker())
+  >>> all_numbers = {}
+  >>> module_grokker.grok('numbers', numbers)
+  True
+  >>> 'finalized' in all_numbers
+  True
+
+Sanity checking
+---------------
+
+Grokkers must return ``True`` if grokking succeeded, or ``False`` if
+it didn't. If they return something else (typically ``None`` as the
+programmer forgot to), the system will raise an error::
+
+  >>> class BrokenGrokker(InstanceGrokker):
+  ...  component_class = Number
+  ...  def grok(self, name, obj):
+  ...    pass
+
+  >>> module_grokker = ModuleGrokker()
+  >>> module_grokker.register(BrokenGrokker())
+  >>> module_grokker.grok('numbers', numbers) 
+  Traceback (most recent call last):
+    ...
+  GrokError: <BrokenGrokker object at ...> returns None instead of 
+  True or False.
+
+Let's also try this with a GlobalGrokker::
+
+  >>> class MyGrokker(GlobalGrokker):
+  ...   def grok(self, name, module):
+  ...     return "Foo"
+  >>> module_grokker = ModuleGrokker()
+  >>> module_grokker.register(MyGrokker())
+  >>> module_grokker.grok('numbers', numbers)
+  Traceback (most recent call last):
+    ...
+  GrokError: <MyGrokker object at ...> returns 'Foo' instead of True or False.

Modified: grok/branches/faassen-martian/martian/src/martian/__init__.py
===================================================================
--- grok/branches/faassen-martian/martian/src/martian/__init__.py	2007-05-06 17:41:06 UTC (rev 75578)
+++ grok/branches/faassen-martian/martian/src/martian/__init__.py	2007-05-06 18:12:36 UTC (rev 75579)
@@ -1,2 +1,3 @@
-from core import ModuleGrokker, MultiGrokker, grok_dotted_name
+from core import ModuleGrokker, MultiGrokker, grok_dotted_name,\
+     grok_package, grok_module
 from components import GlobalGrokker, ClassGrokker, InstanceGrokker

Modified: grok/branches/faassen-martian/martian/src/martian/core.py
===================================================================
--- grok/branches/faassen-martian/martian/src/martian/core.py	2007-05-06 17:41:06 UTC (rev 75578)
+++ grok/branches/faassen-martian/martian/src/martian/core.py	2007-05-06 18:12:36 UTC (rev 75579)
@@ -6,15 +6,18 @@
 from martian import util, scan
 from martian.components import (GrokkerBase, ClassGrokker, InstanceGrokker,
                                 GlobalGrokker)
+from martian.error import GrokError
 
 class ModuleGrokker(GrokkerBase):
     implements(IMultiGrokker)
 
-    def __init__(self, grokker=None):
+    def __init__(self, grokker=None, prepare=None, finalize=None):
         if grokker is None:
             grokker = MultiGrokker()
         self._grokker = grokker
-
+        self.prepare = prepare
+        self.finalize = finalize
+        
     def register(self, grokker):
         self._grokker.register(grokker)
         
@@ -22,6 +25,10 @@
         grokked_status = False
         grokker = self._grokker
 
+        # prepare module grok - this can also influence the kw dictionary
+        if self.prepare is not None:
+            self.prepare(name, module, kw)
+        
         # trigger any global grokkers
         grokked = grokker.grok(name, module, **kw)
         if grokked:
@@ -40,6 +47,10 @@
             if grokked:
                 grokked_status = True
 
+        # finalize module grok
+        if self.finalize is not None:
+            self.finalize(name, module, kw)
+        
         return grokked_status
         
 class MultiGrokkerBase(GrokkerBase):
@@ -64,6 +75,10 @@
             for grokker in grokkers:
                 if grokker not in used_grokkers:
                     grokked = grokker.grok(name, obj, **kw)
+                    if grokked not in (True, False):
+                        raise GrokError(
+                            "%r returns %r instead of True or False." %
+                            (grokker, grokked), None)
                     if grokked:
                         grokked_status = True
                     used_grokkers.add(grokker)
@@ -91,8 +106,12 @@
     def grok(self, name, module, **kw):
         grokked_status = False
         for grokker in self._grokkers:
-            status = grokker.grok(name, module, **kw)
-            if status:
+            grokked = grokker.grok(name, module, **kw)
+            if grokked not in (True, False):
+                raise GrokError(
+                    "%r returns %r instead of True or False." %
+                    (grokker, grokked), None)         
+            if grokked:
                 grokked_status = True
         return grokked_status
 
@@ -134,7 +153,7 @@
     for sub_module_info in module_info.getSubModuleInfos():
         grok_package(sub_module_info, grokker, **kw)
 
-def grok_module(module_info, grokker, **kw):
+def grok_module(module_info, grokker=None, **kw):
     if grokker is None:
         grokker = the_module_grokker
     grokker.grok(module_info.dotted_name, module_info.getModule(), **kw)



More information about the Checkins mailing list