| Benjamin Peterson | 3a7305e | 2008-05-22 23:09:26 +0000 | [diff] [blame] | 1 | import os | 
| Éric Araujo | 9a52830 | 2011-07-29 17:34:35 +0200 | [diff] [blame] | 2 | import sys | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 3 | import difflib | 
| Éric Araujo | 9a52830 | 2011-07-29 17:34:35 +0200 | [diff] [blame] | 4 | import __builtin__ | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 5 | import re | 
| Berker Peksag | dc9d41d | 2015-02-20 12:10:33 +0200 | [diff] [blame] | 6 | import py_compile | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 7 | import pydoc | 
| Antoine Pitrou | f41ffed | 2013-05-19 15:44:54 +0200 | [diff] [blame] | 8 | import contextlib | 
| Georg Brandl | b7e419e | 2008-05-20 08:10:03 +0000 | [diff] [blame] | 9 | import inspect | 
| Ezio Melotti | bdfa2e6 | 2011-04-28 07:59:33 +0300 | [diff] [blame] | 10 | import keyword | 
| Antoine Pitrou | f41ffed | 2013-05-19 15:44:54 +0200 | [diff] [blame] | 11 | import pkgutil | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 12 | import unittest | 
| Brian Curtin | aeb2e82 | 2010-03-31 03:10:21 +0000 | [diff] [blame] | 13 | import xml.etree | 
| R David Murray | 984f630 | 2014-01-05 12:35:59 -0500 | [diff] [blame] | 14 | import types | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 15 | import test.test_support | 
| Raymond Hettinger | 9aa5a34 | 2011-03-25 16:00:13 -0700 | [diff] [blame] | 16 | from collections import namedtuple | 
| Ned Deily | 1a96f8d | 2011-10-06 14:17:34 -0700 | [diff] [blame] | 17 | from test.script_helper import assert_python_ok | 
| Charles-François Natali | 94919a4 | 2014-06-20 22:57:19 +0100 | [diff] [blame] | 18 | from test.test_support import (TESTFN, rmtree, reap_children, captured_stdout, | 
 | 19 |                                captured_stderr, requires_docstrings) | 
| Benjamin Peterson | f5c38da | 2008-05-18 20:48:07 +0000 | [diff] [blame] | 20 |  | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 21 | from test import pydoc_mod | 
 | 22 |  | 
| Serhiy Storchaka | 72121c6 | 2013-01-27 19:45:49 +0200 | [diff] [blame] | 23 | if test.test_support.HAVE_DOCSTRINGS: | 
 | 24 |     expected_data_docstrings = ( | 
 | 25 |         'dictionary for instance variables (if defined)', | 
 | 26 |         'list of weak references to the object (if defined)', | 
 | 27 |         ) | 
 | 28 | else: | 
 | 29 |     expected_data_docstrings = ('', '') | 
 | 30 |  | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 31 | expected_text_pattern = \ | 
 | 32 | """ | 
 | 33 | NAME | 
 | 34 |     test.pydoc_mod - This is a test module for test_pydoc | 
 | 35 |  | 
 | 36 | FILE | 
 | 37 |     %s | 
| Benjamin Peterson | 3a7305e | 2008-05-22 23:09:26 +0000 | [diff] [blame] | 38 | %s | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 39 | CLASSES | 
 | 40 |     __builtin__.object | 
 | 41 |         B | 
| Benjamin Peterson | c3e1e90 | 2014-06-07 16:44:00 -0700 | [diff] [blame] | 42 |         C | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 43 |     A | 
 | 44 | \x20\x20\x20\x20 | 
 | 45 |     class A | 
 | 46 |      |  Hello and goodbye | 
 | 47 |      |\x20\x20 | 
 | 48 |      |  Methods defined here: | 
 | 49 |      |\x20\x20 | 
 | 50 |      |  __init__() | 
 | 51 |      |      Wow, I have no function! | 
 | 52 | \x20\x20\x20\x20 | 
 | 53 |     class B(__builtin__.object) | 
 | 54 |      |  Data descriptors defined here: | 
 | 55 |      |\x20\x20 | 
| Serhiy Storchaka | 72121c6 | 2013-01-27 19:45:49 +0200 | [diff] [blame] | 56 |      |  __dict__%s | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 57 |      |\x20\x20 | 
| Serhiy Storchaka | 72121c6 | 2013-01-27 19:45:49 +0200 | [diff] [blame] | 58 |      |  __weakref__%s | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 59 |      |\x20\x20 | 
 | 60 |      |  ---------------------------------------------------------------------- | 
 | 61 |      |  Data and other attributes defined here: | 
 | 62 |      |\x20\x20 | 
 | 63 |      |  NO_MEANING = 'eggs' | 
| Benjamin Peterson | c3e1e90 | 2014-06-07 16:44:00 -0700 | [diff] [blame] | 64 | \x20\x20\x20\x20 | 
 | 65 |     class C(__builtin__.object) | 
 | 66 |      |  Methods defined here: | 
 | 67 |      |\x20\x20 | 
 | 68 |      |  get_answer(self) | 
 | 69 |      |      Return say_no() | 
 | 70 |      |\x20\x20 | 
 | 71 |      |  is_it_true(self) | 
 | 72 |      |      Return self.get_answer() | 
 | 73 |      |\x20\x20 | 
 | 74 |      |  say_no(self) | 
 | 75 |      |\x20\x20 | 
 | 76 |      |  ---------------------------------------------------------------------- | 
 | 77 |      |  Data descriptors defined here: | 
 | 78 |      |\x20\x20 | 
 | 79 |      |  __dict__ | 
 | 80 |      |      dictionary for instance variables (if defined) | 
 | 81 |      |\x20\x20 | 
 | 82 |      |  __weakref__ | 
 | 83 |      |      list of weak references to the object (if defined) | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 84 |  | 
 | 85 | FUNCTIONS | 
 | 86 |     doc_func() | 
 | 87 |         This function solves all of the world's problems: | 
 | 88 |         hunger | 
 | 89 |         lack of Python | 
 | 90 |         war | 
 | 91 | \x20\x20\x20\x20 | 
 | 92 |     nodoc_func() | 
 | 93 |  | 
 | 94 | DATA | 
 | 95 |     __author__ = 'Benjamin Peterson' | 
 | 96 |     __credits__ = 'Nobody' | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 97 |     __version__ = '1.2.3.4' | 
 | 98 |  | 
 | 99 | VERSION | 
 | 100 |     1.2.3.4 | 
 | 101 |  | 
 | 102 | AUTHOR | 
 | 103 |     Benjamin Peterson | 
 | 104 |  | 
 | 105 | CREDITS | 
 | 106 |     Nobody | 
 | 107 | """.strip() | 
 | 108 |  | 
