[Checkins] SVN: grok/trunk/martian/src/martian/ Now test MultiMartian.

Martijn Faassen faassen at infrae.com
Tue May 1 16:08:14 EDT 2007


Log message for revision 74971:
  Now test MultiMartian.
  

Changed:
  U   grok/trunk/martian/src/martian/README.txt
  U   grok/trunk/martian/src/martian/__init__.py
  U   grok/trunk/martian/src/martian/core.py
  U   grok/trunk/martian/src/martian/interfaces.py

-=-
Modified: grok/trunk/martian/src/martian/README.txt
===================================================================
--- grok/trunk/martian/src/martian/README.txt	2007-05-01 19:32:32 UTC (rev 74970)
+++ grok/trunk/martian/src/martian/README.txt	2007-05-01 20:08:13 UTC (rev 74971)
@@ -140,9 +140,10 @@
   ...
   ...   def grok(self, name, obj, **kw):
   ...     if not name.startswith('handle_'):
-  ...       return
+  ...       return False
   ...     ext = name.split('_')[1]
   ...     filehandler.extension_handlers['.' + ext] = obj
+  ...     return True
 
 This ``InstanceMartian`` allows us to grok instances of a particular
 type (such as functions). We need to define the type of object we're
@@ -150,7 +151,8 @@
 method, we first make sure we only grok functions that have a name
 that starts with ``handle_``. Then we determine the used extension
 from the name and register the funcion in the ``extension_handlers``
-dictionary of the ``filehandler`` module.
+dictionary of the ``filehandler`` module. We return ``True`` if we
+indeed grokked the object.
 
 An instance will provide the IMartian interface::
 
@@ -164,6 +166,7 @@
   >>> def handle_jpg(filepath):
   ...   return "JPG file"
   >>> filetype_martian.grok('handle_jpg', handle_jpg)
+  True
 
 After we grokked, we have have registered a handler for ``.jpg`` files
 (the extension to register under was deduced from the function name)::
@@ -183,6 +186,7 @@
   >>> def something(filepath):
   ...   return 'Something'
   >>> filetype_martian.grok('something', something)
+  False
   >>> 'something' in filehandler.extension_handlers
   False
 
@@ -225,6 +229,7 @@
 Let's grok it::
 
   >>> module_martian.grok('lotsofhandlers', lotsofhandlers)
+  True
 
 The new registrations are now available::
 
@@ -264,6 +269,7 @@
 Let's use martian to do the registrations for us::
 
   >>> module_martian.grok('filehandler', filehandler)
+  True
   >>> filehandler.handle('test.txt')
   'Text file'
 
@@ -291,14 +297,15 @@
   >>> class ColorMartian(InstanceMartian):
   ...   component_class = color.Color
   ...   def grok(self, name, obj):
-  ...       color.all_colors[name] = obj
+  ...     color.all_colors[name] = obj
+  ...     return True
 
-
 Let's create ``color_martian`` and grok a color::
 
   >>> color_martian = ColorMartian()
   >>> black = color.Color(0, 0, 0) # we DO consider black as a color :)
   >>> color_martian.grok('black', black)
+  True
 
 It ends up in the ``all_colors`` dictionary::
 
@@ -317,6 +324,7 @@
   >>> colors = fake_import(colors)
   >>> colors_martian = ModuleMartian(color_martian)
   >>> colors_martian.grok('colors', colors)
