[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