| Serhiy Storchaka | 72121c6 | 2013-01-27 19:45:49 +0200 | [diff] [blame] | 109 | expected_text_data_docstrings = tuple('\n     |      ' + s if s else '' | 
 | 110 |                                       for s in expected_data_docstrings) | 
 | 111 |  | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 112 | expected_html_pattern = \ | 
 | 113 | """ | 
 | 114 | <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading"> | 
 | 115 | <tr bgcolor="#7799ee"> | 
 | 116 | <td valign=bottom> <br> | 
 | 117 | <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 | 
 | 118 | ><td align=right valign=bottom | 
| Benjamin Peterson | 3a7305e | 2008-05-22 23:09:26 +0000 | [diff] [blame] | 119 | ><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:%s">%s</a>%s</font></td></tr></table> | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 120 |     <p><tt>This is a test module for test_pydoc</tt></p> | 
 | 121 | <p> | 
 | 122 | <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> | 
 | 123 | <tr bgcolor="#ee77aa"> | 
 | 124 | <td colspan=3 valign=bottom> <br> | 
 | 125 | <font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr> | 
 | 126 | \x20\x20\x20\x20 | 
 | 127 | <tr><td bgcolor="#ee77aa"><tt>      </tt></td><td> </td> | 
 | 128 | <td width="100%%"><dl> | 
 | 129 | <dt><font face="helvetica, arial"><a href="__builtin__.html#object">__builtin__.object</a> | 
 | 130 | </font></dt><dd> | 
 | 131 | <dl> | 
 | 132 | <dt><font face="helvetica, arial"><a href="test.pydoc_mod.html#B">B</a> | 
| Benjamin Peterson | c3e1e90 | 2014-06-07 16:44:00 -0700 | [diff] [blame] | 133 | </font></dt><dt><font face="helvetica, arial"><a href="test.pydoc_mod.html#C">C</a> | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 134 | </font></dt></dl> | 
 | 135 | </dd> | 
 | 136 | <dt><font face="helvetica, arial"><a href="test.pydoc_mod.html#A">A</a> | 
 | 137 | </font></dt></dl> | 
 | 138 |  <p> | 
 | 139 | <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> | 
 | 140 | <tr bgcolor="#ffc8d8"> | 
 | 141 | <td colspan=3 valign=bottom> <br> | 
 | 142 | <font color="#000000" face="helvetica, arial"><a name="A">class <strong>A</strong></a></font></td></tr> | 
 | 143 | \x20\x20\x20\x20 | 
 | 144 | <tr bgcolor="#ffc8d8"><td rowspan=2><tt>   </tt></td> | 
 | 145 | <td colspan=2><tt>Hello and goodbye<br> </tt></td></tr> | 
 | 146 | <tr><td> </td> | 
 | 147 | <td width="100%%">Methods defined here:<br> | 
 | 148 | <dl><dt><a name="A-__init__"><strong>__init__</strong></a>()</dt><dd><tt>Wow, I have no function!</tt></dd></dl> | 
 | 149 |  | 
 | 150 | </td></tr></table> <p> | 
 | 151 | <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> | 
 | 152 | <tr bgcolor="#ffc8d8"> | 
 | 153 | <td colspan=3 valign=bottom> <br> | 
 | 154 | <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> | 
 | 155 | \x20\x20\x20\x20 | 
 | 156 | <tr><td bgcolor="#ffc8d8"><tt>   </tt></td><td> </td> | 
 | 157 | <td width="100%%">Data descriptors defined here:<br> | 
 | 158 | <dl><dt><strong>__dict__</strong></dt> | 
| Serhiy Storchaka | 72121c6 | 2013-01-27 19:45:49 +0200 | [diff] [blame] | 159 | <dd><tt>%s</tt></dd> | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 160 | </dl> | 
 | 161 | <dl><dt><strong>__weakref__</strong></dt> | 
| Serhiy Storchaka | 72121c6 | 2013-01-27 19:45:49 +0200 | [diff] [blame] | 162 | <dd><tt>%s</tt></dd> | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 163 | </dl> | 
 | 164 | <hr> | 
 | 165 | Data and other attributes defined here:<br> | 
 | 166 | <dl><dt><strong>NO_MEANING</strong> = 'eggs'</dl> | 
 | 167 |  | 
| Benjamin Peterson | c3e1e90 | 2014-06-07 16:44:00 -0700 | [diff] [blame] | 168 | </td></tr></table> <p> | 
 | 169 | <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> | 
 | 170 | <tr bgcolor="#ffc8d8"> | 
 | 171 | <td colspan=3 valign=bottom> <br> | 
 | 172 | <font color="#000000" face="helvetica, arial"><a name="C">class <strong>C</strong></a>(<a href="__builtin__.html#object">__builtin__.object</a>)</font></td></tr> | 
 | 173 | \x20\x20\x20\x20 | 
 | 174 | <tr><td bgcolor="#ffc8d8"><tt>   </tt></td><td> </td> | 
 | 175 | <td width="100%%">Methods defined here:<br> | 
 | 176 | <dl><dt><a name="C-get_answer"><strong>get_answer</strong></a>(self)</dt><dd><tt>Return <a href="#C-say_no">say_no</a>()</tt></dd></dl> | 
 | 177 |  | 
 | 178 | <dl><dt><a name="C-is_it_true"><strong>is_it_true</strong></a>(self)</dt><dd><tt>Return self.<a href="#C-get_answer">get_answer</a>()</tt></dd></dl> | 
 | 179 |  | 
 | 180 | <dl><dt><a name="C-say_no"><strong>say_no</strong></a>(self)</dt></dl> | 
 | 181 |  | 
 | 182 | <hr> | 
 | 183 | Data descriptors defined here:<br> | 
 | 184 | <dl><dt><strong>__dict__</strong></dt> | 
 | 185 | <dd><tt>dictionary for instance variables (if defined)</tt></dd> | 
 | 186 | </dl> | 
 | 187 | <dl><dt><strong>__weakref__</strong></dt> | 
 | 188 | <dd><tt>list of weak references to the object (if defined)</tt></dd> | 
 | 189 | </dl> | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 190 | </td></tr></table></td></tr></table><p> | 
 | 191 | <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> | 
 | 192 | <tr bgcolor="#eeaa77"> | 
 | 193 | <td colspan=3 valign=bottom> <br> | 
 | 194 | <font color="#ffffff" face="helvetica, arial"><big><strong>Functions</strong></big></font></td></tr> | 
 | 195 | \x20\x20\x20\x20 | 
 | 196 | <tr><td bgcolor="#eeaa77"><tt>      </tt></td><td> </td> | 
 | 197 | <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> | 
 | 198 | hunger<br> | 
 | 199 | lack of Python<br> | 
 | 200 | war</tt></dd></dl> | 
 | 201 |  <dl><dt><a name="-nodoc_func"><strong>nodoc_func</strong></a>()</dt></dl> | 
 | 202 | </td></tr></table><p> | 
 | 203 | <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> | 
 | 204 | <tr bgcolor="#55aa55"> | 
 | 205 | <td colspan=3 valign=bottom> <br> | 
 | 206 | <font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr> | 
 | 207 | \x20\x20\x20\x20 | 
 | 208 | <tr><td bgcolor="#55aa55"><tt>      </tt></td><td> </td> | 
 | 209 | <td width="100%%"><strong>__author__</strong> = 'Benjamin Peterson'<br> | 
 | 210 | <strong>__credits__</strong> = 'Nobody'<br> | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 211 | <strong>__version__</strong> = '1.2.3.4'</td></tr></table><p> | 
 | 212 | <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> | 
 | 213 | <tr bgcolor="#7799ee"> | 
 | 214 | <td colspan=3 valign=bottom> <br> | 
 | 215 | <font color="#ffffff" face="helvetica, arial"><big><strong>Author</strong></big></font></td></tr> | 
 | 216 | \x20\x20\x20\x20 | 
 | 217 | <tr><td bgcolor="#7799ee"><tt>      </tt></td><td> </td> | 
 | 218 | <td width="100%%">Benjamin Peterson</td></tr></table><p> | 
 | 219 | <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section"> | 
 | 220 | <tr bgcolor="#7799ee"> | 
 | 221 | <td colspan=3 valign=bottom> <br> | 
 | 222 | <font color="#ffffff" face="helvetica, arial"><big><strong>Credits</strong></big></font></td></tr> | 
 | 223 | \x20\x20\x20\x20 | 
 | 224 | <tr><td bgcolor="#7799ee"><tt>      </tt></td><td> </td> | 
 | 225 | <td width="100%%">Nobody</td></tr></table> | 
 | 226 | """.strip() | 
 | 227 |  | 
