|
1 import sys |
|
2 import os |
|
3 import difflib |
|
4 import subprocess |
|
5 import re |
|
6 import pydoc |
|
7 import inspect |
|
8 import unittest |
|
9 import test.test_support |
|
10 |
|
11 from test import pydoc_mod |
|
12 |
|
13 expected_text_pattern = \ |
|
14 """ |
|
15 NAME |
|
16 test.pydoc_mod - This is a test module for test_pydoc |
|
17 |
|
18 FILE |
|
19 %s |
|
20 %s |
|
21 CLASSES |
|
22 __builtin__.object |
|
23 B |
|
24 A |
|
25 \x20\x20\x20\x20 |
|
26 class A |
|
27 | Hello and goodbye |
|
28 |\x20\x20 |
|
29 | Methods defined here: |
|
30 |\x20\x20 |
|
31 | __init__() |
|
32 | Wow, I have no function! |
|
33 \x20\x20\x20\x20 |
|
34 class B(__builtin__.object) |
|
35 | Data descriptors defined here: |
|
36 |\x20\x20 |
|
37 | __dict__ |
|
38 | dictionary for instance variables (if defined) |
|
39 |\x20\x20 |
|
40 | __weakref__ |
|
41 | list of weak references to the object (if defined) |
|
42 |\x20\x20 |
|
43 | ---------------------------------------------------------------------- |
|
44 | Data and other attributes defined here: |
|
45 |\x20\x20 |
|
46 | NO_MEANING = 'eggs' |
|
47 |
|
48 FUNCTIONS |
|
49 doc_func() |
|
50 This function solves all of the world's problems: |
|
51 hunger |
|
52 lack of Python |
|
53 war |
|
54 \x20\x20\x20\x20 |
|
55 nodoc_func() |
|
56 |
|
57 DATA |
|
58 __author__ = 'Benjamin Peterson' |
|
59 __credits__ = 'Nobody' |
|
60 __version__ = '1.2.3.4' |
|
61 |
|
62 VERSION |
|
63 1.2.3.4 |
|
64 |
|
65 AUTHOR |
|
66 Benjamin Peterson |
|
67 |
|
68 CREDITS |
|
69 Nobody |
|
70 """.strip() |
|
71 |
|
72 expected_html_pattern = \ |
|
73 """ |
|
74 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading"> |
|
75 <tr bgcolor="#7799ee"> |
|
76 <td valign=bottom> <br> |
|
77 <font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="test.html"><font color="#ffffff">test</font></a>.pydoc_mod</strong></big></big> (version 1.2.3.4)</font></td |
|
78 ><td align=right valign=bottom |
|
79 ><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:%s">%s</a>%s</font></td></tr></table> |
|
80 <p><tt>This is a test module for test_pydoc</tt></p> |
|
81 <p> |
|
82 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> |
|
83 <tr bgcolor="#ee77aa"> |
|
84 <td colspan=3 valign=bottom> <br> |
|
85 <font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr> |
|
86 \x20\x20\x20\x20 |
|
87 <tr><td bgcolor="#ee77aa"><tt> </tt></td><td> </td> |
|
88 <td width="100%%"><dl> |
|
89 <dt><font face="helvetica, arial"><a href="__builtin__.html#object">__builtin__.object</a> |
|
90 </font></dt><dd> |
|
91 <dl> |
|
92 <dt><font face="helvetica, arial"><a href="test.pydoc_mod.html#B">B</a> |
|
93 </font></dt></dl> |
|
94 </dd> |
|
95 <dt><font face="helvetica, arial"><a href="test.pydoc_mod.html#A">A</a> |
|
96 </font></dt></dl> |
|
97 <p> |
|
98 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> |
|
99 <tr bgcolor="#ffc8d8"> |
|
100 <td colspan=3 valign=bottom> <br> |
|
101 <font color="#000000" face="helvetica, arial"><a name="A">class <strong>A</strong></a></font></td></tr> |
|
102 \x20\x20\x20\x20 |
|
103 <tr bgcolor="#ffc8d8"><td rowspan=2><tt> </tt></td> |
|
104 <td colspan=2><tt>Hello and goodbye<br> </tt></td></tr> |
|
105 <tr><td> </td> |
|
106 <td width="100%%">Methods defined here:<br> |
|
107 <dl><dt><a name="A-__init__"><strong>__init__</strong></a>()</dt><dd><tt>Wow, I have no function!</tt></dd></dl> |
|
108 |
|
109 </td></tr></table> <p> |
|
110 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> |
|
111 <tr bgcolor="#ffc8d8"> |
|
112 <td colspan=3 valign=bottom> <br> |
|
113 <font color="#000000" face="helvetica, arial"><a name="B">class <strong>B</strong></a>(<a href="__builtin__.html#object">__builtin__.object</a>)</font></td></tr> |
|
114 \x20\x20\x20\x20 |
|
115 <tr><td bgcolor="#ffc8d8"><tt> </tt></td><td> </td> |
|
116 <td width="100%%">Data descriptors defined here:<br> |
|
117 <dl><dt><strong>__dict__</strong></dt> |
|
118 <dd><tt>dictionary for instance variables (if defined)</tt></dd> |
|
119 </dl> |
|
120 <dl><dt><strong>__weakref__</strong></dt> |
|
121 <dd><tt>list of weak references to the object (if defined)</tt></dd> |
|
122 </dl> |
|
123 <hr> |
|
124 Data and other attributes defined here:<br> |
|
125 <dl><dt><strong>NO_MEANING</strong> = 'eggs'</dl> |
|
126 |
|
127 </td></tr></table></td></tr></table><p> |
|
128 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> |
|
129 <tr bgcolor="#eeaa77"> |
|
130 <td colspan=3 valign=bottom> <br> |
|
131 <font color="#ffffff" face="helvetica, arial"><big><strong>Functions</strong></big></font></td></tr> |
|
132 \x20\x20\x20\x20 |
|
133 <tr><td bgcolor="#eeaa77"><tt> </tt></td><td> </td> |
|
134 <td width="100%%"><dl><dt><a name="-doc_func"><strong>doc_func</strong></a>()</dt><dd><tt>This function solves all of the world's problems:<br> |
|
135 hunger<br> |
|
136 lack of Python<br> |
|
137 war</tt></dd></dl> |
|
138 <dl><dt><a name="-nodoc_func"><strong>nodoc_func</strong></a>()</dt></dl> |
|
139 </td></tr></table><p> |
|
140 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> |
|
141 <tr bgcolor="#55aa55"> |
|
142 <td colspan=3 valign=bottom> <br> |
|
143 <font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr> |
|
144 \x20\x20\x20\x20 |
|
145 <tr><td bgcolor="#55aa55"><tt> </tt></td><td> </td> |
|
146 <td width="100%%"><strong>__author__</strong> = 'Benjamin Peterson'<br> |
|
147 <strong>__credits__</strong> = 'Nobody'<br> |
|
148 <strong>__version__</strong> = '1.2.3.4'</td></tr></table><p> |
|
149 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> |
|
150 <tr bgcolor="#7799ee"> |
|
151 <td colspan=3 valign=bottom> <br> |
|
152 <font color="#ffffff" face="helvetica, arial"><big><strong>Author</strong></big></font></td></tr> |
|
153 \x20\x20\x20\x20 |
|
154 <tr><td bgcolor="#7799ee"><tt> </tt></td><td> </td> |
|
155 <td width="100%%">Benjamin Peterson</td></tr></table><p> |
|
156 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> |
|
157 <tr bgcolor="#7799ee"> |
|
158 <td colspan=3 valign=bottom> <br> |
|
159 <font color="#ffffff" face="helvetica, arial"><big><strong>Credits</strong></big></font></td></tr> |
|
160 \x20\x20\x20\x20 |
|
161 <tr><td bgcolor="#7799ee"><tt> </tt></td><td> </td> |
|
162 <td width="100%%">Nobody</td></tr></table> |
|
163 """.strip() |
|
164 |
|
165 |
|
166 # output pattern for missing module |
|
167 missing_pattern = "no Python documentation found for '%s'" |
|
168 |
|
169 def run_pydoc(module_name, *args): |
|
170 """ |
|
171 Runs pydoc on the specified module. Returns the stripped |
|
172 output of pydoc. |
|
173 """ |
|
174 cmd = [sys.executable, pydoc.__file__, " ".join(args), module_name] |
|
175 output = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout.read() |
|
176 return output.strip() |
|
177 |
|
178 def get_pydoc_html(module): |
|
179 "Returns pydoc generated output as html" |
|
180 doc = pydoc.HTMLDoc() |
|
181 output = doc.docmodule(module) |
|
182 loc = doc.getdocloc(pydoc_mod) or "" |
|
183 if loc: |
|
184 loc = "<br><a href=\"" + loc + "\">Module Docs</a>" |
|
185 return output.strip(), loc |
|
186 |
|
187 def get_pydoc_text(module): |
|
188 "Returns pydoc generated output as text" |
|
189 doc = pydoc.TextDoc() |
|
190 loc = doc.getdocloc(pydoc_mod) or "" |
|
191 if loc: |
|
192 loc = "\nMODULE DOCS\n " + loc + "\n" |
|
193 |
|
194 output = doc.docmodule(module) |
|
195 |
|
196 # cleanup the extra text formatting that pydoc preforms |
|
197 patt = re.compile('\b.') |
|
198 output = patt.sub('', output) |
|
199 return output.strip(), loc |
|
200 |
|
201 def print_diffs(text1, text2): |
|
202 "Prints unified diffs for two texts" |
|
203 lines1 = text1.splitlines(True) |
|
204 lines2 = text2.splitlines(True) |
|
205 diffs = difflib.unified_diff(lines1, lines2, n=0, fromfile='expected', |
|
206 tofile='got') |
|
207 print '\n' + ''.join(diffs) |
|
208 |
|
209 |
|
210 class PyDocDocTest(unittest.TestCase): |
|
211 |
|
212 def test_html_doc(self): |
|
213 result, doc_loc = get_pydoc_html(pydoc_mod) |
|
214 mod_file = inspect.getabsfile(pydoc_mod) |
|
215 if sys.platform == 'win32': |
|
216 import nturl2path |
|
217 mod_url = nturl2path.pathname2url(mod_file) |
|
218 else: |
|
219 mod_url = mod_file |
|
220 expected_html = expected_html_pattern % (mod_url, mod_file, doc_loc) |
|
221 if result != expected_html: |
|
222 print_diffs(expected_html, result) |
|
223 self.fail("outputs are not equal, see diff above") |
|
224 |
|
225 def test_text_doc(self): |
|
226 result, doc_loc = get_pydoc_text(pydoc_mod) |
|
227 expected_text = expected_text_pattern % \ |
|
228 (inspect.getabsfile(pydoc_mod), doc_loc) |
|
229 if result != expected_text: |
|
230 print_diffs(expected_text, result) |
|
231 self.fail("outputs are not equal, see diff above") |
|
232 |
|
233 def test_not_here(self): |
|
234 missing_module = "test.i_am_not_here" |
|
235 result = run_pydoc(missing_module) |
|
236 expected = missing_pattern % missing_module |
|
237 self.assertEqual(expected, result, |
|
238 "documentation for missing module found") |
|
239 |
|
240 |
|
241 class TestDescriptions(unittest.TestCase): |
|
242 |
|
243 def test_module(self): |
|
244 # Check that pydocfodder module can be described |
|
245 from test import pydocfodder |
|
246 doc = pydoc.render_doc(pydocfodder) |
|
247 self.assert_("pydocfodder" in doc) |
|
248 |
|
249 def test_classic_class(self): |
|
250 class C: "Classic class" |
|
251 c = C() |
|
252 self.assertEqual(pydoc.describe(C), 'class C') |
|
253 self.assertEqual(pydoc.describe(c), 'instance of C') |
|
254 expected = 'instance of C in module %s' % __name__ |
|
255 self.assert_(expected in pydoc.render_doc(c)) |
|
256 |
|
257 def test_class(self): |
|
258 class C(object): "New-style class" |
|
259 c = C() |
|
260 |
|
261 self.assertEqual(pydoc.describe(C), 'class C') |
|
262 self.assertEqual(pydoc.describe(c), 'C') |
|
263 expected = 'C in module %s object' % __name__ |
|
264 self.assert_(expected in pydoc.render_doc(c)) |
|
265 |
|
266 |
|
267 def test_main(): |
|
268 test.test_support.run_unittest(PyDocDocTest, |
|
269 TestDescriptions) |
|
270 |
|
271 if __name__ == "__main__": |
|
272 test_main() |