Merged revisions 63871 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r63871 | georg.brandl | 2008-06-01 22:33:55 +0200 (Sun, 01 Jun 2008) | 3 lines

  Generate pydoc's topic help from the reST docs via Sphinx'
  new text writer.
........
This commit is contained in:
Georg Brandl 2008-06-01 21:05:17 +00:00
parent 40ab2ec796
commit 6b38daa80d
5 changed files with 269 additions and 135 deletions

View file

@ -93,6 +93,11 @@ doctest: build
@echo "Testing of doctests in the sources finished, look at the " \ @echo "Testing of doctests in the sources finished, look at the " \
"results in build/doctest/output.txt" "results in build/doctest/output.txt"
pydoc-topics: BUILDER = pydoc-topics
pydoc-topics: build
@echo "Building finished; now copy build/pydoc-topics/pydoc_topics.py " \
"into the Lib/ directory"
clean: clean:
-rm -rf build/* -rm -rf build/*
-rm -rf tools/sphinx -rm -rf tools/sphinx

View file

@ -67,6 +67,11 @@ Available make targets are:
* "coverage", which builds a coverage overview for standard library modules * "coverage", which builds a coverage overview for standard library modules
and C API. and C API.
* "pydoc-topics", which builds a Python module containing a dictionary
with plain text documentation for the labels defined in
`tools/sphinxext/pyspecific.py` -- pydoc needs these to show topic
and keyword help.
A "make update" updates the Subversion checkouts in `tools/`. A "make update" updates the Subversion checkouts in `tools/`.

View file

@ -20,5 +20,69 @@ def issue_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
return [refnode], [] return [refnode], []
# Support for building "topic help" for pydoc
pydoc_topic_labels = [
'assert', 'assignment', 'atom-identifiers', 'atom-literals',
'attribute-access', 'attribute-references', 'augassign', 'binary',
'bitwise', 'bltin-code-objects', 'bltin-ellipsis-object',
'bltin-file-objects', 'bltin-null-object', 'bltin-type-objects', 'booleans',
'break', 'callable-types', 'calls', 'class', 'comparisons', 'compound',
'context-managers', 'continue', 'conversions', 'customization', 'debugger',
'del', 'dict', 'dynamic-features', 'else', 'exceptions', 'execmodel',
'exprlists', 'floating', 'for', 'formatstrings', 'function', 'global',
'id-classes', 'identifiers', 'if', 'imaginary', 'import', 'in', 'integers',
'lambda', 'lists', 'naming', 'numbers', 'numeric-types', 'objects',
'operator-summary', 'pass', 'power', 'raise', 'return', 'sequence-types',
'shifting', 'slicings', 'specialattrs', 'specialnames', 'string-methods',
'strings', 'subscriptions', 'truth', 'try', 'types', 'typesfunctions',
'typesmapping', 'typesmethods', 'typesmodules', 'typesseq',
'typesseq-mutable', 'unary', 'while', 'with', 'yield'
]
from os import path
from time import asctime
from pprint import pformat
from docutils.io import StringOutput
from docutils.utils import new_document
from sphinx.builder import Builder
from sphinx.textwriter import TextWriter
class PydocTopicsBuilder(Builder):
name = 'pydoc-topics'
def init(self):
self.topics = {}
def get_outdated_docs(self):
return 'all pydoc topics'
def get_target_uri(self, docname, typ=None):
return '' # no URIs
def write(self, *ignored):
writer = TextWriter(self)
for label in self.status_iterator(pydoc_topic_labels, 'building topics... '):
if label not in self.env.labels:
self.warn('label %r not in documentation' % label)
continue
docname, labelid, sectname = self.env.labels[label]
doctree = self.env.get_and_resolve_doctree(docname, self)
document = new_document('<section node>')
document.append(doctree.ids[labelid])
destination = StringOutput(encoding='utf-8')
writer.write(document, destination)
self.topics[label] = str(writer.output)
def finish(self):
f = open(path.join(self.outdir, 'pydoc_topics.py'), 'w')
try:
f.write('# Autogenerated by Sphinx on %s\n' % asctime())
f.write('topics = ' + pformat(self.topics) + '\n')
finally:
f.close()
def setup(app): def setup(app):
app.add_role('issue', issue_role) app.add_role('issue', issue_role)
app.add_builder(PydocTopicsBuilder)

View file

@ -1524,141 +1524,141 @@ def writedocs(dir, pkgpath='', done=None):
return return
class Helper: 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.
#
# 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
# make pydoc-topics
# in Doc/ and copying the output file into the Lib/ directory.
keywords = { keywords = {
'and': 'BOOLEAN', 'and': 'BOOLEAN',
'as': 'with', 'as': 'with',
'assert': ('ref/assert', ''), 'assert': ('assert', ''),
'break': ('ref/break', 'while for'), 'break': ('break', 'while for'),
'class': ('ref/class', 'CLASSES SPECIALMETHODS'), 'class': ('class', 'CLASSES SPECIALMETHODS'),
'continue': ('ref/continue', 'while for'), 'continue': ('continue', 'while for'),
'def': ('ref/function', ''), 'def': ('function', ''),
'del': ('ref/del', 'BASICMETHODS'), 'del': ('del', 'BASICMETHODS'),
'elif': 'if', 'elif': 'if',
'else': ('ref/if', 'while for'), 'else': ('else', 'while for'),
'except': 'try', 'except': 'except',
'exec': ('ref/exec', ''), 'finally': 'finally',
'finally': 'try', 'for': ('for', 'break continue while'),
'for': ('ref/for', 'break continue while'), 'from': 'from',
'from': 'import', 'global': ('global', 'NAMESPACES'),
'global': ('ref/global', 'NAMESPACES'), 'if': ('if', 'TRUTHVALUE'),
'if': ('ref/if', 'TRUTHVALUE'), 'import': ('import', 'MODULES'),
'import': ('ref/import', 'MODULES'), 'in': ('in', 'SEQUENCEMETHODS2'),
'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
'is': 'COMPARISON', 'is': 'COMPARISON',
'lambda': ('ref/lambdas', 'FUNCTIONS'), 'lambda': ('lambda', 'FUNCTIONS'),
'not': 'BOOLEAN', 'not': 'BOOLEAN',
'or': 'BOOLEAN', 'or': 'BOOLEAN',
'pass': ('ref/pass', ''), 'pass': ('pass', ''),
'print': ('ref/print', ''), 'raise': ('raise', 'EXCEPTIONS'),
'raise': ('ref/raise', 'EXCEPTIONS'), 'return': ('return', 'FUNCTIONS'),
'return': ('ref/return', 'FUNCTIONS'), 'try': ('try', 'EXCEPTIONS'),
'try': ('ref/try', 'EXCEPTIONS'), 'while': ('while', 'break continue if TRUTHVALUE'),
'while': ('ref/while', 'break continue if TRUTHVALUE'), 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
'with': ('ref/with', 'CONTEXTMANAGERS EXCEPTIONS yield'), 'yield': ('yield', ''),
'yield': ('ref/yield', ''),
} }
topics = { topics = {
'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'), 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'), 'FUNCTIONS CLASSES MODULES FILES inspect'),
'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'), 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'), 'FORMATTING TYPES'),
'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'), 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'), 'FORMATTING': ('formatstrings', 'OPERATORS'),
'INTEGER': ('ref/integers', 'int range'), 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
'FLOAT': ('ref/floating', 'float math'), 'FORMATTING TYPES'),
'COMPLEX': ('ref/imaginary', 'complex cmath'), 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING range LISTS'), 'INTEGER': ('integers', 'int range'),
'FLOAT': ('floating', 'float math'),
'COMPLEX': ('imaginary', 'complex cmath'),
'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
'MAPPINGS': 'DICTIONARIES', 'MAPPINGS': 'DICTIONARIES',
'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'), 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'), 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'), 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'), 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
'FRAMEOBJECTS': 'TYPES', 'FRAMEOBJECTS': 'TYPES',
'TRACEBACKS': 'TYPES', 'TRACEBACKS': 'TYPES',
'NONE': ('lib/bltin-null-object', ''), 'NONE': ('bltin-null-object', ''),
'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'), 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
'FILES': ('lib/bltin-file-objects', ''), 'FILES': ('bltin-file-objects', ''),
'SPECIALATTRIBUTES': ('lib/specialattrs', ''), 'SPECIALATTRIBUTES': ('specialattrs', ''),
'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'), 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
'MODULES': ('lib/typesmodules', 'import'), 'MODULES': ('typesmodules', 'import'),
'PACKAGES': 'import', 'PACKAGES': 'import',
'EXPRESSIONS': ('ref/summary', 'lambda or and not in is BOOLEAN COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES LISTS DICTIONARIES'), 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
'LISTS DICTIONARIES'),
'OPERATORS': 'EXPRESSIONS', 'OPERATORS': 'EXPRESSIONS',
'PRECEDENCE': 'EXPRESSIONS', 'PRECEDENCE': 'EXPRESSIONS',
'OBJECTS': ('ref/objects', 'TYPES'), 'OBJECTS': ('objects', 'TYPES'),
'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'), 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'), 'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS '
'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'), 'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'), 'BASICMETHODS': ('customization', 'cmp hash repr str SPECIALMETHODS'),
'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'), 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'), 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'), 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 '
'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'), 'SPECIALMETHODS'),
'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'), 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'), 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
'DYNAMICFEATURES': ('ref/dynamic-features', ''), 'SPECIALMETHODS'),
'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
'NAMESPACES': ('naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
'DYNAMICFEATURES': ('dynamic-features', ''),
'SCOPING': 'NAMESPACES', 'SCOPING': 'NAMESPACES',
'FRAMES': 'NAMESPACES', 'FRAMES': 'NAMESPACES',
'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'), 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
'COERCIONS': ('ref/coercion-rules','CONVERSIONS'), 'CONVERSIONS': ('conversions', ''),
'CONVERSIONS': ('ref/conversions', 'COERCIONS'), 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'), 'SPECIALIDENTIFIERS': ('id-classes', ''),
'SPECIALIDENTIFIERS': ('ref/id-classes', ''), 'PRIVATENAMES': ('atom-identifiers', ''),
'PRIVATENAMES': ('ref/atom-identifiers', ''), 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
'LITERALS': ('ref/atom-literals', 'STRINGS NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'), 'LISTLITERALS DICTIONARYLITERALS'),
'TUPLES': 'SEQUENCES', 'TUPLES': 'SEQUENCES',
'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'), 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'), 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'), 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'), 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'), 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'), 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'), 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS1'),
'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'), 'SLICINGS': ('slicings', 'SEQUENCEMETHODS2'),
'CALLS': ('ref/calls', 'EXPRESSIONS'), 'CALLS': ('calls', 'EXPRESSIONS'),
'POWER': ('ref/power', 'EXPRESSIONS'), 'POWER': ('power', 'EXPRESSIONS'),
'UNARY': ('ref/unary', 'EXPRESSIONS'), 'UNARY': ('unary', 'EXPRESSIONS'),
'BINARY': ('ref/binary', 'EXPRESSIONS'), 'BINARY': ('binary', 'EXPRESSIONS'),
'SHIFTING': ('ref/shifting', 'EXPRESSIONS'), 'SHIFTING': ('shifting', 'EXPRESSIONS'),
'BITWISE': ('ref/bitwise', 'EXPRESSIONS'), 'BITWISE': ('bitwise', 'EXPRESSIONS'),
'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'), 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'), 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
'ASSERTION': 'assert', 'ASSERTION': 'assert',
'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'), 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'), 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
'DELETION': 'del', 'DELETION': 'del',
'PRINTING': 'print',
'RETURNING': 'return', 'RETURNING': 'return',
'IMPORTING': 'import', 'IMPORTING': 'import',
'CONDITIONAL': 'if', 'CONDITIONAL': 'if',
'LOOPING': ('ref/compound', 'for while break continue'), 'LOOPING': ('compound', 'for while break continue'),
'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'), 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
'DEBUGGING': ('lib/module-pdb', 'pdb'), 'DEBUGGING': ('debugger', 'pdb'),
'CONTEXTMANAGERS': ('ref/context-managers', 'with'), 'CONTEXTMANAGERS': ('context-managers', 'with'),
} }
def __init__(self, input, output): def __init__(self, input, output):
self.input = input self.input = input
self.output = output self.output = output
self.docdir = None
execdir = os.path.dirname(sys.executable)
homedir = os.environ.get('PYTHONHOME')
join = os.path.join
for dir in [os.environ.get('PYTHONDOCS'),
homedir and os.path.join(homedir, 'doc'),
join(execdir, 'doc'), # for Windows
join(sys.prefix, 'doc/python-docs-' + sys.version.split()[0]),
join(sys.prefix, 'doc/python-' + sys.version.split()[0]),
join(sys.prefix, 'doc/python-docs-' + sys.version[:3]),
join(sys.prefix, 'doc/python-' + sys.version[:3]),
join(sys.prefix, 'Resources/English.lproj/Documentation')]:
if dir and os.path.isdir(join(dir, 'lib')):
self.docdir = dir
break
if dir and os.path.isdir(join(dir, 'html', 'lib')):
self.docdir = join(dir, 'html')
break
def __repr__(self): def __repr__(self):
if inspect.stack()[1][3] == '?': if inspect.stack()[1][3] == '?':
@ -1760,14 +1760,12 @@ Here is a list of available topics. Enter any topic name to get more help.
self.list(self.topics.keys()) self.list(self.topics.keys())
def showtopic(self, topic): def showtopic(self, topic):
if not self.docdir: try:
import pydoc_topics
except ImportError:
self.output.write(''' self.output.write('''
Sorry, topic and keyword documentation is not available because the Python Sorry, topic and keyword documentation is not available because the
HTML documentation files could not be found. If you have installed them, module "pydoc_topics" could not be found.
please set the environment variable PYTHONDOCS to indicate their location.
On the Microsoft Windows operating system, the files can be built by
running "hh -decompile . PythonNN.chm" in the C:\PythonNN\Doc> directory.
''') ''')
return return
target = self.topics.get(topic, self.keywords.get(topic)) target = self.topics.get(topic, self.keywords.get(topic))
@ -1777,31 +1775,15 @@ running "hh -decompile . PythonNN.chm" in the C:\PythonNN\Doc> directory.
if type(target) is type(''): if type(target) is type(''):
return self.showtopic(target) return self.showtopic(target)
filename, xrefs = target label, xrefs = target
filename = self.docdir + '/' + filename + '.html'
try: try:
file = open(filename) doc = pydoc_topics.topics[label]
except: except KeyError:
self.output.write('could not read docs from %s\n' % filename) self.output.write('no documentation found for %s\n' % repr(topic))
return return
pager(doc.strip() + '\n')
divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
file.close()
import htmllib, formatter, io
buffer = io.StringIO()
parser = htmllib.HTMLParser(
formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
parser.start_table = parser.do_p
parser.end_table = lambda parser=parser: parser.do_p({})
parser.start_tr = parser.do_br
parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
parser.feed(document)
buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
pager(' ' + buffer.strip() + '\n')
if xrefs: if xrefs:
import io, formatter
buffer = io.StringIO() buffer = io.StringIO()
formatter.DumbWriter(buffer).send_flowing_data( formatter.DumbWriter(buffer).send_flowing_data(
'Related help topics: ' + ', '.join(xrefs.split()) + '\n') 'Related help topics: ' + ', '.join(xrefs.split()) + '\n')

78
Lib/pydoc_topics.py Normal file

File diff suppressed because one or more lines are too long