| Serhiy Storchaka | 72121c6 | 2013-01-27 19:45:49 +0200 | [diff] [blame] | 228 | expected_html_data_docstrings = tuple(s.replace(' ', ' ') | 
 | 229 |                                       for s in expected_data_docstrings) | 
| Benjamin Peterson | 3a7305e | 2008-05-22 23:09:26 +0000 | [diff] [blame] | 230 |  | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 231 | # output pattern for missing module | 
 | 232 | missing_pattern = "no Python documentation found for '%s'" | 
 | 233 |  | 
| R. David Murray | ef087da | 2009-06-23 18:02:46 +0000 | [diff] [blame] | 234 | # output pattern for module with bad imports | 
 | 235 | badimport_pattern = "problem in %s - <type 'exceptions.ImportError'>: No module named %s" | 
 | 236 |  | 
| Ned Deily | 1a96f8d | 2011-10-06 14:17:34 -0700 | [diff] [blame] | 237 | def run_pydoc(module_name, *args, **env): | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 238 |     """ | 
 | 239 |     Runs pydoc on the specified module. Returns the stripped | 
 | 240 |     output of pydoc. | 
 | 241 |     """ | 
| Ned Deily | 1a96f8d | 2011-10-06 14:17:34 -0700 | [diff] [blame] | 242 |     args = args + (module_name,) | 
 | 243 |     # do not write bytecode files to avoid caching errors | 
 | 244 |     rc, out, err = assert_python_ok('-B', pydoc.__file__, *args, **env) | 
 | 245 |     return out.strip() | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 246 |  | 
 | 247 | def get_pydoc_html(module): | 
 | 248 |     "Returns pydoc generated output as html" | 
| Benjamin Peterson | 3a7305e | 2008-05-22 23:09:26 +0000 | [diff] [blame] | 249 |     doc = pydoc.HTMLDoc() | 
 | 250 |     output = doc.docmodule(module) | 
 | 251 |     loc = doc.getdocloc(pydoc_mod) or "" | 
 | 252 |     if loc: | 
 | 253 |         loc = "<br><a href=\"" + loc + "\">Module Docs</a>" | 
 | 254 |     return output.strip(), loc | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 255 |  | 
 | 256 | def get_pydoc_text(module): | 
 | 257 |     "Returns pydoc generated output as text" | 
| Benjamin Peterson | 3a7305e | 2008-05-22 23:09:26 +0000 | [diff] [blame] | 258 |     doc = pydoc.TextDoc() | 
 | 259 |     loc = doc.getdocloc(pydoc_mod) or "" | 
 | 260 |     if loc: | 
 | 261 |         loc = "\nMODULE DOCS\n    " + loc + "\n" | 
 | 262 |  | 
 | 263 |     output = doc.docmodule(module) | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 264 |  | 
 | 265 |     # cleanup the extra text formatting that pydoc preforms | 
 | 266 |     patt = re.compile('\b.') | 
 | 267 |     output = patt.sub('', output) | 
| Benjamin Peterson | 3a7305e | 2008-05-22 23:09:26 +0000 | [diff] [blame] | 268 |     return output.strip(), loc | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 269 |  | 
 | 270 | def print_diffs(text1, text2): | 
 | 271 |     "Prints unified diffs for two texts" | 
| Georg Brandl | fb3de1f | 2008-05-20 08:07:36 +0000 | [diff] [blame] | 272 |     lines1 = text1.splitlines(True) | 
 | 273 |     lines2 = text2.splitlines(True) | 
 | 274 |     diffs = difflib.unified_diff(lines1, lines2, n=0, fromfile='expected', | 
 | 275 |                                  tofile='got') | 
 | 276 |     print '\n' + ''.join(diffs) | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 277 |  | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 278 |  | 
| Antoine Pitrou | f41ffed | 2013-05-19 15:44:54 +0200 | [diff] [blame] | 279 | class PydocBaseTest(unittest.TestCase): | 
 | 280 |  | 
 | 281 |     def _restricted_walk_packages(self, walk_packages, path=None): | 
 | 282 |         """ | 
 | 283 |         A version of pkgutil.walk_packages() that will restrict itself to | 
 | 284 |         a given path. | 
 | 285 |         """ | 
 | 286 |         default_path = path or [os.path.dirname(__file__)] | 
 | 287 |         def wrapper(path=None, prefix='', onerror=None): | 
 | 288 |             return walk_packages(path or default_path, prefix, onerror) | 
 | 289 |         return wrapper | 
 | 290 |  | 
 | 291 |     @contextlib.contextmanager | 
 | 292 |     def restrict_walk_packages(self, path=None): | 
 | 293 |         walk_packages = pkgutil.walk_packages | 
 | 294 |         pkgutil.walk_packages = self._restricted_walk_packages(walk_packages, | 
 | 295 |                                                                path) | 
 | 296 |         try: | 
 | 297 |             yield | 
 | 298 |         finally: | 
 | 299 |             pkgutil.walk_packages = walk_packages | 
 | 300 |  | 
 | 301 |  | 
 | 302 | class PydocDocTest(unittest.TestCase): | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 303 |  | 
| Charles-François Natali | 94919a4 | 2014-06-20 22:57:19 +0100 | [diff] [blame] | 304 |     @requires_docstrings | 
| R. David Murray | f28fd24 | 2010-02-23 00:24:49 +0000 | [diff] [blame] | 305 |     @unittest.skipIf(sys.flags.optimize >= 2, | 
 | 306 |                      "Docstrings are omitted with -O2 and above") | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 307 |     def test_html_doc(self): | 
| Benjamin Peterson | 3a7305e | 2008-05-22 23:09:26 +0000 | [diff] [blame] | 308 |         result, doc_loc = get_pydoc_html(pydoc_mod) | 
| Georg Brandl | b7e419e | 2008-05-20 08:10:03 +0000 | [diff] [blame] | 309 |         mod_file = inspect.getabsfile(pydoc_mod) | 
| Amaury Forgeot d'Arc | 8e8de4a | 2008-06-10 21:37:15 +0000 | [diff] [blame] | 310 |         if sys.platform == 'win32': | 
 | 311 |             import nturl2path | 
 | 312 |             mod_url = nturl2path.pathname2url(mod_file) | 
 | 313 |         else: | 
 | 314 |             mod_url = mod_file | 
| Serhiy Storchaka | 72121c6 | 2013-01-27 19:45:49 +0200 | [diff] [blame] | 315 |         expected_html = expected_html_pattern % ( | 
 | 316 |                         (mod_url, mod_file, doc_loc) + | 
 | 317 |                         expected_html_data_docstrings) | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 318 |         if result != expected_html: | 
| Georg Brandl | fb3de1f | 2008-05-20 08:07:36 +0000 | [diff] [blame] | 319 |             print_diffs(expected_html, result) | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 320 |             self.fail("outputs are not equal, see diff above") | 
 | 321 |  | 
| Charles-François Natali | 94919a4 | 2014-06-20 22:57:19 +0100 | [diff] [blame] | 322 |     @requires_docstrings | 
| R. David Murray | f28fd24 | 2010-02-23 00:24:49 +0000 | [diff] [blame] | 323 |     @unittest.skipIf(sys.flags.optimize >= 2, | 
 | 324 |                      "Docstrings are omitted with -O2 and above") | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 325 |     def test_text_doc(self): | 
