summaryrefslogtreecommitdiff
path: root/doc/sphinxext/phantom_import.py
diff options
context:
space:
mode:
Diffstat (limited to 'doc/sphinxext/phantom_import.py')
-rw-r--r--doc/sphinxext/phantom_import.py162
1 files changed, 0 insertions, 162 deletions
diff --git a/doc/sphinxext/phantom_import.py b/doc/sphinxext/phantom_import.py
deleted file mode 100644
index c77eeb544..000000000
--- a/doc/sphinxext/phantom_import.py
+++ /dev/null
@@ -1,162 +0,0 @@
-"""
-==============
-phantom_import
-==============
-
-Sphinx extension to make directives from ``sphinx.ext.autodoc`` and similar
-extensions to use docstrings loaded from an XML file.
-
-This extension loads an XML file in the Pydocweb format [1] and
-creates a dummy module that contains the specified docstrings. This
-can be used to get the current docstrings from a Pydocweb instance
-without needing to rebuild the documented module.
-
-.. [1] http://code.google.com/p/pydocweb
-
-"""
-import imp, sys, compiler, types, os, inspect, re
-
-def setup(app):
- app.connect('builder-inited', initialize)
- app.add_config_value('phantom_import_file', None, True)
-
-def initialize(app):
- fn = app.config.phantom_import_file
- if (fn and os.path.isfile(fn)):
- print "[numpydoc] Phantom importing modules from", fn, "..."
- import_phantom_module(fn)
-
-#------------------------------------------------------------------------------
-# Creating 'phantom' modules from an XML description
-#------------------------------------------------------------------------------
-def import_phantom_module(xml_file):
- """
- Insert a fake Python module to sys.modules, based on a XML file.
-
- The XML file is expected to conform to Pydocweb DTD. The fake
- module will contain dummy objects, which guarantee the following:
-
- - Docstrings are correct.
- - Class inheritance relationships are correct (if present in XML).
- - Function argspec is *NOT* correct (even if present in XML).
- Instead, the function signature is prepended to the function docstring.
- - Class attributes are *NOT* correct; instead, they are dummy objects.
-
- Parameters
- ----------
- xml_file : str
- Name of an XML file to read
-
- """
- import lxml.etree as etree
-
- object_cache = {}
-
- tree = etree.parse(xml_file)
- root = tree.getroot()
-
- # Sort items so that
- # - Base classes come before classes inherited from them
- # - Modules come before their contents
- all_nodes = dict([(n.attrib['id'], n) for n in root])
-
- def _get_bases(node, recurse=False):
- bases = [x.attrib['ref'] for x in node.findall('base')]
- if recurse:
- j = 0
- while True:
- try:
- b = bases[j]
- except IndexError: break
- if b in all_nodes:
- bases.extend(_get_bases(all_nodes[b]))
- j += 1
- return bases
-
- type_index = ['module', 'class', 'callable', 'object']
-
- def base_cmp(a, b):
- x = cmp(type_index.index(a.tag), type_index.index(b.tag))
- if x != 0: return x
-
- if a.tag == 'class' and b.tag == 'class':
- a_bases = _get_bases(a, recurse=True)
- b_bases = _get_bases(b, recurse=True)
- x = cmp(len(a_bases), len(b_bases))
- if x != 0: return x
- if a.attrib['id'] in b_bases: return -1
- if b.attrib['id'] in a_bases: return 1
-
- return cmp(a.attrib['id'].count('.'), b.attrib['id'].count('.'))
-
- nodes = root.getchildren()
- nodes.sort(base_cmp)
-
- # Create phantom items
- for node in nodes:
- name = node.attrib['id']
- doc = (node.text or '').decode('string-escape') + "\n"
- if doc == "\n": doc = ""
-
- # create parent, if missing
- parent = name
- while True:
- parent = '.'.join(parent.split('.')[:-1])
- if not parent: break
- if parent in object_cache: break
- obj = imp.new_module(parent)
- object_cache[parent] = obj
- sys.modules[parent] = obj
-
- # create object
- if node.tag == 'module':
- obj = imp.new_module(name)
- obj.__doc__ = doc
- sys.modules[name] = obj
- elif node.tag == 'class':
- bases = [object_cache[b] for b in _get_bases(node)
- if b in object_cache]
- bases.append(object)
- init = lambda self: None
- init.__doc__ = doc
- obj = type(name, tuple(bases), {'__doc__': doc, '__init__': init})
- obj.__name__ = name.split('.')[-1]
- elif node.tag == 'callable':
- funcname = node.attrib['id'].split('.')[-1]
- argspec = node.attrib.get('argspec')
- if argspec:
- argspec = re.sub('^[^(]*', '', argspec)
- doc = "%s%s\n\n%s" % (funcname, argspec, doc)
- obj = lambda: 0
- obj.__argspec_is_invalid_ = True
- obj.func_name = funcname
- obj.__name__ = name
- obj.__doc__ = doc
- if inspect.isclass(object_cache[parent]):
- obj.__objclass__ = object_cache[parent]
- else:
- class Dummy(object): pass
- obj = Dummy()
- obj.__name__ = name
- obj.__doc__ = doc
- if inspect.isclass(object_cache[parent]):
- obj.__get__ = lambda: None
- object_cache[name] = obj
-
- if parent:
- if inspect.ismodule(object_cache[parent]):
- obj.__module__ = parent
- setattr(object_cache[parent], name.split('.')[-1], obj)
-
- # Populate items
- for node in root:
- obj = object_cache.get(node.attrib['id'])
- if obj is None: continue
- for ref in node.findall('ref'):
- if node.tag == 'class':
- if ref.attrib['ref'].startswith(node.attrib['id'] + '.'):
- setattr(obj, ref.attrib['name'],
- object_cache.get(ref.attrib['ref']))
- else:
- setattr(obj, ref.attrib['name'],
- object_cache.get(ref.attrib['ref']))