summaryrefslogtreecommitdiff
path: root/Lib/pydoc.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/pydoc.py')
-rwxr-xr-xLib/pydoc.py109
1 files changed, 65 insertions, 44 deletions
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
index 86a6aa02c1..19a71d8304 100755
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -37,7 +37,7 @@ Reference Manual pages.
__author__ = "Ka-Ping Yee <ping@lfw.org>"
__date__ = "26 February 2001"
-__version__ = "$Revision$"
+__version__ = "$Revision: 88564 $"
__credits__ = """Guido van Rossum, for an excellent programming language.
Tommy Burnette, the original creator of manpy.
Paul Prescod, for all his work on onlinehelp.
@@ -52,7 +52,7 @@ Richard Chamberlain, for the first implementation of textdoc.
# the current directory is changed with os.chdir(), an incorrect
# path will be displayed.
-import sys, imp, os, re, types, inspect, __builtin__, pkgutil
+import sys, imp, os, re, types, inspect, __builtin__, pkgutil, warnings
from repr import Repr
from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
from traceback import extract_tb
@@ -156,7 +156,7 @@ def _split_list(s, predicate):
no.append(x)
return yes, no
-def visiblename(name, all=None):
+def visiblename(name, all=None, obj=None):
"""Decide whether to show documentation on a variable."""
# Certain special names are redundant.
_hidden_names = ('__builtins__', '__doc__', '__file__', '__path__',
@@ -164,6 +164,9 @@ def visiblename(name, all=None):
if name in _hidden_names: return 0
# Private names are hidden, but special names are displayed.
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:
# only document that which the programmer exported in __all__
return name in all
@@ -209,8 +212,8 @@ def source_synopsis(file):
def synopsis(filename, cache={}):
"""Get the one-line summary out of a module file."""
mtime = os.stat(filename).st_mtime
- lastupdate, result = cache.get(filename, (0, None))
- if lastupdate < mtime:
+ lastupdate, result = cache.get(filename, (None, None))
+ if lastupdate is None or lastupdate < mtime:
info = inspect.getmoduleinfo(filename)
try:
file = open(filename)
@@ -475,9 +478,9 @@ class HTMLDoc(Doc):
def multicolumn(self, list, format, cols=4):
"""Format a list of items into a multi-column list."""
result = ''
- rows = (len(list)+cols-1)/cols
+ rows = (len(list)+cols-1)//cols
for col in range(cols):
- result = result + '<td width="%d%%" valign=top>' % (100/cols)
+ result = result + '<td width="%d%%" valign=top>' % (100//cols)
for i in range(rows*col, rows*col+rows):
if i < len(list):
result = result + format(list[i]) + '<br>\n'
@@ -627,7 +630,7 @@ class HTMLDoc(Doc):
# if __all__ exists, believe it. Otherwise use old heuristic.
if (all is not None or
(inspect.getmodule(value) or object) is object):
- if visiblename(key, all):
+ if visiblename(key, all, object):
classes.append((key, value))
cdict[key] = cdict[value] = '#' + key
for key, value in classes:
@@ -643,13 +646,13 @@ class HTMLDoc(Doc):
# if __all__ exists, believe it. Otherwise use old heuristic.
if (all is not None or
inspect.isbuiltin(value) or inspect.getmodule(value) is object):
- if visiblename(key, all):
+ if visiblename(key, all, object):
funcs.append((key, value))
fdict[key] = '#-' + key
if inspect.isfunction(value): fdict[value] = fdict[key]
data = []
for key, value in inspect.getmembers(object, isdata):
- if visiblename(key, all):
+ if visiblename(key, all, object):
data.append((key, value))
doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
@@ -737,8 +740,15 @@ class HTMLDoc(Doc):
hr.maybe()
push(msg)
for name, kind, homecls, value in ok:
- push(self.document(getattr(object, name), name, mod,
- funcs, classes, mdict, object))
+ try:
+ value = getattr(object, name)
+ except Exception:
+ # Some descriptors may meet a failure in their __get__.
+ # (bug #1785)
+ push(self._docdescriptor(name, value, mod))
+ else:
+ push(self.document(value, name, mod,
+ funcs, classes, mdict, object))
push('\n')
return attrs
@@ -773,12 +783,17 @@ class HTMLDoc(Doc):
push('\n')
return attrs
- attrs = filter(lambda data: visiblename(data[0]),
+ attrs = filter(lambda data: visiblename(data[0], obj=object),
classify_class_attrs(object))
mdict = {}
for key, kind, homecls, value in attrs:
mdict[key] = anchor = '#' + name + '-' + key
- value = getattr(object, key)
+ try:
+ value = getattr(object, name)
+ except Exception:
+ # Some descriptors may meet a failure in their __get__.
+ # (bug #1785)
+ pass
try:
# The value may not be hashable (e.g., a data attr with
# a dict or list value).
@@ -1042,18 +1057,18 @@ class TextDoc(Doc):
# if __all__ exists, believe it. Otherwise use old heuristic.
if (all is not None
or (inspect.getmodule(value) or object) is object):
- if visiblename(key, all):
+ if visiblename(key, all, object):
classes.append((key, value))
funcs = []
for key, value in inspect.getmembers(object, inspect.isroutine):
# if __all__ exists, believe it. Otherwise use old heuristic.
if (all is not None or
inspect.isbuiltin(value) or inspect.getmodule(value) is object):
- if visiblename(key, all):
+ if visiblename(key, all, object):
funcs.append((key, value))
data = []
for key, value in inspect.getmembers(object, isdata):
- if visiblename(key, all):
+ if visiblename(key, all, object):
data.append((key, value))
modpkgs = []
@@ -1113,7 +1128,7 @@ class TextDoc(Doc):
result = result + self.section('CREDITS', str(object.__credits__))
return result
- def docclass(self, object, name=None, mod=None):
+ def docclass(self, object, name=None, mod=None, *ignored):
"""Produce text documentation for a given class object."""
realname = object.__name__
name = name or realname
@@ -1158,8 +1173,15 @@ class TextDoc(Doc):
hr.maybe()
push(msg)
for name, kind, homecls, value in ok:
- push(self.document(getattr(object, name),
- name, mod, object))
+ try:
+ value = getattr(object, name)
+ except Exception:
+ # Some descriptors may meet a failure in their __get__.
+ # (bug #1785)
+ push(self._docdescriptor(name, value, mod))
+ else:
+ push(self.document(value,
+ name, mod, object))
return attrs
def spilldescriptors(msg, attrs, predicate):
@@ -1186,7 +1208,7 @@ class TextDoc(Doc):
name, mod, maxlen=70, doc=doc) + '\n')
return attrs
- attrs = filter(lambda data: visiblename(data[0]),
+ attrs = filter(lambda data: visiblename(data[0], obj=object),
classify_class_attrs(object))
while attrs:
if mro:
@@ -1451,13 +1473,14 @@ def locate(path, forceload=0):
else: break
if module:
object = module
- for part in parts[n:]:
- try: object = getattr(object, part)
- except AttributeError: return None
- return object
else:
- if hasattr(__builtin__, path):
- return getattr(__builtin__, path)
+ object = __builtin__
+ for part in parts[n:]:
+ try:
+ object = getattr(object, part)
+ except AttributeError:
+ return None
+ return object
# --------------------------------------- interactive interpreter interface
@@ -1533,11 +1556,11 @@ class Helper:
# These dictionaries map a topic name to either an alias, or a tuple
# (label, seealso-items). The "label" is the label of the corresponding
# section in the .rst file under Doc/ and an index into the dictionary
- # in pydoc_topics.py.
+ # in pydoc_data/topics.py.
#
# CAUTION: if you change one of these dictionaries, be sure to adapt the
# list of needed labels in Doc/tools/sphinxext/pyspecific.py and
- # regenerate the pydoc_topics.py file by running
+ # regenerate the pydoc_data/topics.py file by running
# make pydoc-topics
# in Doc/ and copying the output file into the Lib/ directory.
@@ -1718,8 +1741,9 @@ class Helper:
return ''
return '<pydoc.Helper instance>'
- def __call__(self, request=None):
- if request is not None:
+ _GoInteractive = object()
+ def __call__(self, request=_GoInteractive):
+ if request is not self._GoInteractive:
self.help(request)
else:
self.intro()
@@ -1825,11 +1849,11 @@ Here is a list of available topics. Enter any topic name to get more help.
def showtopic(self, topic, more_xrefs=''):
try:
- import pydoc_topics
+ import pydoc_data.topics
except ImportError:
self.output.write('''
Sorry, topic and keyword documentation is not available because the
-module "pydoc_topics" could not be found.
+module "pydoc_data.topics" could not be found.
''')
return
target = self.topics.get(topic, self.keywords.get(topic))
@@ -1841,7 +1865,7 @@ module "pydoc_topics" could not be found.
label, xrefs = target
try:
- doc = pydoc_topics.topics[label]
+ doc = pydoc_data.topics.topics[label]
except KeyError:
self.output.write('no documentation found for %s\n' % repr(topic))
return
@@ -1963,10 +1987,11 @@ def apropos(key):
if modname[-9:] == '.__init__':
modname = modname[:-9] + ' (package)'
print modname, desc and '- ' + desc
- try: import warnings
- except ImportError: pass
- else: warnings.filterwarnings('ignore') # ignore problems during import
- ModuleScanner().run(callback, key)
+ def onerror(modname):
+ pass
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore') # ignore problems during import
+ ModuleScanner().run(callback, key, onerror=onerror)
# --------------------------------------------------- web browser interface
@@ -2031,8 +2056,8 @@ pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
class DocServer(BaseHTTPServer.HTTPServer):
def __init__(self, port, callback):
- host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
- self.address = ('', port)
+ host = 'localhost'
+ self.address = (host, port)
self.url = 'http://%s:%d/' % (host, port)
self.callback = callback
self.base.__init__(self, self.address, self.handler)
@@ -2148,10 +2173,6 @@ def gui():
except ImportError: # pre-webbrowser.py compatibility
if sys.platform == 'win32':
os.system('start "%s"' % url)
- elif sys.platform == 'mac':
- try: import ic
- except ImportError: pass
- else: ic.launchurl(url)
else:
rc = os.system('netscape -remote "openURL(%s)" &' % url)
if rc: os.system('netscape "%s" &' % url)