| Benjamin Peterson | 3a7305e | 2008-05-22 23:09:26 +0000 | [diff] [blame] | 326 |         result, doc_loc = get_pydoc_text(pydoc_mod) | 
| Serhiy Storchaka | 72121c6 | 2013-01-27 19:45:49 +0200 | [diff] [blame] | 327 |         expected_text = expected_text_pattern % ( | 
 | 328 |                         (inspect.getabsfile(pydoc_mod), doc_loc) + | 
 | 329 |                         expected_text_data_docstrings) | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 330 |         if result != expected_text: | 
| Georg Brandl | fb3de1f | 2008-05-20 08:07:36 +0000 | [diff] [blame] | 331 |             print_diffs(expected_text, result) | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 332 |             self.fail("outputs are not equal, see diff above") | 
 | 333 |  | 
| Brian Curtin | aeb2e82 | 2010-03-31 03:10:21 +0000 | [diff] [blame] | 334 |     def test_issue8225(self): | 
 | 335 |         # Test issue8225 to ensure no doc link appears for xml.etree | 
 | 336 |         result, doc_loc = get_pydoc_text(xml.etree) | 
 | 337 |         self.assertEqual(doc_loc, "", "MODULE DOCS incorrectly includes a link") | 
 | 338 |  | 
| Benjamin Peterson | 75a55c3 | 2014-06-07 20:14:26 -0700 | [diff] [blame] | 339 |     def test_getpager_with_stdin_none(self): | 
 | 340 |         previous_stdin = sys.stdin | 
 | 341 |         try: | 
 | 342 |             sys.stdin = None | 
 | 343 |             pydoc.getpager() # Shouldn't fail. | 
 | 344 |         finally: | 
 | 345 |             sys.stdin = previous_stdin | 
 | 346 |  | 
| R David Murray | c313b1d | 2012-04-23 13:27:11 -0400 | [diff] [blame] | 347 |     def test_non_str_name(self): | 
 | 348 |         # issue14638 | 
 | 349 |         # Treat illegal (non-str) name like no name | 
 | 350 |         class A: | 
 | 351 |             __name__ = 42 | 
 | 352 |         class B: | 
 | 353 |             pass | 
 | 354 |         adoc = pydoc.render_doc(A()) | 
 | 355 |         bdoc = pydoc.render_doc(B()) | 
 | 356 |         self.assertEqual(adoc.replace("A", "B"), bdoc) | 
 | 357 |  | 
| Benjamin Peterson | f5c38da | 2008-05-18 20:48:07 +0000 | [diff] [blame] | 358 |     def test_not_here(self): | 
 | 359 |         missing_module = "test.i_am_not_here" | 
 | 360 |         result = run_pydoc(missing_module) | 
 | 361 |         expected = missing_pattern % missing_module | 
 | 362 |         self.assertEqual(expected, result, | 
 | 363 |             "documentation for missing module found") | 
 | 364 |  | 
| R. David Murray | d67ea7d | 2009-05-27 20:07:21 +0000 | [diff] [blame] | 365 |     def test_input_strip(self): | 
 | 366 |         missing_module = " test.i_am_not_here " | 
 | 367 |         result = run_pydoc(missing_module) | 
 | 368 |         expected = missing_pattern % missing_module.strip() | 
 | 369 |         self.assertEqual(expected, result, | 
 | 370 |             "white space was not stripped from module name " | 
 | 371 |             "or other error output mismatch") | 
 | 372 |  | 
| Ezio Melotti | e511fc7 | 2010-02-16 23:26:09 +0000 | [diff] [blame] | 373 |     def test_stripid(self): | 
 | 374 |         # test with strings, other implementations might have different repr() | 
 | 375 |         stripid = pydoc.stripid | 
 | 376 |         # strip the id | 
 | 377 |         self.assertEqual(stripid('<function stripid at 0x88dcee4>'), | 
 | 378 |                          '<function stripid>') | 
 | 379 |         self.assertEqual(stripid('<function stripid at 0x01F65390>'), | 
 | 380 |                          '<function stripid>') | 
 | 381 |         # nothing to strip, return the same text | 
 | 382 |         self.assertEqual(stripid('42'), '42') | 
 | 383 |         self.assertEqual(stripid("<type 'exceptions.Exception'>"), | 
 | 384 |                          "<type 'exceptions.Exception'>") | 
 | 385 |  | 
| Berker Peksag | dc9d41d | 2015-02-20 12:10:33 +0200 | [diff] [blame] | 386 |     def test_synopsis(self): | 
 | 387 |         with test.test_support.temp_cwd() as test_dir: | 
 | 388 |             init_path = os.path.join(test_dir, 'dt.py') | 
 | 389 |             with open(init_path, 'w') as fobj: | 
 | 390 |                 fobj.write('''\ | 
 | 391 | """ | 
 | 392 | my doc | 
 | 393 |  | 
 | 394 | second line | 
 | 395 | """ | 
 | 396 | foo = 1 | 
 | 397 | ''') | 
 | 398 |             py_compile.compile(init_path) | 
 | 399 |             synopsis = pydoc.synopsis(init_path, {}) | 
 | 400 |             self.assertEqual(synopsis, 'my doc') | 
 | 401 |  | 
 | 402 |     def test_synopsis_sourceless_empty_doc(self): | 
 | 403 |         with test.test_support.temp_cwd() as test_dir: | 
 | 404 |             init_path = os.path.join(test_dir, 'foomod42.py') | 
 | 405 |             cached_path = os.path.join(test_dir, 'foomod42.pyc') | 
 | 406 |             with open(init_path, 'w') as fobj: | 
 | 407 |                 fobj.write("foo = 1") | 
 | 408 |             py_compile.compile(init_path) | 
 | 409 |             synopsis = pydoc.synopsis(init_path, {}) | 
 | 410 |             self.assertIsNone(synopsis) | 
 | 411 |             synopsis_cached = pydoc.synopsis(cached_path, {}) | 
 | 412 |             self.assertIsNone(synopsis_cached) | 
 | 413 |  | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 414 |  | 