+  True
   >>> sorted(color.all_colors.items())
   [('black', <Color 0 0 0>), 
    ('blue', <Color 0 0 255>), 
@@ -332,6 +340,7 @@
   ...   octarine = SpecialColor(-255, 0, -255)
   >>> subcolors = fake_import(subcolors)
   >>> colors_martian.grok('subcolors', subcolors)
+  True
   >>> 'octarine' in color.all_colors
   True
 
@@ -355,7 +364,8 @@
   >>> class SoundMartian(InstanceMartian):
   ...   component_class = sound.Sound
   ...   def grok(self, name, obj):
-  ...       sound.all_sounds[name] = obj
+  ...     sound.all_sounds[name] = obj
+  ...     return True
   >>> sound_martian = SoundMartian()
  
 What if we now want to look for ``Sound`` and ``Color`` instances at
@@ -372,6 +382,7 @@
 
   >>> grey = Color(100, 100, 100)
   >>> multi_martian.grok('grey', grey)
+  True
   >>> 'grey' in color.all_colors
   True
 
@@ -379,6 +390,7 @@
   
   >>> moo = sound.Sound('Moo!')
   >>> multi_martian.grok('moo', moo)
+  True
   >>> 'moo' in sound.all_sounds
   True
 
@@ -386,6 +398,7 @@
 
   >>> something_else = object()
   >>> multi_martian.grok('something_else', something_else)
+  False
 
 Let's put our ``multi_martian`` in a ``ModuleMartian``::
 
@@ -401,6 +414,7 @@
   ...   cheer = Sound('cheer')
   >>> lightandsound = fake_import(lightandsound)
   >>> module_martian.grok('lightandsound', lightandsound)
+  True
   >>> 'dark_red' in color.all_colors
   True
   >>> 'dark_green' in color.all_colors
@@ -433,6 +447,7 @@
   ...   component_class = animal.Animal
   ...   def grok(self, name, obj, **kw):
   ...     animal.all_animals[obj.name] = obj
+  ...     return True
 
 Let's test our martian::
 
@@ -440,6 +455,7 @@
   >>> class Snake(animal.Animal):
   ...   name = 'snake'
   >>> animal_martian.grok('snake', Snake)
+  True
   >>> animal.all_animals.keys()
   ['snake']
 
@@ -476,6 +492,7 @@
 
   >>> martian = ModuleMartian(multi_martian)
   >>> martian.grok('animals', animals)
+  True
 
 The animals (but not anything else) should have become available::
 
@@ -489,6 +506,158 @@
   >>> animal.create_animal('tiger')
   <Animal tiger>
 
+MultiMartian
+------------
+
+``MultiInstanceMartian`` and ``MultiClassMartian`` can grok instances
+and classes respectively, but a ``MultiInstanceMartian`` won't work
+correctly if it runs into a class and vice versa. For that we use a
+``MultiMartian``, which can deal with the full range of objects that
+can be grokked, and skips those it doesn't recognize.
+
+Let's fill a ``MultiMartian`` with a bunch of martians::
+
+  >>> from martian import MultiMartian
+  >>> multi = MultiMartian()
+  >>> multi.register(filetype_martian)
+  >>> multi.register(color_martian)
+  >>> multi.register(sound_martian)
+  >>> multi.register(animal_martian)
+
+Let's try it with some individual objects::
+
+  >>> class Whale(animal.Animal):
+  ...    name = 'whale'
+  >>> multi.grok('Whale', Whale)
+  True
+  >>> 'whale' in animal.all_animals
+  True
+ 
+This should have no effect, but not fail::
+
+  >>> my_whale = Whale()
+  >>> multi.grok('my_whale', my_whale)
+  False
+
+Grokked by the ColorMartian::
+
+  >>> multi.grok('dark_grey', Color(50, 50, 50))
+  True
+  >>> 'dark_grey' in color.all_colors 
+  True
+
+Grokked by the SoundMartian::
+  
+  >>> multi.grok('music', Sound('music'))
+  True
+  >>> 'music' in sound.all_sounds
+  True
+
+Not grokked::
+
+  >>> class RockMusic(Sound):
+  ...   pass
+  >>> multi.grok('RockMusic', RockMusic)
+  False
+
+Grokked by SoundMartian::
+
+  >>> multi.grok('rocknroll', RockMusic('rock n roll'))
+  True
+  >>> 'rocknroll' in sound.all_sounds
+  True
+
+Not grokked::
+
+  >>> class Chair(object):
+  ...   pass
+  >>> multi.grok('Chair', Chair)
+  False
+
+Grokked by ``filetype_martian``::
+
+  >>> def handle_py(filepath):
+  ...   return "Python file"
+  >>> multi.grok('handle_py', handle_py)
+  True
+  >>> '.py' in filehandler.extension_handlers
+  True
+
+Not grokked:
+
+  >>> def foo():
+  ...   pass
+  >>> multi.grok('foo', foo)
+  False
+
+Not grokked either::
+  
+  >>> another = object()
+  >>> multi.grok('another', another)
+  False
+  
+Let's make a module which has a mixture between classes and instances,
+some of which can be grokked::
+
+  >>> class mix(FakeModule):
+  ...   # grokked by AnimalMartian
+  ...   class Whale(animal.Animal):
+  ...      name = 'whale'
+  ...   # not grokked
+  ...   my_whale = Whale()
+  ...   # grokked by ColorMartian
+  ...   dark_grey = Color(50, 50, 50)
+  ...   # grokked by SoundMartian
+  ...   music = Sound('music')
+  ...   # not grokked
+  ...   class RockMusic(Sound):
+  ...      pass
+  ...   # grokked by SoundMartian
+  ...   rocknroll = RockMusic('rock n roll')
+  ...   # grokked by AnimalMartian
+  ...   class Dragon(animal.Animal):
+  ...     name = 'dragon'
+  ...   # not grokked
+  ...   class Chair(object):
+  ...     pass
+  ...   # grokked by filetype_martian
+  ...   def handle_py(filepath):
+  ...     return "Python file"
+  ...   # not grokked
+  ...   def foo():
+  ...     pass
+  ...   # grokked by AnimalMartian
+  ...   class SpermWhale(Whale):
+  ...     name = 'sperm whale'
+  ...   # not grokked
+  ...   another = object()
+  >>> mix = fake_import(mix)
+
+Let's construct a ``ModuleMartian`` that can grok this module::
+
+  >>> mix_martian = ModuleMartian(multi)
+
+Before we do the grokking, let's clean up our registration
+dictionaries::
+
+  >>> filehandler.extension_handlers = {}
+  >>> color.all_colors = {} 
+  >>> sound.all_sounds = {}
+  >>> animal.all_animals = {}
+
+Now we grok::
+
+  >>> mix_martian.grok('mix', mix)
+  True
+  >>> sorted(filehandler.extension_handlers.keys())
+  ['.py']
+  >>> sorted(color.all_colors.keys())
+  ['dark_grey']
+  >>> sorted(sound.all_sounds.keys())
+  ['music', 'rocknroll']
+  >>> sorted(animal.all_animals.keys())
+  ['dragon', 'sperm whale', 'whale']
+
 GlobalMartian
 -------------
 

Modified: grok/trunk/martian/src/martian/__init__.py
===================================================================
--- grok/trunk/martian/src/martian/__init__.py	2007-05-01 19:32:32 UTC (rev 74970)
+++ grok/trunk/martian/src/martian/__init__.py	2007-05-01 20:08:13 UTC (rev 74971)
@@ -1,2 +1,2 @@
-from core import ModuleMartian
+from core import ModuleMartian, MultiMartian
 from components import GlobalMartian, ClassMartian, InstanceMartian

Modified: grok/trunk/martian/src/martian/core.py
===================================================================
--- grok/trunk/martian/src/martian/core.py	2007-05-01 19:32:32 UTC (rev 74970)
+++ grok/trunk/martian/src/martian/core.py	2007-05-01 20:08:13 UTC (rev 74971)
@@ -3,14 +3,16 @@
 from zope.interface import implements
 
 from martian.interfaces import IMartian, IMultiMartian
-from martian import components, util
+from martian import util
+from martian.components import (MartianBase, ClassMartian, InstanceMartian,
+                                GlobalMartian)
 
 def is_baseclass(name, component):
     return (type(component) is type and
             (name.endswith('Base') or
              util.class_annotation_nobase(component, 'grok.baseclass', False)))
         
-class ModuleMartian(components.MartianBase):
+class ModuleMartian(MartianBase):
     implements(IMartian)
 
     def __init__(self, martian):
@@ -18,11 +20,9 @@
    
     def grok(self, name, module, **kw):
         martian = self._martian
+
+        grokked_status = False
         
-        if isinstance(martian, components.GlobalMartian):
-            martian.grok(name, module, **kw)
-            return
-
         for name in dir(module):
             if name.startswith('__grok_'):
                 continue
@@ -31,9 +31,13 @@
                 continue
             if is_baseclass(name, obj):
                 continue
-            martian.grok(name, obj, **kw)
+            grokked = martian.grok(name, obj, **kw)
+            if grokked:
+                grokked_status = True
 
-class MultiMartianBase(components.MartianBase):
+        return grokked_status
+    
+class MultiMartianBase(MartianBase):
     implements(IMultiMartian)
 
     def __init__(self):
@@ -47,15 +51,19 @@
     
     def grok(self, name, obj, **kw):
         used_martians = set()
+        grokked_status = False
         for base in self.get_bases(obj):
             martians = self._martians.get(base)
             if martians is None:
                 continue
             for martian in martians:
                 if martian not in used_martians:
-                    martian.grok(name, obj, **kw)
+                    grokked = martian.grok(name, obj, **kw)
+                    if grokked:
+                        grokked_status = True
                     used_martians.add(martian)
-        
+        return grokked_status
+    
 class MultiInstanceMartian(MultiMartianBase):
     def get_bases(self, obj):
         # XXX how to work with old-style classes?
@@ -74,7 +82,7 @@
     # XXX to be written
     pass
 
-class MultiMartian(components.MartianBase):
+class MultiMartian(MartianBase):
     implements(IMultiMartian)
 
     # XXX extend with old-style class support
@@ -93,6 +101,6 @@
 
     def grok(self, name, obj, **kw):
         if type(obj) is type:
-            self._multi_class_martian.grok(name, obj, **kw)
+            return self._multi_class_martian.grok(name, obj, **kw)
         else:
-            self._multi_instance_martian.grok(name, obj, **kw)
+            return self._multi_instance_martian.grok(name, obj, **kw)

Modified: grok/trunk/martian/src/martian/interfaces.py
===================================================================
--- grok/trunk/martian/src/martian/interfaces.py	2007-05-01 19:32:32 UTC (rev 74970)
+++ grok/trunk/martian/src/martian/interfaces.py	2007-05-01 20:08:13 UTC (rev 74971)
@@ -23,6 +23,9 @@
         **kw - optional parameters passed along the grokking process.
 
         May do extra filtering based on name or obj.
+
+        Returns True if grok is attempted, False if object is filtered
+        out by this martian.
         """
 
 class IComponentMartian(IMartian):



More information about the Checkins mailing list