[Checkins] SVN: manuel/branches/pwilson-try-fake-modules/src/manuel/ Initial proof-of-concept attempt at fake module support.
Paul Wilson
paulalexwilson at gmail.com
Fri Oct 23 06:10:22 EDT 2009
Log message for revision 105238:
Initial proof-of-concept attempt at fake module support.
Added code and tests to allow modules to be defined within
a doctest. These modules are created and imported into sys.modules
and available to the rest of the doctest by some defined name.
Changed:
A manuel/branches/pwilson-try-fake-modules/src/manuel/fake_module.py
A manuel/branches/pwilson-try-fake-modules/src/manuel/fake_module.txt
U manuel/branches/pwilson-try-fake-modules/src/manuel/tests.py
-=-
Added: manuel/branches/pwilson-try-fake-modules/src/manuel/fake_module.py
===================================================================
--- manuel/branches/pwilson-try-fake-modules/src/manuel/fake_module.py (rev 0)
+++ manuel/branches/pwilson-try-fake-modules/src/manuel/fake_module.py 2009-10-23 10:10:21 UTC (rev 105238)
@@ -0,0 +1,55 @@
+import manuel
+import re
+import sys
+import new
+import textwrap
+
+FAKE_MODULE_START = re.compile(
+ r'^\.\.\s*module-block::?\s*(?P<module_name>[a-zA-Z_]*)',
+ re.MULTILINE)
+FAKE_MODULE_END = re.compile(r'(\n\Z|\n(?=\S))')
+MODULE_NS = "manueltest.fake"
+
+# To store our fake module's lines
+class FakeModuleSnippet(object):
+ def __init__(self, code, module_name):
+ self.code = code
+ self.module_name = module_name
+
+def find_fakes(document):
+ for region in document.find_regions(FAKE_MODULE_START, FAKE_MODULE_END):
+ module_name = region.start_match.group('module_name')
+ # Sanitise indentation
+ source = textwrap.dedent('\n'.join(region.source.splitlines()[1:]))
+ source_location = '%s:%d' % (document.location, region.lineno)
+
+ code = compile(source, source_location, 'exec')
+ document.claim_region(region)
+ region.parsed = FakeModuleSnippet(code, module_name)
+
+def execute_into_module(region, document, doc_globs):
+ # build a suitable module
+ module_name = region.parsed.module_name
+ full_module_name = MODULE_NS + "." + module_name
+ module = new.module(full_module_name)
+ module_name_parts = full_module_name.split('.')
+ module.__file__ = '/' + '/'.join(module_name_parts)
+
+ exec region.parsed.code in module.__dict__
+
+ # Make the module visible and usable in the given name
+ doc_globs[module_name] = module
+
+ # Make the module also available through normal import
+ if not MODULE_NS in sys.modules:
+ sys.modules['manueltest'] = new.module('manueltest')
+ sys.modules['manueltest.fake'] = new.module('manueltest.fake')
+ sys.modules['manueltest'].fake = sys.modules['manueltest.fake']
+
+ sys.modules[full_module_name] = module
+ setattr(sys.modules['manueltest.fake'], full_module_name.split('.')[-1],
+ module)
+
+class Manuel(manuel.Manuel):
+ def __init__(self):
+ manuel.Manuel.__init__(self, [find_modules], [execute_into_module])
Property changes on: manuel/branches/pwilson-try-fake-modules/src/manuel/fake_module.py
___________________________________________________________________
Added: svn:eol-style
+ native
Added: manuel/branches/pwilson-try-fake-modules/src/manuel/fake_module.txt
===================================================================
--- manuel/branches/pwilson-try-fake-modules/src/manuel/fake_module.txt (rev 0)
+++ manuel/branches/pwilson-try-fake-modules/src/manuel/fake_module.txt 2009-10-23 10:10:21 UTC (rev 105238)
@@ -0,0 +1,113 @@
+manuel.fake_modules
+===================
+
+This document discusses the fake_module plugin for manuel that allows
+doctests to define and then use modules.
+
+ >>> import manuel
+ >>> import manuel.fake_module
+
+ >>> source = """\
+ ... This is a module doc-test:
+ ...
+ ... .. module-block:: fake_module
+ ... import whatever
+ ... class Something:
+ ... pass
+ ...
+ ... As you can see, it does much!!
+ ... """
+
+ >>> doc = manuel.Document(source)
+ >>> manuel.fake_module.find_fakes(doc)
+
+Let's extract the module name and its source:
+
+ >>> for region in doc:
+ ... if region.parsed:
+ ... print region.parsed.module_name
+ ... print region.source
+ fake_module
+ .. module-block:: fake_module
+ import whatever
+ class Something:
+ pass
+ <BLANKLINE>
+ <BLANKLINE>
+
+The code can correctly parse multiple modules:
+
+ >>> source = """\
+ ... Our system has a few modules:
+ ...
+ ... .. module-block:: some_module
+ ... class Foo:
+ ... pass
+ ...
+ ... and:
+ ...
+ ... .. module-block:: an_other_module
+ ... class Bar:
+ ... pass
+ ...
+ ... fin
+ ... """
+
+ >>> doc = manuel.Document(source)
+ >>> manuel.fake_module.find_fakes(doc)
+
+Again, we extract the various parsed regions:
+
+ >>> for region in doc:
+ ... if region.parsed:
+ ... print region.parsed.module_name
+ ... print region.source
+ some_module
+ .. module-block:: some_module
+ class Foo:
+ pass
+ <BLANKLINE>
+ <BLANKLINE>
+ an_other_module
+ .. module-block:: an_other_module
+ class Bar:
+ pass
+ <BLANKLINE>
+ <BLANKLINE>
+
+Let's execute these regions into a globs dictionary of our own:
+
+ >>> glob = {}
+ >>> for region in doc:
+ ... if region.parsed:
+ ... manuel.fake_module.execute_into_module(
+ ... region, doc, glob)
+
+Let's check that our glob contains the modules with their names:
+
+ >>> for module in glob.values():
+ ... print module.__name__, ":", type(module)
+ manueltest.fake.some_module : <type 'module'>
+ manueltest.fake.an_other_module : <type 'module'>
+
+Let's also confirm that the modules contain their respective class
+definitions:
+
+ >>> for module in glob.values():
+ ... print dir(module)
+ ['Foo', '__builtins__', '__doc__', '__file__', '__name__']
+ ['Bar', '__builtins__', '__doc__', '__file__', '__name__']
+
+We would also want to ensure that we can import the module correctly
+too. The fake_module system also adds the modules under their own
+namespace 'manueltest.fake', as you can see from the previous tests:
+
+ >>> import manueltest.fake.some_module
+ >>> import manueltest.fake.an_other_module
+ >>> manueltest.fake.some_module.Foo
+ <class manueltest.fake.some_module.Foo at ...>
+ >>> manueltest.fake.an_other_module.Bar
+ <class manueltest.fake.an_other_module.Bar at ...>
+
+Note: There is no checking done to ensure that the module definition
+hasn't overridden any previous modules defined in the doctest.
Property changes on: manuel/branches/pwilson-try-fake-modules/src/manuel/fake_module.txt
___________________________________________________________________
Added: svn:eol-style
+ native
Modified: manuel/branches/pwilson-try-fake-modules/src/manuel/tests.py
===================================================================
--- manuel/branches/pwilson-try-fake-modules/src/manuel/tests.py 2009-10-23 09:57:34 UTC (rev 105237)
+++ manuel/branches/pwilson-try-fake-modules/src/manuel/tests.py 2009-10-23 10:10:21 UTC (rev 105238)
@@ -32,7 +32,7 @@
])
tests = ['../index.txt', 'table-example.txt', 'README.txt', 'bugs.txt',
- 'capture.txt']
+ 'capture.txt', 'fake_module.txt']
m = manuel.ignore.Manuel()
m += manuel.doctest.Manuel(optionflags=optionflags, checker=checker)
More information about the checkins
mailing list