mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
bpo-31128: Allow pydoc to bind to arbitrary hostnames (#3011)
New -n flag allow overriding localhost with custom value, for example to run from containers.
This commit is contained in:
parent
ccb3c7654c
commit
6a396c9807
5 changed files with 39 additions and 19 deletions
|
@ -70,6 +70,12 @@ will start a HTTP server on port 1234, allowing you to browse the
|
||||||
documentation at ``http://localhost:1234/`` in your preferred Web browser.
|
documentation at ``http://localhost:1234/`` in your preferred Web browser.
|
||||||
Specifying ``0`` as the port number will select an arbitrary unused port.
|
Specifying ``0`` as the port number will select an arbitrary unused port.
|
||||||
|
|
||||||
|
:program:`pydoc -n <hostname>` will start the server listening at the given
|
||||||
|
hostname. By default the hostname is 'localhost' but if you want the server to
|
||||||
|
be reached from other machines, you may want to change the host name that the
|
||||||
|
server responds to. During development this is especially useful if you want
|
||||||
|
to run pydoc from within a container.
|
||||||
|
|
||||||
:program:`pydoc -b` will start the server and additionally open a web
|
:program:`pydoc -b` will start the server and additionally open a web
|
||||||
browser to a module index page. Each served page has a navigation bar at the
|
browser to a module index page. Each served page has a navigation bar at the
|
||||||
top where you can *Get* help on an individual item, *Search* all modules with a
|
top where you can *Get* help on an individual item, *Search* all modules with a
|
||||||
|
@ -98,3 +104,6 @@ Reference Manual pages.
|
||||||
:mod:`pydoc` now uses :func:`inspect.signature` rather than
|
:mod:`pydoc` now uses :func:`inspect.signature` rather than
|
||||||
:func:`inspect.getfullargspec` to extract signature information from
|
:func:`inspect.getfullargspec` to extract signature information from
|
||||||
callables.
|
callables.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.7
|
||||||
|
Added the ``-n`` option.
|
||||||
|
|
43
Lib/pydoc.py
43
Lib/pydoc.py
|
@ -16,12 +16,15 @@ backslash on Windows) it is treated as the path to a Python source file.
|
||||||
Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
|
Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
|
||||||
of all available modules.
|
of all available modules.
|
||||||
|
|
||||||
|
Run "pydoc -n <hostname>" to start an HTTP server with the given
|
||||||
|
hostname (default: localhost) on the local machine.
|
||||||
|
|
||||||
Run "pydoc -p <port>" to start an HTTP server on the given port on the
|
Run "pydoc -p <port>" to start an HTTP server on the given port on the
|
||||||
local machine. Port number 0 can be used to get an arbitrary unused port.
|
local machine. Port number 0 can be used to get an arbitrary unused port.
|
||||||
|
|
||||||
Run "pydoc -b" to start an HTTP server on an arbitrary unused port and
|
Run "pydoc -b" to start an HTTP server on an arbitrary unused port and
|
||||||
open a Web browser to interactively browse documentation. The -p option
|
open a Web browser to interactively browse documentation. Combine with
|
||||||
can be used with the -b option to explicitly specify the server port.
|
the -n and -p options to control the hostname and port used.
|
||||||
|
|
||||||
Run "pydoc -w <name>" to write out the HTML documentation for a module
|
Run "pydoc -w <name>" to write out the HTML documentation for a module
|
||||||
to a file named "<name>.html".
|
to a file named "<name>.html".
|
||||||
|
@ -2162,7 +2165,7 @@ def apropos(key):
|
||||||
|
|
||||||
# --------------------------------------- enhanced Web browser interface
|
# --------------------------------------- enhanced Web browser interface
|
||||||
|
|
||||||
def _start_server(urlhandler, port):
|
def _start_server(urlhandler, hostname, port):
|
||||||
"""Start an HTTP server thread on a specific port.
|
"""Start an HTTP server thread on a specific port.
|
||||||
|
|
||||||
Start an HTML/text server thread, so HTML or text documents can be
|
Start an HTML/text server thread, so HTML or text documents can be
|
||||||
|
@ -2247,8 +2250,8 @@ def _start_server(urlhandler, port):
|
||||||
|
|
||||||
class DocServer(http.server.HTTPServer):
|
class DocServer(http.server.HTTPServer):
|
||||||
|
|
||||||
def __init__(self, port, callback):
|
def __init__(self, host, port, callback):
|
||||||
self.host = 'localhost'
|
self.host = host
|
||||||
self.address = (self.host, port)
|
self.address = (self.host, port)
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
self.base.__init__(self, self.address, self.handler)
|
self.base.__init__(self, self.address, self.handler)
|
||||||
|
@ -2268,8 +2271,9 @@ def _start_server(urlhandler, port):
|
||||||
|
|
||||||
class ServerThread(threading.Thread):
|
class ServerThread(threading.Thread):
|
||||||
|
|
||||||
def __init__(self, urlhandler, port):
|
def __init__(self, urlhandler, host, port):
|
||||||
self.urlhandler = urlhandler
|
self.urlhandler = urlhandler
|
||||||
|
self.host = host
|
||||||
self.port = int(port)
|
self.port = int(port)
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.serving = False
|
self.serving = False
|
||||||
|
@ -2282,7 +2286,7 @@ def _start_server(urlhandler, port):
|
||||||
DocServer.handler = DocHandler
|
DocServer.handler = DocHandler
|
||||||
DocHandler.MessageClass = email.message.Message
|
DocHandler.MessageClass = email.message.Message
|
||||||
DocHandler.urlhandler = staticmethod(self.urlhandler)
|
DocHandler.urlhandler = staticmethod(self.urlhandler)
|
||||||
docsvr = DocServer(self.port, self.ready)
|
docsvr = DocServer(self.host, self.port, self.ready)
|
||||||
self.docserver = docsvr
|
self.docserver = docsvr
|
||||||
docsvr.serve_until_quit()
|
docsvr.serve_until_quit()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -2304,7 +2308,7 @@ def _start_server(urlhandler, port):
|
||||||
self.serving = False
|
self.serving = False
|
||||||
self.url = None
|
self.url = None
|
||||||
|
|
||||||
thread = ServerThread(urlhandler, port)
|
thread = ServerThread(urlhandler, hostname, port)
|
||||||
thread.start()
|
thread.start()
|
||||||
# Wait until thread.serving is True to make sure we are
|
# Wait until thread.serving is True to make sure we are
|
||||||
# really up before returning.
|
# really up before returning.
|
||||||
|
@ -2568,14 +2572,14 @@ def _url_handler(url, content_type="text/html"):
|
||||||
raise TypeError('unknown content type %r for url %s' % (content_type, url))
|
raise TypeError('unknown content type %r for url %s' % (content_type, url))
|
||||||
|
|
||||||
|
|
||||||
def browse(port=0, *, open_browser=True):
|
def browse(port=0, *, open_browser=True, hostname='localhost'):
|
||||||
"""Start the enhanced pydoc Web server and open a Web browser.
|
"""Start the enhanced pydoc Web server and open a Web browser.
|
||||||
|
|
||||||
Use port '0' to start the server on an arbitrary port.
|
Use port '0' to start the server on an arbitrary port.
|
||||||
Set open_browser to False to suppress opening a browser.
|
Set open_browser to False to suppress opening a browser.
|
||||||
"""
|
"""
|
||||||
import webbrowser
|
import webbrowser
|
||||||
serverthread = _start_server(_url_handler, port)
|
serverthread = _start_server(_url_handler, hostname, port)
|
||||||
if serverthread.error:
|
if serverthread.error:
|
||||||
print(serverthread.error)
|
print(serverthread.error)
|
||||||
return
|
return
|
||||||
|
@ -2622,11 +2626,12 @@ def cli():
|
||||||
sys.path.insert(0, '.')
|
sys.path.insert(0, '.')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
opts, args = getopt.getopt(sys.argv[1:], 'bk:p:w')
|
opts, args = getopt.getopt(sys.argv[1:], 'bk:n:p:w')
|
||||||
writing = False
|
writing = False
|
||||||
start_server = False
|
start_server = False
|
||||||
open_browser = False
|
open_browser = False
|
||||||
port = None
|
port = 0
|
||||||
|
hostname = 'localhost'
|
||||||
for opt, val in opts:
|
for opt, val in opts:
|
||||||
if opt == '-b':
|
if opt == '-b':
|
||||||
start_server = True
|
start_server = True
|
||||||
|
@ -2639,11 +2644,12 @@ def cli():
|
||||||
port = val
|
port = val
|
||||||
if opt == '-w':
|
if opt == '-w':
|
||||||
writing = True
|
writing = True
|
||||||
|
if opt == '-n':
|
||||||
|
start_server = True
|
||||||
|
hostname = val
|
||||||
|
|
||||||
if start_server:
|
if start_server:
|
||||||
if port is None:
|
browse(port, hostname=hostname, open_browser=open_browser)
|
||||||
port = 0
|
|
||||||
browse(port, open_browser=open_browser)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if not args: raise BadUsage
|
if not args: raise BadUsage
|
||||||
|
@ -2679,14 +2685,17 @@ def cli():
|
||||||
{cmd} -k <keyword>
|
{cmd} -k <keyword>
|
||||||
Search for a keyword in the synopsis lines of all available modules.
|
Search for a keyword in the synopsis lines of all available modules.
|
||||||
|
|
||||||
|
{cmd} -n <hostname>
|
||||||
|
Start an HTTP server with the given hostname (default: localhost).
|
||||||
|
|
||||||
{cmd} -p <port>
|
{cmd} -p <port>
|
||||||
Start an HTTP server on the given port on the local machine. Port
|
Start an HTTP server on the given port on the local machine. Port
|
||||||
number 0 can be used to get an arbitrary unused port.
|
number 0 can be used to get an arbitrary unused port.
|
||||||
|
|
||||||
{cmd} -b
|
{cmd} -b
|
||||||
Start an HTTP server on an arbitrary unused port and open a Web browser
|
Start an HTTP server on an arbitrary unused port and open a Web browser
|
||||||
to interactively browse documentation. The -p option can be used with
|
to interactively browse documentation. This option can be used in
|
||||||
the -b option to explicitly specify the server port.
|
combination with -n and/or -p.
|
||||||
|
|
||||||
{cmd} -w <name> ...
|
{cmd} -w <name> ...
|
||||||
Write out the HTML documentation for a module to a file in the current
|
Write out the HTML documentation for a module to a file in the current
|
||||||
|
|
|
@ -909,8 +909,8 @@ class PydocServerTest(unittest.TestCase):
|
||||||
text = 'the URL sent was: (%s, %s)' % (url, content_type)
|
text = 'the URL sent was: (%s, %s)' % (url, content_type)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
serverthread = pydoc._start_server(my_url_handler, port=0)
|
serverthread = pydoc._start_server(my_url_handler, hostname='0.0.0.0', port=0)
|
||||||
self.assertIn('localhost', serverthread.docserver.address)
|
self.assertIn('0.0.0.0', serverthread.docserver.address)
|
||||||
|
|
||||||
starttime = time.time()
|
starttime = time.time()
|
||||||
timeout = 1 #seconds
|
timeout = 1 #seconds
|
||||||
|
|
|
@ -1177,6 +1177,7 @@ Claude Paroz
|
||||||
Heikki Partanen
|
Heikki Partanen
|
||||||
Harri Pasanen
|
Harri Pasanen
|
||||||
Gaël Pasgrimaud
|
Gaël Pasgrimaud
|
||||||
|
Feanil Patel
|
||||||
Ashish Nitin Patil
|
Ashish Nitin Patil
|
||||||
Alecsandru Patrascu
|
Alecsandru Patrascu
|
||||||
Randy Pausch
|
Randy Pausch
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Allow the pydoc server to bind to arbitrary hostnames.
|
Loading…
Add table
Add a link
Reference in a new issue