[Checkins] SVN: manuelpi.fakemodule/trunk/src/manuelpi/fakemodule/fakemodule. Changes to support martian doctests.
Paul Wilson
paulalexwilson at gmail.com
Tue Dec 15 20:01:04 EST 2009
Log message for revision 106603:
Changes to support martian doctests.
Principally:
- Force doctest globs into __builtins__ so they
are available as a fallback after module scoped
stuff
- Remove the aggregation of globs forced into each
module. This was playing havoc with martian's
directive storage facility and causing all 'gets'
from BoundDirectives to return their defaults.
Changed:
U manuelpi.fakemodule/trunk/src/manuelpi/fakemodule/fakemodule.py
U manuelpi.fakemodule/trunk/src/manuelpi/fakemodule/fakemodule.txt
-=-
Modified: manuelpi.fakemodule/trunk/src/manuelpi/fakemodule/fakemodule.py
===================================================================
--- manuelpi.fakemodule/trunk/src/manuelpi/fakemodule/fakemodule.py 2009-12-16 00:55:36 UTC (rev 106602)
+++ manuelpi.fakemodule/trunk/src/manuelpi/fakemodule/fakemodule.py 2009-12-16 01:01:04 UTC (rev 106603)
@@ -8,7 +8,7 @@
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"
+MODULE_NAMESPACE = "manueltest.fake"
# To store our fake module's lines
class FakeModuleSnippet(object):
@@ -36,26 +36,73 @@
# build a suitable module
module_name = region.parsed.module_name
- full_module_name = MODULE_NS + "." + module_name
+ full_module_name = MODULE_NAMESPACE + "." + module_name
module = new.module(full_module_name)
module_name_parts = full_module_name.split('.')
module.__file__ = '/' + '/'.join(module_name_parts)
# Make the module also available through normal import
- if not MODULE_NS in sys.modules:
+ if not MODULE_NAMESPACE 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']
+ # We want to be able to resolve items that are in the surrounding
+ # doctest globs. To acheive this, we force all doctest globals into
+ # builtins such that they are resolved after module-scoped objects.
+ import __builtin__
+ __builtin__.__dict__.update(doc_globs)
+
exec region.parsed.code in module.__dict__
- # XXX Do I want del module['__builtin__']??
- # Make the module visible and usable in the given name
+ # When we exec code within the dictionary namespace as
+ # above, the __module__ attributes of the objects created are set
+ # to __builtin__. We know better than the interpreter in this case
+ # and are able to set the defined namespace accordingly. We
+ # iterate through and change the relevant attributes:
+ for name in dir(module):
+ if name.startswith('__'):
+ continue
+ obj = getattr(module, name)
+ try:
+ obj = obj.im_func
+ except:
+ pass
+ __module__ = None
+ try:
+ __module__ = obj.__dict__.get('__module__')
+ except AttributeError:
+ try:
+ __module__ = obj.__module__
+ except AttributeError:
+ pass
+ if __module__ in (None, '__builtin__'):
+ try:
+ obj.__module__ = full_module_name
+ except AttributeError:
+ pass
+ setattr(module, name, obj)
+
+ # Provide correct globals for functions
+ for name in dir(module):
+ if name.startswith('__'):
+ continue
+ obj = getattr(module, name)
+ try:
+ code = obj.func_code
+ new_func = new.function(code, module.__dict__, name)
+ new_func.__module__ = module.__name__
+ setattr(module, name, new_func)
+ except AttributeError:
+ pass
+
+ # Make the module visible and usable in the rest of the doctest
doc_globs[module_name] = module
sys.modules[full_module_name] = module
- setattr(sys.modules['manueltest.fake'], full_module_name.split('.')[-1],
- module)
+ setattr(sys.modules['manueltest.fake'],
+ full_module_name.split('.')[-1],
+ module)
class Manuel(manuel.Manuel):
def __init__(self):
Modified: manuelpi.fakemodule/trunk/src/manuelpi/fakemodule/fakemodule.txt
===================================================================
--- manuelpi.fakemodule/trunk/src/manuelpi/fakemodule/fakemodule.txt 2009-12-16 00:55:36 UTC (rev 106602)
+++ manuelpi.fakemodule/trunk/src/manuelpi/fakemodule/fakemodule.txt 2009-12-16 01:01:04 UTC (rev 106603)
@@ -16,6 +16,8 @@
.. module-block:: test_module
import pprint
+
+ a = manuel
class Something:
pass
@@ -42,6 +44,8 @@
.. module-block:: test_module
import pprint
<BLANKLINE>
+ a = manuel
+ <BLANKLINE>
class Something:
pass
<BLANKLINE>
@@ -164,6 +168,50 @@
>>> print glob['cls_n_func'].faz_func.__module__
manueltest.fake.cls_n_func
+Test Continuity
+===============
+
+We also would like to define objects in a doctest and have the
+module use them too. For example, we might want to define a class
+and have a module use it directly::
+
+ >>> class Parent:
+ ... pass
+
+Let's now create a module that creates instances of this object::
+
+.. module-block:: enclosing_ns_available
+
+ dad = Parent()
+
+Now lets use `dad`::
+
+ >>> print enclosing_ns_available.dad
+ <....Parent instance at ...>
+ >>> print enclosing_ns_available.dad.__module__
+ manueltest.fake.enclosing_ns_available
+
+However, we would also like to have module globals equally available
+to local scopes. Consider the case that a class relies upon some
+module level utility function::
+
+.. module-block:: module_globals
+
+ foobar = True
+
+ def utility_func():
+ return foobar
+
+ class DelegatingClass(object):
+ def __init__(self):
+ self.v = utility_func()
+
+The class should be able to use the utlilty function properly:
+
+ >>> dc = module_globals.DelegatingClass()
+ >>> dc.v
+ True
+
Invalid Modules
===============
More information about the checkins
mailing list