| Antoine Pitrou | f41ffed | 2013-05-19 15:44:54 +0200 | [diff] [blame] | 415 | class PydocImportTest(PydocBaseTest): | 
| Ned Deily | 1a96f8d | 2011-10-06 14:17:34 -0700 | [diff] [blame] | 416 |  | 
 | 417 |     def setUp(self): | 
 | 418 |         self.test_dir = os.mkdir(TESTFN) | 
 | 419 |         self.addCleanup(rmtree, TESTFN) | 
 | 420 |  | 
 | 421 |     def test_badimport(self): | 
 | 422 |         # This tests the fix for issue 5230, where if pydoc found the module | 
 | 423 |         # but the module had an internal import error pydoc would report no doc | 
 | 424 |         # found. | 
 | 425 |         modname = 'testmod_xyzzy' | 
 | 426 |         testpairs = ( | 
 | 427 |             ('i_am_not_here', 'i_am_not_here'), | 
 | 428 |             ('test.i_am_not_here_either', 'i_am_not_here_either'), | 
 | 429 |             ('test.i_am_not_here.neither_am_i', 'i_am_not_here.neither_am_i'), | 
 | 430 |             ('i_am_not_here.{}'.format(modname), | 
 | 431 |              'i_am_not_here.{}'.format(modname)), | 
 | 432 |             ('test.{}'.format(modname), modname), | 
 | 433 |             ) | 
 | 434 |  | 
 | 435 |         sourcefn = os.path.join(TESTFN, modname) + os.extsep + "py" | 
 | 436 |         for importstring, expectedinmsg in testpairs: | 
 | 437 |             with open(sourcefn, 'w') as f: | 
 | 438 |                 f.write("import {}\n".format(importstring)) | 
 | 439 |             result = run_pydoc(modname, PYTHONPATH=TESTFN) | 
 | 440 |             expected = badimport_pattern % (modname, expectedinmsg) | 
 | 441 |             self.assertEqual(expected, result) | 
 | 442 |  | 
 | 443 |     def test_apropos_with_bad_package(self): | 
 | 444 |         # Issue 7425 - pydoc -k failed when bad package on path | 
 | 445 |         pkgdir = os.path.join(TESTFN, "syntaxerr") | 
 | 446 |         os.mkdir(pkgdir) | 
 | 447 |         badsyntax = os.path.join(pkgdir, "__init__") + os.extsep + "py" | 
 | 448 |         with open(badsyntax, 'w') as f: | 
 | 449 |             f.write("invalid python syntax = $1\n") | 
| Antoine Pitrou | f41ffed | 2013-05-19 15:44:54 +0200 | [diff] [blame] | 450 |         with self.restrict_walk_packages(path=[TESTFN]): | 
 | 451 |             with captured_stdout() as out: | 
 | 452 |                 with captured_stderr() as err: | 
 | 453 |                     pydoc.apropos('xyzzy') | 
 | 454 |             # No result, no error | 
 | 455 |             self.assertEqual(out.getvalue(), '') | 
 | 456 |             self.assertEqual(err.getvalue(), '') | 
 | 457 |             # The package name is still matched | 
 | 458 |             with captured_stdout() as out: | 
 | 459 |                 with captured_stderr() as err: | 
 | 460 |                     pydoc.apropos('syntaxerr') | 
 | 461 |             self.assertEqual(out.getvalue().strip(), 'syntaxerr') | 
 | 462 |             self.assertEqual(err.getvalue(), '') | 
| Ned Deily | 1a96f8d | 2011-10-06 14:17:34 -0700 | [diff] [blame] | 463 |  | 
 | 464 |     def test_apropos_with_unreadable_dir(self): | 
 | 465 |         # Issue 7367 - pydoc -k failed when unreadable dir on path | 
 | 466 |         self.unreadable_dir = os.path.join(TESTFN, "unreadable") | 
 | 467 |         os.mkdir(self.unreadable_dir, 0) | 
 | 468 |         self.addCleanup(os.rmdir, self.unreadable_dir) | 
 | 469 |         # Note, on Windows the directory appears to be still | 
 | 470 |         #   readable so this is not really testing the issue there | 
| Antoine Pitrou | f41ffed | 2013-05-19 15:44:54 +0200 | [diff] [blame] | 471 |         with self.restrict_walk_packages(path=[TESTFN]): | 
 | 472 |             with captured_stdout() as out: | 
 | 473 |                 with captured_stderr() as err: | 
 | 474 |                     pydoc.apropos('SOMEKEY') | 
 | 475 |         # No result, no error | 
 | 476 |         self.assertEqual(out.getvalue(), '') | 
 | 477 |         self.assertEqual(err.getvalue(), '') | 
| Ned Deily | 1a96f8d | 2011-10-06 14:17:34 -0700 | [diff] [blame] | 478 |  | 
 | 479 |  | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 480 | class TestDescriptions(unittest.TestCase): | 
| Benjamin Peterson | f5c38da | 2008-05-18 20:48:07 +0000 | [diff] [blame] | 481 |  | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 482 |     def test_module(self): | 
 | 483 |         # Check that pydocfodder module can be described | 
 | 484 |         from test import pydocfodder | 
 | 485 |         doc = pydoc.render_doc(pydocfodder) | 
