[Checkins] SVN: martian/trunk/ Make resolve() work for fake modules by letting them properly importable

Martijn Faassen faassen at infrae.com
Mon Jan 12 15:30:52 EST 2009


Log message for revision 94709:
  Make resolve() work for fake modules by letting them properly importable
  modules.
  

Changed:
  U   martian/trunk/CHANGES.txt
  U   martian/trunk/src/martian/README.txt
  U   martian/trunk/src/martian/core.txt
  U   martian/trunk/src/martian/directive.txt
  U   martian/trunk/src/martian/edgecase.txt
  U   martian/trunk/src/martian/testing.py
  U   martian/trunk/src/martian/tests/test_all.py

-=-
Modified: martian/trunk/CHANGES.txt
===================================================================
--- martian/trunk/CHANGES.txt	2009-01-12 19:53:00 UTC (rev 94708)
+++ martian/trunk/CHANGES.txt	2009-01-12 20:30:51 UTC (rev 94709)
@@ -20,6 +20,13 @@
 * Pass along ``exclude_filter`` (and the new ``ignore_nonsource``
   flag) to ModuleInfo constructor when it calls itself recursively.
 
+* Replace ``fake_import`` to import fake modules in tests with a real
+  python import statement (``from martiantest.fake import
+  my_fake_module``). This works by introducing a metaclass for
+  ``FakeModule`` that automatically registers it as a module. The
+  irony does not escape us. This also means that
+  ``martian.scan.resolve()`` will now work on fake modules.
+
 0.11 (2008-09-24)
 =================
 

Modified: martian/trunk/src/martian/README.txt
===================================================================
--- martian/trunk/src/martian/README.txt	2009-01-12 19:53:00 UTC (rev 94708)
+++ martian/trunk/src/martian/README.txt	2009-01-12 20:30:51 UTC (rev 94709)
@@ -125,10 +125,10 @@
 class. Whenever you see ``FakeModule`` subclasses, imagine you're
 looking at a module definition in a ``.py`` file. Now that we have
 defined a module ``templating``, we also need to be able to import
-it. To do so we can use a a fake import statement that lets us do
-this::
+it. Fake modules are always placed automatically into the
+``martiantest.fake`` namespace so you can import them from there::
 
-  >>> templating = fake_import(templating)
+  >>> from martiantest.fake import templating
 
 Now let's try the ``render`` function for the registered template
 types, to demonstrate that our framework works::
@@ -163,7 +163,7 @@
   ...          return text
   ...
   ...   templating.extension_handlers['.silly'] = SillyTemplate
