488e97fff1a573ecb3d46d00b1cc8985382ee3f3
[plcapi.git] / psycopg2 / scripts / ext2html.py
1 #!/usr/bin/env python\r
2 \r
3 # Author: Daniele Varrazzo\r
4 # Contact: daniele dot varrazzo at gmail dot com\r
5 # Revision: $Revision$\r
6 # Date: $Date$\r
7 # Copyright: This module has been placed in the public domain.\r
8 \r
9 """\r
10 A minimal front end to the Docutils Publisher, producing HTML.\r
11 \r
12 Output can refer to Epydoc-generated APIs through the iterpreted text role\r
13 "api".\r
14 """\r
15 \r
16 import types\r
17 import sys\r
18 \r
19 # The url fragment where the api "index.html" resides w.r.t. the generated docs\r
20 api_root = "api/"\r
21 \r
22 try:\r
23     import locale\r
24     locale.setlocale(locale.LC_ALL, '')\r
25 except:\r
26     pass\r
27 \r
28 from docutils.core import publish_cmdline, default_description\r
29 from docutils.parsers.rst.roles import register_canonical_role\r
30 from docutils import nodes, utils\r
31 \r
32 # api references are searched for in these modules\r
33 api_modules = [\r
34     'psycopg2',\r
35     'psycopg2._psycopg',\r
36     'psycopg2.extensions',\r
37 ]\r
38 \r
39 # name starting with a dot are looking as those objects attributes.
40 searched_objects = [
41     # module_name, object_name
42     ('psycopg2.extensions', 'connection'),
43     ('psycopg2.extensions', 'cursor'),
44 ]
45
46 # import all the referenced modules\r
47 for modname in api_modules:\r
48     __import__(modname)\r
49     \r
50 class EpydocTarget:
51     """Representation of an element language."""\r
52     def __init__(self, name, element):\r
53         self.name = name\r
54         \r
55         # The python object described\r
56         self.element = element\r
57     \r
58         # The base name of the page\r
59         self.page = None\r
60         \r
61         # The url fragment\r
62         self.fragment = None\r
63         \r
64     def get_url(self):\r
65         # is it a private element?\r
66         components = self.page.split('.')\r
67         if self.fragment: components.append(self.fragment)\r
68             \r
69         for component in components:\r
70             if component.startswith('_'):\r
71                 private = True\r
72                 break\r
73         else:\r
74             private = False\r
75             \r
76         ref = api_root + (private and "private/" or "public/") \\r
77             + self.page + "-" + self.get_type() + ".html"\r
78         if self.fragment:\r
79             ref = ref + "#" + self.fragment\r
80         \r
81         return ref\r
82 \r
83     def get_type(self):\r
84         # detect the element type\r
85         if isinstance(self.element, types.TypeType):\r
86             return 'class'\r
87         elif isinstance(self.element, types.ModuleType):\r
88             return 'module'\r
89         else:\r
90             raise ValueError("Can't choose a type for '%s'." % self.name)\r
91             \r
92 def filter_par(name):\r
93     """Filter parenthesis away from a name."""\r
94     if name.endswith(")"):\r
95         return name.split("(")[0]\r
96     else:\r
97         return name\r
98         \r
99 def get_element_target(name):\r
100     """Return the life, the death, the miracles about a package element."""\r
101     \r
102     name = filter_par(name)\r
103     
104     if name.startswith('.'):
105         for modname, objname in searched_objects:
106             if hasattr(getattr(sys.modules[modname], objname), name[1:]):
107                 name = objname + name
108                 break
109         \r
110     # is the element a module?\r
111     if name in api_modules:\r
112         out = EpydocTarget(name, sys.modules[name])\r
113         out.page = name\r
114         return out\r
115         \r
116     # look for the element in some module\r
117     for modname in api_modules:\r
118         element = getattr(sys.modules[modname], name, None)\r
119         if element is not None:\r
120             \r
121             # Check if it is a function defined in a module\r
122             if isinstance(element, \r
123                     (int, types.FunctionType, types.BuiltinFunctionType)):\r
124                 out = EpydocTarget(name, sys.modules[modname])\r
125                 out.page = modname\r
126                 out.fragment = name\r
127             else:\r
128                 out = EpydocTarget(name, element)\r
129                 out.page = modname + '.' + name\r
130                 \r
131             return out\r
132     \r
133     # maybe a qualified name?\r
134     if '.' in name:\r
135         out = get_element_target('.'.join(name.split('.')[:-1]))\r
136         if out is not None:\r
137             out.fragment = filter_par(name.split('.')[-1])\r
138             return out\r
139                 \r
140     raise ValueError("Can't find '%s' in any provided module." % name)\r
141     \r
142 def api_role(role, rawtext, text, lineno, inliner,
143                        options={}, content=[]):\r
144     try:\r
145         target = get_element_target(text)\r
146     except Exception, exc:\r
147         msg = inliner.reporter.error(str(exc), line=lineno)
148         prb = inliner.problematic(rawtext, rawtext, msg)
149         return [prb], [msg]
150         \r
151     ref = target.get_url()\r
152     node2 = nodes.literal(rawtext, utils.unescape(text))
153     node = nodes.reference(rawtext, '', node2, refuri=ref,\r
154                            **options)\r
155     return [node], []
156 \r
157
158 register_canonical_role('api', api_role)
159 \r
160 # Register the 'api' role as canonical role
161 from docutils.parsers.rst import roles 
162 roles.DEFAULT_INTERPRETED_ROLE = 'api'
163 \r
164
165 description = ('Generates (X)HTML documents from standalone reStructuredText '\r
166                'sources with links to Epydoc API.  ' + default_description)\r
167 \r
168
169 publish_cmdline(writer_name='html', description=description)\r