Merge from trunk
[plcapi.git] / trunk / psycopg2 / scripts / ext2html.py
diff --git a/trunk/psycopg2/scripts/ext2html.py b/trunk/psycopg2/scripts/ext2html.py
new file mode 100755 (executable)
index 0000000..488e97f
--- /dev/null
@@ -0,0 +1,169 @@
+#!/usr/bin/env python\r
+\r
+# Author: Daniele Varrazzo\r
+# Contact: daniele dot varrazzo at gmail dot com\r
+# Revision: $Revision$\r
+# Date: $Date$\r
+# Copyright: This module has been placed in the public domain.\r
+\r
+"""\r
+A minimal front end to the Docutils Publisher, producing HTML.\r
+\r
+Output can refer to Epydoc-generated APIs through the iterpreted text role\r
+"api".\r
+"""\r
+\r
+import types\r
+import sys\r
+\r
+# The url fragment where the api "index.html" resides w.r.t. the generated docs\r
+api_root = "api/"\r
+\r
+try:\r
+    import locale\r
+    locale.setlocale(locale.LC_ALL, '')\r
+except:\r
+    pass\r
+\r
+from docutils.core import publish_cmdline, default_description\r
+from docutils.parsers.rst.roles import register_canonical_role\r
+from docutils import nodes, utils\r
+\r
+# api references are searched for in these modules\r
+api_modules = [\r
+    'psycopg2',\r
+    'psycopg2._psycopg',\r
+    'psycopg2.extensions',\r
+]\r
+\r
+# name starting with a dot are looking as those objects attributes.
+searched_objects = [
+    # module_name, object_name
+    ('psycopg2.extensions', 'connection'),
+    ('psycopg2.extensions', 'cursor'),
+]
+
+# import all the referenced modules\r
+for modname in api_modules:\r
+    __import__(modname)\r
+    \r
+class EpydocTarget:
+    """Representation of an element language."""\r
+    def __init__(self, name, element):\r
+        self.name = name\r
+        \r
+        # The python object described\r
+        self.element = element\r
+    \r
+        # The base name of the page\r
+        self.page = None\r
+        \r
+        # The url fragment\r
+        self.fragment = None\r
+        \r
+    def get_url(self):\r
+        # is it a private element?\r
+        components = self.page.split('.')\r
+        if self.fragment: components.append(self.fragment)\r
+            \r
+        for component in components:\r
+            if component.startswith('_'):\r
+                private = True\r
+                break\r
+        else:\r
+            private = False\r
+            \r
+        ref = api_root + (private and "private/" or "public/") \\r
+            + self.page + "-" + self.get_type() + ".html"\r
+        if self.fragment:\r
+            ref = ref + "#" + self.fragment\r
+        \r
+        return ref\r
+\r
+    def get_type(self):\r
+        # detect the element type\r
+        if isinstance(self.element, types.TypeType):\r
+            return 'class'\r
+        elif isinstance(self.element, types.ModuleType):\r
+            return 'module'\r
+        else:\r
+            raise ValueError("Can't choose a type for '%s'." % self.name)\r
+            \r
+def filter_par(name):\r
+    """Filter parenthesis away from a name."""\r
+    if name.endswith(")"):\r
+        return name.split("(")[0]\r
+    else:\r
+        return name\r
+        \r
+def get_element_target(name):\r
+    """Return the life, the death, the miracles about a package element."""\r
+    \r
+    name = filter_par(name)\r
+    
+    if name.startswith('.'):
+        for modname, objname in searched_objects:
+            if hasattr(getattr(sys.modules[modname], objname), name[1:]):
+                name = objname + name
+                break
+        \r
+    # is the element a module?\r
+    if name in api_modules:\r
+        out = EpydocTarget(name, sys.modules[name])\r
+        out.page = name\r
+        return out\r
+        \r
+    # look for the element in some module\r
+    for modname in api_modules:\r
+        element = getattr(sys.modules[modname], name, None)\r
+        if element is not None:\r
+            \r
+            # Check if it is a function defined in a module\r
+            if isinstance(element, \r
+                    (int, types.FunctionType, types.BuiltinFunctionType)):\r
+                out = EpydocTarget(name, sys.modules[modname])\r
+                out.page = modname\r
+                out.fragment = name\r
+            else:\r
+                out = EpydocTarget(name, element)\r
+                out.page = modname + '.' + name\r
+                \r
+            return out\r
+    \r
+    # maybe a qualified name?\r
+    if '.' in name:\r
+        out = get_element_target('.'.join(name.split('.')[:-1]))\r
+        if out is not None:\r
+            out.fragment = filter_par(name.split('.')[-1])\r
+            return out\r
+                \r
+    raise ValueError("Can't find '%s' in any provided module." % name)\r
+    \r
+def api_role(role, rawtext, text, lineno, inliner,
+                       options={}, content=[]):\r
+    try:\r
+        target = get_element_target(text)\r
+    except Exception, exc:\r
+        msg = inliner.reporter.error(str(exc), line=lineno)
+        prb = inliner.problematic(rawtext, rawtext, msg)
+        return [prb], [msg]
+        \r
+    ref = target.get_url()\r
+    node2 = nodes.literal(rawtext, utils.unescape(text))
+    node = nodes.reference(rawtext, '', node2, refuri=ref,\r
+                           **options)\r
+    return [node], []
+\r
+
+register_canonical_role('api', api_role)
+\r
+# Register the 'api' role as canonical role
+from docutils.parsers.rst import roles 
+roles.DEFAULT_INTERPRETED_ROLE = 'api'
+\r
+
+description = ('Generates (X)HTML documents from standalone reStructuredText '\r
+               'sources with links to Epydoc API.  ' + default_description)\r
+\r
+
+publish_cmdline(writer_name='html', description=description)\r