Index: Lib/pydoc.py =================================================================== --- Lib/pydoc.py (revision 88122) +++ Lib/pydoc.py (working copy) @@ -70,7 +70,7 @@ import warnings from collections import deque from reprlib import Repr -from traceback import extract_tb +from traceback import extract_tb, format_exception_only # --------------------------------------------------------- common routines @@ -1883,6 +1883,7 @@ """Return unbuffered tuple of (topic, xrefs). If an error occurs, topic is the error message, and xrefs is ''. + This function duplicates the showtopic method but returns its result directly so it can be formatted for display in an html page. """ @@ -1895,14 +1896,11 @@ ''' , '') target = self.topics.get(topic, self.keywords.get(topic)) if not target: - return 'no documentation found for %r' % topic, '' + raise ValueError('could not find object') if isinstance(target, str): return self._gettopic(target, more_xrefs) label, xrefs = target - try: - doc = pydoc_data.topics.topics[label] - except KeyError: - return 'no documentation found for %r' % topic, '' + doc = pydoc_data.topics.topics[label] if more_xrefs: xrefs = (xrefs or '') + ' ' + more_xrefs return doc, xrefs @@ -2479,7 +2477,7 @@ css_path) return '''\ -Python: %s +PyDoc: %s %s%s ''' % (title, css_link, contents) @@ -2495,8 +2493,9 @@ platform.python_build()[0], platform.python_compiler()) return """ +
- Python %s
%s

+ Python %s
%s
@@ -2504,11 +2503,10 @@ : Topics : Keywords
-
-
+
+ -    
@@ -2516,7 +2514,7 @@
-
 
+
""" % (version, platform.platform(terse=True)) def html_index(): @@ -2589,7 +2587,7 @@ """Index of topic texts available.""" def bltinlink(name): - return '%s' % (name, name) + return '%s' % (name, name) heading = html.heading( 'INDEX', @@ -2609,7 +2607,7 @@ names = sorted(Helper.keywords.keys()) def bltinlink(name): - return '%s' % (name, name) + return '%s' % (name, name) contents = html.multicolumn(names, bltinlink) contents = heading + html.bigsection( @@ -2633,7 +2631,7 @@ xrefs = sorted(xrefs.split()) def bltinlink(name): - return '%s' % (name, name) + return '%s' % (name, name) xrefs = html.multicolumn(xrefs, bltinlink) xrefs = html.section('Related help topics: ', @@ -2641,66 +2639,72 @@ return ('%s %s' % (title, topic), ''.join((heading, contents, xrefs))) - def html_error(url): + def html_getobj(url): + obj = locate(url, forceload=1) + if obj is None and url != 'None': + raise ValueError('could not find object') + title = describe(obj) + content = html.document(obj, url) + return title, content + + def html_error(url, exc): heading = html.heading( 'Error', - '#ffffff', '#ee0000') - return heading + url + '#ffffff', '#7799ee') + contents = '
'.join(format_exception_only(type(exc), exc)) + contents = heading + html.bigsection(url, '#ffffff', '#bb0000', + contents) + return "Error - %s" % url, contents def get_html_page(url): """Generate an HTML page for url.""" + complete_url = 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: - obj = locate(url, forceload=1) - except ErrorDuringImport as value: - contents = html.escape(str(value)) - if obj: - title = describe(obj) - contents = html.document(obj, url) - elif url in Helper.keywords or url in Helper.topics: - title, contents = html_topicpage(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": + title, content = html_search(url) + elif op == "getfile?key": + title, content = html_getfile(url) + elif op == "topic?key": + title, content = html_topicpage(url) + elif op == "get?key": + # try objects first, then topics. + if url in ("", "index"): + title, content = html_index() + else: + try: + title, content = html_getobj(url) + except ValueError: + title, content = html_topicpage(url) + else: + raise ValueError('bad pydoc url') else: - contents = html_error( - 'no Python documentation found for %r' % url) - title = 'Error' - return html.page(title, html_navbar() + contents) + title, content = html_getobj(url) + except Exception as exc: + # Catch any errors and display them in an error page. + title, content = html_error(complete_url, exc) + return html.page(title, html_navbar() + 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 + css_path = os.path.join(path_here, url) + with open(css_path) as fp: + return ''.join(fp.readlines()) elif content_type == 'text/html': return get_html_page(url) - return 'Error: unknown content type %r' % content_type + # Errors outside the url handler are caught by the server. + raise TypeError('unknown content type %r' % ([url, content_type])) def browse(port=0, *, open_browser=True): Index: Lib/test/test_pydoc.py =================================================================== --- Lib/test/test_pydoc.py (revision 88122) +++ 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(TypeError, f, 'A', '') + self.assertRaises(TypeError, f, 'B', '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"), + ("topic?key=def", "PyDoc: KEYWORD def"), + ("topic?key=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)