-  >>> sillytemplating = fake_import(sillytemplating)
+  >>> from martiantest.fake import sillytemplating
 
 In the extension module, we manipulate the ``extension_handlers``
 dictionary of the ``templating`` module (in normal code we'd need to
@@ -256,7 +256,7 @@
   ...      # this hasn't changed
   ...      template = extension_handlers[extension](data)
   ...      return template.render(**kw)
-  >>> templating = fake_import(templating)
+  >>> from martiantest.fake import templating
 
 As you can see, there have been very few changes:
 
@@ -278,7 +278,7 @@
   ...     def execute(self, class_, extension, **kw):
   ...       templating.extension_handlers[extension] = class_
   ...       return True
-  >>> meta = fake_import(meta)
+  >>> from martiantest.fake import meta
 
 What does this do? A ``ClassGrokker`` has its ``execute`` method
 called for subclasses of what's indicated by the ``martian.component``
@@ -341,7 +341,7 @@
   ...          for key, value in kw.items():
   ...              text = text.replace('{%s}' % key, value)
   ...          return text
-  >>> sillytemplating = fake_import(sillytemplating)
+  >>> from martiantest.fake import sillytemplating
 
 As you can see, the developer that uses the framework has no need
 anymore to know about ``templating.extension_handlers``. Instead we can
@@ -389,7 +389,7 @@
   ...   elephant = Animal('elephant')
   ...   lion = Animal('lion')
   ...   animals = {}
-  >>> zoo = fake_import(zoo)
+  >>> from martiantest.fake import zoo
  
 We define an ``InstanceGrokker`` subclass to grok ``Animal`` instances::
 
@@ -399,7 +399,7 @@
   ...     def execute(self, instance, **kw):
   ...       zoo.animals[instance.name] = instance
   ...       return True
-  >>> meta = fake_import(meta)
+  >>> from martiantest.fake import meta
 
 Let's create a new registry with the ``AnimalGrokker`` in it::
    

Modified: martian/trunk/src/martian/core.txt
===================================================================
--- martian/trunk/src/martian/core.txt	2009-01-12 19:53:00 UTC (rev 94708)
+++ martian/trunk/src/martian/core.txt	2009-01-12 20:30:51 UTC (rev 94709)
@@ -21,7 +21,7 @@
   ...   def handle(filepath):
   ...      name, ext = os.path.splitext(filepath)
   ...      return extension_handlers[ext](filepath)
-  >>> filehandler = fake_import(filehandler)
+  >>> from martiantest.fake import filehandler
 
 Now let's try the ``handle`` function for a few file types::
 
@@ -46,7 +46,7 @@
   ...        return "PNG file"
   ...
   ...    filehandler.extension_handlers['.png'] = handle_png
-  >>> pnghandler = fake_import(pnghandler)
+  >>> from martiantest.fake import pnghandler
 
 In the extension module, we manipulate the ``extension_handlers``
 dictionary of the ``filehandler`` module and plug in our own
@@ -153,7 +153,7 @@
   ...
   ...   def handle_svg(filepath):
   ...     return "SVG file"
-  >>> lotsofhandlers = fake_import(lotsofhandlers)
+  >>> from martiantest.fake import lotsofhandlers
 
 Let's grok it::
 
@@ -192,9 +192,8 @@
   ...   def handle(filepath):
   ...      name, ext = os.path.splitext(filepath)
   ...      return extension_handlers[ext](filepath)
+  >>> from martiantest.fake import filehandler
 
-  >>> filehandler = fake_import(filehandler)
-
 Let's use martian to do the registrations for us::
 
   >>> module_grokker.grok('filehandler', filehandler)
@@ -217,7 +216,7 @@
   ...     def __repr__(self):
   ...       return '<Color %s %s %s>' % (self.r, self.g, self.b)
   ...   all_colors = {}
-  >>> color = fake_import(color)
+  >>> from martiantest.fake import color
 
 We now want a grokker that can recognize colors and put them in the
 ``all_colors`` dictionary, with the names as the keys, and the color
@@ -250,7 +249,7 @@
   ...   green = Color(0, 255, 0)
   ...   blue = Color(0, 0, 255)
   ...   white = Color(255, 255, 255)
-  >>> colors = fake_import(colors)
+  >>> from martiantest.fake import colors
   >>> colors_grokker = martian.ModuleGrokker()
   >>> colors_grokker.register(color_grokker)
   >>> colors_grokker.grok('colors', colors)
@@ -268,7 +267,7 @@
   ...   class SpecialColor(Color):
   ...     pass
   ...   octarine = SpecialColor(-255, 0, -255)
-  >>> subcolors = fake_import(subcolors)
+  >>> from martiantest.fake import subcolors
   >>> colors_grokker.grok('subcolors', subcolors)
   True
   >>> 'octarine' in color.all_colors
@@ -289,7 +288,7 @@
   ...     def __repr__(self):
   ...       return '<Sound %s>' % (self.desc)
   ...   all_sounds = {}
-  >>> sound = fake_import(sound)
+  >>> from martiantest.fake import sound
 
   >>> class SoundGrokker(martian.InstanceGrokker):
   ...   martian.component(sound.Sound)
@@ -343,7 +342,7 @@
   ...   scream = Sound('scream')
   ...   dark_green = Color(0, 150, 0)
   ...   cheer = Sound('cheer')
-  >>> lightandsound = fake_import(lightandsound)
+  >>> from martiantest.fake import lightandsound
   >>> module_grokker.grok('lightandsound', lightandsound)
   True
   >>> 'dark_red' in color.all_colors
@@ -376,7 +375,7 @@
   ...   all_animals = {}
   ...   def create_animal(name):
   ...     return all_animals[name]()
-  >>> animal = fake_import(animal)
+  >>> from martiantest.fake import animal
 
 Let's define a grokker that can grok an ``Animal``.  We could either
 implement the ``grok`` method as with ``InstanceGrokkers``, or we can
@@ -570,7 +569,7 @@
   ...     animal.name('lion')
   ...   class Chair(object):
   ...     animal.name('chair')
-  >>> animals = fake_import(animals)
+  >>> from martiantest.fake import animals
 
 First we need to wrap our ``AnimalGrokker`` into a ``MultiClassGrokker``::
 
@@ -721,7 +720,7 @@
   ...     animal.name('sperm whale')
   ...   # not grokked
   ...   another = object()
-  >>> mix = fake_import(mix)
+  >>> from martiantest.fake import mix
 
 Let's construct a ``ModuleGrokker`` that can grok this module::
 
@@ -762,7 +761,7 @@
 
   >>> class g(FakeModule):
   ...   amount = 50
-  >>> g = fake_import(g)
+  >>> from martiantest.fake import g
 
 Now let's create a ``GlobalGrokker`` that reads ``amount`` and stores
 it in the ``read_amount`` dictionary::
@@ -798,7 +797,7 @@
   ...     pass
   ...   all_machines = {}
   ...   all_machine_instances = {}
-  >>> oldstyle = fake_import(oldstyle)
+  >>> from martiantest.fake import oldstyle
 
 Let's make a grokker for the old style class::
 
@@ -899,7 +898,7 @@
   ...   one = Number(1)
   ...   two = Number(2)
   ...   four = Number(4)
-  >>> numbers = fake_import(numbers)
+  >>> from martiantest.fake import numbers
   >>> module_grokker.grok('numbers', numbers)
   True
   >>> sorted(all_numbers.items())
@@ -1045,7 +1044,7 @@
   ...     def grok(self, name, obj, **kw):
   ...        executed.append(name)
   ...        return True
-  >>> somemodule = fake_import(somemodule)
+  >>> from martiantest.fake import somemodule
   >>> module_grokker = martian.ModuleGrokker(MetaMultiGrokker())
 
 Let's grok the module once::
@@ -1064,7 +1063,7 @@
   >>> class anothermodule(FakeModule):
   ...   class TestSub(TestOnce):
   ...      pass
-  >>> anothermodule = fake_import(anothermodule)
+  >>> from martiantest.fake import anothermodule
   >>> module_grokker.grok('anothermodule', anothermodule)
   True
   >>> executed
@@ -1081,7 +1080,7 @@
   ...     def grok(self, name, obj, **kw):
   ...        executed.append(name)
   ...        return True
-  >>> somemodule = fake_import(somemodule)
+  >>> from martiantest.fake import somemodule
   >>> module_grokker.clear()
   >>> module_grokker.grok('somemodule', somemodule) # once
   True
@@ -1089,7 +1088,7 @@
   True
   >>> class anothermodule(FakeModule):
   ...   test = TestInstanceOnce()
-  >>> anothermodule = fake_import(anothermodule)
+  >>> from martiantest.fake import anothermodule
   >>> module_grokker.grok('anothermodule', anothermodule)
   True
   >>> executed
@@ -1103,7 +1102,7 @@
   ...     def grok(self, name, obj, **kw):
   ...       executed.append(name)
   ...       return True
-  >>> somemodule = fake_import(somemodule)
+  >>> from martiantest.fake import somemodule
   >>> module_grokker.clear()
   >>> module_grokker.grok('somemodule', somemodule) # once
   True
@@ -1119,7 +1118,7 @@
 
   >>> class anothermodule(FakeModule):
   ...   pass
-  >>> anothermodule = fake_import(anothermodule)
+  >>> from martiantest.fake import anothermodule
   >>> module_grokker.grok('anothermodule', anothermodule)
   True
   >>> executed
@@ -1172,7 +1171,7 @@
   ...     pass
   ...   class BSub(B):
   ...     pass
-  >>> mymodule = fake_import(mymodule)
+  >>> from martiantest.fake import mymodule
 
 We'll grok it::
 

Modified: martian/trunk/src/martian/directive.txt
===================================================================
--- martian/trunk/src/martian/directive.txt	2009-01-12 19:53:00 UTC (rev 94708)
+++ martian/trunk/src/martian/directive.txt	2009-01-12 20:30:51 UTC (rev 94709)
@@ -151,7 +151,7 @@
   ...    layer('Test2')
   ...    class Foo(object):
   ...       pass
-  >>> testmodule = fake_import(testmodule)
+  >>> from martiantest.fake import testmodule
 
 When we now try to access ``layer`` on ``Foo``, we find the
 module-level default which we just set. We pass the module as the
@@ -165,7 +165,7 @@
   >>> class testmodule(FakeModule):
   ...   class Foo(object):
   ...      pass
-  >>> testmodule = fake_import(testmodule)
+  >>> from martiantest.fake import testmodule
 
 In this case, the value cannot be found so the system falls back on
 the default, ``None``::
@@ -325,7 +325,7 @@
   ...     multi('One')
   ...     multi('Two')
   ...
-  >>> module_with_directive = fake_import(module_with_directive)
+  >>> from martiantest.fake import module_with_directive
   >>> print multi.bind().get(module=module_with_directive)
   ['One', 'Two']
 
@@ -343,7 +343,7 @@
   ...     multi(1, 'One')
   ...     multi(2, 'Two')
   ...
-  >>> module_with_directive = fake_import(module_with_directive)
+  >>> from martiantest.fake import module_with_directive
   >>> d = multi.bind().get(module=module_with_directive)
   >>> print sorted(d.items())
   [(1, 'One'), (2, 'Two')]

Modified: martian/trunk/src/martian/edgecase.txt
===================================================================
--- martian/trunk/src/martian/edgecase.txt	2009-01-12 19:53:00 UTC (rev 94708)
+++ martian/trunk/src/martian/edgecase.txt	2009-01-12 20:30:51 UTC (rev 94709)
@@ -24,7 +24,7 @@
   ...
   ...     store(some_function)
   ...
-  >>> module_with_directive = fake_import(module_with_directive)
+  >>> from martiantest.fake import module_with_directive
 
 Now imagine we have the following grokker for functions:
 

Modified: martian/trunk/src/martian/testing.py
===================================================================
--- martian/trunk/src/martian/testing.py	2009-01-12 19:53:00 UTC (rev 94708)
+++ martian/trunk/src/martian/testing.py	2009-01-12 20:30:51 UTC (rev 94709)
@@ -1,10 +1,12 @@
 import new
+import sys
 
-class FakeModule(object):
-    pass
-
 def fake_import(fake_module):
-    module = new.module(fake_module.__name__)
+    module_name = 'martiantest.fake.' + fake_module.__name__
+    module = new.module(module_name)
+    module_name_parts = module_name.split('.')
+    module.__file__ =  '/' + '/'.join(module_name_parts)
+    
     glob = {}
     for name in dir(fake_module):
         if name.startswith('__') and '.' not in name:
@@ -43,4 +45,22 @@
             glob[name] = new_func
         except AttributeError:
             pass
+
+    if not 'martiantest' in sys.modules:
+        sys.modules['martiantest'] = new.module('martiantest')
+        sys.modules['martiantest.fake'] = new.module('martiantest.fake')
+        sys.modules['martiantest'].fake = sys.modules['martiantest.fake']
+
+    sys.modules[module_name] = module
+    setattr(sys.modules['martiantest.fake'], module_name.split('.')[-1],
+            module)
+    
     return module
+
+class FakeModuleMetaclass(type):
+    def __init__(cls, classname, bases, dict_):
+        fake_import(cls)
+        return type.__init__(cls, classname, bases, dict_)
+
+class FakeModule(object):
+    __metaclass__ = FakeModuleMetaclass

Modified: martian/trunk/src/martian/tests/test_all.py
===================================================================
--- martian/trunk/src/martian/tests/test_all.py	2009-01-12 19:53:00 UTC (rev 94708)
+++ martian/trunk/src/martian/tests/test_all.py	2009-01-12 20:30:51 UTC (rev 94709)
@@ -1,10 +1,10 @@
 import unittest
 from zope.testing import doctest
-from martian.testing import FakeModule, fake_import
+from martian.testing import FakeModule
 
 optionflags = doctest.NORMALIZE_WHITESPACE + doctest.ELLIPSIS
 
-globs = dict(FakeModule=FakeModule, fake_import=fake_import)
+globs = dict(FakeModule=FakeModule)
 
 def test_suite():
     suite = unittest.TestSuite()



More information about the Checkins mailing list