mirror of
https://github.com/python/cpython.git
synced 2026-02-05 17:35:34 +00:00
Merge 3c4ac40062 into b6d8aa436b
This commit is contained in:
commit
1c1ffbfebe
3 changed files with 71 additions and 46 deletions
114
Lib/pydoc.py
114
Lib/pydoc.py
|
|
@ -75,6 +75,7 @@ class or function within a module or module in a package. If the
|
|||
import warnings
|
||||
from annotationlib import Format
|
||||
from collections import deque
|
||||
from html import escape as html_escape
|
||||
from reprlib import Repr
|
||||
from traceback import format_exception_only
|
||||
|
||||
|
|
@ -552,7 +553,7 @@ def repr1(self, x, level):
|
|||
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)
|
||||
|
|
@ -560,18 +561,18 @@ def repr_string(self, x, level):
|
|||
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'<span class="repr">\1</span>',
|
||||
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
|
||||
|
||||
|
|
@ -633,7 +634,7 @@ def bigsection(self, title, *args):
|
|||
|
||||
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', '<br>\n')
|
||||
|
||||
|
|
@ -711,7 +712,7 @@ def filelink(self, url, path):
|
|||
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|https|ftp)://\S+[\w/]|'
|
||||
|
|
@ -794,9 +795,9 @@ def docmodule(self, object, name=None, mod=None, *ignored):
|
|||
if version := self._get_version(object):
|
||||
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)
|
||||
|
|
@ -2156,6 +2157,11 @@ def showsymbol(self, symbol):
|
|||
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('''
|
||||
|
|
@ -2321,6 +2327,7 @@ def _start_server(urlhandler, hostname, port):
|
|||
import email.message
|
||||
import select
|
||||
import threading
|
||||
from urllib.parse import unquote
|
||||
|
||||
class DocHandler(http.server.BaseHTTPRequestHandler):
|
||||
|
||||
|
|
@ -2440,11 +2447,14 @@ def page(self, title, contents):
|
|||
%s</head><body>%s<div style="clear:both;padding-top:.5em;">%s</div>
|
||||
</body></html>''' % (title, css_link, html_navbar(), contents)
|
||||
|
||||
def filelink(self, url, path):
|
||||
return ('<a href="getfile?key=%s">%s</a>' %
|
||||
(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 """
|
||||
|
|
@ -2456,6 +2466,7 @@ def html_navbar():
|
|||
<a href="index.html">Module Index</a>
|
||||
: <a href="topics.html">Topics</a>
|
||||
: <a href="keywords.html">Keywords</a>
|
||||
: <a href="symbols.html">Symbols</a>
|
||||
</div>
|
||||
<div>
|
||||
<form action="get" style='display:inline;'>
|
||||
|
|
@ -2468,7 +2479,7 @@ def html_navbar():
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
""" % (version, html.escape(platform.platform(terse=True)))
|
||||
""" % (version, html_escape(platform.platform(terse=True)))
|
||||
|
||||
def html_index():
|
||||
"""Module Index page."""
|
||||
|
|
@ -2524,7 +2535,20 @@ def bltinlink(name):
|
|||
'key = %s' % key, 'index', '<br>'.join(results))
|
||||
return 'Search Results', contents
|
||||
|
||||
def html_topics():
|
||||
def html_getfile(path):
|
||||
"""Get and display a source file listing safely."""
|
||||
path = urllib.parse.unquote(path)
|
||||
with tokenize.open(path) as fp:
|
||||
lines = html_escape(fp.read())
|
||||
body = '<pre>%s</pre>' % lines
|
||||
heading = html.heading(
|
||||
'<strong class="title">File Listing</strong>',
|
||||
)
|
||||
contents = heading + html.bigsection(
|
||||
'File: %s' % path, 'index', body)
|
||||
return 'getfile %s' % path, contents
|
||||
|
||||
def html_topicindex(title):
|
||||
"""Index of topic texts available."""
|
||||
|
||||
def bltinlink(name):
|
||||
|
|
@ -2533,51 +2557,48 @@ def bltinlink(name):
|
|||
heading = html.heading(
|
||||
'<strong class="title">INDEX</strong>',
|
||||
)
|
||||
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', 'index', contents)
|
||||
return 'Topics', contents
|
||||
|
||||
def html_keywords():
|
||||
"""Index of keywords."""
|
||||
heading = html.heading(
|
||||
'<strong class="title">INDEX</strong>',
|
||||
)
|
||||
names = sorted(Helper.keywords.keys())
|
||||
|
||||
def bltinlink(name):
|
||||
return '<a href="topic?key=%s">%s</a>' % (name, name)
|
||||
|
||||
contents = html.multicolumn(names, bltinlink)
|
||||
contents = heading + html.bigsection(
|
||||
'Keywords', 'index', contents)
|
||||
return 'Keywords', contents
|
||||
title.capitalize(), 'index', contents)
|
||||
return title.capitalize(), 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'
|
||||
else:
|
||||
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:
|
||||
raise ValueError(f'could not find topic {topic!r}')
|
||||
heading = html.heading(
|
||||
'<strong class="title">%s</strong>' % title,
|
||||
f'<strong class="title">{title}</strong>',
|
||||
)
|
||||
contents = '<pre>%s</pre>' % html.markup(contents)
|
||||
contents = f'<pre>{html.markup(contents)}</pre>'
|
||||
contents = html.bigsection(topic , 'index', contents)
|
||||
if xrefs:
|
||||
xrefs = sorted(xrefs.split())
|
||||
|
||||
def bltinlink(name):
|
||||
return '<a href="topic?key=%s">%s</a>' % (name, name)
|
||||
return f'<a href="topic?key={html_escape(name)}>{html_escape(name)}</a>'
|
||||
|
||||
xrefs = html.multicolumn(xrefs, bltinlink)
|
||||
xrefs = html.section('Related help topics: ', 'index', xrefs)
|
||||
return ('%s %s' % (title, topic),
|
||||
return (f'{title} {topic}',
|
||||
''.join((heading, contents, xrefs)))
|
||||
|
||||
def html_getobj(url):
|
||||
|
|
@ -2592,7 +2613,7 @@ def html_error(url, exc):
|
|||
heading = html.heading(
|
||||
'<strong class="title">Error</strong>',
|
||||
)
|
||||
contents = '<br>'.join(html.escape(line) for line in
|
||||
contents = '<br>'.join(html_escape(line) for line in
|
||||
format_exception_only(type(exc), exc))
|
||||
contents = heading + html.bigsection(url, 'error', contents)
|
||||
return "Error - %s" % url, contents
|
||||
|
|
@ -2605,21 +2626,21 @@ def get_html_page(url):
|
|||
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 == "topic?key":
|
||||
elif op == "getfile":
|
||||
title, content = html_getfile(url)
|
||||
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()
|
||||
|
|
@ -2814,5 +2835,6 @@ class BadUsage(Exception): pass
|
|||
it names a directory, documentation is written for all the contents.
|
||||
""".format(cmd=cmd, sep=os.sep))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
|
|
|
|||
|
|
@ -2128,6 +2128,7 @@ def test_url_requests(self):
|
|||
("index", "Pydoc: Index of Modules"),
|
||||
("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"),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
Add 'symbols' link to pydoc's html menu bar. Original patch by Ron Adam.
|
||||
Enhanced by Sanyam Khurana.
|
||||
Loading…
Add table
Add a link
Reference in a new issue