Index: Lib/pydoc_data/_pydoc.css =================================================================== --- Lib/pydoc_data/_pydoc.css (revision 87586) +++ Lib/pydoc_data/_pydoc.css (working copy) @@ -2,5 +2,233 @@ CSS file for pydoc. Contents of this file are subject to change without notice. +*/ + +/* Setting underline on hover only is less busy. */ +a:link{text-decoration: none;} +a:visited{text-decoration: none;} +a:hover, a:active{text-decoration: underline;} + +body{ + margin: 0; + padding: 0; + width: 100%; + font-size: 100%; /* Improves scaling consistency. */ + color: #000000; + background-color: #f8f8f8; +} + + +/* Contains header, navbar, and content and sets page padding. */ +#page{padding: 1em;} + + +/* Contains title, version, and navigation bar. */ +#page-header{width: 100%;} + + +/* Title */ +#page-title{ + display: inline-block; + margin: 0; + padding: 0 2em 0 0; + color: #5599cc; + background-color: #f8f8f8; +} + +/* Version info */ +#python_version{ + display: inline-block; + margin: 0; + padding: 0; + font-style: italic; + color: #888888; + background-color: #f8f8f8; +} + +/* Navigation bar. */ +#navbar{ + margin: 0; + padding: .2em; + color: #000000; + background-color: #f0f0f4; + border: 1px solid #888888; + overflow: auto; +} +#navbar li{ + margin: 0; + padding: .25em .5em .25em .5em; + list-style: none; + display: inline-block; +} +#navbar form{ + margin: 0; + padding: 0; + display: inline-block; +} +#navbar a{padding-right: 1em;} + + +/* Contains main content. */ +#page-content{ + margin-top: 1em; + overflow: auto; +} + +/* Content title. */ +#subject{ + margin: 0; + padding: .25em; + color: #ffffff; + background-color: #5599cc; +} + + +/* A content section that has a title. + + Combine these with a section type to set the + title colors. + + Use:
+
*/ +dl.section dt{ + font-weight: bold; + padding: .75em; +} +dl.section dd{ + padding: 1em; + color: #000000; + background-color: #f8f8f8; +} + +/* A section with no left vertical bar. */ +dl.subsection dt{ + font-weight: bold; + padding: .25em .25em .25em .5em; +} +dl.subsection dd{ + margin-left: 0; + padding: 1ex; + color: #000000; + background-color: #f8f8f8; +} + +/* Set title colors for section and sub-section. */ +dl.modules{ + color: #ffffff; + background-color: #aa55cc; +} + +dl.module{} /* These are not used yet. */ + +dl.classes{} + +dl.class{} + +dl.methods{} + +dl.method{} + +dl.functions{} + +dl.function{} + +dl.data{} + +ul.data-item li{} + +dl.file{ + color: #ffffff; + background-color: #009900; +} + +dl.topics{ + color: #ffffff; + background-color: #5f99cc; +} + +dl.topic{ + color: #ffffff; + background-color: #009900; +} + +dl.error{ + color: #ffffff; + background-color: #cc4444; +} + + + +/* index */ +ul.index-lines{padding-left: 9ex;} +ul.index-lines li{ + text-indent: -8ex; + list-style: none; +} + + +/* index aligned in columns */ +ul.index-columns{ + margin: 0; + padding: 0; + list-style: none; + overflow: auto; /* Limit floats. */ +} +ul.index-columns li{ + margin: 0 1em .2em 0; + width: 15em; + float: left; +} + + +/* links to modules and packages */ +span.module {} + +span.package { + font-style: italic; + color: #555; + background-color: #f8f8f8; +} +span.package a{ + font-style: normal; + font-weight: bold; + font-size: 98%; /* Bold effects floats without this. */ +} + + +pre.docstring{ + margin: 0; + padding: .25em; +} + + +pre.topic-info{ + margin: 0; + padding: .25em; + color: #000000; + background-color: #ffffff; + border: 1px solid #aaaaaa; +} + + +pre.python-code{ + margin: 0; + padding: .25em; + color: #000000; + background-color: #ffffff; + border: 1px solid #aaaaaa; + overflow: auto; +} +pre.python-code code{ + color: #000000; + background-color: #f4f4ff; /* Shows white space. */ +} + + +#page-footer p{ + color: #888888; + background-color: #f8f8f8; + text-align: right; +} 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 = ( - '' % - css_path) - return '''\ - -Python: %s - -%s%s -''' % (title, css_link, contents) + values = dict(title=title, + css_path="pydoc_data/_pydoc.css", + header=html_header(), + content=contents, + ) + template = \ +''' + + + PyDoc: {title} + + + + +
+ {header} + {content} +
+ + +''' + return template.format(**values) def filelink(self, url, path): return '%s' % (url, path) - html = _HTMLDoc() + def _index_section(self, title, items, css_class): + """Make an index sub-section""" + items = '\n
  • '.join(items) + values = dict(title = title, + items = items, + css_class=css_class, + ) + template = ('
    {title}
    ' + '
    ' + '
      ' + '
    • {items}
    • ' + '
    ' + '
    ' + ) + return template.format(**values) - def html_navbar(): - version = "%s [%s, %s]" % (platform.python_version(), - platform.python_build()[0], - platform.python_compiler()) - return """ -
    - Python %s
    %s

    -
    -
    -
    - Module Index - : Topics - : Keywords -
    -
    -
    - - -     -
    -
    - - -
    -
    -
    -
     
    - """ % (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") + template = ('
    ' + ' {section}' + '
    ' + ) + 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 = ('
    ' + ' {section}' + '
    ' + ) + return template.format(css_class=css_class, section=section) - def bltinlink(name): - return '%s' % (name, name) + html = _HTMLDoc() - heading = html.heading( - 'Index of Modules', - '#ffffff', '#7799ee') - names = [name for name in sys.builtin_module_names - if name != '__main__'] - contents = html.multicolumn(names, bltinlink) - contents = [heading, '

    ' + 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 = \ +""" +

    +""" + return template.format(**values) - seen = {} + def html_modules(): + """Module Index page.""" + link_list = ['%s' % (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 = ('' + '{name} (package)') + else: + template = ('' + '{name}') + link = template.format(name=name) + links.append(link) + contents.append(html.index_columns(dir, + links, css_class='section modules')) + content =''.join(contents) + template = ('
    ' + '

    Index of Modules

    ' + ' {content}' + '
    ' + '' + ) + return 'Index of Modules', template.format(content=content) - contents.append( - '

    pydoc by Ka-Ping Yee' - '<ping@lfw.org>') - 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 = ['%s%s' % (name, name, desc) + for name, desc in search_result] + content = html.index_lines('key = %s' % key, link_list, + css_class='section modules') + template = ('

    ' + '

    Search Results

    ' + ' {content}' + '
    ' + ) + return 'Search Results', template.format(content=content) - # format page - def bltinlink(name): - return '%s' % (name, name) - - results = [] - heading = html.heading( - 'Search Results', - '#ffffff', '#7799ee') - for name, desc in search_result: - results.append(bltinlink(name) + desc) - contents = heading + html.bigsection( - 'key = %s' % key, '#ffffff', '#ee77aa', '
    '.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 = '
    %s
    ' % lines - heading = html.heading( - 'File Listing', - '#ffffff', '#7799ee') - contents = heading + html.bigsection( - 'File: %s' % path, '#ffffff', '#ee77aa', body) - return 'getfile %s' % path, contents + title = 'getfile %s' % path.replace('%20', ' ') + template = ('
    ' + '

    File Listing

    ' + '
    ' + '
    File: {path}
    ' + '
    {lines}
    ' + '
    ' + '
    ' + '
    ' + ) + return title, template.format(path=path, lines=lines) def html_topics(): """Index of topic texts available.""" + link_list = ['%s' % (name, name) + for name in sorted(Helper.topics.keys())] + content = html.index_columns('Topics', link_list, + css_class="section topics") + template = ('
    ' + '

    Index

    ' + ' {content}' + '
    ' + ) + return 'Topics', template.format(content=content) - def bltinlink(name): - return '%s' % (name, name) - - heading = html.heading( - 'INDEX', - '#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( - 'INDEX', - '#ffffff', '#7799ee') - names = sorted(Helper.keywords.keys()) + link_list = ['%s' % (name, name) + for name in sorted(Helper.keywords.keys())] + content = html.index_columns('Keywords', link_list, + css_class="section topics") + template = ('
    ' + '

    Index

    ' + ' {content}' + '
    ' + ) + return 'Keywords', template.format(content=content) - def bltinlink(name): - return '%s' % (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( - '%s' % title, - '#ffffff', '#7799ee') - contents = '
    %s
    ' % contents - contents = html.bigsection(topic , '#ffffff','#ee77aa', contents) - xrefs = sorted(xrefs.split()) + title = 'Topic' + text = html.markup(contents) + link_list = ['%s' % (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, + ) + template = ('
    ' + '

    {title}

    ' + '
    ' + '
    {topic}
    ' + '
    {text}
    ' + '
    ' + ' {xrefs}' + '
    ' + ) + return '%s %s' % (title, topic), template.format(**values) - def bltinlink(name): - return '%s' % (name, name) + def html_error(exc, url): + values = dict( + title = url, + exc = repr(exc), + err = str(exc), + ) + template = ('
    ' + '

    Error

    ' + '
    ' + '
    {title}
    ' + '
    ' + '

    {exc}' + '

    {err}' + '

    ' + '
    ' + '
    ' + ) + 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( - 'Error', - '#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 = ('
    %s
    ' % + 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': Index: Lib/test/test_pydoc.py =================================================================== --- Lib/test/test_pydoc.py (revision 87586) +++ Lib/test/test_pydoc.py (working copy) @@ -419,30 +419,27 @@ """Tests for pydoc._url_handler""" def test_content_type_err(self): - err = 'Error: unknown content type ' f = pydoc._url_handler - result = f("", "") - self.assertEqual(result, err + "''") - result = f("", "foobar") - self.assertEqual(result, err + "'foobar'") + self.assertRaises(ValueError, f, "", "") + self.assertRaises(ValueError, f, "", "foobar") def test_url_requests(self): # Test for the correct title in the html pages returned. # This tests the different parts of the URL handler without # getting too picky about the exact html. requests = [ - ("", "Python: Index of Modules"), - ("get?key=", "Python: Index of Modules"), - ("index", "Python: Index of Modules"), - ("topics", "Python: Topics"), - ("keywords", "Python: Keywords"), - ("pydoc", "Python: module pydoc"), - ("get?key=pydoc", "Python: module pydoc"), - ("search?key=pydoc", "Python: Search Results"), - ("def", "Python: KEYWORD def"), - ("STRINGS", "Python: TOPIC STRINGS"), - ("foobar", "Python: Error"), - ("getfile?key=foobar", "Python: Read Error"), + ("", "PyDoc: Index of Modules"), + ("get?key=", "PyDoc: Index of Modules"), + ("index", "PyDoc: Index of Modules"), + ("topics", "PyDoc: Topics"), + ("keywords", "PyDoc: Keywords"), + ("pydoc", "PyDoc: module pydoc"), + ("get?key=pydoc", "PyDoc: module pydoc"), + ("search?key=pydoc", "PyDoc: Search Results"), + ("def", "PyDoc: Keyword def"), + ("STRINGS", "PyDoc: Topic STRINGS"), + ("foobar", "PyDoc: Error - foobar"), + ("getfile?key=foobar", "PyDoc: Error - getfile?key=foobar"), ] for url, title in requests: @@ -451,7 +448,7 @@ self.assertEqual(result, title) path = string.__file__ - title = "Python: getfile " + path + title = "PyDoc: getfile " + path url = "getfile?key=" + path text = pydoc._url_handler(url, "text/html") result = get_html_title(text)