| Ezio Melotti | aa98058 | 2010-01-23 23:04:36 +0000 | [diff] [blame] | 486 |         self.assertIn("pydocfodder", doc) | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 487 |  | 
 | 488 |     def test_classic_class(self): | 
 | 489 |         class C: "Classic class" | 
 | 490 |         c = C() | 
| Benjamin Peterson | f5c38da | 2008-05-18 20:48:07 +0000 | [diff] [blame] | 491 |         self.assertEqual(pydoc.describe(C), 'class C') | 
 | 492 |         self.assertEqual(pydoc.describe(c), 'instance of C') | 
| Benjamin Peterson | 3a7305e | 2008-05-22 23:09:26 +0000 | [diff] [blame] | 493 |         expected = 'instance of C in module %s' % __name__ | 
| Ezio Melotti | aa98058 | 2010-01-23 23:04:36 +0000 | [diff] [blame] | 494 |         self.assertIn(expected, pydoc.render_doc(c)) | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 495 |  | 
 | 496 |     def test_class(self): | 
 | 497 |         class C(object): "New-style class" | 
 | 498 |         c = C() | 
 | 499 |  | 
| Benjamin Peterson | f5c38da | 2008-05-18 20:48:07 +0000 | [diff] [blame] | 500 |         self.assertEqual(pydoc.describe(C), 'class C') | 
 | 501 |         self.assertEqual(pydoc.describe(c), 'C') | 
| Benjamin Peterson | 3a7305e | 2008-05-22 23:09:26 +0000 | [diff] [blame] | 502 |         expected = 'C in module %s object' % __name__ | 
| Ezio Melotti | aa98058 | 2010-01-23 23:04:36 +0000 | [diff] [blame] | 503 |         self.assertIn(expected, pydoc.render_doc(c)) | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 504 |  | 
| Raymond Hettinger | 9aa5a34 | 2011-03-25 16:00:13 -0700 | [diff] [blame] | 505 |     def test_namedtuple_public_underscore(self): | 
 | 506 |         NT = namedtuple('NT', ['abc', 'def'], rename=True) | 
 | 507 |         with captured_stdout() as help_io: | 
| Terry Jan Reedy | c0e6047 | 2013-11-04 21:45:33 -0500 | [diff] [blame] | 508 |             pydoc.help(NT) | 
| Raymond Hettinger | 9aa5a34 | 2011-03-25 16:00:13 -0700 | [diff] [blame] | 509 |         helptext = help_io.getvalue() | 
 | 510 |         self.assertIn('_1', helptext) | 
 | 511 |         self.assertIn('_replace', helptext) | 
 | 512 |         self.assertIn('_asdict', helptext) | 
 | 513 |  | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 514 |  | 
| R David Murray | 984f630 | 2014-01-05 12:35:59 -0500 | [diff] [blame] | 515 | @unittest.skipUnless(test.test_support.have_unicode, | 
 | 516 |                      "test requires unicode support") | 
 | 517 | class TestUnicode(unittest.TestCase): | 
 | 518 |  | 
 | 519 |     def setUp(self): | 
 | 520 |         # Better not to use unicode escapes in literals, lest the | 
 | 521 |         # parser choke on it if Python has been built without | 
 | 522 |         # unicode support. | 
 | 523 |         self.Q  = types.ModuleType( | 
 | 524 |             'Q', 'Rational numbers: \xe2\x84\x9a'.decode('utf8')) | 
 | 525 |         self.Q.__version__ = '\xe2\x84\x9a'.decode('utf8') | 
 | 526 |         self.Q.__date__ = '\xe2\x84\x9a'.decode('utf8') | 
 | 527 |         self.Q.__author__ = '\xe2\x84\x9a'.decode('utf8') | 
 | 528 |         self.Q.__credits__ = '\xe2\x84\x9a'.decode('utf8') | 
 | 529 |  | 
 | 530 |         self.assertIsInstance(self.Q.__doc__, unicode) | 
 | 531 |  | 
 | 532 |     def test_render_doc(self): | 
 | 533 |         # render_doc is robust against unicode in docstrings | 
 | 534 |         doc = pydoc.render_doc(self.Q) | 
 | 535 |         self.assertIsInstance(doc, str) | 
 | 536 |  | 
 | 537 |     def test_encode(self): | 
 | 538 |         # _encode is robust against characters out the specified encoding | 
 | 539 |         self.assertEqual(pydoc._encode(self.Q.__doc__, 'ascii'), 'Rational numbers: ℚ') | 
 | 540 |  | 
 | 541 |     def test_pipepager(self): | 
 | 542 |         # pipepager does not choke on unicode | 
 | 543 |         doc = pydoc.render_doc(self.Q) | 
 | 544 |  | 
 | 545 |         saved, os.popen = os.popen, open | 
 | 546 |         try: | 
 | 547 |             with test.test_support.temp_cwd(): | 
 | 548 |                 pydoc.pipepager(doc, 'pipe') | 
 | 549 |                 self.assertEqual(open('pipe').read(), pydoc._encode(doc)) | 
 | 550 |         finally: | 
 | 551 |             os.popen = saved | 
 | 552 |  | 
 | 553 |     def test_tempfilepager(self): | 
 | 554 |         # tempfilepager does not choke on unicode | 
 | 555 |         doc = pydoc.render_doc(self.Q) | 
 | 556 |  | 
 | 557 |         output = {} | 
 | 558 |         def mock_system(cmd): | 
