| Index: Lib/pydoc.py |
| =================================================================== |
| --- Lib/pydoc.py (revision 87586) |
| +++ Lib/pydoc.py (working copy) |
| @@ -2471,234 +2471,299 @@ |
| def page(self, title, contents): |
| """Format an HTML page.""" |
| - css_path = "pydoc_data/_pydoc.css" |
| - css_link = ( |
| - '<link rel="stylesheet" type="text/css" href="%s">' % |
| - css_path) |
| - return '''\ |
| -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> |
| -<html><head><title>Python: %s</title> |
| -<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
| -%s</head><body bgcolor="#f0f0f8">%s |
| -</body></html>''' % (title, css_link, contents) |
| + values = dict(title=title, |
| + css_path="pydoc_data/_pydoc.css", |
| + header=html_header(), |
| + content=contents, |
| + ) |
| + template = \ |
| +'''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" |
| + "http://www.w3.org/TR/html4/strict.dtd"> |
| +<html> |
| + <head> |
| + <title>PyDoc: {title}</title> |
| + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
| + <link rel="stylesheet" type="text/css" href="{css_path}"> |
| + </head> |
| + <body> |
| + <div id=page> |
| + {header} |
| + {content} |
| + </div> |
| + </body> |
| +</html> |
| +''' |
| + return template.format(**values) |
| def filelink(self, url, path): |
| return '<a href="getfile?key=%s">%s</a>' % (url, path) |
| - html = _HTMLDoc() |
| + def _index_section(self, title, items, css_class): |
| + """Make an index sub-section""" |
| + items = '</li>\n<li>'.join(items) |
| + values = dict(title = title, |
| + items = items, |
|
ezio.melotti
2011/03/11 23:13:43
The spaces around the = can go.
|
| + css_class=css_class, |
| + ) |
|
ezio.melotti
2011/03/11 23:13:43
The ) should be closed on the previous line.
eric.araujo
2011/03/11 23:35:54
That’s done on purpose by Ron so that any future a
ezio.melotti
2011/03/12 14:35:09
I don't think having one more line is a big deal.
|
| + template = (' <dt>{title}</dt>' |
| + ' <dd>' |
| + ' <ul class="{css_class}">' |
| + ' <li>{items}</li>' |
| + ' </ul>' |
| + ' </dd>' |
|
ezio.melotti
2011/03/11 23:13:43
It's better to add a \n at the end of the line or
|
| + ) |
|
ezio.melotti
2011/03/11 23:13:43
The ) should be closed on the previous line.
|
| + return template.format(**values) |
| - def html_navbar(): |
| - version = "%s [%s, %s]" % (platform.python_version(), |
| - platform.python_build()[0], |
| - platform.python_compiler()) |
| - return """ |
| - <div style='float:left'> |
| - Python %s<br>%s<br><br> |
| - </div> |
| - <div style='float:right'> |
| - <div style='text-align:center'> |
| - <a href="index.html">Module Index</a> |
| - : <a href="topics.html">Topics</a> |
| - : <a href="keywords.html">Keywords</a> |
| - </div> |
| - <div> |
| - <form action="get" style='float:left'> |
| - <input type=text name=key size=15> |
| - <input type=submit value="Get"> |
| - |
| - </form> |
| - <form action="search" style='float:right'> |
| - <input type=text name=key size=15> |
| - <input type=submit value="Search"> |
| - </form> |
| - </div> |
| - </div> |
| - <div clear='all'> </div> |
| - """ % (version, platform.platform(terse=True)) |
| + def index_columns(self, title, items, css_class): |
| + """Create a index section with columns.""" |
| + section = html._index_section(title, items, |
| + css_class="index-columns") |
|
ezio.melotti
2011/03/11 23:13:43
css_class should be indented under title.
|
| + template = ('<dl class="{css_class}">' |
| + ' {section}' |
| + '</dl>' |
| + ) |
|
ezio.melotti
2011/03/11 23:13:43
See previous comments about \n and the ).
|
| + return template.format(css_class=css_class, section=section) |
| - def html_index(): |
| - """Module Index page.""" |
| + def index_lines(self, title, items, css_class): |
| + """Create an index section with line.""" |
| + section = html._index_section(title, items, |
| + css_class="index-lines") |
| + template = ('<dl class="{css_class}">' |
| + ' {section}' |
| + '</dl>' |
| + ) |
| + return template.format(css_class=css_class, section=section) |
|
ezio.melotti
2011/03/11 23:13:43
See previous comments.
Also this function is very
|
| - def bltinlink(name): |
| - return '<a href="%s.html">%s</a>' % (name, name) |
| + html = _HTMLDoc() |
| - heading = html.heading( |
| - '<big><big><strong>Index of Modules</strong></big></big>', |
| - '#ffffff', '#7799ee') |
| - names = [name for name in sys.builtin_module_names |
| - if name != '__main__'] |
| - contents = html.multicolumn(names, bltinlink) |
| - contents = [heading, '<p>' + html.bigsection( |
| - 'Built-in Modules', '#ffffff', '#ee77aa', contents)] |
| + def html_header(): |
| + values = dict(version=platform.python_version(), |
| + build=platform.python_build()[0], |
| + compiler=platform.python_compiler(), |
| + platform=platform.platform(terse=True), |
| + ) |
| + template = \ |
| +""" |
| +<div id="page-header"> |
| + <h1 id="page-title">PyDoc</h1> |
| + <p id="python_version"> |
| + Python {version} - [{build}, {compiler}, {platform}] |
|
ezio.melotti
2011/03/11 23:13:43
</p>
|
| + <ul id="navbar"> |
| + <li><form action="get"><div> |
| + <input name="key" size="15" type="text"> |
| + <input value="Get" type="submit"> |
| + </div></form></li> |
| + <li><form action="search"><div> |
| + <input name="key" size="15" type="text"> |
| + <input value="Search" type="submit"> |
| + </div></form></li> |
| + <li> |
| + <a href="index.html">modules</a> |
| + <a href="keywords.html">keywords</a> |
| + <a href="topics.html">topics</a> |
| + </li> |
| + </ul> |
| +</div> <!-- end header --> |
| +""" |
| + return template.format(**values) |
| - seen = {} |
| + def html_modules(): |
| + """Module Index page.""" |
| + link_list = ['<a href="%s.html">%s</a>' % (name, name) |
| + for name in sys.builtin_module_names |
| + if name != '__main__'] |
| + contents = [html.index_columns('Built-in modules', link_list, |
| + css_class='section modules')] |
| + shadowed = set() |
| for dir in sys.path: |
| - contents.append(html.index(dir, seen)) |
| + modules = [] |
| + for importer, name, ispkg in pkgutil.iter_modules([dir]): |
| + if name not in shadowed: |
| + modules.append((name, ispkg)) |
| + shadowed.add(name) |
| + modules.sort() |
| + links = [] |
| + for name, ispkg in modules: |
| + if ispkg: |
| + template = ('<span class="package"><a href="{name}.html">' |
| + '{name}</a> (package)</span>') |
| + else: |
| + template = ('<a class="module" href="{name}.html">' |
| + '{name}</a>') |
|
ezio.melotti
2011/03/11 23:13:43
I don't like too much the fact that the packages h
eric.araujo
2011/03/11 23:35:54
Why don’t you like it?
ezio.melotti
2011/03/12 14:35:09
Because it's not symmetric, if I want to parse the
|
| + link = template.format(name=name) |
| + links.append(link) |
| + contents.append(html.index_columns(dir, |
| + links, css_class='section modules')) |
| + content =''.join(contents) |
|
ezio.melotti
2011/03/11 23:13:43
Missing space after the =.
|
| + template = ('<div id="page-content">' |
| + ' <h2 id="subject">Index of Modules</h2>' |
| + ' {content}' |
| + '</div>' |
| + '<div id="page-footer">' |
| + ' <p>PyDoc by Ka-Ping Yee<ping@lfw.org>' |
| + '</div>' |
| + ) |
|
ezio.melotti
2011/03/11 23:13:43
\n and ).
There are also other occurrences later.
|
| + return 'Index of Modules', template.format(content=content) |
| - contents.append( |
| - '<p align=right><font color="#909090" face="helvetica,' |
| - 'arial"><strong>pydoc</strong> by Ka-Ping Yee' |
| - '<ping@lfw.org></font>') |
| - return 'Index of Modules', ''.join(contents) |
| - |
| def html_search(key): |
| """Search results page.""" |
| # scan for modules |
| search_result = [] |
| - |
| def callback(path, modname, desc): |
| if modname[-9:] == '.__init__': |
| modname = modname[:-9] + ' (package)' |
| - search_result.append((modname, desc and '- ' + desc)) |
| - |
| + search_result.append((modname, desc and ' - ' + desc)) |
| with warnings.catch_warnings(): |
| warnings.filterwarnings('ignore') # ignore problems during import |
| ModuleScanner().run(callback, key) |
| + link_list = ['<a href="%s.html">%s</a>%s' % (name, name, desc) |
| + for name, desc in search_result] |
| + content = html.index_lines('key = %s' % key, link_list, |
| + css_class='section modules') |
| + template = ('<div id="page-content">' |
| + ' <h2 id="subject">Search Results</h2>' |
| + ' {content}' |
| + '</div>' |
| + ) |
| + return 'Search Results', template.format(content=content) |
| - # format page |
| - def bltinlink(name): |
| - return '<a href="%s.html">%s</a>' % (name, name) |
| - |
| - results = [] |
| - heading = html.heading( |
| - '<big><big><strong>Search Results</strong></big></big>', |
| - '#ffffff', '#7799ee') |
| - for name, desc in search_result: |
| - results.append(bltinlink(name) + desc) |
| - contents = heading + html.bigsection( |
| - 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results)) |
| - return 'Search Results', contents |
| - |
| def html_getfile(path): |
| """Get and display a source file listing safely.""" |
| - path = path.replace('%20', ' ') |
| with open(path, 'r') as fp: |
| lines = html.escape(fp.read()) |
| - body = '<pre>%s</pre>' % lines |
| - heading = html.heading( |
| - '<big><big><strong>File Listing</strong></big></big>', |
| - '#ffffff', '#7799ee') |
| - contents = heading + html.bigsection( |
| - 'File: %s' % path, '#ffffff', '#ee77aa', body) |
| - return 'getfile %s' % path, contents |
| + title = 'getfile %s' % path.replace('%20', ' ') |
|
ezio.melotti
2011/03/11 23:13:43
urllib.unquote()?
|
| + template = ('<div id="page-content">' |
| + ' <h2 id="subject">File Listing</h2>' |
| + ' <dl class="section file">' |
| + ' <dt>File: {path}</dt>' |
| + ' <dd><pre class="python-code"><code' |
| + ' >{lines}</code></pre>' |
| + ' </dd>' |
| + ' </dl>' |
| + '</div>' |
| + ) |
| + return title, template.format(path=path, lines=lines) |
| def html_topics(): |
| """Index of topic texts available.""" |
| + link_list = ['<a href="%s.html">%s</a>' % (name, name) |
| + for name in sorted(Helper.topics.keys())] |
| + content = html.index_columns('Topics', link_list, |
| + css_class="section topics") |
| + template = ('<div id="page-content">' |
| + ' <h2 id="subject">Index</h2>' |
| + ' {content}' |
| + '</div>' |
| + ) |
| + return 'Topics', template.format(content=content) |
| - def bltinlink(name): |
| - return '<a href="%s.html">%s</a>' % (name, name) |
| - |
| - heading = html.heading( |
| - '<big><big><strong>INDEX</strong></big></big>', |
| - '#ffffff', '#7799ee') |
| - names = sorted(Helper.topics.keys()) |
| - |
| - 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( |
| - '<big><big><strong>INDEX</strong></big></big>', |
| - '#ffffff', '#7799ee') |
| - names = sorted(Helper.keywords.keys()) |
| + link_list = ['<a href="%s.html">%s</a>' % (name, name) |
| + for name in sorted(Helper.keywords.keys())] |
| + content = html.index_columns('Keywords', link_list, |
| + css_class="section topics") |
| + template = ('<div id="page-content">' |
| + ' <h2 id="subject">Index</h2>' |
| + ' {content}' |
| + '</div>' |
| + ) |
| + return 'Keywords', template.format(content=content) |
| - def bltinlink(name): |
| - return '<a href="%s.html">%s</a>' % (name, name) |
| - contents = html.multicolumn(names, bltinlink) |
| - contents = heading + html.bigsection( |
| - 'Keywords', '#ffffff', '#ee77aa', contents) |
| - return 'Keywords', 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' |
| + title = 'Keyword' |
| else: |
| - title = 'TOPIC' |
| - heading = html.heading( |
| - '<big><big><strong>%s</strong></big></big>' % title, |
| - '#ffffff', '#7799ee') |
| - contents = '<pre>%s</pre>' % contents |
| - contents = html.bigsection(topic , '#ffffff','#ee77aa', contents) |
| - xrefs = sorted(xrefs.split()) |
| + title = 'Topic' |
| + text = html.markup(contents) |
| + link_list = ['<a href="%s.html">%s</a>' % (name, name) |
| + for name in sorted(xrefs.split())] |
| + xrefs = html.index_columns('Related help Topics', link_list, |
| + css_class="section topics") |
| + values = dict( |
| + title=title, |
| + topic=topic, |
| + text=text, |
| + xrefs=xrefs, |
| + ) |
|
ezio.melotti
2011/03/11 23:13:43
I use either:
values = dict(foo=bar,
eric.araujo
2011/03/11 23:35:54
I don’t see why you said that: The code uses the s
ezio.melotti
2011/03/12 14:35:09
In the second style the ) is closed under the 'v'
|
| + template = ('<div id="page-content">' |
| + ' <h2 id="subject">{title}</h2>' |
| + ' <dl class="section topic">' |
| + ' <dt>{topic}</dt>' |
| + ' <dd><pre class="topic-info">{text}</pre></dd>' |
| + ' </dl>' |
| + ' {xrefs}' |
| + '</div>' |
| + ) |
| + return '%s %s' % (title, topic), template.format(**values) |
| - def bltinlink(name): |
| - return '<a href="%s.html">%s</a>' % (name, name) |
| + def html_error(exc, url): |
| + values = dict( |
| + title = url, |
| + exc = repr(exc), |
| + err = str(exc), |
|
ezio.melotti
2011/03/11 23:13:43
You can remove the spaces around the =, if you wan
eric.araujo
2011/03/11 23:35:54
This contradicts a previous comment you made :) E
ezio.melotti
2011/03/12 14:35:09
I don't use spaces myself, but it's ok for me if s
|
| + ) |
| + template = ('<div id="page-content">' |
| + ' <h2 id="subject">Error</h2>' |
| + ' <dl class="section error">' |
| + ' <dt>{title}</dt>' |
| + ' <dd>' |
| + ' <p>{exc}' |
| + ' <p>{err}' |
|
ezio.melotti
2011/03/11 23:13:43
It's always better to close the </p>, even if it's
eric.araujo
2011/03/11 23:35:54
I agree, it’s more readable to close elements.
|
| + ' </dd>' |
| + ' </dl>' |
| + '</div>' |
| + ) |
| + return "Error - " + url, template.format(**values) |
| - xrefs = html.multicolumn(xrefs, bltinlink) |
| - xrefs = html.section('Related help topics: ', |
| - '#ffffff', '#ee77aa', xrefs) |
| - return ('%s %s' % (title, topic), |
| - ''.join((heading, contents, xrefs))) |
| - |
| - def html_error(url): |
| - heading = html.heading( |
| - '<big><big><strong>Error</strong></big></big>', |
| - '#ffffff', '#ee0000') |
| - return heading + url |
| - |
| def get_html_page(url): |
| """Generate an HTML page for url.""" |
| - if url.endswith('.html'): |
| - url = url[:-5] |
| - if url.startswith('/'): |
| - url = url[1:] |
| - if url.startswith("get?key="): |
| - url = url[8:] |
| - title = url |
| - contents = '' |
| - if url in ("", ".", "index"): |
| - title, contents = html_index() |
| - elif url == "topics": |
| - title, contents = html_topics() |
| - elif url == "keywords": |
| - title, contents = html_keywords() |
| - elif url.startswith("search?key="): |
| - title, contents = html_search(url[11:]) |
| - elif url.startswith("getfile?key="): |
| - url = url[12:] |
| - try: |
| - title, contents = html_getfile(url) |
| - except IOError: |
| - contents = html_error('could not read file %r' % url) |
| - title = 'Read Error' |
| - else: |
| - obj = None |
| - try: |
| + try: |
| + if url.endswith('.html'): |
| + url = url[:-5] |
| + if url.startswith('/'): |
| + url = url[1:] |
| + if url.startswith("get?key="): |
| + url = url[8:] |
| + if url in ("", ".", "index"): |
| + title, content = html_modules() |
| + elif url == "topics": |
| + title, content = html_topics() |
| + elif url == "keywords": |
| + title, content = html_keywords() |
| + elif url.startswith("search?key="): |
| + title, content = html_search(url[11:]) |
| + elif url.startswith("getfile?key="): |
| + path = url[12:] |
| + title, content = html_getfile(path) |
| + elif url in Helper.keywords or url in Helper.topics: |
| + title, content = html_topicpage(url) |
| + else: |
| obj = locate(url, forceload=1) |
| - except ErrorDuringImport as value: |
| - contents = html.escape(str(value)) |
| - if obj: |
| + if obj is None and url != "None": |
| + raise ValueError('could not find "%s"' % url) |
| title = describe(obj) |
| - contents = html.document(obj, url) |
| - elif url in Helper.keywords or url in Helper.topics: |
| - title, contents = html_topicpage(url) |
| - else: |
| - contents = html_error( |
| - 'no Python documentation found for %r' % url) |
| - title = 'Error' |
| - return html.page(title, html_navbar() + contents) |
| + content = ('<div id="page-content">%s</div>' % |
| + html.document(obj, url)) |
| + except Exception as exc: |
| + title, content = html_error(exc, url) |
| + return html.page(title, content) |
| if url.startswith('/'): |
| url = url[1:] |
| if content_type == 'text/css': |
| path_here = os.path.dirname(os.path.realpath(__file__)) |
| - try: |
| - with open(os.path.join(path_here, url)) as fp: |
| - return ''.join(fp.readlines()) |
| - except IOError: |
| - return 'Error: can not open css file %r' % url |
| + with open(os.path.join(path_here, url)) as fp: |
| + return ''.join(fp.readlines()) |
| elif content_type == 'text/html': |
| return get_html_page(url) |
| - return 'Error: unknown content type %r' % content_type |
| + raise ValueError('unknown content type: (%r, %r)' % (content_type, url)) |
| def browse(port=0, *, open_browser=True): |
| @@ -2720,6 +2785,8 @@ |
| print('Server ready at', serverthread.url) |
| print(server_help_msg) |
| while serverthread.serving: |
| + if serverthread.error: |
| + print(serverthread.error) |
| cmd = input('server> ') |
| cmd = cmd.lower() |
| if cmd == 'q': |