»Core Development>Code coverage>Lib/test/test_pydoc.py

Python code coverage for Lib/test/test_pydoc.py

#countcontent
1n/aimport os
2n/aimport sys
3n/aimport builtins
4n/aimport contextlib
5n/aimport importlib.util
6n/aimport inspect
7n/aimport pydoc
8n/aimport py_compile
9n/aimport keyword
10n/aimport _pickle
11n/aimport pkgutil
12n/aimport re
13n/aimport stat
14n/aimport string
15n/aimport test.support
16n/aimport time
17n/aimport types
18n/aimport typing
19n/aimport unittest
20n/aimport urllib.parse
21n/aimport xml.etree
22n/aimport xml.etree.ElementTree
23n/aimport textwrap
24n/afrom io import StringIO
25n/afrom collections import namedtuple
26n/afrom test.support.script_helper import assert_python_ok
27n/afrom test.support import (
28n/a TESTFN, rmtree,
29n/a reap_children, reap_threads, captured_output, captured_stdout,
30n/a captured_stderr, unlink, requires_docstrings
31n/a)
32n/afrom test import pydoc_mod
33n/a
34n/atry:
35n/a import threading
36n/aexcept ImportError:
37n/a threading = None
38n/a
39n/aclass nonascii:
40n/a 'Це не латиниця'
41n/a pass
42n/a
43n/aif test.support.HAVE_DOCSTRINGS:
44n/a expected_data_docstrings = (
45n/a 'dictionary for instance variables (if defined)',
46n/a 'list of weak references to the object (if defined)',
47n/a ) * 2
48n/aelse:
49n/a expected_data_docstrings = ('', '', '', '')
50n/a
51n/aexpected_text_pattern = """
52n/aNAME
53n/a test.pydoc_mod - This is a test module for test_pydoc
54n/a%s
55n/aCLASSES
56n/a builtins.object
57n/a A
58n/a B
59n/a C
60n/a\x20\x20\x20\x20
61n/a class A(builtins.object)
62n/a | Hello and goodbye
63n/a |\x20\x20
64n/a | Methods defined here:
65n/a |\x20\x20
66n/a | __init__()
67n/a | Wow, I have no function!
68n/a |\x20\x20
69n/a | ----------------------------------------------------------------------
70n/a | Data descriptors defined here:
71n/a |\x20\x20
72n/a | __dict__%s
73n/a |\x20\x20
74n/a | __weakref__%s
75n/a\x20\x20\x20\x20
76n/a class B(builtins.object)
77n/a | Data descriptors defined here:
78n/a |\x20\x20
79n/a | __dict__%s
80n/a |\x20\x20
81n/a | __weakref__%s
82n/a |\x20\x20
83n/a | ----------------------------------------------------------------------
84n/a | Data and other attributes defined here:
85n/a |\x20\x20
86n/a | NO_MEANING = 'eggs'
87n/a |\x20\x20
88n/a | __annotations__ = {'NO_MEANING': <class 'str'>}
89n/a\x20\x20\x20\x20
90n/a class C(builtins.object)
91n/a | Methods defined here:
92n/a |\x20\x20
93n/a | get_answer(self)
94n/a | Return say_no()
95n/a |\x20\x20
96n/a | is_it_true(self)
97n/a | Return self.get_answer()
98n/a |\x20\x20
99n/a | say_no(self)
100n/a |\x20\x20
101n/a | ----------------------------------------------------------------------
102n/a | Data descriptors defined here:
103n/a |\x20\x20
104n/a | __dict__
105n/a | dictionary for instance variables (if defined)
106n/a |\x20\x20
107n/a | __weakref__
108n/a | list of weak references to the object (if defined)
109n/a
110n/aFUNCTIONS
111n/a doc_func()
112n/a This function solves all of the world's problems:
113n/a hunger
114n/a lack of Python
115n/a war
116n/a\x20\x20\x20\x20
117n/a nodoc_func()
118n/a
119n/aDATA
120n/a __xyz__ = 'X, Y and Z'
121n/a
122n/aVERSION
123n/a 1.2.3.4
124n/a
125n/aAUTHOR
126n/a Benjamin Peterson
127n/a
128n/aCREDITS
129n/a Nobody
130n/a
131n/aFILE
132n/a %s
133n/a""".strip()
134n/a
135n/aexpected_text_data_docstrings = tuple('\n | ' + s if s else ''
136n/a for s in expected_data_docstrings)
137n/a
138n/aexpected_html_pattern = """
139n/a<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
140n/a<tr bgcolor="#7799ee">
141n/a<td valign=bottom>&nbsp;<br>
142n/a<font color="#ffffff" face="helvetica, arial">&nbsp;<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
143n/a><td align=right valign=bottom
144n/a><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:%s">%s</a>%s</font></td></tr></table>
145n/a <p><tt>This&nbsp;is&nbsp;a&nbsp;test&nbsp;module&nbsp;for&nbsp;test_pydoc</tt></p>
146n/a<p>
147n/a<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
148n/a<tr bgcolor="#ee77aa">
149n/a<td colspan=3 valign=bottom>&nbsp;<br>
150n/a<font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr>
151n/a\x20\x20\x20\x20
152n/a<tr><td bgcolor="#ee77aa"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
153n/a<td width="100%%"><dl>
154n/a<dt><font face="helvetica, arial"><a href="builtins.html#object">builtins.object</a>
155n/a</font></dt><dd>
156n/a<dl>
157n/a<dt><font face="helvetica, arial"><a href="test.pydoc_mod.html#A">A</a>
158n/a</font></dt><dt><font face="helvetica, arial"><a href="test.pydoc_mod.html#B">B</a>
159n/a</font></dt><dt><font face="helvetica, arial"><a href="test.pydoc_mod.html#C">C</a>
160n/a</font></dt></dl>
161n/a</dd>
162n/a</dl>
163n/a <p>
164n/a<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
165n/a<tr bgcolor="#ffc8d8">
166n/a<td colspan=3 valign=bottom>&nbsp;<br>
167n/a<font color="#000000" face="helvetica, arial"><a name="A">class <strong>A</strong></a>(<a href="builtins.html#object">builtins.object</a>)</font></td></tr>
168n/a\x20\x20\x20\x20
169n/a<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
170n/a<td colspan=2><tt>Hello&nbsp;and&nbsp;goodbye<br>&nbsp;</tt></td></tr>
171n/a<tr><td>&nbsp;</td>
172n/a<td width="100%%">Methods defined here:<br>
173n/a<dl><dt><a name="A-__init__"><strong>__init__</strong></a>()</dt><dd><tt>Wow,&nbsp;I&nbsp;have&nbsp;no&nbsp;function!</tt></dd></dl>
174n/a
175n/a<hr>
176n/aData descriptors defined here:<br>
177n/a<dl><dt><strong>__dict__</strong></dt>
178n/a<dd><tt>%s</tt></dd>
179n/a</dl>
180n/a<dl><dt><strong>__weakref__</strong></dt>
181n/a<dd><tt>%s</tt></dd>
182n/a</dl>
183n/a</td></tr></table> <p>
184n/a<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
185n/a<tr bgcolor="#ffc8d8">
186n/a<td colspan=3 valign=bottom>&nbsp;<br>
187n/a<font color="#000000" face="helvetica, arial"><a name="B">class <strong>B</strong></a>(<a href="builtins.html#object">builtins.object</a>)</font></td></tr>
188n/a\x20\x20\x20\x20
189n/a<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
190n/a<td width="100%%">Data descriptors defined here:<br>
191n/a<dl><dt><strong>__dict__</strong></dt>
192n/a<dd><tt>%s</tt></dd>
193n/a</dl>
194n/a<dl><dt><strong>__weakref__</strong></dt>
195n/a<dd><tt>%s</tt></dd>
196n/a</dl>
197n/a<hr>
198n/aData and other attributes defined here:<br>
199n/a<dl><dt><strong>NO_MEANING</strong> = 'eggs'</dl>
200n/a
201n/a<dl><dt><strong>__annotations__</strong> = {'NO_MEANING': &lt;class 'str'&gt;}</dl>
202n/a
203n/a</td></tr></table> <p>
204n/a<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
205n/a<tr bgcolor="#ffc8d8">
206n/a<td colspan=3 valign=bottom>&nbsp;<br>
207n/a<font color="#000000" face="helvetica, arial"><a name="C">class <strong>C</strong></a>(<a href="builtins.html#object">builtins.object</a>)</font></td></tr>
208n/a\x20\x20\x20\x20
209n/a<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
210n/a<td width="100%%">Methods defined here:<br>
211n/a<dl><dt><a name="C-get_answer"><strong>get_answer</strong></a>(self)</dt><dd><tt>Return&nbsp;<a href="#C-say_no">say_no</a>()</tt></dd></dl>
212n/a
213n/a<dl><dt><a name="C-is_it_true"><strong>is_it_true</strong></a>(self)</dt><dd><tt>Return&nbsp;self.<a href="#C-get_answer">get_answer</a>()</tt></dd></dl>
214n/a
215n/a<dl><dt><a name="C-say_no"><strong>say_no</strong></a>(self)</dt></dl>
216n/a
217n/a<hr>
218n/aData descriptors defined here:<br>
219n/a<dl><dt><strong>__dict__</strong></dt>
220n/a<dd><tt>dictionary&nbsp;for&nbsp;instance&nbsp;variables&nbsp;(if&nbsp;defined)</tt></dd>
221n/a</dl>
222n/a<dl><dt><strong>__weakref__</strong></dt>
223n/a<dd><tt>list&nbsp;of&nbsp;weak&nbsp;references&nbsp;to&nbsp;the&nbsp;object&nbsp;(if&nbsp;defined)</tt></dd>
224n/a</dl>
225n/a</td></tr></table></td></tr></table><p>
226n/a<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
227n/a<tr bgcolor="#eeaa77">
228n/a<td colspan=3 valign=bottom>&nbsp;<br>
229n/a<font color="#ffffff" face="helvetica, arial"><big><strong>Functions</strong></big></font></td></tr>
230n/a\x20\x20\x20\x20
231n/a<tr><td bgcolor="#eeaa77"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
232n/a<td width="100%%"><dl><dt><a name="-doc_func"><strong>doc_func</strong></a>()</dt><dd><tt>This&nbsp;function&nbsp;solves&nbsp;all&nbsp;of&nbsp;the&nbsp;world's&nbsp;problems:<br>
233n/ahunger<br>
234n/alack&nbsp;of&nbsp;Python<br>
235n/awar</tt></dd></dl>
236n/a <dl><dt><a name="-nodoc_func"><strong>nodoc_func</strong></a>()</dt></dl>
237n/a</td></tr></table><p>
238n/a<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
239n/a<tr bgcolor="#55aa55">
240n/a<td colspan=3 valign=bottom>&nbsp;<br>
241n/a<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
242n/a\x20\x20\x20\x20
243n/a<tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
244n/a<td width="100%%"><strong>__xyz__</strong> = 'X, Y and Z'</td></tr></table><p>
245n/a<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
246n/a<tr bgcolor="#7799ee">
247n/a<td colspan=3 valign=bottom>&nbsp;<br>
248n/a<font color="#ffffff" face="helvetica, arial"><big><strong>Author</strong></big></font></td></tr>
249n/a\x20\x20\x20\x20
250n/a<tr><td bgcolor="#7799ee"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
251n/a<td width="100%%">Benjamin&nbsp;Peterson</td></tr></table><p>
252n/a<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
253n/a<tr bgcolor="#7799ee">
254n/a<td colspan=3 valign=bottom>&nbsp;<br>
255n/a<font color="#ffffff" face="helvetica, arial"><big><strong>Credits</strong></big></font></td></tr>
256n/a\x20\x20\x20\x20
257n/a<tr><td bgcolor="#7799ee"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
258n/a<td width="100%%">Nobody</td></tr></table>
259n/a""".strip() # ' <- emacs turd
260n/a
261n/aexpected_html_data_docstrings = tuple(s.replace(' ', '&nbsp;')
262n/a for s in expected_data_docstrings)
263n/a
264n/a# output pattern for missing module
265n/amissing_pattern = '''\
266n/aNo Python documentation found for %r.
267n/aUse help() to get the interactive help utility.
268n/aUse help(str) for help on the str class.'''.replace('\n', os.linesep)
269n/a
270n/a# output pattern for module with bad imports
271n/abadimport_pattern = "problem in %s - ModuleNotFoundError: No module named %r"
272n/a
273n/aexpected_dynamicattribute_pattern = """
274n/aHelp on class DA in module %s:
275n/a
276n/aclass DA(builtins.object)
277n/a | Data descriptors defined here:
278n/a |\x20\x20
279n/a | __dict__%s
280n/a |\x20\x20
281n/a | __weakref__%s
282n/a |\x20\x20
283n/a | ham
284n/a |\x20\x20
285n/a | ----------------------------------------------------------------------
286n/a | Data and other attributes inherited from Meta:
287n/a |\x20\x20
288n/a | ham = 'spam'
289n/a""".strip()
290n/a
291n/aexpected_virtualattribute_pattern1 = """
292n/aHelp on class Class in module %s:
293n/a
294n/aclass Class(builtins.object)
295n/a | Data and other attributes inherited from Meta:
296n/a |\x20\x20
297n/a | LIFE = 42
298n/a""".strip()
299n/a
300n/aexpected_virtualattribute_pattern2 = """
301n/aHelp on class Class1 in module %s:
302n/a
303n/aclass Class1(builtins.object)
304n/a | Data and other attributes inherited from Meta1:
305n/a |\x20\x20
306n/a | one = 1
307n/a""".strip()
308n/a
309n/aexpected_virtualattribute_pattern3 = """
310n/aHelp on class Class2 in module %s:
311n/a
312n/aclass Class2(Class1)
313n/a | Method resolution order:
314n/a | Class2
315n/a | Class1
316n/a | builtins.object
317n/a |\x20\x20
318n/a | Data and other attributes inherited from Meta1:
319n/a |\x20\x20
320n/a | one = 1
321n/a |\x20\x20
322n/a | ----------------------------------------------------------------------
323n/a | Data and other attributes inherited from Meta3:
324n/a |\x20\x20
325n/a | three = 3
326n/a |\x20\x20
327n/a | ----------------------------------------------------------------------
328n/a | Data and other attributes inherited from Meta2:
329n/a |\x20\x20
330n/a | two = 2
331n/a""".strip()
332n/a
333n/aexpected_missingattribute_pattern = """
334n/aHelp on class C in module %s:
335n/a
336n/aclass C(builtins.object)
337n/a | Data and other attributes defined here:
338n/a |\x20\x20
339n/a | here = 'present!'
340n/a""".strip()
341n/a
342n/adef run_pydoc(module_name, *args, **env):
343n/a """
344n/a Runs pydoc on the specified module. Returns the stripped
345n/a output of pydoc.
346n/a """
347n/a args = args + (module_name,)
348n/a # do not write bytecode files to avoid caching errors
349n/a rc, out, err = assert_python_ok('-B', pydoc.__file__, *args, **env)
350n/a return out.strip()
351n/a
352n/adef get_pydoc_html(module):
353n/a "Returns pydoc generated output as html"
354n/a doc = pydoc.HTMLDoc()
355n/a output = doc.docmodule(module)
356n/a loc = doc.getdocloc(pydoc_mod) or ""
357n/a if loc:
358n/a loc = "<br><a href=\"" + loc + "\">Module Docs</a>"
359n/a return output.strip(), loc
360n/a
361n/adef get_pydoc_link(module):
362n/a "Returns a documentation web link of a module"
363n/a dirname = os.path.dirname
364n/a basedir = dirname(dirname(__file__))
365n/a doc = pydoc.TextDoc()
366n/a loc = doc.getdocloc(module, basedir=basedir)
367n/a return loc
368n/a
369n/adef get_pydoc_text(module):
370n/a "Returns pydoc generated output as text"
371n/a doc = pydoc.TextDoc()
372n/a loc = doc.getdocloc(pydoc_mod) or ""
373n/a if loc:
374n/a loc = "\nMODULE DOCS\n " + loc + "\n"
375n/a
376n/a output = doc.docmodule(module)
377n/a
378n/a # clean up the extra text formatting that pydoc performs
379n/a patt = re.compile('\b.')
380n/a output = patt.sub('', output)
381n/a return output.strip(), loc
382n/a
383n/adef get_html_title(text):
384n/a # Bit of hack, but good enough for test purposes
385n/a header, _, _ = text.partition("</head>")
386n/a _, _, title = header.partition("<title>")
387n/a title, _, _ = title.partition("</title>")
388n/a return title
389n/a
390n/a
391n/aclass PydocBaseTest(unittest.TestCase):
392n/a
393n/a def _restricted_walk_packages(self, walk_packages, path=None):
394n/a """
395n/a A version of pkgutil.walk_packages() that will restrict itself to
396n/a a given path.
397n/a """
398n/a default_path = path or [os.path.dirname(__file__)]
399n/a def wrapper(path=None, prefix='', onerror=None):
400n/a return walk_packages(path or default_path, prefix, onerror)
401n/a return wrapper
402n/a
403n/a @contextlib.contextmanager
404n/a def restrict_walk_packages(self, path=None):
405n/a walk_packages = pkgutil.walk_packages
406n/a pkgutil.walk_packages = self._restricted_walk_packages(walk_packages,
407n/a path)
408n/a try:
409n/a yield
410n/a finally:
411n/a pkgutil.walk_packages = walk_packages
412n/a
413n/a def call_url_handler(self, url, expected_title):
414n/a text = pydoc._url_handler(url, "text/html")
415n/a result = get_html_title(text)
416n/a # Check the title to ensure an unexpected error page was not returned
417n/a self.assertEqual(result, expected_title, text)
418n/a return text
419n/a
420n/a
421n/aclass PydocDocTest(unittest.TestCase):
422n/a
423n/a @unittest.skipIf(sys.flags.optimize >= 2,
424n/a "Docstrings are omitted with -O2 and above")
425n/a @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
426n/a 'trace function introduces __locals__ unexpectedly')
427n/a @requires_docstrings
428n/a def test_html_doc(self):
429n/a result, doc_loc = get_pydoc_html(pydoc_mod)
430n/a mod_file = inspect.getabsfile(pydoc_mod)
431n/a mod_url = urllib.parse.quote(mod_file)
432n/a expected_html = expected_html_pattern % (
433n/a (mod_url, mod_file, doc_loc) +
434n/a expected_html_data_docstrings)
435n/a self.assertEqual(result, expected_html)
436n/a
437n/a @unittest.skipIf(sys.flags.optimize >= 2,
438n/a "Docstrings are omitted with -O2 and above")
439n/a @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
440n/a 'trace function introduces __locals__ unexpectedly')
441n/a @requires_docstrings
442n/a def test_text_doc(self):
443n/a result, doc_loc = get_pydoc_text(pydoc_mod)
444n/a expected_text = expected_text_pattern % (
445n/a (doc_loc,) +
446n/a expected_text_data_docstrings +
447n/a (inspect.getabsfile(pydoc_mod),))
448n/a self.assertEqual(expected_text, result)
449n/a
450n/a def test_text_enum_member_with_value_zero(self):
451n/a # Test issue #20654 to ensure enum member with value 0 can be
452n/a # displayed. It used to throw KeyError: 'zero'.
453n/a import enum
454n/a class BinaryInteger(enum.IntEnum):
455n/a zero = 0
456n/a one = 1
457n/a doc = pydoc.render_doc(BinaryInteger)
458n/a self.assertIn('<BinaryInteger.zero: 0>', doc)
459n/a
460n/a def test_mixed_case_module_names_are_lower_cased(self):
461n/a # issue16484
462n/a doc_link = get_pydoc_link(xml.etree.ElementTree)
463n/a self.assertIn('xml.etree.elementtree', doc_link)
464n/a
465n/a def test_issue8225(self):
466n/a # Test issue8225 to ensure no doc link appears for xml.etree
467n/a result, doc_loc = get_pydoc_text(xml.etree)
468n/a self.assertEqual(doc_loc, "", "MODULE DOCS incorrectly includes a link")
469n/a
470n/a def test_getpager_with_stdin_none(self):
471n/a previous_stdin = sys.stdin
472n/a try:
473n/a sys.stdin = None
474n/a pydoc.getpager() # Shouldn't fail.
475n/a finally:
476n/a sys.stdin = previous_stdin
477n/a
478n/a def test_non_str_name(self):
479n/a # issue14638
480n/a # Treat illegal (non-str) name like no name
481n/a class A:
482n/a __name__ = 42
483n/a class B:
484n/a pass
485n/a adoc = pydoc.render_doc(A())
486n/a bdoc = pydoc.render_doc(B())
487n/a self.assertEqual(adoc.replace("A", "B"), bdoc)
488n/a
489n/a def test_not_here(self):
490n/a missing_module = "test.i_am_not_here"
491n/a result = str(run_pydoc(missing_module), 'ascii')
492n/a expected = missing_pattern % missing_module
493n/a self.assertEqual(expected, result,
494n/a "documentation for missing module found")
495n/a
496n/a @unittest.skipIf(sys.flags.optimize >= 2,
497n/a 'Docstrings are omitted with -OO and above')
498n/a def test_not_ascii(self):
499n/a result = run_pydoc('test.test_pydoc.nonascii', PYTHONIOENCODING='ascii')
500n/a encoded = nonascii.__doc__.encode('ascii', 'backslashreplace')
501n/a self.assertIn(encoded, result)
502n/a
503n/a def test_input_strip(self):
504n/a missing_module = " test.i_am_not_here "
505n/a result = str(run_pydoc(missing_module), 'ascii')
506n/a expected = missing_pattern % missing_module.strip()
507n/a self.assertEqual(expected, result)
508n/a
509n/a def test_stripid(self):
510n/a # test with strings, other implementations might have different repr()
511n/a stripid = pydoc.stripid
512n/a # strip the id
513n/a self.assertEqual(stripid('<function stripid at 0x88dcee4>'),
514n/a '<function stripid>')
515n/a self.assertEqual(stripid('<function stripid at 0x01F65390>'),
516n/a '<function stripid>')
517n/a # nothing to strip, return the same text
518n/a self.assertEqual(stripid('42'), '42')
519n/a self.assertEqual(stripid("<type 'exceptions.Exception'>"),
520n/a "<type 'exceptions.Exception'>")
521n/a
522n/a @unittest.skipIf(sys.flags.optimize >= 2,
523n/a 'Docstrings are omitted with -O2 and above')
524n/a @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
525n/a 'trace function introduces __locals__ unexpectedly')
526n/a @requires_docstrings
527n/a def test_help_output_redirect(self):
528n/a # issue 940286, if output is set in Helper, then all output from
529n/a # Helper.help should be redirected
530n/a old_pattern = expected_text_pattern
531n/a getpager_old = pydoc.getpager
532n/a getpager_new = lambda: (lambda x: x)
533n/a self.maxDiff = None
534n/a
535n/a buf = StringIO()
536n/a helper = pydoc.Helper(output=buf)
537n/a unused, doc_loc = get_pydoc_text(pydoc_mod)
538n/a module = "test.pydoc_mod"
539n/a help_header = """
540n/a Help on module test.pydoc_mod in test:
541n/a
542n/a """.lstrip()
543n/a help_header = textwrap.dedent(help_header)
544n/a expected_help_pattern = help_header + expected_text_pattern
545n/a
546n/a pydoc.getpager = getpager_new
547n/a try:
548n/a with captured_output('stdout') as output, \
549n/a captured_output('stderr') as err:
550n/a helper.help(module)
551n/a result = buf.getvalue().strip()
552n/a expected_text = expected_help_pattern % (
553n/a (doc_loc,) +
554n/a expected_text_data_docstrings +
555n/a (inspect.getabsfile(pydoc_mod),))
556n/a self.assertEqual('', output.getvalue())
557n/a self.assertEqual('', err.getvalue())
558n/a self.assertEqual(expected_text, result)
559n/a finally:
560n/a pydoc.getpager = getpager_old
561n/a
562n/a def test_namedtuple_public_underscore(self):
563n/a NT = namedtuple('NT', ['abc', 'def'], rename=True)
564n/a with captured_stdout() as help_io:
565n/a pydoc.help(NT)
566n/a helptext = help_io.getvalue()
567n/a self.assertIn('_1', helptext)
568n/a self.assertIn('_replace', helptext)
569n/a self.assertIn('_asdict', helptext)
570n/a
571n/a def test_synopsis(self):
572n/a self.addCleanup(unlink, TESTFN)
573n/a for encoding in ('ISO-8859-1', 'UTF-8'):
574n/a with open(TESTFN, 'w', encoding=encoding) as script:
575n/a if encoding != 'UTF-8':
576n/a print('#coding: {}'.format(encoding), file=script)
577n/a print('"""line 1: h\xe9', file=script)
578n/a print('line 2: hi"""', file=script)
579n/a synopsis = pydoc.synopsis(TESTFN, {})
580n/a self.assertEqual(synopsis, 'line 1: h\xe9')
581n/a
582n/a @unittest.skipIf(sys.flags.optimize >= 2,
583n/a 'Docstrings are omitted with -OO and above')
584n/a def test_synopsis_sourceless(self):
585n/a expected = os.__doc__.splitlines()[0]
586n/a filename = os.__cached__
587n/a synopsis = pydoc.synopsis(filename)
588n/a
589n/a self.assertEqual(synopsis, expected)
590n/a
591n/a def test_synopsis_sourceless_empty_doc(self):
592n/a with test.support.temp_cwd() as test_dir:
593n/a init_path = os.path.join(test_dir, 'foomod42.py')
594n/a cached_path = importlib.util.cache_from_source(init_path)
595n/a with open(init_path, 'w') as fobj:
596n/a fobj.write("foo = 1")
597n/a py_compile.compile(init_path)
598n/a synopsis = pydoc.synopsis(init_path, {})
599n/a self.assertIsNone(synopsis)
600n/a synopsis_cached = pydoc.synopsis(cached_path, {})
601n/a self.assertIsNone(synopsis_cached)
602n/a
603n/a def test_splitdoc_with_description(self):
604n/a example_string = "I Am A Doc\n\n\nHere is my description"
605n/a self.assertEqual(pydoc.splitdoc(example_string),
606n/a ('I Am A Doc', '\nHere is my description'))
607n/a
608n/a def test_is_object_or_method(self):
609n/a doc = pydoc.Doc()
610n/a # Bound Method
611n/a self.assertTrue(pydoc._is_some_method(doc.fail))
612n/a # Method Descriptor
613n/a self.assertTrue(pydoc._is_some_method(int.__add__))
614n/a # String
615n/a self.assertFalse(pydoc._is_some_method("I am not a method"))
616n/a
617n/a def test_is_package_when_not_package(self):
618n/a with test.support.temp_cwd() as test_dir:
619n/a self.assertFalse(pydoc.ispackage(test_dir))
620n/a
621n/a def test_is_package_when_is_package(self):
622n/a with test.support.temp_cwd() as test_dir:
623n/a init_path = os.path.join(test_dir, '__init__.py')
624n/a open(init_path, 'w').close()
625n/a self.assertTrue(pydoc.ispackage(test_dir))
626n/a os.remove(init_path)
627n/a
628n/a def test_allmethods(self):
629n/a # issue 17476: allmethods was no longer returning unbound methods.
630n/a # This test is a bit fragile in the face of changes to object and type,
631n/a # but I can't think of a better way to do it without duplicating the
632n/a # logic of the function under test.
633n/a
634n/a class TestClass(object):
635n/a def method_returning_true(self):
636n/a return True
637n/a
638n/a # What we expect to get back: everything on object...
639n/a expected = dict(vars(object))
640n/a # ...plus our unbound method...
641n/a expected['method_returning_true'] = TestClass.method_returning_true
642n/a # ...but not the non-methods on object.
643n/a del expected['__doc__']
644n/a del expected['__class__']
645n/a # inspect resolves descriptors on type into methods, but vars doesn't,
646n/a # so we need to update __subclasshook__ and __init_subclass__.
647n/a expected['__subclasshook__'] = TestClass.__subclasshook__
648n/a expected['__init_subclass__'] = TestClass.__init_subclass__
649n/a
650n/a methods = pydoc.allmethods(TestClass)
651n/a self.assertDictEqual(methods, expected)
652n/a
653n/a
654n/aclass PydocImportTest(PydocBaseTest):
655n/a
656n/a def setUp(self):
657n/a self.test_dir = os.mkdir(TESTFN)
658n/a self.addCleanup(rmtree, TESTFN)
659n/a importlib.invalidate_caches()
660n/a
661n/a def test_badimport(self):
662n/a # This tests the fix for issue 5230, where if pydoc found the module
663n/a # but the module had an internal import error pydoc would report no doc
664n/a # found.
665n/a modname = 'testmod_xyzzy'
666n/a testpairs = (
667n/a ('i_am_not_here', 'i_am_not_here'),
668n/a ('test.i_am_not_here_either', 'test.i_am_not_here_either'),
669n/a ('test.i_am_not_here.neither_am_i', 'test.i_am_not_here'),
670n/a ('i_am_not_here.{}'.format(modname), 'i_am_not_here'),
671n/a ('test.{}'.format(modname), 'test.{}'.format(modname)),
672n/a )
673n/a
674n/a sourcefn = os.path.join(TESTFN, modname) + os.extsep + "py"
675n/a for importstring, expectedinmsg in testpairs:
676n/a with open(sourcefn, 'w') as f:
677n/a f.write("import {}\n".format(importstring))
678n/a result = run_pydoc(modname, PYTHONPATH=TESTFN).decode("ascii")
679n/a expected = badimport_pattern % (modname, expectedinmsg)
680n/a self.assertEqual(expected, result)
681n/a
682n/a def test_apropos_with_bad_package(self):
683n/a # Issue 7425 - pydoc -k failed when bad package on path
684n/a pkgdir = os.path.join(TESTFN, "syntaxerr")
685n/a os.mkdir(pkgdir)
686n/a badsyntax = os.path.join(pkgdir, "__init__") + os.extsep + "py"
687n/a with open(badsyntax, 'w') as f:
688n/a f.write("invalid python syntax = $1\n")
689n/a with self.restrict_walk_packages(path=[TESTFN]):
690n/a with captured_stdout() as out:
691n/a with captured_stderr() as err:
692n/a pydoc.apropos('xyzzy')
693n/a # No result, no error
694n/a self.assertEqual(out.getvalue(), '')
695n/a self.assertEqual(err.getvalue(), '')
696n/a # The package name is still matched
697n/a with captured_stdout() as out:
698n/a with captured_stderr() as err:
699n/a pydoc.apropos('syntaxerr')
700n/a self.assertEqual(out.getvalue().strip(), 'syntaxerr')
701n/a self.assertEqual(err.getvalue(), '')
702n/a
703n/a def test_apropos_with_unreadable_dir(self):
704n/a # Issue 7367 - pydoc -k failed when unreadable dir on path
705n/a self.unreadable_dir = os.path.join(TESTFN, "unreadable")
706n/a os.mkdir(self.unreadable_dir, 0)
707n/a self.addCleanup(os.rmdir, self.unreadable_dir)
708n/a # Note, on Windows the directory appears to be still
709n/a # readable so this is not really testing the issue there
710n/a with self.restrict_walk_packages(path=[TESTFN]):
711n/a with captured_stdout() as out:
712n/a with captured_stderr() as err:
713n/a pydoc.apropos('SOMEKEY')
714n/a # No result, no error
715n/a self.assertEqual(out.getvalue(), '')
716n/a self.assertEqual(err.getvalue(), '')
717n/a
718n/a def test_apropos_empty_doc(self):
719n/a pkgdir = os.path.join(TESTFN, 'walkpkg')
720n/a os.mkdir(pkgdir)
721n/a self.addCleanup(rmtree, pkgdir)
722n/a init_path = os.path.join(pkgdir, '__init__.py')
723n/a with open(init_path, 'w') as fobj:
724n/a fobj.write("foo = 1")
725n/a current_mode = stat.S_IMODE(os.stat(pkgdir).st_mode)
726n/a try:
727n/a os.chmod(pkgdir, current_mode & ~stat.S_IEXEC)
728n/a with self.restrict_walk_packages(path=[TESTFN]), captured_stdout() as stdout:
729n/a pydoc.apropos('')
730n/a self.assertIn('walkpkg', stdout.getvalue())
731n/a finally:
732n/a os.chmod(pkgdir, current_mode)
733n/a
734n/a def test_url_search_package_error(self):
735n/a # URL handler search should cope with packages that raise exceptions
736n/a pkgdir = os.path.join(TESTFN, "test_error_package")
737n/a os.mkdir(pkgdir)
738n/a init = os.path.join(pkgdir, "__init__.py")
739n/a with open(init, "wt", encoding="ascii") as f:
740n/a f.write("""raise ValueError("ouch")\n""")
741n/a with self.restrict_walk_packages(path=[TESTFN]):
742n/a # Package has to be importable for the error to have any effect
743n/a saved_paths = tuple(sys.path)
744n/a sys.path.insert(0, TESTFN)
745n/a try:
746n/a with self.assertRaisesRegex(ValueError, "ouch"):
747n/a import test_error_package # Sanity check
748n/a
749n/a text = self.call_url_handler("search?key=test_error_package",
750n/a "Pydoc: Search Results")
751n/a found = ('<a href="test_error_package.html">'
752n/a 'test_error_package</a>')
753n/a self.assertIn(found, text)
754n/a finally:
755n/a sys.path[:] = saved_paths
756n/a
757n/a @unittest.skip('causes undesirable side-effects (#20128)')
758n/a def test_modules(self):
759n/a # See Helper.listmodules().
760n/a num_header_lines = 2
761n/a num_module_lines_min = 5 # Playing it safe.
762n/a num_footer_lines = 3
763n/a expected = num_header_lines + num_module_lines_min + num_footer_lines
764n/a
765n/a output = StringIO()
766n/a helper = pydoc.Helper(output=output)
767n/a helper('modules')
768n/a result = output.getvalue().strip()
769n/a num_lines = len(result.splitlines())
770n/a
771n/a self.assertGreaterEqual(num_lines, expected)
772n/a
773n/a @unittest.skip('causes undesirable side-effects (#20128)')
774n/a def test_modules_search(self):
775n/a # See Helper.listmodules().
776n/a expected = 'pydoc - '
777n/a
778n/a output = StringIO()
779n/a helper = pydoc.Helper(output=output)
780n/a with captured_stdout() as help_io:
781n/a helper('modules pydoc')
782n/a result = help_io.getvalue()
783n/a
784n/a self.assertIn(expected, result)
785n/a
786n/a @unittest.skip('some buildbots are not cooperating (#20128)')
787n/a def test_modules_search_builtin(self):
788n/a expected = 'gc - '
789n/a
790n/a output = StringIO()
791n/a helper = pydoc.Helper(output=output)
792n/a with captured_stdout() as help_io:
793n/a helper('modules garbage')
794n/a result = help_io.getvalue()
795n/a
796n/a self.assertTrue(result.startswith(expected))
797n/a
798n/a def test_importfile(self):
799n/a loaded_pydoc = pydoc.importfile(pydoc.__file__)
800n/a
801n/a self.assertIsNot(loaded_pydoc, pydoc)
802n/a self.assertEqual(loaded_pydoc.__name__, 'pydoc')
803n/a self.assertEqual(loaded_pydoc.__file__, pydoc.__file__)
804n/a self.assertEqual(loaded_pydoc.__spec__, pydoc.__spec__)
805n/a
806n/a
807n/aclass TestDescriptions(unittest.TestCase):
808n/a
809n/a def test_module(self):
810n/a # Check that pydocfodder module can be described
811n/a from test import pydocfodder
812n/a doc = pydoc.render_doc(pydocfodder)
813n/a self.assertIn("pydocfodder", doc)
814n/a
815n/a def test_class(self):
816n/a class C: "New-style class"
817n/a c = C()
818n/a
819n/a self.assertEqual(pydoc.describe(C), 'class C')
820n/a self.assertEqual(pydoc.describe(c), 'C')
821n/a expected = 'C in module %s object' % __name__
822n/a self.assertIn(expected, pydoc.render_doc(c))
823n/a
824n/a def test_typing_pydoc(self):
825n/a def foo(data: typing.List[typing.Any],
826n/a x: int) -> typing.Iterator[typing.Tuple[int, typing.Any]]:
827n/a ...
828n/a T = typing.TypeVar('T')
829n/a class C(typing.Generic[T], typing.Mapping[int, str]): ...
830n/a self.assertEqual(pydoc.render_doc(foo).splitlines()[-1],
831n/a 'f\x08fo\x08oo\x08o(data:List[Any], x:int)'
832n/a ' -> Iterator[Tuple[int, Any]]')
833n/a self.assertEqual(pydoc.render_doc(C).splitlines()[2],
834n/a 'class C\x08C(typing.Mapping)')
835n/a
836n/a def test_builtin(self):
837n/a for name in ('str', 'str.translate', 'builtins.str',
838n/a 'builtins.str.translate'):
839n/a # test low-level function
840n/a self.assertIsNotNone(pydoc.locate(name))
841n/a # test high-level function
842n/a try:
843n/a pydoc.render_doc(name)
844n/a except ImportError:
845n/a self.fail('finding the doc of {!r} failed'.format(name))
846n/a
847n/a for name in ('notbuiltins', 'strrr', 'strr.translate',
848n/a 'str.trrrranslate', 'builtins.strrr',
849n/a 'builtins.str.trrranslate'):
850n/a self.assertIsNone(pydoc.locate(name))
851n/a self.assertRaises(ImportError, pydoc.render_doc, name)
852n/a
853n/a @staticmethod
854n/a def _get_summary_line(o):
855n/a text = pydoc.plain(pydoc.render_doc(o))
856n/a lines = text.split('\n')
857n/a assert len(lines) >= 2
858n/a return lines[2]
859n/a
860n/a # these should include "self"
861n/a def test_unbound_python_method(self):
862n/a self.assertEqual(self._get_summary_line(textwrap.TextWrapper.wrap),
863n/a "wrap(self, text)")
864n/a
865n/a @requires_docstrings
866n/a def test_unbound_builtin_method(self):
867n/a self.assertEqual(self._get_summary_line(_pickle.Pickler.dump),
868n/a "dump(self, obj, /)")
869n/a
870n/a # these no longer include "self"
871n/a def test_bound_python_method(self):
872n/a t = textwrap.TextWrapper()
873n/a self.assertEqual(self._get_summary_line(t.wrap),
874n/a "wrap(text) method of textwrap.TextWrapper instance")
875n/a
876n/a def test_field_order_for_named_tuples(self):
877n/a Person = namedtuple('Person', ['nickname', 'firstname', 'agegroup'])
878n/a s = pydoc.render_doc(Person)
879n/a self.assertLess(s.index('nickname'), s.index('firstname'))
880n/a self.assertLess(s.index('firstname'), s.index('agegroup'))
881n/a
882n/a class NonIterableFields:
883n/a _fields = None
884n/a
885n/a class NonHashableFields:
886n/a _fields = [[]]
887n/a
888n/a # Make sure these doesn't fail
889n/a pydoc.render_doc(NonIterableFields)
890n/a pydoc.render_doc(NonHashableFields)
891n/a
892n/a @requires_docstrings
893n/a def test_bound_builtin_method(self):
894n/a s = StringIO()
895n/a p = _pickle.Pickler(s)
896n/a self.assertEqual(self._get_summary_line(p.dump),
897n/a "dump(obj, /) method of _pickle.Pickler instance")
898n/a
899n/a # this should *never* include self!
900n/a @requires_docstrings
901n/a def test_module_level_callable(self):
902n/a self.assertEqual(self._get_summary_line(os.stat),
903n/a "stat(path, *, dir_fd=None, follow_symlinks=True)")
904n/a
905n/a
906n/a@unittest.skipUnless(threading, 'Threading required for this test.')
907n/aclass PydocServerTest(unittest.TestCase):
908n/a """Tests for pydoc._start_server"""
909n/a
910n/a def test_server(self):
911n/a
912n/a # Minimal test that starts the server, then stops it.
913n/a def my_url_handler(url, content_type):
914n/a text = 'the URL sent was: (%s, %s)' % (url, content_type)
915n/a return text
916n/a
917n/a serverthread = pydoc._start_server(my_url_handler, port=0)
918n/a self.assertIn('localhost', serverthread.docserver.address)
919n/a
920n/a starttime = time.time()
921n/a timeout = 1 #seconds
922n/a
923n/a while serverthread.serving:
924n/a time.sleep(.01)
925n/a if serverthread.serving and time.time() - starttime > timeout:
926n/a serverthread.stop()
927n/a break
928n/a
929n/a self.assertEqual(serverthread.error, None)
930n/a
931n/a
932n/aclass PydocUrlHandlerTest(PydocBaseTest):
933n/a """Tests for pydoc._url_handler"""
934n/a
935n/a def test_content_type_err(self):
936n/a f = pydoc._url_handler
937n/a self.assertRaises(TypeError, f, 'A', '')
938n/a self.assertRaises(TypeError, f, 'B', 'foobar')
939n/a
940n/a def test_url_requests(self):
941n/a # Test for the correct title in the html pages returned.
942n/a # This tests the different parts of the URL handler without
943n/a # getting too picky about the exact html.
944n/a requests = [
945n/a ("", "Pydoc: Index of Modules"),
946n/a ("get?key=", "Pydoc: Index of Modules"),
947n/a ("index", "Pydoc: Index of Modules"),
948n/a ("topics", "Pydoc: Topics"),
949n/a ("keywords", "Pydoc: Keywords"),
950n/a ("pydoc", "Pydoc: module pydoc"),
951n/a ("get?key=pydoc", "Pydoc: module pydoc"),
952n/a ("search?key=pydoc", "Pydoc: Search Results"),
953n/a ("topic?key=def", "Pydoc: KEYWORD def"),
954n/a ("topic?key=STRINGS", "Pydoc: TOPIC STRINGS"),
955n/a ("foobar", "Pydoc: Error - foobar"),
956n/a ("getfile?key=foobar", "Pydoc: Error - getfile?key=foobar"),
957n/a ]
958n/a
959n/a with self.restrict_walk_packages():
960n/a for url, title in requests:
961n/a self.call_url_handler(url, title)
962n/a
963n/a path = string.__file__
964n/a title = "Pydoc: getfile " + path
965n/a url = "getfile?key=" + path
966n/a self.call_url_handler(url, title)
967n/a
968n/a
969n/aclass TestHelper(unittest.TestCase):
970n/a def test_keywords(self):
971n/a self.assertEqual(sorted(pydoc.Helper.keywords),
972n/a sorted(keyword.kwlist))
973n/a
974n/aclass PydocWithMetaClasses(unittest.TestCase):
975n/a @unittest.skipIf(sys.flags.optimize >= 2,
976n/a "Docstrings are omitted with -O2 and above")
977n/a @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
978n/a 'trace function introduces __locals__ unexpectedly')
979n/a def test_DynamicClassAttribute(self):
980n/a class Meta(type):
981n/a def __getattr__(self, name):
982n/a if name == 'ham':
983n/a return 'spam'
984n/a return super().__getattr__(name)
985n/a class DA(metaclass=Meta):
986n/a @types.DynamicClassAttribute
987n/a def ham(self):
988n/a return 'eggs'
989n/a expected_text_data_docstrings = tuple('\n | ' + s if s else ''
990n/a for s in expected_data_docstrings)
991n/a output = StringIO()
992n/a helper = pydoc.Helper(output=output)
993n/a helper(DA)
994n/a expected_text = expected_dynamicattribute_pattern % (
995n/a (__name__,) + expected_text_data_docstrings[:2])
996n/a result = output.getvalue().strip()
997n/a self.assertEqual(expected_text, result)
998n/a
999n/a @unittest.skipIf(sys.flags.optimize >= 2,
1000n/a "Docstrings are omitted with -O2 and above")
1001n/a @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
1002n/a 'trace function introduces __locals__ unexpectedly')
1003n/a def test_virtualClassAttributeWithOneMeta(self):
1004n/a class Meta(type):
1005n/a def __dir__(cls):
1006n/a return ['__class__', '__module__', '__name__', 'LIFE']
1007n/a def __getattr__(self, name):
1008n/a if name =='LIFE':
1009n/a return 42
1010n/a return super().__getattr(name)
1011n/a class Class(metaclass=Meta):
1012n/a pass
1013n/a output = StringIO()
1014n/a helper = pydoc.Helper(output=output)
1015n/a helper(Class)
1016n/a expected_text = expected_virtualattribute_pattern1 % __name__
1017n/a result = output.getvalue().strip()
1018n/a self.assertEqual(expected_text, result)
1019n/a
1020n/a @unittest.skipIf(sys.flags.optimize >= 2,
1021n/a "Docstrings are omitted with -O2 and above")
1022n/a @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
1023n/a 'trace function introduces __locals__ unexpectedly')
1024n/a def test_virtualClassAttributeWithTwoMeta(self):
1025n/a class Meta1(type):
1026n/a def __dir__(cls):
1027n/a return ['__class__', '__module__', '__name__', 'one']
1028n/a def __getattr__(self, name):
1029n/a if name =='one':
1030n/a return 1
1031n/a return super().__getattr__(name)
1032n/a class Meta2(type):
1033n/a def __dir__(cls):
1034n/a return ['__class__', '__module__', '__name__', 'two']
1035n/a def __getattr__(self, name):
1036n/a if name =='two':
1037n/a return 2
1038n/a return super().__getattr__(name)
1039n/a class Meta3(Meta1, Meta2):
1040n/a def __dir__(cls):
1041n/a return list(sorted(set(
1042n/a ['__class__', '__module__', '__name__', 'three'] +
1043n/a Meta1.__dir__(cls) + Meta2.__dir__(cls))))
1044n/a def __getattr__(self, name):
1045n/a if name =='three':
1046n/a return 3
1047n/a return super().__getattr__(name)
1048n/a class Class1(metaclass=Meta1):
1049n/a pass
1050n/a class Class2(Class1, metaclass=Meta3):
1051n/a pass
1052n/a fail1 = fail2 = False
1053n/a output = StringIO()
1054n/a helper = pydoc.Helper(output=output)
1055n/a helper(Class1)
1056n/a expected_text1 = expected_virtualattribute_pattern2 % __name__
1057n/a result1 = output.getvalue().strip()
1058n/a self.assertEqual(expected_text1, result1)
1059n/a output = StringIO()
1060n/a helper = pydoc.Helper(output=output)
1061n/a helper(Class2)
1062n/a expected_text2 = expected_virtualattribute_pattern3 % __name__
1063n/a result2 = output.getvalue().strip()
1064n/a self.assertEqual(expected_text2, result2)
1065n/a
1066n/a @unittest.skipIf(sys.flags.optimize >= 2,
1067n/a "Docstrings are omitted with -O2 and above")
1068n/a @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
1069n/a 'trace function introduces __locals__ unexpectedly')
1070n/a def test_buggy_dir(self):
1071n/a class M(type):
1072n/a def __dir__(cls):
1073n/a return ['__class__', '__name__', 'missing', 'here']
1074n/a class C(metaclass=M):
1075n/a here = 'present!'
1076n/a output = StringIO()
1077n/a helper = pydoc.Helper(output=output)
1078n/a helper(C)
1079n/a expected_text = expected_missingattribute_pattern % __name__
1080n/a result = output.getvalue().strip()
1081n/a self.assertEqual(expected_text, result)
1082n/a
1083n/a def test_resolve_false(self):
1084n/a # Issue #23008: pydoc enum.{,Int}Enum failed
1085n/a # because bool(enum.Enum) is False.
1086n/a with captured_stdout() as help_io:
1087n/a pydoc.help('enum.Enum')
1088n/a helptext = help_io.getvalue()
1089n/a self.assertIn('class Enum', helptext)
1090n/a
1091n/a
1092n/a@reap_threads
1093n/adef test_main():
1094n/a try:
1095n/a test.support.run_unittest(PydocDocTest,
1096n/a PydocImportTest,
1097n/a TestDescriptions,
1098n/a PydocServerTest,
1099n/a PydocUrlHandlerTest,
1100n/a TestHelper,
1101n/a PydocWithMetaClasses,
1102n/a )
1103n/a finally:
1104n/a reap_children()
1105n/a
1106n/aif __name__ == "__main__":
1107n/a test_main()