--- /dev/null
+#!/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