Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 #!/usr/bin/env python3 | 1 #!/usr/bin/env python3 |
2 """Generate Python documentation in HTML or text for interactive use. | 2 """Generate Python documentation in HTML or text for interactive use. |
3 | 3 |
4 In the Python interpreter, do "from pydoc import help" to provide online | 4 In the Python interpreter, do "from pydoc import help" to provide online |
5 help. Calling help(thing) on a Python object documents the object. | 5 help. Calling help(thing) on a Python object documents the object. |
6 | 6 |
7 Or, at the shell command line outside of Python: | 7 Or, at the shell command line outside of Python: |
8 | 8 |
9 Run "pydoc <name>" to show documentation on something. <name> may be | 9 Run "pydoc <name>" to show documentation on something. <name> may be |
10 the name of a function, module, package, or a dotted reference to a | 10 the name of a function, module, package, or a dotted reference to a |
(...skipping 23 matching lines...) Expand all Loading... | |
34 http://docs.python.org/X.Y/library/ | 34 http://docs.python.org/X.Y/library/ |
35 | 35 |
36 This can be overridden by setting the PYTHONDOCS environment variable | 36 This can be overridden by setting the PYTHONDOCS environment variable |
37 to a different URL or to a local directory containing the Library | 37 to a different URL or to a local directory containing the Library |
38 Reference Manual pages. | 38 Reference Manual pages. |
39 """ | 39 """ |
40 __all__ = ['help'] | 40 __all__ = ['help'] |
41 __author__ = "Ka-Ping Yee <ping@lfw.org>" | 41 __author__ = "Ka-Ping Yee <ping@lfw.org>" |
42 __date__ = "26 February 2001" | 42 __date__ = "26 February 2001" |
43 | 43 |
44 __version__ = "$Revision: 86504 $" | 44 __version__ = "$Revision: 86608 $" |
45 __credits__ = """Guido van Rossum, for an excellent programming language. | 45 __credits__ = """Guido van Rossum, for an excellent programming language. |
46 Tommy Burnette, the original creator of manpy. | 46 Tommy Burnette, the original creator of manpy. |
47 Paul Prescod, for all his work on onlinehelp. | 47 Paul Prescod, for all his work on onlinehelp. |
48 Richard Chamberlain, for the first implementation of textdoc. | 48 Richard Chamberlain, for the first implementation of textdoc. |
49 """ | 49 """ |
50 | 50 |
51 # Known bugs that can't be fixed here: | 51 # Known bugs that can't be fixed here: |
52 # - imp.load_module() cannot be prevented from clobbering existing | 52 # - imp.load_module() cannot be prevented from clobbering existing |
53 # loaded modules, so calling synopsis() on a binary module file | 53 # loaded modules, so calling synopsis() on a binary module file |
54 # changes the contents of any existing module with the same name. | 54 # changes the contents of any existing module with the same name. |
55 # - If the __file__ attribute on a module is a relative path and | 55 # - If the __file__ attribute on a module is a relative path and |
56 # the current directory is changed with os.chdir(), an incorrect | 56 # the current directory is changed with os.chdir(), an incorrect |
57 # path will be displayed. | 57 # path will be displayed. |
58 | 58 |
59 import sys | 59 import sys |
60 import imp | 60 import imp |
61 import os | 61 import os |
62 import re | 62 import re |
63 import inspect | 63 import inspect |
64 import builtins | 64 import builtins |
65 import pkgutil | 65 import pkgutil |
66 import time | 66 import time |
67 import warnings | 67 import warnings |
68 import platform | |
68 from reprlib import Repr | 69 from reprlib import Repr |
69 from traceback import extract_tb as _extract_tb | 70 from traceback import extract_tb as _extract_tb |
70 from collections import deque | 71 from collections import deque |
71 | 72 |
72 | 73 |
73 # --------------------------------------------------------- common routines | 74 # --------------------------------------------------------- common routines |
74 | 75 |
75 def pathdirs(): | 76 def pathdirs(): |
76 """Convert sys.path into a list of absolute, existing, unique paths.""" | 77 """Convert sys.path into a list of absolute, existing, unique paths.""" |
77 dirs = [] | 78 dirs = [] |
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
427 escape = _repr_instance.escape | 428 escape = _repr_instance.escape |
428 | 429 |
429 def page(self, title, contents): | 430 def page(self, title, contents): |
430 """Format an HTML page.""" | 431 """Format an HTML page.""" |
431 return '''\ | 432 return '''\ |
432 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> | 433 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> |
433 <html><head><title>Python: %s</title> | 434 <html><head><title>Python: %s</title> |
434 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | 435 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
435 </head><body bgcolor="#f0f0f8"> | 436 </head><body bgcolor="#f0f0f8"> |
436 %s | 437 %s |
437 </body></html>''' % (title, contents) | 438 </body></html>''' % (title, contents, css_path) |
ron3200
2010/11/21 06:48:24
remove css_path left over from previous edit.
| |
438 | 439 |
439 def heading(self, title, fgcol, bgcol, extras=''): | 440 def heading(self, title, fgcol, bgcol, extras=''): |
440 """Format a page heading.""" | 441 """Format a page heading.""" |
441 return ''' | 442 return ''' |
442 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading"> | 443 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading"> |
443 <tr bgcolor="%s"> | 444 <tr bgcolor="%s"> |
444 <td valign=bottom> <br> | 445 <td valign=bottom> <br> |
445 <font color="%s" face="helvetica, arial"> <br>%s</font></td | 446 <font color="%s" face="helvetica, arial"> <br>%s</font></td |
446 ><td align=right valign=bottom | 447 ><td align=right valign=bottom |
447 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table> | 448 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table> |
(...skipping 1116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1564 'class': ('class', 'CLASSES SPECIALMETHODS'), | 1565 'class': ('class', 'CLASSES SPECIALMETHODS'), |
1565 'continue': ('continue', 'while for'), | 1566 'continue': ('continue', 'while for'), |
1566 'def': ('function', ''), | 1567 'def': ('function', ''), |
1567 'del': ('del', 'BASICMETHODS'), | 1568 'del': ('del', 'BASICMETHODS'), |
1568 'elif': 'if', | 1569 'elif': 'if', |
1569 'else': ('else', 'while for'), | 1570 'else': ('else', 'while for'), |
1570 'except': 'try', | 1571 'except': 'try', |
1571 'finally': 'try', | 1572 'finally': 'try', |
1572 'for': ('for', 'break continue while'), | 1573 'for': ('for', 'break continue while'), |
1573 'from': 'import', | 1574 'from': 'import', |
1574 'global': ('global', 'NAMESPACES'), | 1575 'global': ('global', 'nonlocal NAMESPACES'), |
1575 'if': ('if', 'TRUTHVALUE'), | 1576 'if': ('if', 'TRUTHVALUE'), |
1576 'import': ('import', 'MODULES'), | 1577 'import': ('import', 'MODULES'), |
1577 'in': ('in', 'SEQUENCEMETHODS'), | 1578 'in': ('in', 'SEQUENCEMETHODS'), |
1578 'is': 'COMPARISON', | 1579 'is': 'COMPARISON', |
1579 'lambda': ('lambda', 'FUNCTIONS'), | 1580 'lambda': ('lambda', 'FUNCTIONS'), |
1581 'nonlocal': ('nonlocal', 'global NAMESPACES'), | |
1580 'not': 'BOOLEAN', | 1582 'not': 'BOOLEAN', |
1581 'or': 'BOOLEAN', | 1583 'or': 'BOOLEAN', |
1582 'pass': ('pass', ''), | 1584 'pass': ('pass', ''), |
1583 'raise': ('raise', 'EXCEPTIONS'), | 1585 'raise': ('raise', 'EXCEPTIONS'), |
1584 'return': ('return', 'FUNCTIONS'), | 1586 'return': ('return', 'FUNCTIONS'), |
1585 'try': ('try', 'EXCEPTIONS'), | 1587 'try': ('try', 'EXCEPTIONS'), |
1586 'while': ('while', 'break continue if TRUTHVALUE'), | 1588 'while': ('while', 'break continue if TRUTHVALUE'), |
1587 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'), | 1589 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'), |
1588 'yield': ('yield', ''), | 1590 'yield': ('yield', ''), |
1589 } | 1591 } |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1664 'NUMBERMETHODS CLASSES'), | 1666 'NUMBERMETHODS CLASSES'), |
1665 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'), | 1667 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'), |
1666 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'), | 1668 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'), |
1667 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'), | 1669 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'), |
1668 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS ' | 1670 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS ' |
1669 'SPECIALMETHODS'), | 1671 'SPECIALMETHODS'), |
1670 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'), | 1672 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'), |
1671 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT ' | 1673 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT ' |
1672 'SPECIALMETHODS'), | 1674 'SPECIALMETHODS'), |
1673 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'), | 1675 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'), |
1674 'NAMESPACES': ('naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'), | 1676 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEA TURES'), |
1675 'DYNAMICFEATURES': ('dynamic-features', ''), | 1677 'DYNAMICFEATURES': ('dynamic-features', ''), |
1676 'SCOPING': 'NAMESPACES', | 1678 'SCOPING': 'NAMESPACES', |
1677 'FRAMES': 'NAMESPACES', | 1679 'FRAMES': 'NAMESPACES', |
1678 'EXCEPTIONS': ('exceptions', 'try except finally raise'), | 1680 'EXCEPTIONS': ('exceptions', 'try except finally raise'), |
1679 'CONVERSIONS': ('conversions', ''), | 1681 'CONVERSIONS': ('conversions', ''), |
1680 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'), | 1682 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'), |
1681 'SPECIALIDENTIFIERS': ('id-classes', ''), | 1683 'SPECIALIDENTIFIERS': ('id-classes', ''), |
1682 'PRIVATENAMES': ('atom-identifiers', ''), | 1684 'PRIVATENAMES': ('atom-identifiers', ''), |
1683 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS ' | 1685 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS ' |
1684 'LISTLITERALS DICTIONARYLITERALS'), | 1686 'LISTLITERALS DICTIONARYLITERALS'), |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1869 This function duplicates the showtopic method but returns it's | 1871 This function duplicates the showtopic method but returns it's |
1870 result directly so it can be formatted for display in an html page. | 1872 result directly so it can be formatted for display in an html page. |
1871 """ | 1873 """ |
1872 try: | 1874 try: |
1873 import pydoc_data.topics | 1875 import pydoc_data.topics |
1874 except ImportError: | 1876 except ImportError: |
1875 return(''' | 1877 return(''' |
1876 Sorry, topic and keyword documentation is not available because the | 1878 Sorry, topic and keyword documentation is not available because the |
1877 module "pydoc_data.topics" could not be found. | 1879 module "pydoc_data.topics" could not be found. |
1878 ''' , '') | 1880 ''' , '') |
1879 return | |
ron3200
2010/11/18 23:02:57
Remove extra return.
ron3200
2010/11/19 00:23:48
Done.
| |
1880 target = self.topics.get(topic, self.keywords.get(topic)) | 1881 target = self.topics.get(topic, self.keywords.get(topic)) |
1881 if not target: | 1882 if not target: |
1882 return 'no documentation found for %s' % repr(topic), '' | 1883 return 'no documentation found for %s' % repr(topic), '' |
1883 if type(target) is type(''): | 1884 if type(target) is type(''): |
1884 return self._gettopic(target, more_xrefs) | 1885 return self._gettopic(target, more_xrefs) |
1885 label, xrefs = target | 1886 label, xrefs = target |
1886 try: | 1887 try: |
1887 doc = pydoc_data.topics.topics[label] | 1888 doc = pydoc_data.topics.topics[label] |
1888 except KeyError: | 1889 except KeyError: |
1889 return 'no documentation found for %s' % repr(topic), '' | 1890 return 'no documentation found for %s' % repr(topic), '' |
ron3200
2010/11/18 23:02:57
The showtopic() method above, also uses repr(topic
| |
1890 if more_xrefs: | 1891 if more_xrefs: |
1891 xrefs = (xrefs or '') + ' ' + more_xrefs | 1892 xrefs = (xrefs or '') + ' ' + more_xrefs |
1892 return doc, xrefs | 1893 return doc, xrefs |
1893 | 1894 |
1894 def showsymbol(self, symbol): | 1895 def showsymbol(self, symbol): |
1895 target = self.symbols[symbol] | 1896 target = self.symbols[symbol] |
1896 topic, _, xrefs = target.partition(' ') | 1897 topic, _, xrefs = target.partition(' ') |
1897 self.showtopic(topic, xrefs) | 1898 self.showtopic(topic, xrefs) |
1898 | 1899 |
1899 def listmodules(self, key=''): | 1900 def listmodules(self, key=''): |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1971 | 1972 |
1972 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror): | 1973 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror): |
1973 if self.quit: | 1974 if self.quit: |
1974 break | 1975 break |
1975 ················ | 1976 ················ |
1976 # XXX Skipping this file is a get-around for a bug | 1977 # XXX Skipping this file is a get-around for a bug |
1977 # that causes python to crash with a segfault. | 1978 # that causes python to crash with a segfault. |
1978 # http://bugs.python.org/issue9319 | 1979 # http://bugs.python.org/issue9319 |
1979 # | 1980 # |
1980 # TODO: Remove the this once the bug is fixed. | 1981 # TODO: Remove the this once the bug is fixed. |
1981 if modname == "test.badsyntax_pep3120": | 1982 if modname in ["test.badsyntax_pep3120", "badsyntax_pep3120"]: |
1982 continue | 1983 continue |
1983 | 1984 |
1984 if key is None: | 1985 if key is None: |
1985 callback(None, modname, '') | 1986 callback(None, modname, '') |
1986 else: | 1987 else: |
1987 try: | 1988 try: |
1988 loader = importer.find_module(modname) | 1989 loader = importer.find_module(modname) |
1989 except SyntaxError: | 1990 except SyntaxError: |
1990 # raised by tests for bad coding cookies or BOM | 1991 # raised by tests for bad coding cookies or BOM |
1991 continue | 1992 continue |
1992 if hasattr(loader, 'get_source'): | 1993 if hasattr(loader, 'get_source'): |
1993 try: | 1994 try: |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2298 gui = GUI(root) | 2299 gui = GUI(root) |
2299 root.mainloop() | 2300 root.mainloop() |
2300 finally: | 2301 finally: |
2301 root.destroy() | 2302 root.destroy() |
2302 except KeyboardInterrupt: | 2303 except KeyboardInterrupt: |
2303 pass | 2304 pass |
2304 ········ | 2305 ········ |
2305 ········ | 2306 ········ |
2306 # --------------------------------------- enhanced web browser interface | 2307 # --------------------------------------- enhanced web browser interface |
2307 | 2308 |
2308 def _startserver(urlhandler, port): | 2309 def _start_server(urlhandler, port): |
2309 """ Start an HTTP server thread on a specific port. | 2310 """ Start an HTTP server thread on a specific port. |
2310 ···· | 2311 ···· |
2311 Start an HTML/text server thread, so HTML or text documents can be | 2312 Start an HTML/text server thread, so HTML or text documents can be |
2312 browsed dynamically and interactively with a web browser. | 2313 browsed dynamically and interactively with a web browser. |
2313 ········ | 2314 ········ |
2314 Example use | 2315 Example use |
2315 =========== | 2316 =========== |
2316 | 2317 |
2317 >>> import time | 2318 >>> import time |
2318 >>> import pydoc | 2319 >>> import pydoc |
2319 | 2320 |
2320 Define a URL handler. To determine what the client is asking | 2321 Define a URL handler. To determine what the client is asking |
2321 for, check the URL and content_type. | 2322 for, check the URL and content_type. |
2322 | 2323 |
2323 Then get or generate some text or HTML code and return it. | 2324 Then get or generate some text or HTML code and return it. |
2324 | 2325 |
2325 >>> def my_url_handler(url, content_type): | 2326 >>> def my_url_handler(url, content_type): |
2326 ... text = 'the URL sent was: (%s, %s)' % (url, content_type) | 2327 ... text = 'the URL sent was: (%s, %s)' % (url, content_type) |
2327 ... return text | 2328 ... return text |
2328 | 2329 |
2329 Start server thread on port 0. | 2330 Start server thread on port 0. |
2330 If you use port 0, the server will pick a random port number. | 2331 If you use port 0, the server will pick a random port number. |
2331 You can then use serverthread.port to get the port number. | 2332 You can then use serverthread.port to get the port number. |
2332 | 2333 |
2333 >>> port = 0 | 2334 >>> port = 0 |
2334 >>> serverthread = pydoc._startserver(my_url_handler, port) | 2335 >>> serverthread = pydoc._startserver(my_url_handler, port) |
ron3200
2010/11/21 06:48:24
pydoc._startserver( -> pydoc._start_server(
| |
2335 | 2336 |
2336 Check that the server is really started. If it is, open browser | 2337 Check that the server is really started. If it is, open browser |
2337 and get first page. Use serverthread.url as the starting page. | 2338 and get first page. Use serverthread.url as the starting page. |
2338 | 2339 |
2339 >>> if serverthread.serving: | 2340 >>> if serverthread.serving: |
2340 ... import webbrowser | 2341 ... import webbrowser |
2341 | 2342 |
2343 The next two lines are commented out so a browser doesn't open if | |
2344 doctest is run on this module. | |
2345 ············ | |
2342 #... webbrowser.open(serverthread.url) | 2346 #... webbrowser.open(serverthread.url) |
2343 #True | 2347 #True |
ron3200
2010/11/18 23:02:57
These lines are commented out to avoid opening the
ron3200
2010/11/19 17:30:44
Added line explaining comments.
Done.
| |
2344 | 2348 |
2345 Let the server do it's thing. We just need to monitor its status. | 2349 Let the server do it's thing. We just need to monitor its status. |
2346 Use time.sleep so the loop doesn't hog the CPU. | 2350 Use time.sleep so the loop doesn't hog the CPU. |
2347 | 2351 |
2348 >>> starttime = time.time() | 2352 >>> starttime = time.time() |
2349 >>> timeout = 1 #seconds | 2353 >>> timeout = 1 #seconds |
2350 | 2354 |
2351 This is a short timeout for testing purposes. | 2355 This is a short timeout for testing purposes. |
2352 | 2356 |
2353 >>> while serverthread.serving: | 2357 >>> while serverthread.serving: |
2354 ... time.sleep(.01) | 2358 ... time.sleep(.01) |
2355 ... if serverthread.serving and time.time() - starttime > timeou t: | 2359 ... if serverthread.serving and time.time() - starttime > timeou t: |
2356 ... serverthread.stop() | 2360 ... serverthread.stop() |
2357 ... break | 2361 ... break |
2358 | 2362 |
2359 Print any errors that may have occurred. | 2363 Print any errors that may have occurred. |
2360 | 2364 |
2361 >>> print(serverthread.error) | 2365 >>> print(serverthread.error) |
2362 None | 2366 None |
2363 | 2367 |
2364 """· | 2368 """· |
2365 import http.server | 2369 import http.server |
2366 import email.message | 2370 import email.message |
2367 import select | 2371 import select |
2368 import threading | 2372 import threading |
ron3200
2010/11/18 23:02:57
These imports are only needed in the case the serv
| |
2369 | 2373 |
2370 class DocHandler(http.server.BaseHTTPRequestHandler): | 2374 class DocHandler(http.server.BaseHTTPRequestHandler): |
2371 """ Handle server requests from browser. """ | 2375 """ Handle server requests from browser. """ |
2372 def do_GET(self): | 2376 def do_GET(self): |
2373 """ Process a request from a HTML browser. | 2377 """ Process a request from a HTML browser. |
2374 The URL received is in self.path. | 2378 The URL received is in self.path. |
2375 Get an HTML page from self.urlhandler and send it. | 2379 Get an HTML page from self.urlhandler and send it. |
2376 """ | 2380 """ |
2377 if self.path.endswith('.css'): | 2381 if self.path.endswith('.css'): |
2378 content_type = 'text/css' | 2382 content_type = 'text/css' |
2379 else: | 2383 else: |
2380 content_type = 'text/html' | 2384 content_type = 'text/html' |
ron3200
2010/11/18 23:02:57
Add "charset" parameter.
ron3200
2010/11/19 00:23:48
Attempt at changeing 'text/html' to 'text/html; ch
ron3200
2010/11/19 00:37:02
Worked with 'chrset', not 'charset'.
Done.
| |
2381 self.send_response(200) | 2385 self.send_response(200) |
2382 self.send_header('Content-Type', content_type) | 2386 self.send_header('Content-Type', content_type + ';chrset=UTF-8') |
2383 self.end_headers() | 2387 self.end_headers() |
2384 self.wfile.write(bytes(self.urlhandler(self.path, content_type), | 2388 self.wfile.write(bytes(self.urlhandler(self.path, content_type), |
2385 'UTF-8')) | 2389 'UTF-8')) |
2386 | 2390 |
2387 def log_message(self, *args): | 2391 def log_message(self, *args): |
2388 # Don't log messages. | 2392 # Don't log messages. |
2389 pass | 2393 pass |
2390 | 2394 |
2391 class DocServer(http.server.HTTPServer): | 2395 class DocServer(http.server.HTTPServer): |
2392 def __init__(self, port, callback): | 2396 def __init__(self, port, callback): |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2442 self.url = None | 2446 self.url = None |
2443 ········ | 2447 ········ |
2444 thread = ServerThread(urlhandler, port) | 2448 thread = ServerThread(urlhandler, port) |
2445 thread.start() | 2449 thread.start() |
2446 # Wait until thread.serving is True to make sure we are | 2450 # Wait until thread.serving is True to make sure we are |
2447 # really up before returning. | 2451 # really up before returning. |
2448 while not thread.error and not thread.serving: | 2452 while not thread.error and not thread.serving: |
2449 time.sleep(.01) | 2453 time.sleep(.01) |
2450 return thread | 2454 return thread |
2451 | 2455 |
2452 def browse(port=0, *, open_browser=True): | 2456 |
2453 """ Start the enhanced pydoc web server and open a web browser. | 2457 def _url_handler(url, content_type="text/html"): |
2458 """ The pydoc url handler for use with the pydoc server. | |
2459 ···· | |
2460 If the content_type is 'text/css', the _pydoc.css style | |
2461 sheet is read and returned if it exits. | |
2462 ········ | |
2463 If the content_type is 'text/html', then the result of | |
2464 get_html_page(url) is returned. | |
2465 ········ | |
2454 """ | 2466 """ |
2455 import webbrowser | |
2456 ···· | |
2457 class _HTMLDoc(HTMLDoc): | 2467 class _HTMLDoc(HTMLDoc): |
2468 ········ | |
2469 def page(self, title, contents): | |
2470 """Format an HTML page.""" | |
2471 css_path = "pydoc_data/_pydoc.css" | |
2472 css_link = ( | |
2473 """<link rel="stylesheet" type="text/css" href="%s">""" | |
2474 % css_path) | |
2475 return '''\ | |
2476 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> | |
2477 <html><head><title>Python: %s</title> | |
2478 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |
2479 %s</head><body bgcolor="#f0f0f8">%s | |
2480 </body></html>''' % (title, css_link, contents) | |
2481 ········ | |
2458 def filelink(self, url, path):···· | 2482 def filelink(self, url, path):···· |
2459 return '<a href="getfile?key=%s">%s</a>' % (url, path) | 2483 return '<a href="getfile?key=%s">%s</a>' % (url, path) |
2484 ····················· | |
2460 ········ | 2485 ········ |
2461 html = _HTMLDoc() | 2486 html = _HTMLDoc() |
2462 | 2487 |
2463 def html_navbar(): return \ | 2488 def html_navbar():· |
2464 """ | 2489 version = "%s [%s, %s]" % ( |
2465 <table><tr> | 2490 platform.python_version(), |
2466 <td width="50%%"> Python %s </td> | 2491 platform.python_build()[0], |
2467 <td><form action="get"> | 2492 platform.python_compiler()) |
2468 <input type=text name=key size=15> | 2493 return """ |
2469 <input type=submit value="Get"> | 2494 <div style='float:left'> |
2470 </form></td> | 2495 Python %s<br>%s<br><br> |
2471 <td><form action="search"> | 2496 </div> |
2472 <input type=text name=key size=15> | 2497 <div style='float:right'> |
2473 <input type=submit value="Search"> | 2498 <div style='text-align:center'> |
2474 </form></td> | 2499 <a href="index.html">Module Index</a> |
2475 <td> | 2500 : <a href="topics.html">Topics</a> |
2476 <a href="index.html">Module Index</a> | 2501 : <a href="keywords.html">Keywords</a> |
2477 : <a href="topics.html">Topics</a> | 2502 </div> |
2478 : <a href="keywords.html">Keywords</a> | 2503 <div> |
2479 </td> | 2504 <form action="get" style='float:left'> |
2480 </tr></table> | 2505 <input type=text name=key size=15> |
2481 """ % sys.version | 2506 <input type=submit value="Get"> |
ron3200
2010/11/18 23:02:57
Shorten version info, and try to make it less clut
ron3200
2010/11/19 17:30:44
Done.
| |
2507 | |
2508 </form> | |
2509 <form action="search" style='float:right'> | |
2510 <input type=text name=key size=15> | |
2511 <input type=submit value="Search"> | |
2512 </form> | |
2513 </div> | |
2514 </div> | |
2515 <div clear='all'> </div> | |
2516 """ % (version, platform.platform(terse=True)) | |
2482 | 2517 |
2483 def html_index(): | 2518 def html_index(): |
2484 """ Module Index web page. """ | 2519 """ Module Index web page. """ |
2485 def bltinlink(name): | 2520 def bltinlink(name): |
2486 return '<a href="%s.html">%s</a>' % (name, name) | 2521 return '<a href="%s.html">%s</a>' % (name, name) |
2487 heading = html.heading( | 2522 heading = html.heading( |
2488 '<big><big><strong>Index of Modules</strong></big></big>', | 2523 '<big><big><strong>Index of Modules</strong></big></big>', |
2489 '#ffffff', '#7799ee') | 2524 '#ffffff', '#7799ee') |
2490 names = list(filter(lambda x: x != '__main__', | 2525 names = list(filter(lambda x: x != '__main__', |
2491 sys.builtin_module_names)) | 2526 sys.builtin_module_names)) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2524 '#ffffff', '#7799ee') | 2559 '#ffffff', '#7799ee') |
2525 for name, desc in search_result: | 2560 for name, desc in search_result: |
2526 results.append(bltinlink(name) + desc) | 2561 results.append(bltinlink(name) + desc) |
2527 contents = heading + html.bigsection( | 2562 contents = heading + html.bigsection( |
2528 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results)) | 2563 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results)) |
2529 return html.page('Search Results', contents) | 2564 return html.page('Search Results', contents) |
2530 | 2565 |
2531 def html_getfile(path): | 2566 def html_getfile(path): |
2532 """ Get and display a source file listing safely. """ | 2567 """ Get and display a source file listing safely. """ |
2533 path = os.sep + path.replace('%20', ' ') | 2568 path = os.sep + path.replace('%20', ' ') |
2534 try: | 2569 with open(path, 'r') as fp: |
2535 f = open(path, 'r') | 2570 lines = html.escape(fp.read()) |
2536 lines = html.escape(f.read()) | |
2537 finally: | |
2538 f.close() | |
ron3200
2010/11/19 21:10:27
Use with statement here.
ron3200
2010/11/19 21:11:55
Done.
| |
2539 body = '<pre>%s</pre>' % lines | 2571 body = '<pre>%s</pre>' % lines |
2540 heading = html.heading( | 2572 heading = html.heading( |
2541 '<big><big><strong>File Listing</strong></big></big>', | 2573 '<big><big><strong>File Listing</strong></big></big>', |
2542 '#ffffff', '#7799ee') | 2574 '#ffffff', '#7799ee') |
2543 contents = heading + html.bigsection( | 2575 contents = heading + html.bigsection( |
2544 'File: %s' % path, '#ffffff', '#ee77aa', body) | 2576 'File: %s' % path, '#ffffff', '#ee77aa', body) |
2545 return html.page('getfile: %s' % path, contents) | 2577 return html.page('getfile %s' % path, contents) |
2546 | 2578 |
2547 def html_topics(): | 2579 def html_topics(): |
2548 """ Index of topic texts available. """ | 2580 """ Index of topic texts available. """ |
2549 def bltinlink(name): | 2581 def bltinlink(name): |
2550 return '<a href="%s.html">%s</a>' % (name, name) | 2582 return '<a href="%s.html">%s</a>' % (name, name) |
2551 heading = html.heading( | 2583 heading = html.heading( |
2552 '<big><big><strong>INDEX</strong></big></big>', | 2584 '<big><big><strong>INDEX</strong></big></big>', |
2553 '#ffffff', '#7799ee') | 2585 '#ffffff', '#7799ee') |
2554 names = sorted(Helper.topics.keys()) | 2586 names = sorted(Helper.topics.keys()) |
2555 def bltinlink(name): | 2587 def bltinlink(name): |
(...skipping 29 matching lines...) Expand all Loading... | |
2585 heading = html.heading( | 2617 heading = html.heading( |
2586 '<big><big><strong>%s</strong></big></big>' % title, | 2618 '<big><big><strong>%s</strong></big></big>' % title, |
2587 '#ffffff', '#7799ee') | 2619 '#ffffff', '#7799ee') |
2588 contents = '<pre>%s</pre>' % contents | 2620 contents = '<pre>%s</pre>' % contents |
2589 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents) | 2621 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents) |
2590 xrefs = sorted(xrefs.split()) | 2622 xrefs = sorted(xrefs.split()) |
2591 def bltinlink(name): | 2623 def bltinlink(name): |
2592 return '<a href="%s.html">%s</a>' % (name, name) | 2624 return '<a href="%s.html">%s</a>' % (name, name) |
2593 xrefs = html.multicolumn(xrefs, bltinlink) | 2625 xrefs = html.multicolumn(xrefs, bltinlink) |
2594 xrefs = html.section('Related help topics: ', '#ffffff', '#ee77aa', xref s) | 2626 xrefs = html.section('Related help topics: ', '#ffffff', '#ee77aa', xref s) |
2595 return html.page('%s: %s' % (title, topic), heading + contents + xrefs) | 2627 return html.page('%s %s' % (title, topic), heading + contents + xrefs) |
2596 | 2628 |
2597 def html_error(url): | 2629 def html_error(url): |
2598 heading = html.heading( | 2630 heading = html.heading( |
2599 '<big><big><strong>Error</strong></big></big>', | 2631 '<big><big><strong>Error</strong></big></big>', |
2600 '#ffffff', '#ee0000') | 2632 '#ffffff', '#ee0000') |
2601 return heading + url | 2633 return heading + url |
2602 | 2634 |
2603 def get_html_page(url): | 2635 def get_html_page(url): |
2604 """ Function url handler uses to get the html page to get | 2636 """ Generate an HTML page for url. """ |
2605 depending on the url. | |
2606 """ | |
2607 if url[-5:] == '.html': | 2637 if url[-5:] == '.html': |
2608 url = url[:-5] | 2638 url = url[:-5] |
2609 if url[:1] == '/': | 2639 if url[:1] == '/': |
2610 url = url[1:] | 2640 url = url[1:] |
2611 if url.startswith("get?key="): | 2641 if url.startswith("get?key="): |
2612 url = url[8:] | 2642 url = url[8:] |
2613 title = url | 2643 title = url |
2614 contents = '' | 2644 contents = '' |
2615 if url in ("", ".", "index"): | 2645 if url in ("", ".", "index"): |
2616 contents = html_index() | 2646 contents = html_index() |
2617 elif url == "topics": | 2647 elif url == "topics": |
2618 contents = html_topics() | 2648 contents = html_topics() |
2619 elif url == "keywords": | 2649 elif url == "keywords": |
2620 contents = html_keywords() | 2650 contents = html_keywords() |
2621 elif url.startswith("search?key="): | 2651 elif url.startswith("search?key="): |
2622 contents = html_search(url[11:]) | 2652 contents = html_search(url[11:]) |
2623 elif url.startswith("getfile?key="): | 2653 elif url.startswith("getfile?key="): |
2624 url = url[12:] | 2654 url = url[12:] |
2625 try: | 2655 try: |
2626 contents = html_getfile(url) | 2656 contents = html_getfile(url) |
2627 except IOError: | 2657 except IOError: |
2628 contents = html_error('could not read file %s' % repr(url)) | 2658 contents = html_error('could not read file %s' % repr(url)) |
2659 title = 'Read Error' | |
2629 else: | 2660 else: |
2630 obj = None | 2661 obj = None |
2631 try: | 2662 try: |
2632 obj = locate(url, forceload=1) | 2663 obj = locate(url, forceload=1) |
2633 except ErrorDuringImport as value: | 2664 except ErrorDuringImport as value: |
2634 contents = html.escape(str(value)) | 2665 contents = html.escape(str(value)) |
2635 if obj: | 2666 if obj: |
2636 title = describe(obj) | 2667 title = describe(obj) |
2637 contents = html.document(obj, url) | 2668 contents = html.document(obj, url) |
2638 elif url in Helper.keywords or url in Helper.topics: | 2669 elif url in Helper.keywords or url in Helper.topics: |
2639 contents = html_topicpage(url) | 2670 contents = html_topicpage(url) |
2640 else: | 2671 else: |
2641 contents = html_error('no Python documentation found for %s' | 2672 contents = html_error('no Python documentation found for %s' |
2642 % repr(url)) | 2673 % repr(url)) |
2674 title = 'Error' | |
2643 return html.page(title, html_navbar() + contents) | 2675 return html.page(title, html_navbar() + contents) |
2644 | 2676 |
2645 def url_handler(url, content_type): | 2677 if url.startswith('/'): |
2646 """ html server html and style sheet requests. """ | 2678 url = url[1:] |
2647 if url.startswith('/'): | 2679 if content_type == 'text/css': |
2648 url = url[1:] | 2680 path_here = os.path.dirname(os.path.realpath(__file__)) |
2649 if content_type == 'text/css': | 2681 #try: |
2650 fp = open(os.path.join(path_here, url)) | 2682 with open(os.path.join(path_here, url)) as fp: |
ron3200
2010/11/19 00:23:48
The value of path_here is not set. Fix or comment
ron3200
2010/11/19 21:10:27
Done.
| |
2651 css = ''.join(fp.readlines()) | 2683 return ''.join(fp.readlines()) |
2652 fp.close() | 2684 #except IOError: |
ron3200
2010/11/19 00:23:48
Use with statement here.
ron3200
2010/11/19 21:10:27
Done.
| |
2653 return css | 2685 # return 'Error: can not open css file ' + url |
2654 elif content_type == 'text/html': | 2686 elif content_type == 'text/html': |
2655 return get_html_page(url) | 2687 return get_html_page(url) |
2656 return 'Error: unknown content type ' + content_type | 2688 return 'Error: unknown content type ' + content_type |
2657 | 2689 |
2658 serverthread = _startserver(url_handler, port) | 2690 |
2691 def browse(port=0, *, open_browser=True): | |
2692 """ Start the enhanced pydoc web server and open a web browser. | |
2693 ···· | |
2694 Use port '0' to start the server on an arbitrary port. | |
2695 Set open_browser to False to suppress opening a browser. | |
2696 """ | |
2697 import webbrowser | |
2698 serverthread = _start_server(_url_handler, port) | |
2659 if serverthread.error: | 2699 if serverthread.error: |
2660 print(serverthread.error) | 2700 print(serverthread.error) |
2661 return | 2701 return |
2662 if serverthread.serving: | 2702 if serverthread.serving: |
2663 server_help_msg = """Python version: %s | 2703 server_help_msg = ( "Server ready at: %s\n" |
2664 Server ready at: %s | 2704 "Server commands: [b]rowser, [q]uit" |
2665 Server commands: [b]rowser, [q]uit'""" % (sys.version, serverthread.url) | 2705 % serverthread.url ) |
2666 if open_browser: | 2706 if open_browser: |
2667 webbrowser.open(serverthread.url) | 2707 webbrowser.open(serverthread.url) |
2668 try: | 2708 try: |
2669 print(server_help_msg) | 2709 print(server_help_msg) |
2670 while serverthread.serving: | 2710 while serverthread.serving: |
2671 cmd = input('server>') | 2711 cmd = input('server>') |
2672 cmd = cmd.lower() | 2712 cmd = cmd.lower() |
2673 if cmd == 'q': | 2713 if cmd == 'q': |
2674 break | 2714 break |
2675 elif cmd == 'b': | 2715 elif cmd == 'b': |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2743 writedoc(arg) | 2783 writedoc(arg) |
2744 else: | 2784 else: |
2745 help.help(arg) | 2785 help.help(arg) |
2746 except ErrorDuringImport as value: | 2786 except ErrorDuringImport as value: |
2747 print(value) | 2787 print(value) |
2748 | 2788 |
2749 except (getopt.error, BadUsage): | 2789 except (getopt.error, BadUsage): |
2750 cmd = os.path.basename(sys.argv[0]) | 2790 cmd = os.path.basename(sys.argv[0]) |
2751 print("""pydoc - the Python documentation tool | 2791 print("""pydoc - the Python documentation tool |
2752 | 2792 |
2753 %s <name> ... | 2793 {cmd} <name> ... |
2754 Show text documentation on something. <name> may be the name of a | 2794 Show text documentation on something. <name> may be the name of a |
2755 Python keyword, topic, function, module, or package, or a dotted | 2795 Python keyword, topic, function, module, or package, or a dotted |
2756 reference to a class or function within a module or module in a | 2796 reference to a class or function within a module or module in a |
2757 package. If <name> contains a '%s', it is used as the path to a | 2797 package. If <name> contains a '{sep}', it is used as the path to a |
2758 Python source file to document. If name is 'keywords', 'topics', | 2798 Python source file to document. If name is 'keywords', 'topics', |
2759 or 'modules', a listing of these things is displayed. | 2799 or 'modules', a listing of these things is displayed. |
2760 | 2800 |
2761 %s -k <keyword> | 2801 {cmd} -k <keyword> |
2762 Search for a keyword in the synopsis lines of all available modules. | 2802 Search for a keyword in the synopsis lines of all available modules. |
2763 | 2803 |
2764 %s -p <port> | 2804 {cmd} -p <port> |
2765 Start an HTTP server on the given port on the local machine. Port | 2805 Start an HTTP server on the given port on the local machine. Port |
2766 number 0 can be used to get an arbitrary unused port. | 2806 number 0 can be used to get an arbitrary unused port. |
2767 | 2807 |
2768 %s -b | 2808 {cmd} -b |
2769 Start an HTTP server on an arbitrary unused port and open a web browser | 2809 Start an HTTP server on an arbitrary unused port and open a web browser |
2770 to interactively browse documentation. The -p option can be used with | 2810 to interactively browse documentation. The -p option can be used with |
2771 the -b option to explicitly specify the server port. | 2811 the -b option to explicitly specify the server port. |
2772 ···· | 2812 ···· |
2773 %s -g | 2813 {cmd} -g |
2774 The "-g" option is deprecated. | 2814 The "-g" option is deprecated. |
2775 | 2815 |
2776 %s -w <name> ... | 2816 {cmd} -w <name> ... |
2777 Write out the HTML documentation for a module to a file in the current | 2817 Write out the HTML documentation for a module to a file in the current |
2778 directory. If <name> contains a '%s', it is treated as a filename; if | 2818 directory. If <name> contains a '{sep}', it is treated as a filename; if |
2779 it names a directory, documentation is written for all the contents. | 2819 it names a directory, documentation is written for all the contents. |
2780 """ % (cmd, os.sep, cmd, cmd, cmd, cmd, cmd, os.sep)) | 2820 """.format(cmd=cmd, sep=os.sep)) |
ron3200
2010/11/18 23:02:57
Use keyword substitutions.
ron3200
2010/11/19 17:30:44
Done.
| |
2781 | 2821 |
2782 if __name__ == '__main__': | 2822 if __name__ == '__main__': |
2783 cli() | 2823 cli() |
2784 | 2824 |
LEFT | RIGHT |