Commit 9aa5a34b authored by Raymond Hettinger's avatar Raymond Hettinger

Issue #11666: Teach pydoc to display full help for named tuples

parent f9e9a6f4
...@@ -156,7 +156,7 @@ def _split_list(s, predicate): ...@@ -156,7 +156,7 @@ def _split_list(s, predicate):
no.append(x) no.append(x)
return yes, no return yes, no
def visiblename(name, all=None): def visiblename(name, all=None, obj=None):
"""Decide whether to show documentation on a variable.""" """Decide whether to show documentation on a variable."""
# Certain special names are redundant. # Certain special names are redundant.
_hidden_names = ('__builtins__', '__doc__', '__file__', '__path__', _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__',
...@@ -164,6 +164,9 @@ def visiblename(name, all=None): ...@@ -164,6 +164,9 @@ def visiblename(name, all=None):
if name in _hidden_names: return 0 if name in _hidden_names: return 0
# Private names are hidden, but special names are displayed. # Private names are hidden, but special names are displayed.
if name.startswith('__') and name.endswith('__'): return 1 if name.startswith('__') and name.endswith('__'): return 1
# Namedtuples have public fields and methods with a single leading underscore
if name.startswith('_') and hasattr(obj, '_fields'):
return 1
if all is not None: if all is not None:
# only document that which the programmer exported in __all__ # only document that which the programmer exported in __all__
return name in all return name in all
...@@ -627,7 +630,7 @@ class HTMLDoc(Doc): ...@@ -627,7 +630,7 @@ class HTMLDoc(Doc):
# if __all__ exists, believe it. Otherwise use old heuristic. # if __all__ exists, believe it. Otherwise use old heuristic.
if (all is not None or if (all is not None or
(inspect.getmodule(value) or object) is object): (inspect.getmodule(value) or object) is object):
if visiblename(key, all): if visiblename(key, all, object):
classes.append((key, value)) classes.append((key, value))
cdict[key] = cdict[value] = '#' + key cdict[key] = cdict[value] = '#' + key
for key, value in classes: for key, value in classes:
...@@ -643,13 +646,13 @@ class HTMLDoc(Doc): ...@@ -643,13 +646,13 @@ class HTMLDoc(Doc):
# if __all__ exists, believe it. Otherwise use old heuristic. # if __all__ exists, believe it. Otherwise use old heuristic.
if (all is not None or if (all is not None or
inspect.isbuiltin(value) or inspect.getmodule(value) is object): inspect.isbuiltin(value) or inspect.getmodule(value) is object):
if visiblename(key, all): if visiblename(key, all, object):
funcs.append((key, value)) funcs.append((key, value))
fdict[key] = '#-' + key fdict[key] = '#-' + key
if inspect.isfunction(value): fdict[value] = fdict[key] if inspect.isfunction(value): fdict[value] = fdict[key]
data = [] data = []
for key, value in inspect.getmembers(object, isdata): for key, value in inspect.getmembers(object, isdata):
if visiblename(key, all): if visiblename(key, all, object):
data.append((key, value)) data.append((key, value))
doc = self.markup(getdoc(object), self.preformat, fdict, cdict) doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
...@@ -773,7 +776,7 @@ class HTMLDoc(Doc): ...@@ -773,7 +776,7 @@ class HTMLDoc(Doc):
push('\n') push('\n')
return attrs return attrs
attrs = filter(lambda data: visiblename(data[0]), attrs = filter(lambda data: visiblename(data[0], obj=object),
classify_class_attrs(object)) classify_class_attrs(object))
mdict = {} mdict = {}
for key, kind, homecls, value in attrs: for key, kind, homecls, value in attrs:
...@@ -1042,18 +1045,18 @@ class TextDoc(Doc): ...@@ -1042,18 +1045,18 @@ class TextDoc(Doc):
# if __all__ exists, believe it. Otherwise use old heuristic. # if __all__ exists, believe it. Otherwise use old heuristic.
if (all is not None if (all is not None
or (inspect.getmodule(value) or object) is object): or (inspect.getmodule(value) or object) is object):
if visiblename(key, all): if visiblename(key, all, object):
classes.append((key, value)) classes.append((key, value))
funcs = [] funcs = []
for key, value in inspect.getmembers(object, inspect.isroutine): for key, value in inspect.getmembers(object, inspect.isroutine):
# if __all__ exists, believe it. Otherwise use old heuristic. # if __all__ exists, believe it. Otherwise use old heuristic.
if (all is not None or if (all is not None or
inspect.isbuiltin(value) or inspect.getmodule(value) is object): inspect.isbuiltin(value) or inspect.getmodule(value) is object):
if visiblename(key, all): if visiblename(key, all, object):
funcs.append((key, value)) funcs.append((key, value))
data = [] data = []
for key, value in inspect.getmembers(object, isdata): for key, value in inspect.getmembers(object, isdata):
if visiblename(key, all): if visiblename(key, all, object):
data.append((key, value)) data.append((key, value))
modpkgs = [] modpkgs = []
...@@ -1186,7 +1189,7 @@ class TextDoc(Doc): ...@@ -1186,7 +1189,7 @@ class TextDoc(Doc):
name, mod, maxlen=70, doc=doc) + '\n') name, mod, maxlen=70, doc=doc) + '\n')
return attrs return attrs
attrs = filter(lambda data: visiblename(data[0]), attrs = filter(lambda data: visiblename(data[0], obj=object),
classify_class_attrs(object)) classify_class_attrs(object))
while attrs: while attrs:
if mro: if mro:
......
...@@ -10,8 +10,9 @@ import unittest ...@@ -10,8 +10,9 @@ import unittest
import xml.etree import xml.etree
import test.test_support import test.test_support
from contextlib import contextmanager from contextlib import contextmanager
from collections import namedtuple
from test.test_support import ( from test.test_support import (
TESTFN, forget, rmtree, EnvironmentVarGuard, reap_children) TESTFN, forget, rmtree, EnvironmentVarGuard, reap_children, captured_stdout)
from test import pydoc_mod from test import pydoc_mod
...@@ -340,6 +341,15 @@ class TestDescriptions(unittest.TestCase): ...@@ -340,6 +341,15 @@ class TestDescriptions(unittest.TestCase):
expected = 'C in module %s object' % __name__ expected = 'C in module %s object' % __name__
self.assertIn(expected, pydoc.render_doc(c)) self.assertIn(expected, pydoc.render_doc(c))
def test_namedtuple_public_underscore(self):
NT = namedtuple('NT', ['abc', 'def'], rename=True)
with captured_stdout() as help_io:
help(NT)
helptext = help_io.getvalue()
self.assertIn('_1', helptext)
self.assertIn('_replace', helptext)
self.assertIn('_asdict', helptext)
def test_main(): def test_main():
test.test_support.run_unittest(PyDocDocTest, test.test_support.run_unittest(PyDocDocTest,
......
...@@ -43,6 +43,9 @@ Core and Builtins ...@@ -43,6 +43,9 @@ Core and Builtins
Library Library
------- -------
- Issue #11666: let help() display named tuple attributes and methods
that start with a leading underscore.
- Issue #11673: Fix multiprocessing Array and RawArray constructors to accept a - Issue #11673: Fix multiprocessing Array and RawArray constructors to accept a
size of type 'long', rather than only accepting 'int'. size of type 'long', rather than only accepting 'int'.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment