@@ -71,6 +71,7 @@ class or function within a module or module in a package. If the
7171import urllib .parse
7272import warnings
7373from collections import deque
74+ from html import escape as html_escape
7475from reprlib import Repr
7576from traceback import format_exception_only
7677
@@ -430,9 +431,6 @@ def __init__(self):
430431 self .maxdict = 10
431432 self .maxstring = self .maxother = 100
432433
433- def escape (self , text ):
434- return replace (text , '&' , '&' , '<' , '<' , '>' , '>' )
435-
436434 def repr (self , object ):
437435 return Repr .repr (self , object )
438436
@@ -441,26 +439,26 @@ def repr1(self, x, level):
441439 methodname = 'repr_' + '_' .join (type (x ).__name__ .split ())
442440 if hasattr (self , methodname ):
443441 return getattr (self , methodname )(x , level )
444- return self . escape (cram (stripid (repr (x )), self .maxother ))
442+ return html_escape (cram (stripid (repr (x )), self .maxother ))
445443
446444 def repr_string (self , x , level ):
447445 test = cram (x , self .maxstring )
448446 testrepr = repr (test )
449447 if '\\ ' in test and '\\ ' not in replace (testrepr , r'\\' , '' ):
450448 # Backslashes are only literal in the string and are never
451449 # needed to make any special characters, so show a raw string.
452- return 'r' + testrepr [0 ] + self . escape (test ) + testrepr [0 ]
450+ return 'r' + testrepr [0 ] + html_escape (test ) + testrepr [0 ]
453451 return re .sub (r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)' ,
454452 r'<font color="#c040c0">\1</font>' ,
455- self . escape (testrepr ))
453+ html_escape (testrepr , quote = False ))
456454
457455 repr_str = repr_string
458456
459457 def repr_instance (self , x , level ):
460458 try :
461- return self . escape (cram (stripid (repr (x )), self .maxstring ))
459+ return html_escape (cram (stripid (repr (x )), self .maxstring ))
462460 except :
463- return self . escape ('<%s instance>' % x .__class__ .__name__ )
461+ return html_escape ('<%s instance>' % x .__class__ .__name__ )
464462
465463 repr_unicode = repr_string
466464
@@ -471,7 +469,6 @@ class HTMLDoc(Doc):
471469
472470 _repr_instance = HTMLRepr ()
473471 repr = _repr_instance .repr
474- escape = _repr_instance .escape
475472
476473 def page (self , title , contents ):
477474 """Format an HTML page."""
@@ -523,7 +520,7 @@ def bigsection(self, title, *args):
523520
524521 def preformat (self , text ):
525522 """Format literal preformatted text."""
526- text = self . escape (text .expandtabs ())
523+ text = html_escape (text .expandtabs (), quote = False )
527524 return replace (text , '\n \n ' , '\n \n ' , '\n \n ' , '\n \n ' ,
528525 ' ' , ' ' , '\n ' , '<br>\n ' )
529526
@@ -582,7 +579,7 @@ def filelink(self, url, path):
582579 def markup (self , text , escape = None , funcs = {}, classes = {}, methods = {}):
583580 """Mark up some plain text, given a context of symbols to look for.
584581 Each context dictionary maps object names to anchor names."""
585- escape = escape or self . escape
582+ escape = escape or html_escape
586583 results = []
587584 here = 0
588585 pattern = re .compile (r'\b((http|ftp)://\S+[\w/]|'
@@ -667,9 +664,9 @@ def docmodule(self, object, name=None, mod=None, *ignored):
667664 version = str (object .__version__ )
668665 if version [:11 ] == '$' + 'Revision: ' and version [- 1 :] == '$' :
669666 version = version [11 :- 1 ].strip ()
670- info .append ('version %s' % self . escape (version ))
667+ info .append ('version %s' % html_escape (version ))
671668 if hasattr (object , '__date__' ):
672- info .append (self . escape (str (object .__date__ )))
669+ info .append (html_escape (str (object .__date__ )))
673670 if info :
674671 head = head + ' (%s)' % ', ' .join (info )
675672 docloc = self .getdocloc (object )
@@ -2072,6 +2069,11 @@ def showsymbol(self, symbol):
20722069 topic , _ , xrefs = target .partition (' ' )
20732070 self .showtopic (topic , xrefs )
20742071
2072+ def _getsymbol (self , symbol ):
2073+ target = self .symbols [symbol ]
2074+ topic , _ , xrefs = target .partition (' ' )
2075+ return self ._gettopic (topic , xrefs )
2076+
20752077 def listmodules (self , key = '' ):
20762078 if key :
20772079 self .output .write ('''
@@ -2237,6 +2239,7 @@ def _start_server(urlhandler, hostname, port):
22372239 import email .message
22382240 import select
22392241 import threading
2242+ from urllib .parse import unquote
22402243
22412244 class DocHandler (http .server .BaseHTTPRequestHandler ):
22422245
@@ -2354,13 +2357,14 @@ def page(self, title, contents):
23542357</body></html>''' % (title , css_link , html_navbar (), contents )
23552358
23562359 def filelink (self , url , path ):
2357- return '<a href="getfile?key=%s">%s</a>' % (url , path )
2360+ return ('<a href="getfile?key=%s">%s</a>' %
2361+ (html_escape (url ), html_escape (path )))
23582362
23592363
23602364 html = _HTMLDoc ()
23612365
23622366 def html_navbar ():
2363- version = html . escape ("%s [%s, %s]" % (platform .python_version (),
2367+ version = html_escape ("%s [%s, %s]" % (platform .python_version (),
23642368 platform .python_build ()[0 ],
23652369 platform .python_compiler ()))
23662370 return """
@@ -2372,6 +2376,7 @@ def html_navbar():
23722376 <a href="index.html">Module Index</a>
23732377 : <a href="topics.html">Topics</a>
23742378 : <a href="keywords.html">Keywords</a>
2379+ : <a href="symbols.html">Symbols</a>
23752380 </div>
23762381 <div>
23772382 <form action="get" style='display:inline;'>
@@ -2384,7 +2389,7 @@ def html_navbar():
23842389 </form>
23852390 </div>
23862391 </div>
2387- """ % (version , html . escape (platform .platform (terse = True )))
2392+ """ % (version , html_escape (platform .platform (terse = True )))
23882393
23892394 def html_index ():
23902395 """Module Index page."""
@@ -2445,7 +2450,7 @@ def html_getfile(path):
24452450 """Get and display a source file listing safely."""
24462451 path = urllib .parse .unquote (path )
24472452 with tokenize .open (path ) as fp :
2448- lines = html . escape (fp .read ())
2453+ lines = html_escape (fp .read ())
24492454 body = '<pre>%s</pre>' % lines
24502455 heading = html .heading (
24512456 '<big><big><strong>File Listing</strong></big></big>' ,
@@ -2454,46 +2459,43 @@ def html_getfile(path):
24542459 'File: %s' % path , '#ffffff' , '#ee77aa' , body )
24552460 return 'getfile %s' % path , contents
24562461
2457- def html_topics ( ):
2462+ def html_topicindex ( title ):
24582463 """Index of topic texts available."""
24592464
24602465 def bltinlink (name ):
24612466 return '<a href="topic?key=%s">%s</a>' % (name , name )
24622467
24632468 heading = html .heading (
2464- '<big><big><strong>INDEX </strong></big></big>' ,
2469+ '<big><big><strong>%s </strong></big></big>' % title . upper () ,
24652470 '#ffffff' , '#7799ee' )
2466- names = sorted (Helper .topics .keys ())
24672471
2468- contents = html .multicolumn (names , bltinlink )
2469- contents = heading + html .bigsection (
2470- 'Topics' , '#ffffff' , '#ee77aa' , contents )
2471- return 'Topics' , contents
2472-
2473- def html_keywords ():
2474- """Index of keywords."""
2475- heading = html .heading (
2476- '<big><big><strong>INDEX</strong></big></big>' ,
2477- '#ffffff' , '#7799ee' )
2478- names = sorted (Helper .keywords .keys ())
2479-
2480- def bltinlink (name ):
2481- return '<a href="topic?key=%s">%s</a>' % (name , name )
2472+ keys = {
2473+ 'topics' : Helper .topics .keys ,
2474+ 'keywords' : Helper .keywords .keys ,
2475+ 'symbols' : Helper .symbols .keys ,
2476+ }
2477+ names = sorted (keys [title ]())
24822478
24832479 contents = html .multicolumn (names , bltinlink )
24842480 contents = heading + html .bigsection (
2485- 'Keywords' , '#ffffff' , '#ee77aa' , contents )
2486- return 'Keywords' , contents
2481+ title , '#ffffff' , '#ee77aa' , contents )
2482+ return title , contents
24872483
24882484 def html_topicpage (topic ):
24892485 """Topic or keyword help page."""
24902486 buf = io .StringIO ()
24912487 htmlhelp = Helper (buf , buf )
2492- contents , xrefs = htmlhelp ._gettopic (topic )
24932488 if topic in htmlhelp .keywords :
24942489 title = 'KEYWORD'
2495- else :
2490+ contents , xrefs = htmlhelp ._gettopic (topic )
2491+ elif topic in htmlhelp .topics :
24962492 title = 'TOPIC'
2493+ contents , xrefs = htmlhelp ._gettopic (topic )
2494+ elif topic in htmlhelp .symbols :
2495+ title = 'SYMBOL'
2496+ contents , xrefs = htmlhelp ._getsymbol (topic )
2497+ else :
2498+ raise ValueError ('could not find topic %s' % repr (topic ))
24972499 heading = html .heading (
24982500 '<big><big><strong>%s</strong></big></big>' % title ,
24992501 '#ffffff' , '#7799ee' )
@@ -2503,7 +2505,7 @@ def html_topicpage(topic):
25032505 xrefs = sorted (xrefs .split ())
25042506
25052507 def bltinlink (name ):
2506- return '<a href="topic?key=%s">%s</a>' % (name , name )
2508+ return '<a href="topic?key=%s">%s</a>' % (html_escape ( name ), html_escape ( name ) )
25072509
25082510 xrefs = html .multicolumn (xrefs , bltinlink )
25092511 xrefs = html .section ('Related help topics: ' ,
@@ -2523,7 +2525,7 @@ def html_error(url, exc):
25232525 heading = html .heading (
25242526 '<big><big><strong>Error</strong></big></big>' ,
25252527 '#ffffff' , '#7799ee' )
2526- contents = '<br>' .join (html . escape (line ) for line in
2528+ contents = '<br>' .join (html_escape (line ) for line in
25272529 format_exception_only (type (exc ), exc ))
25282530 contents = heading + html .bigsection (url , '#ffffff' , '#bb0000' ,
25292531 contents )
@@ -2537,23 +2539,21 @@ def get_html_page(url):
25372539 try :
25382540 if url in ("" , "index" ):
25392541 title , content = html_index ()
2540- elif url == "topics" :
2541- title , content = html_topics ()
2542- elif url == "keywords" :
2543- title , content = html_keywords ()
2544- elif '=' in url :
2545- op , _ , url = url .partition ('=' )
2546- if op == "search?key" :
2542+ elif url in ("topics" , "keywords" , "symbols" ):
2543+ title , content = html_topicindex (url )
2544+ elif '?key=' in url :
2545+ op , _ , url = url .partition ('?key=' )
2546+ if op == "search" :
25472547 title , content = html_search (url )
2548- elif op == "getfile?key " :
2548+ elif op == "getfile" :
25492549 title , content = html_getfile (url )
2550- elif op == "topic?key " :
2550+ elif op == "topic" :
25512551 # try topics first, then objects.
25522552 try :
25532553 title , content = html_topicpage (url )
25542554 except ValueError :
25552555 title , content = html_getobj (url )
2556- elif op == "get?key " :
2556+ elif op == "get" :
25572557 # try objects first, then topics.
25582558 if url in ("" , "index" ):
25592559 title , content = html_index ()
@@ -2747,5 +2747,6 @@ class BadUsage(Exception): pass
27472747 it names a directory, documentation is written for all the contents.
27482748""" .format (cmd = cmd , sep = os .sep ))
27492749
2750+
27502751if __name__ == '__main__' :
27512752 cli ()
0 commit comments