# HG changeset patch # Parent db9fe49069edccee480196978e670968e271d2e8 diff -r db9fe49069ed Lib/pydoc.py --- a/Lib/pydoc.py Sun Jul 14 12:45:18 2013 -0700 +++ b/Lib/pydoc.py Mon Jul 15 13:26:54 2013 -0500 @@ -67,7 +67,7 @@ from collections import deque from reprlib import Repr from traceback import extract_tb, format_exception_only - +from html import escape as html_escape # --------------------------------------------------------- common routines @@ -398,9 +398,6 @@ self.maxdict = 10 self.maxstring = self.maxother = 100 - def escape(self, text): - return replace(text, '&', '&', '<', '<', '>', '>') - def repr(self, object): return Repr.repr(self, object) @@ -409,7 +406,7 @@ methodname = 'repr_' + '_'.join(type(x).__name__.split()) if hasattr(self, methodname): return getattr(self, methodname)(x, level) - return self.escape(cram(stripid(repr(x)), self.maxother)) + return html_escape(cram(stripid(repr(x)), self.maxother)) def repr_string(self, x, level): test = cram(x, self.maxstring) @@ -417,18 +414,18 @@ if '\\' in test and '\\' not in replace(testrepr, r'\\', ''): # Backslashes are only literal in the string and are never # needed to make any special characters, so show a raw string. - return 'r' + testrepr[0] + self.escape(test) + testrepr[0] + return 'r' + testrepr[0] + html_escape(test) + testrepr[0] return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)', r'\1', - self.escape(testrepr)) + html_escape(testrepr, quote=False)) repr_str = repr_string def repr_instance(self, x, level): try: - return self.escape(cram(stripid(repr(x)), self.maxstring)) + return html_escape(cram(stripid(repr(x)), self.maxstring)) except: - return self.escape('<%s instance>' % x.__class__.__name__) + return html_escape('<%s instance>' % x.__class__.__name__) repr_unicode = repr_string @@ -439,7 +436,6 @@ _repr_instance = HTMLRepr() repr = _repr_instance.repr - escape = _repr_instance.escape def page(self, title, contents): """Format an HTML page.""" @@ -491,7 +487,7 @@ def preformat(self, text): """Format literal preformatted text.""" - text = self.escape(text.expandtabs()) + text = html_escape(text.expandtabs(), quote=False) return replace(text, '\n\n', '\n \n', '\n\n', '\n \n', ' ', ' ', '\n', '
\n') @@ -550,7 +546,7 @@ def markup(self, text, escape=None, funcs={}, classes={}, methods={}): """Mark up some plain text, given a context of symbols to look for. Each context dictionary maps object names to anchor names.""" - escape = escape or self.escape + escape = escape or html_escape results = [] here = 0 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|' @@ -633,9 +629,9 @@ version = str(object.__version__) if version[:11] == '$' + 'Revision: ' and version[-1:] == '$': version = version[11:-1].strip() - info.append('version %s' % self.escape(version)) + info.append('version %s' % html_escape(version)) if hasattr(object, '__date__'): - info.append(self.escape(str(object.__date__))) + info.append(html_escape(str(object.__date__))) if info: head = head + ' (%s)' % ', '.join(info) docloc = self.getdocloc(object) @@ -1649,7 +1645,7 @@ 'STRINGS' : ("'", "'''", "r'", "b'", '"""', '"', 'r"', 'b"'), 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&', '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'), - 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'), + 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!='), 'UNARY' : ('-', '~'), 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=', '^=', '<<=', '>>=', '**=', '//='), @@ -1667,7 +1663,6 @@ '\\': 'STRINGS', '_': 'PRIVATENAMES', '__': 'PRIVATENAMES SPECIALMETHODS', - '`': 'BACKQUOTES', '(': 'TUPLES FUNCTIONS CALLS', ')': 'TUPLES FUNCTIONS CALLS', '[': 'LISTS SUBSCRIPTS SLICINGS', @@ -1953,6 +1948,11 @@ topic, _, xrefs = target.partition(' ') self.showtopic(topic, xrefs) + def _getsymbol(self, symbol): + target = self.symbols[symbol] + topic, _, xrefs = target.partition(' ') + return self._gettopic(topic, xrefs) + def listmodules(self, key=''): if key: self.output.write(''' @@ -2117,6 +2117,7 @@ import email.message import select import threading + from urllib.parse import unquote class DocHandler(http.server.BaseHTTPRequestHandler): @@ -2134,7 +2135,7 @@ self.send_header('Content-Type', '%s; charset=UTF-8' % content_type) self.end_headers() self.wfile.write(self.urlhandler( - self.path, content_type).encode('utf-8')) + unquote(self.path), content_type).encode('utf-8')) def log_message(self, *args): # Don't log messages. @@ -2214,7 +2215,6 @@ get_html_page(url) is returned. """ class _HTMLDoc(HTMLDoc): - def page(self, title, contents): """Format an HTML page.""" css_path = "pydoc_data/_pydoc.css" @@ -2229,13 +2229,14 @@ ''' % (title, css_link, html_navbar(), contents) def filelink(self, url, path): - return '%s' % (url, path) + return ('%s' % + (html_escape(url), html_escape(path))) html = _HTMLDoc() def html_navbar(): - version = html.escape("%s [%s, %s]" % (platform.python_version(), + version = html_escape("%s [%s, %s]" % (platform.python_version(), platform.python_build()[0], platform.python_compiler())) return """ @@ -2247,6 +2248,7 @@ Module Index : Topics : Keywords + : Symbols
@@ -2259,7 +2261,7 @@
- """ % (version, html.escape(platform.platform(terse=True))) + """ % (version, html_escape(platform.platform(terse=True))) def html_index(): """Module Index page.""" @@ -2318,7 +2320,7 @@ """Get and display a source file listing safely.""" path = path.replace('%20', ' ') with tokenize.open(path) as fp: - lines = html.escape(fp.read()) + lines = html_escape(fp.read()) body = '
%s
' % lines heading = html.heading( 'File Listing', @@ -2327,46 +2329,42 @@ 'File: %s' % path, '#ffffff', '#ee77aa', body) return 'getfile %s' % path, contents - def html_topics(): + def html_topicindex(title): """Index of topic texts available.""" def bltinlink(name): - return '%s' % (name, name) + return ('%s' % + (html_escape(name), html_escape(name))) heading = html.heading( - 'INDEX', + '%s' % title.upper(), '#ffffff', '#7799ee') - names = sorted(Helper.topics.keys()) - + keys = { + 'topics': Helper.topics.keys, + 'keywords': Helper.keywords.keys, + 'symbols': Helper.symbols.keys, + } + names = sorted(keys[title]()) contents = html.multicolumn(names, bltinlink) contents = heading + html.bigsection( - 'Topics', '#ffffff', '#ee77aa', contents) - return 'Topics', contents - - def html_keywords(): - """Index of keywords.""" - heading = html.heading( - 'INDEX', - '#ffffff', '#7799ee') - names = sorted(Helper.keywords.keys()) - - def bltinlink(name): - return '%s' % (name, name) - - contents = html.multicolumn(names, bltinlink) - contents = heading + html.bigsection( - 'Keywords', '#ffffff', '#ee77aa', contents) - return 'Keywords', contents + title, '#ffffff', '#ee77aa', contents) + return title, contents def html_topicpage(topic): """Topic or keyword help page.""" buf = io.StringIO() htmlhelp = Helper(buf, buf) - contents, xrefs = htmlhelp._gettopic(topic) if topic in htmlhelp.keywords: title = 'KEYWORD' + contents, xrefs = htmlhelp._gettopic(topic) + elif topic in htmlhelp.topics: + title = 'TOPIC' + contents, xrefs = htmlhelp._gettopic(topic) + elif topic in htmlhelp.symbols: + title = 'SYMBOL' + contents, xrefs = htmlhelp._getsymbol(topic) else: - title = 'TOPIC' + raise ValueError('could not find topic %s' % repr(topic)) heading = html.heading( '%s' % title, '#ffffff', '#7799ee') @@ -2376,7 +2374,7 @@ xrefs = sorted(xrefs.split()) def bltinlink(name): - return '%s' % (name, name) + return '%s' % (html_escape(name), html_escape(name)) xrefs = html.multicolumn(xrefs, bltinlink) xrefs = html.section('Related help topics: ', @@ -2396,7 +2394,7 @@ heading = html.heading( 'Error', '#ffffff', '#7799ee') - contents = '
'.join(html.escape(line) for line in + contents = '
'.join(html_escape(line) for line in format_exception_only(type(exc), exc)) contents = heading + html.bigsection(url, '#ffffff', '#bb0000', contents) @@ -2410,23 +2408,21 @@ try: if url in ("", "index"): title, content = html_index() - elif url == "topics": - title, content = html_topics() - elif url == "keywords": - title, content = html_keywords() - elif '=' in url: - op, _, url = url.partition('=') - if op == "search?key": + elif url in ("topics", "keywords", "symbols"): + title, content = html_topicindex(url) + elif '?key=' in url: + op, _, url = url.partition('?key=') + if op == "search": title, content = html_search(url) - elif op == "getfile?key": + elif op == "getfile": title, content = html_getfile(url) - elif op == "topic?key": + elif op == "topic": # try topics first, then objects. try: title, content = html_topicpage(url) except ValueError: title, content = html_getobj(url) - elif op == "get?key": + elif op == "get": # try objects first, then topics. if url in ("", "index"): title, content = html_index() @@ -2585,3 +2581,4 @@ if __name__ == '__main__': cli() + diff -r db9fe49069ed Lib/test/test_pydoc.py --- a/Lib/test/test_pydoc.py Sun Jul 14 12:45:18 2013 -0700 +++ b/Lib/test/test_pydoc.py Mon Jul 15 13:26:54 2013 -0500 @@ -606,8 +606,9 @@ ("", "Pydoc: Index of Modules"), ("get?key=", "Pydoc: Index of Modules"), ("index", "Pydoc: Index of Modules"), - ("topics", "Pydoc: Topics"), - ("keywords", "Pydoc: Keywords"), + ("topics", "Pydoc: topics"), + ("keywords", "Pydoc: keywords"), + ("symbols", "Pydoc: symbols"), ("pydoc", "Pydoc: module pydoc"), ("get?key=pydoc", "Pydoc: module pydoc"), ("search?key=pydoc", "Pydoc: Search Results"),