Commit 1103d057 authored by Raymond Hettinger's avatar Raymond Hettinger

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

parent 66a4e12d
...@@ -165,7 +165,7 @@ def _split_list(s, predicate): ...@@ -165,7 +165,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__',
...@@ -175,6 +175,9 @@ def visiblename(name, all=None): ...@@ -175,6 +175,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 True
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
...@@ -642,7 +645,7 @@ class HTMLDoc(Doc): ...@@ -642,7 +645,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:
...@@ -658,13 +661,13 @@ class HTMLDoc(Doc): ...@@ -658,13 +661,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)
...@@ -789,7 +792,7 @@ class HTMLDoc(Doc): ...@@ -789,7 +792,7 @@ class HTMLDoc(Doc):
attrs = [(name, kind, cls, value) attrs = [(name, kind, cls, value)
for name, kind, cls, value in classify_class_attrs(object) for name, kind, cls, value in classify_class_attrs(object)
if visiblename(name)] if visiblename(name, obj=object)]
mdict = {} mdict = {}
for key, kind, homecls, value in attrs: for key, kind, homecls, value in attrs:
...@@ -1056,18 +1059,18 @@ doubt, consult the module reference at the location listed above. ...@@ -1056,18 +1059,18 @@ doubt, consult the module reference at the location listed above.
# 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 = []
...@@ -1206,7 +1209,7 @@ doubt, consult the module reference at the location listed above. ...@@ -1206,7 +1209,7 @@ doubt, consult the module reference at the location listed above.
attrs = [(name, kind, cls, value) attrs = [(name, kind, cls, value)
for name, kind, cls, value in classify_class_attrs(object) for name, kind, cls, value in classify_class_attrs(object)
if visiblename(name)] if visiblename(name, obj=object)]
while attrs: while attrs:
if mro: if mro:
......
...@@ -12,9 +12,10 @@ import unittest ...@@ -12,9 +12,10 @@ import unittest
import xml.etree import xml.etree
import textwrap import textwrap
from io import StringIO from io import StringIO
from collections import namedtuple
from contextlib import contextmanager from contextlib import contextmanager
from test.support import TESTFN, forget, rmtree, EnvironmentVarGuard, \ from test.support import TESTFN, forget, rmtree, EnvironmentVarGuard, \
reap_children, captured_output reap_children, captured_output, captured_stdout
from test import pydoc_mod from test import pydoc_mod
...@@ -373,6 +374,15 @@ class PydocDocTest(unittest.TestCase): ...@@ -373,6 +374,15 @@ class PydocDocTest(unittest.TestCase):
finally: finally:
pydoc.getpager = getpager_old pydoc.getpager = getpager_old
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)
class TestDescriptions(unittest.TestCase): class TestDescriptions(unittest.TestCase):
......
...@@ -51,6 +51,9 @@ Library ...@@ -51,6 +51,9 @@ Library
- Issue #11628: cmp_to_key generated class should use __slots__ - Issue #11628: cmp_to_key generated class should use __slots__
- Issue #11666: let help() display named tuple attributes and methods
that start with a leading underscore.
- Issue #5537: Fix time2isoz() and time2netscape() functions of - Issue #5537: Fix time2isoz() and time2netscape() functions of
httplib.cookiejar for expiration year greater than 2038 on 32-bit systems. httplib.cookiejar for expiration year greater than 2038 on 32-bit systems.
......
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