| Serhiy Storchaka | ee105dc | 2014-01-10 22:43:03 +0200 | [diff] [blame] | 559 |             filename = cmd.strip()[1:-1] | 
 | 560 |             self.assertEqual('"' + filename + '"', cmd.strip()) | 
 | 561 |             output['content'] = open(filename).read() | 
| R David Murray | 984f630 | 2014-01-05 12:35:59 -0500 | [diff] [blame] | 562 |         saved, os.system = os.system, mock_system | 
 | 563 |         try: | 
 | 564 |             pydoc.tempfilepager(doc, '') | 
 | 565 |             self.assertEqual(output['content'], pydoc._encode(doc)) | 
 | 566 |         finally: | 
 | 567 |             os.system = saved | 
 | 568 |  | 
 | 569 |     def test_plainpager(self): | 
 | 570 |         # plainpager does not choke on unicode | 
 | 571 |         doc = pydoc.render_doc(self.Q) | 
 | 572 |  | 
 | 573 |         # Note: captured_stdout is too permissive when it comes to | 
 | 574 |         # unicode, and using it here would make the test always | 
 | 575 |         # pass. | 
 | 576 |         with test.test_support.temp_cwd(): | 
 | 577 |             with open('output', 'w') as f: | 
 | 578 |                 saved, sys.stdout = sys.stdout, f | 
 | 579 |                 try: | 
 | 580 |                     pydoc.plainpager(doc) | 
 | 581 |                 finally: | 
 | 582 |                     sys.stdout = saved | 
 | 583 |             self.assertIn('Rational numbers:', open('output').read()) | 
 | 584 |  | 
 | 585 |     def test_ttypager(self): | 
 | 586 |         # ttypager does not choke on unicode | 
 | 587 |         doc = pydoc.render_doc(self.Q) | 
 | 588 |         # Test ttypager | 
 | 589 |         with test.test_support.temp_cwd(), test.test_support.captured_stdin(): | 
 | 590 |             with open('output', 'w') as f: | 
 | 591 |                 saved, sys.stdout = sys.stdout, f | 
 | 592 |                 try: | 
 | 593 |                     pydoc.ttypager(doc) | 
 | 594 |                 finally: | 
 | 595 |                     sys.stdout = saved | 
 | 596 |             self.assertIn('Rational numbers:', open('output').read()) | 
 | 597 |  | 
 | 598 |     def test_htmlpage(self): | 
 | 599 |         # html.page does not choke on unicode | 
 | 600 |         with test.test_support.temp_cwd(): | 
 | 601 |             with captured_stdout() as output: | 
 | 602 |                 pydoc.writedoc(self.Q) | 
 | 603 |         self.assertEqual(output.getvalue(), 'wrote Q.html\n') | 
 | 604 |  | 
| Ezio Melotti | bdfa2e6 | 2011-04-28 07:59:33 +0300 | [diff] [blame] | 605 | class TestHelper(unittest.TestCase): | 
 | 606 |     def test_keywords(self): | 
 | 607 |         self.assertEqual(sorted(pydoc.Helper.keywords), | 
 | 608 |                          sorted(keyword.kwlist)) | 
 | 609 |  | 
| Éric Araujo | 9a52830 | 2011-07-29 17:34:35 +0200 | [diff] [blame] | 610 |     def test_builtin(self): | 
 | 611 |         for name in ('str', 'str.translate', '__builtin__.str', | 
 | 612 |                      '__builtin__.str.translate'): | 
 | 613 |             # test low-level function | 
 | 614 |             self.assertIsNotNone(pydoc.locate(name)) | 
 | 615 |             # test high-level function | 
 | 616 |             try: | 
 | 617 |                 pydoc.render_doc(name) | 
 | 618 |             except ImportError: | 
| Terry Jan Reedy | 7299818 | 2014-06-20 14:59:07 -0400 | [diff] [blame] | 619 |                 self.fail('finding the doc of {!r} failed'.format(name)) | 
| Éric Araujo | 9a52830 | 2011-07-29 17:34:35 +0200 | [diff] [blame] | 620 |  | 
 | 621 |         for name in ('not__builtin__', 'strrr', 'strr.translate', | 
 | 622 |                      'str.trrrranslate', '__builtin__.strrr', | 
 | 623 |                      '__builtin__.str.trrranslate'): | 
 | 624 |             self.assertIsNone(pydoc.locate(name)) | 
 | 625 |             self.assertRaises(ImportError, pydoc.render_doc, name) | 
 | 626 |  | 
| Ezio Melotti | bdfa2e6 | 2011-04-28 07:59:33 +0300 | [diff] [blame] | 627 |  | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 628 | def test_main(): | 
| Ned Deily | 1a96f8d | 2011-10-06 14:17:34 -0700 | [diff] [blame] | 629 |     try: | 
| Antoine Pitrou | f41ffed | 2013-05-19 15:44:54 +0200 | [diff] [blame] | 630 |         test.test_support.run_unittest(PydocDocTest, | 
| Ned Deily | 1a96f8d | 2011-10-06 14:17:34 -0700 | [diff] [blame] | 631 |                                        PydocImportTest, | 
 | 632 |                                        TestDescriptions, | 
| R David Murray | 984f630 | 2014-01-05 12:35:59 -0500 | [diff] [blame] | 633 |                                        TestUnicode, | 
| Ned Deily | 1a96f8d | 2011-10-06 14:17:34 -0700 | [diff] [blame] | 634 |                                        TestHelper) | 
 | 635 |     finally: | 
 | 636 |         reap_children() | 
| Georg Brandl | 8632cc2 | 2008-05-18 16:32:48 +0000 | [diff] [blame] | 637 |  | 
 | 638 | if __name__ == "__main__": | 
 | 639 |     test_main() |