We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Allow for configuring the IP address of the Bokeh server
I have downloaded the bokeh developer build "conda install -c bokeh/channel/dev bokeh", which has a new Bokeh server "https://github.com/bokeh/bokeh/wiki/Porting-guide:-new-Bokeh-server".

For previous Bokeh server, this capability is added (see "add ability to use a different ip address and port for bokeh-server #383"). 

Please tell me how to use a different ip address for the new bokeh server "boken serve".
BTW, I know that I can change to a different port by using "bokeh serve --port PORT"

Thank you very much!


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bokeh/server/server.py`
Content:
```
1 ''' Provides a Server which instantiates Application instances as clients connect
2 
3 '''
4 from __future__ import absolute_import, print_function
5 
6 import logging
7 log = logging.getLogger(__name__)
8 
9 import sys
10 
11 from tornado.httpserver import HTTPServer
12 
13 from .tornado import BokehTornado
14 
15 from bokeh.application import Application
16 
17 from bokeh.resources import DEFAULT_SERVER_PORT
18 
19 class Server(object):
20     ''' A Server which creates a new Session for each connection, using an Application to initialize each Session.
21 
22     Args:
23         applications (dict of str: bokeh.application.Application) or bokeh.application.Application:
24             mapping from URL paths to Application instances, or a single Application to put at the root URL
25             The Application is a factory for Document, with a new Document initialized for each Session.
26             Each application should be identified by a path meant to go in a URL, like "/" or "/foo"
27     '''
28 
29     def __init__(self, applications, **kwargs):
30         if isinstance(applications, Application):
31             self._applications = { '/' : applications }
32         else:
33             self._applications = applications
34         io_loop = None
35         if 'io_loop' in kwargs:
36             io_loop = kwargs['io_loop']
37         self._tornado = BokehTornado(self._applications, io_loop=io_loop)
38         self._http = HTTPServer(self._tornado)
39         self._port = DEFAULT_SERVER_PORT
40         if 'port' in kwargs:
41             self._port = kwargs['port']
42         # these queue a callback on the ioloop rather than
43         # doing the operation immediately (I think - havocp)
44         try:
45             self._http.bind(self._port)
46             self._http.start(1)
47         except OSError:
48             log.critical("Cannot start bokeh server, port %s already in use" % self._port)
49             sys.exit(1)
50 
51     # TODO this is broken, it's only used by test_client_server.py so fix that then remove this
52     @property
53     def ws_url(self):
54         return "ws://localhost:" + str(self._port) + "/ws"
55 
56     @property
57     def port(self):
58         return self._port
59 
60     @property
61     def io_loop(self):
62         return self._tornado.io_loop
63 
64     def start(self):
65         ''' Start the Bokeh Server's IO loop.
66 
67         Returns:
68             None
69 
70         Notes:
71             Keyboard interrupts or sigterm will cause the server to shut down.
72 
73         '''
74         self._tornado.start()
75 
76     def stop(self):
77         ''' Stop the Bokeh Server's IO loop.
78 
79         Returns:
80             None
81 
82         '''
83         self._tornado.stop()
84 
85     def unlisten(self):
86         '''Stop listening on ports (Server will no longer be usable after calling this)
87 
88         Returns:
89             None
90         '''
91         self._http.stop()
92 
93     def get_session(self, app_path, session_id):
94         '''Gets a session by name (session must already exist)'''
95 
96         return self._tornado.get_session(app_path, session_id)
97 
98     def show(self, app_path, browser=None, new='tab'):
99         ''' Opens an app in a browser window or tab.
100 
101             Useful for testing server applications on your local desktop but
102             should not call when running bokeh-server on an actual server.
103 
104         Args:
105             app_path (str) : the app path to open
106                 The part of the URL after the hostname:port, with leading slash.
107 
108             browser (str, optional) : browser to show with (default: None)
109                 For systems that support it, the **browser** argument allows
110                 specifying which browser to display in, e.g. "safari", "firefox",
111                 "opera", "windows-default" (see the ``webbrowser`` module
112                 documentation in the standard lib for more details).
113 
114             new (str, optional) : window or tab (default: "tab")
115                 If ``new`` is 'tab', then opens a new tab.
116                 If ``new`` is 'window', then opens a new window.
117 
118         Returns:
119             None
120         '''
121         if not app_path.startswith("/"):
122             raise ValueError("app_path must start with a /")
123         from bokeh.browserlib import view
124         url = "http://localhost:%d%s" % (self.port, app_path)
125         view(url, browser=browser, new=new)
126 
127
```

Path: `bokeh/command/__init__.py`
Content:
```
1 from __future__ import print_function
2 
3 import argparse
4 import sys
5 import os
6 
7 from bokeh.settings import settings
8 from bokeh.application import Application
9 from bokeh.server.server import Server
10 from bokeh.application.spellings import ScriptHandler, DirectoryHandler
11 from bokeh.io import output_file, save, show
12 
13 import logging
14 log = logging.getLogger(__name__)
15 
16 def die(message):
17     print(message, file=sys.stderr)
18     sys.exit(1)
19 
20 class Subcommand(object):
21     """Abstract base class for subcommands"""
22 
23     def __init__(self, parser):
24         """Initialize the subcommand with its parser; can call parser.add_argument to add subcommand flags"""
25         self.parser = parser
26 
27     def func(self, args):
28         """Takes over main program flow to perform the subcommand"""
29         pass
30 
31 class ApplicationsSubcommand(Subcommand):
32     """Abstract base class for subcommand that operates on a list of applications."""
33 
34     def __init__(self, **kwargs):
35         super(ApplicationsSubcommand, self).__init__(**kwargs)
36         self.parser.add_argument('files', metavar='DIRECTORY-OR-SCRIPT', nargs='*',  help="The app directories or scripts to serve (serve empty document if not specified)", default=None)
37 
38     def build_applications(self, args):
39         if args.files:
40             files = args.files
41         else:
42             files = []
43 
44         applications = {}
45 
46         for file in files:
47             file = os.path.abspath(file)
48             if os.path.isdir(file):
49                 handler = DirectoryHandler(filename=file)
50             else:
51                 handler = ScriptHandler(filename=file)
52 
53             if handler.failed:
54                 die("Error loading %s:\n\n%s\n%s " % (file, handler.error, handler.error_detail))
55 
56             application = Application()
57             application.add(handler)
58 
59             route = handler.url_path()
60             if not route:
61                 if '/' in applications:
62                     die("Don't know the URL path to use for %s" % (file))
63                 route = '/'
64             applications[route] = application
65 
66         if len(applications) == 0:
67             # create an empty application by default, used with output_server typically
68             applications['/'] = Application()
69 
70         return applications
71 
72 class Serve(ApplicationsSubcommand):
73     """Subcommand to launch the Bokeh server."""
74 
75     name = "serve"
76     help = "Run a Bokeh server hosting one or more applications"
77 
78     def __init__(self, **kwargs):
79         super(Serve, self).__init__(**kwargs)
80         self.parser.add_argument('--port', metavar='PORT', type=int, help="Port to listen on", default=-1)
81         self.parser.add_argument('--develop', action='store_true', help="Enable develop-time features that should not be used in production")
82         self.parser.add_argument('--show', action='store_true', help="Open server app(s) in a browser")
83         self.port = 5006
84         self.develop_mode = False
85         self.server = None
86 
87     def func(self, args):
88         if args.port >= 0:
89             self.port = args.port
90 
91         self.develop_mode = args.develop
92 
93         applications = self.build_applications(args)
94 
95         # TODO make log level a command line option
96         logging.basicConfig(level=logging.DEBUG)
97 
98         server = Server(applications, port=self.port)
99 
100         if args.show:
101             # we have to defer opening in browser until
102             # we start up the server
103             def show_callback():
104                 for route in applications.keys():
105                     server.show(route)
106             server.io_loop.add_callback(show_callback)
107 
108         if self.develop_mode:
109             log.info("Using develop mode (do not enable --develop in production)")
110         log.info("Starting Bokeh server on port %d with apps at %r", server.port, sorted(applications.keys()))
111         server.start()
112 
113 class Html(ApplicationsSubcommand):
114     """Subcommand to output applications as standalone HTML files."""
115 
116     name = "html"
117     help = "Create standalone HTML files for one or more applications"
118 
119     def __init__(self, **kwargs):
120         super(Html, self).__init__(**kwargs)
121         self.parser.add_argument('--show', action='store_true', help="Open generated file(s) in a browser")
122 
123     def func(self, args):
124         applications = self.build_applications(args)
125 
126         for (route, app) in applications.items():
127             doc = app.create_document()
128             if route == "/":
129                 filename = "index.html"
130             else:
131                 filename = route[1:] + ".html"
132 
133             output_file(filename)
134 
135             if args.show:
136                 show(doc, new='tab')
137             else:
138                 save(doc)
139 
140 subcommands = [Serve, Html]
141 
142 def main(argv):
143     parser = argparse.ArgumentParser(prog=argv[0])
144     # does this get set by anything other than BOKEH_VERSION env var?
145     version = settings.version()
146     if not version:
147         version = "unknown version"
148     parser.add_argument('-v', '--version', action='version', version=version)
149     subs = parser.add_subparsers(help="Sub-commands")
150     for klass in subcommands:
151         c_parser = subs.add_parser(klass.name, help=klass.help)
152         c = klass(parser=c_parser)
153         c_parser.set_defaults(func=c.func)
154 
155     args = parser.parse_args(argv[1:])
156     args.func(args)
157
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/bokeh/command/__init__.py b/bokeh/command/__init__.py
--- a/bokeh/command/__init__.py
+++ b/bokeh/command/__init__.py
@@ -77,9 +77,10 @@
 
     def __init__(self, **kwargs):
         super(Serve, self).__init__(**kwargs)
-        self.parser.add_argument('--port', metavar='PORT', type=int, help="Port to listen on", default=-1)
         self.parser.add_argument('--develop', action='store_true', help="Enable develop-time features that should not be used in production")
         self.parser.add_argument('--show', action='store_true', help="Open server app(s) in a browser")
+        self.parser.add_argument('--port', metavar='PORT', type=int, help="Port to listen on", default=-1)
+        self.parser.add_argument('--address', metavar='ADDRESS', type=str, help="Address to listen on", default=None)
         self.port = 5006
         self.develop_mode = False
         self.server = None
@@ -95,7 +96,7 @@
         # TODO make log level a command line option
         logging.basicConfig(level=logging.DEBUG)
 
-        server = Server(applications, port=self.port)
+        server = Server(applications, port=self.port, address=args.address)
 
         if args.show:
             # we have to defer opening in browser until
@@ -107,7 +108,13 @@
 
         if self.develop_mode:
             log.info("Using develop mode (do not enable --develop in production)")
-        log.info("Starting Bokeh server on port %d with apps at %r", server.port, sorted(applications.keys()))
+        address_string = ''
+        if server.address is not None and server.address != '':
+            address_string = ' address ' + server.address
+        log.info("Starting Bokeh server on port %d%s with applications at paths %r",
+                 server.port,
+                 address_string,
+                 sorted(applications.keys()))
         server.start()
 
 class Html(ApplicationsSubcommand):
diff --git a/bokeh/server/server.py b/bokeh/server/server.py
--- a/bokeh/server/server.py
+++ b/bokeh/server/server.py
@@ -39,13 +39,23 @@
         self._port = DEFAULT_SERVER_PORT
         if 'port' in kwargs:
             self._port = kwargs['port']
+        self._address = None
+        if 'address' in kwargs:
+            self._address = kwargs['address']
         # these queue a callback on the ioloop rather than
         # doing the operation immediately (I think - havocp)
         try:
-            self._http.bind(self._port)
+            self._http.bind(self._port, address=self._address)
             self._http.start(1)
-        except OSError:
-            log.critical("Cannot start bokeh server, port %s already in use" % self._port)
+        except OSError as e:
+            import errno
+            if e.errno == errno.EADDRINUSE:
+                log.critical("Cannot start Bokeh server, port %s is already in use", self._port)
+            elif e.errno == errno.EADDRNOTAVAIL:
+                log.critical("Cannot start Bokeh server, address '%s' not available", self._address)
+            else:
+                codename = errno.errorcode[e.errno]
+                log.critical("Cannot start Bokeh server, %s %r", codename, e)
             sys.exit(1)
 
     # TODO this is broken, it's only used by test_client_server.py so fix that then remove this
@@ -57,6 +67,10 @@
     def port(self):
         return self._port
 
+    @property
+    def address(self):
+        return self._address
+
     @property
     def io_loop(self):
         return self._tornado.io_loop

{"golden_diff": "diff --git a/bokeh/command/__init__.py b/bokeh/command/__init__.py\n--- a/bokeh/command/__init__.py\n+++ b/bokeh/command/__init__.py\n@@ -77,9 +77,10 @@\n \n     def __init__(self, **kwargs):\n         super(Serve, self).__init__(**kwargs)\n-        self.parser.add_argument('--port', metavar='PORT', type=int, help=\"Port to listen on\", default=-1)\n         self.parser.add_argument('--develop', action='store_true', help=\"Enable develop-time features that should not be used in production\")\n         self.parser.add_argument('--show', action='store_true', help=\"Open server app(s) in a browser\")\n+        self.parser.add_argument('--port', metavar='PORT', type=int, help=\"Port to listen on\", default=-1)\n+        self.parser.add_argument('--address', metavar='ADDRESS', type=str, help=\"Address to listen on\", default=None)\n         self.port = 5006\n         self.develop_mode = False\n         self.server = None\n@@ -95,7 +96,7 @@\n         # TODO make log level a command line option\n         logging.basicConfig(level=logging.DEBUG)\n \n-        server = Server(applications, port=self.port)\n+        server = Server(applications, port=self.port, address=args.address)\n \n         if args.show:\n             # we have to defer opening in browser until\n@@ -107,7 +108,13 @@\n \n         if self.develop_mode:\n             log.info(\"Using develop mode (do not enable --develop in production)\")\n-        log.info(\"Starting Bokeh server on port %d with apps at %r\", server.port, sorted(applications.keys()))\n+        address_string = ''\n+        if server.address is not None and server.address != '':\n+            address_string = ' address ' + server.address\n+        log.info(\"Starting Bokeh server on port %d%s with applications at paths %r\",\n+                 server.port,\n+                 address_string,\n+                 sorted(applications.keys()))\n         server.start()\n \n class Html(ApplicationsSubcommand):\ndiff --git a/bokeh/server/server.py b/bokeh/server/server.py\n--- a/bokeh/server/server.py\n+++ b/bokeh/server/server.py\n@@ -39,13 +39,23 @@\n         self._port = DEFAULT_SERVER_PORT\n         if 'port' in kwargs:\n             self._port = kwargs['port']\n+        self._address = None\n+        if 'address' in kwargs:\n+            self._address = kwargs['address']\n         # these queue a callback on the ioloop rather than\n         # doing the operation immediately (I think - havocp)\n         try:\n-            self._http.bind(self._port)\n+            self._http.bind(self._port, address=self._address)\n             self._http.start(1)\n-        except OSError:\n-            log.critical(\"Cannot start bokeh server, port %s already in use\" % self._port)\n+        except OSError as e:\n+            import errno\n+            if e.errno == errno.EADDRINUSE:\n+                log.critical(\"Cannot start Bokeh server, port %s is already in use\", self._port)\n+            elif e.errno == errno.EADDRNOTAVAIL:\n+                log.critical(\"Cannot start Bokeh server, address '%s' not available\", self._address)\n+            else:\n+                codename = errno.errorcode[e.errno]\n+                log.critical(\"Cannot start Bokeh server, %s %r\", codename, e)\n             sys.exit(1)\n \n     # TODO this is broken, it's only used by test_client_server.py so fix that then remove this\n@@ -57,6 +67,10 @@\n     def port(self):\n         return self._port\n \n+    @property\n+    def address(self):\n+        return self._address\n+\n     @property\n     def io_loop(self):\n         return self._tornado.io_loop\n", "issue": "Allow for configuring the IP address of the Bokeh server\nI have downloaded the bokeh developer build \"conda install -c bokeh/channel/dev bokeh\", which has a new Bokeh server \"https://github.com/bokeh/bokeh/wiki/Porting-guide:-new-Bokeh-server\".\n\nFor previous Bokeh server, this capability is added (see \"add ability to use a different ip address and port for bokeh-server #383\"). \n\nPlease tell me how to use a different ip address for the new bokeh server \"boken serve\".\nBTW, I know that I can change to a different port by using \"bokeh serve --port PORT\"\n\nThank you very much!\n\n", "before_files": [{"content": "''' Provides a Server which instantiates Application instances as clients connect\n\n'''\nfrom __future__ import absolute_import, print_function\n\nimport logging\nlog = logging.getLogger(__name__)\n\nimport sys\n\nfrom tornado.httpserver import HTTPServer\n\nfrom .tornado import BokehTornado\n\nfrom bokeh.application import Application\n\nfrom bokeh.resources import DEFAULT_SERVER_PORT\n\nclass Server(object):\n    ''' A Server which creates a new Session for each connection, using an Application to initialize each Session.\n\n    Args:\n        applications (dict of str: bokeh.application.Application) or bokeh.application.Application:\n            mapping from URL paths to Application instances, or a single Application to put at the root URL\n            The Application is a factory for Document, with a new Document initialized for each Session.\n            Each application should be identified by a path meant to go in a URL, like \"/\" or \"/foo\"\n    '''\n\n    def __init__(self, applications, **kwargs):\n        if isinstance(applications, Application):\n            self._applications = { '/' : applications }\n        else:\n            self._applications = applications\n        io_loop = None\n        if 'io_loop' in kwargs:\n            io_loop = kwargs['io_loop']\n        self._tornado = BokehTornado(self._applications, io_loop=io_loop)\n        self._http = HTTPServer(self._tornado)\n        self._port = DEFAULT_SERVER_PORT\n        if 'port' in kwargs:\n            self._port = kwargs['port']\n        # these queue a callback on the ioloop rather than\n        # doing the operation immediately (I think - havocp)\n        try:\n            self._http.bind(self._port)\n            self._http.start(1)\n        except OSError:\n            log.critical(\"Cannot start bokeh server, port %s already in use\" % self._port)\n            sys.exit(1)\n\n    # TODO this is broken, it's only used by test_client_server.py so fix that then remove this\n    @property\n    def ws_url(self):\n        return \"ws://localhost:\" + str(self._port) + \"/ws\"\n\n    @property\n    def port(self):\n        return self._port\n\n    @property\n    def io_loop(self):\n        return self._tornado.io_loop\n\n    def start(self):\n        ''' Start the Bokeh Server's IO loop.\n\n        Returns:\n            None\n\n        Notes:\n            Keyboard interrupts or sigterm will cause the server to shut down.\n\n        '''\n        self._tornado.start()\n\n    def stop(self):\n        ''' Stop the Bokeh Server's IO loop.\n\n        Returns:\n            None\n\n        '''\n        self._tornado.stop()\n\n    def unlisten(self):\n        '''Stop listening on ports (Server will no longer be usable after calling this)\n\n        Returns:\n            None\n        '''\n        self._http.stop()\n\n    def get_session(self, app_path, session_id):\n        '''Gets a session by name (session must already exist)'''\n\n        return self._tornado.get_session(app_path, session_id)\n\n    def show(self, app_path, browser=None, new='tab'):\n        ''' Opens an app in a browser window or tab.\n\n            Useful for testing server applications on your local desktop but\n            should not call when running bokeh-server on an actual server.\n\n        Args:\n            app_path (str) : the app path to open\n                The part of the URL after the hostname:port, with leading slash.\n\n            browser (str, optional) : browser to show with (default: None)\n                For systems that support it, the **browser** argument allows\n                specifying which browser to display in, e.g. \"safari\", \"firefox\",\n                \"opera\", \"windows-default\" (see the ``webbrowser`` module\n                documentation in the standard lib for more details).\n\n            new (str, optional) : window or tab (default: \"tab\")\n                If ``new`` is 'tab', then opens a new tab.\n                If ``new`` is 'window', then opens a new window.\n\n        Returns:\n            None\n        '''\n        if not app_path.startswith(\"/\"):\n            raise ValueError(\"app_path must start with a /\")\n        from bokeh.browserlib import view\n        url = \"http://localhost:%d%s\" % (self.port, app_path)\n        view(url, browser=browser, new=new)\n\n", "path": "bokeh/server/server.py"}, {"content": "from __future__ import print_function\n\nimport argparse\nimport sys\nimport os\n\nfrom bokeh.settings import settings\nfrom bokeh.application import Application\nfrom bokeh.server.server import Server\nfrom bokeh.application.spellings import ScriptHandler, DirectoryHandler\nfrom bokeh.io import output_file, save, show\n\nimport logging\nlog = logging.getLogger(__name__)\n\ndef die(message):\n    print(message, file=sys.stderr)\n    sys.exit(1)\n\nclass Subcommand(object):\n    \"\"\"Abstract base class for subcommands\"\"\"\n\n    def __init__(self, parser):\n        \"\"\"Initialize the subcommand with its parser; can call parser.add_argument to add subcommand flags\"\"\"\n        self.parser = parser\n\n    def func(self, args):\n        \"\"\"Takes over main program flow to perform the subcommand\"\"\"\n        pass\n\nclass ApplicationsSubcommand(Subcommand):\n    \"\"\"Abstract base class for subcommand that operates on a list of applications.\"\"\"\n\n    def __init__(self, **kwargs):\n        super(ApplicationsSubcommand, self).__init__(**kwargs)\n        self.parser.add_argument('files', metavar='DIRECTORY-OR-SCRIPT', nargs='*',  help=\"The app directories or scripts to serve (serve empty document if not specified)\", default=None)\n\n    def build_applications(self, args):\n        if args.files:\n            files = args.files\n        else:\n            files = []\n\n        applications = {}\n\n        for file in files:\n            file = os.path.abspath(file)\n            if os.path.isdir(file):\n                handler = DirectoryHandler(filename=file)\n            else:\n                handler = ScriptHandler(filename=file)\n\n            if handler.failed:\n                die(\"Error loading %s:\\n\\n%s\\n%s \" % (file, handler.error, handler.error_detail))\n\n            application = Application()\n            application.add(handler)\n\n            route = handler.url_path()\n            if not route:\n                if '/' in applications:\n                    die(\"Don't know the URL path to use for %s\" % (file))\n                route = '/'\n            applications[route] = application\n\n        if len(applications) == 0:\n            # create an empty application by default, used with output_server typically\n            applications['/'] = Application()\n\n        return applications\n\nclass Serve(ApplicationsSubcommand):\n    \"\"\"Subcommand to launch the Bokeh server.\"\"\"\n\n    name = \"serve\"\n    help = \"Run a Bokeh server hosting one or more applications\"\n\n    def __init__(self, **kwargs):\n        super(Serve, self).__init__(**kwargs)\n        self.parser.add_argument('--port', metavar='PORT', type=int, help=\"Port to listen on\", default=-1)\n        self.parser.add_argument('--develop', action='store_true', help=\"Enable develop-time features that should not be used in production\")\n        self.parser.add_argument('--show', action='store_true', help=\"Open server app(s) in a browser\")\n        self.port = 5006\n        self.develop_mode = False\n        self.server = None\n\n    def func(self, args):\n        if args.port >= 0:\n            self.port = args.port\n\n        self.develop_mode = args.develop\n\n        applications = self.build_applications(args)\n\n        # TODO make log level a command line option\n        logging.basicConfig(level=logging.DEBUG)\n\n        server = Server(applications, port=self.port)\n\n        if args.show:\n            # we have to defer opening in browser until\n            # we start up the server\n            def show_callback():\n                for route in applications.keys():\n                    server.show(route)\n            server.io_loop.add_callback(show_callback)\n\n        if self.develop_mode:\n            log.info(\"Using develop mode (do not enable --develop in production)\")\n        log.info(\"Starting Bokeh server on port %d with apps at %r\", server.port, sorted(applications.keys()))\n        server.start()\n\nclass Html(ApplicationsSubcommand):\n    \"\"\"Subcommand to output applications as standalone HTML files.\"\"\"\n\n    name = \"html\"\n    help = \"Create standalone HTML files for one or more applications\"\n\n    def __init__(self, **kwargs):\n        super(Html, self).__init__(**kwargs)\n        self.parser.add_argument('--show', action='store_true', help=\"Open generated file(s) in a browser\")\n\n    def func(self, args):\n        applications = self.build_applications(args)\n\n        for (route, app) in applications.items():\n            doc = app.create_document()\n            if route == \"/\":\n                filename = \"index.html\"\n            else:\n                filename = route[1:] + \".html\"\n\n            output_file(filename)\n\n            if args.show:\n                show(doc, new='tab')\n            else:\n                save(doc)\n\nsubcommands = [Serve, Html]\n\ndef main(argv):\n    parser = argparse.ArgumentParser(prog=argv[0])\n    # does this get set by anything other than BOKEH_VERSION env var?\n    version = settings.version()\n    if not version:\n        version = \"unknown version\"\n    parser.add_argument('-v', '--version', action='version', version=version)\n    subs = parser.add_subparsers(help=\"Sub-commands\")\n    for klass in subcommands:\n        c_parser = subs.add_parser(klass.name, help=klass.help)\n        c = klass(parser=c_parser)\n        c_parser.set_defaults(func=c.func)\n\n    args = parser.parse_args(argv[1:])\n    args.func(args)\n", "path": "bokeh/command/__init__.py"}], "after_files": [{"content": "''' Provides a Server which instantiates Application instances as clients connect\n\n'''\nfrom __future__ import absolute_import, print_function\n\nimport logging\nlog = logging.getLogger(__name__)\n\nimport sys\n\nfrom tornado.httpserver import HTTPServer\n\nfrom .tornado import BokehTornado\n\nfrom bokeh.application import Application\n\nfrom bokeh.resources import DEFAULT_SERVER_PORT\n\nclass Server(object):\n    ''' A Server which creates a new Session for each connection, using an Application to initialize each Session.\n\n    Args:\n        applications (dict of str: bokeh.application.Application) or bokeh.application.Application:\n            mapping from URL paths to Application instances, or a single Application to put at the root URL\n            The Application is a factory for Document, with a new Document initialized for each Session.\n            Each application should be identified by a path meant to go in a URL, like \"/\" or \"/foo\"\n    '''\n\n    def __init__(self, applications, **kwargs):\n        if isinstance(applications, Application):\n            self._applications = { '/' : applications }\n        else:\n            self._applications = applications\n        io_loop = None\n        if 'io_loop' in kwargs:\n            io_loop = kwargs['io_loop']\n        self._tornado = BokehTornado(self._applications, io_loop=io_loop)\n        self._http = HTTPServer(self._tornado)\n        self._port = DEFAULT_SERVER_PORT\n        if 'port' in kwargs:\n            self._port = kwargs['port']\n        self._address = None\n        if 'address' in kwargs:\n            self._address = kwargs['address']\n        # these queue a callback on the ioloop rather than\n        # doing the operation immediately (I think - havocp)\n        try:\n            self._http.bind(self._port, address=self._address)\n            self._http.start(1)\n        except OSError as e:\n            import errno\n            if e.errno == errno.EADDRINUSE:\n                log.critical(\"Cannot start Bokeh server, port %s is already in use\", self._port)\n            elif e.errno == errno.EADDRNOTAVAIL:\n                log.critical(\"Cannot start Bokeh server, address '%s' not available\", self._address)\n            else:\n                codename = errno.errorcode[e.errno]\n                log.critical(\"Cannot start Bokeh server, %s %r\", codename, e)\n            sys.exit(1)\n\n    # TODO this is broken, it's only used by test_client_server.py so fix that then remove this\n    @property\n    def ws_url(self):\n        return \"ws://localhost:\" + str(self._port) + \"/ws\"\n\n    @property\n    def port(self):\n        return self._port\n\n    @property\n    def address(self):\n        return self._address\n\n    @property\n    def io_loop(self):\n        return self._tornado.io_loop\n\n    def start(self):\n        ''' Start the Bokeh Server's IO loop.\n\n        Returns:\n            None\n\n        Notes:\n            Keyboard interrupts or sigterm will cause the server to shut down.\n\n        '''\n        self._tornado.start()\n\n    def stop(self):\n        ''' Stop the Bokeh Server's IO loop.\n\n        Returns:\n            None\n\n        '''\n        self._tornado.stop()\n\n    def unlisten(self):\n        '''Stop listening on ports (Server will no longer be usable after calling this)\n\n        Returns:\n            None\n        '''\n        self._http.stop()\n\n    def get_session(self, app_path, session_id):\n        '''Gets a session by name (session must already exist)'''\n\n        return self._tornado.get_session(app_path, session_id)\n\n    def show(self, app_path, browser=None, new='tab'):\n        ''' Opens an app in a browser window or tab.\n\n            Useful for testing server applications on your local desktop but\n            should not call when running bokeh-server on an actual server.\n\n        Args:\n            app_path (str) : the app path to open\n                The part of the URL after the hostname:port, with leading slash.\n\n            browser (str, optional) : browser to show with (default: None)\n                For systems that support it, the **browser** argument allows\n                specifying which browser to display in, e.g. \"safari\", \"firefox\",\n                \"opera\", \"windows-default\" (see the ``webbrowser`` module\n                documentation in the standard lib for more details).\n\n            new (str, optional) : window or tab (default: \"tab\")\n                If ``new`` is 'tab', then opens a new tab.\n                If ``new`` is 'window', then opens a new window.\n\n        Returns:\n            None\n        '''\n        if not app_path.startswith(\"/\"):\n            raise ValueError(\"app_path must start with a /\")\n        from bokeh.browserlib import view\n        url = \"http://localhost:%d%s\" % (self.port, app_path)\n        view(url, browser=browser, new=new)\n\n", "path": "bokeh/server/server.py"}, {"content": "from __future__ import print_function\n\nimport argparse\nimport sys\nimport os\n\nfrom bokeh.settings import settings\nfrom bokeh.application import Application\nfrom bokeh.server.server import Server\nfrom bokeh.application.spellings import ScriptHandler, DirectoryHandler\nfrom bokeh.io import output_file, save, show\n\nimport logging\nlog = logging.getLogger(__name__)\n\ndef die(message):\n    print(message, file=sys.stderr)\n    sys.exit(1)\n\nclass Subcommand(object):\n    \"\"\"Abstract base class for subcommands\"\"\"\n\n    def __init__(self, parser):\n        \"\"\"Initialize the subcommand with its parser; can call parser.add_argument to add subcommand flags\"\"\"\n        self.parser = parser\n\n    def func(self, args):\n        \"\"\"Takes over main program flow to perform the subcommand\"\"\"\n        pass\n\nclass ApplicationsSubcommand(Subcommand):\n    \"\"\"Abstract base class for subcommand that operates on a list of applications.\"\"\"\n\n    def __init__(self, **kwargs):\n        super(ApplicationsSubcommand, self).__init__(**kwargs)\n        self.parser.add_argument('files', metavar='DIRECTORY-OR-SCRIPT', nargs='*',  help=\"The app directories or scripts to serve (serve empty document if not specified)\", default=None)\n\n    def build_applications(self, args):\n        if args.files:\n            files = args.files\n        else:\n            files = []\n\n        applications = {}\n\n        for file in files:\n            file = os.path.abspath(file)\n            if os.path.isdir(file):\n                handler = DirectoryHandler(filename=file)\n            else:\n                handler = ScriptHandler(filename=file)\n\n            if handler.failed:\n                die(\"Error loading %s:\\n\\n%s\\n%s \" % (file, handler.error, handler.error_detail))\n\n            application = Application()\n            application.add(handler)\n\n            route = handler.url_path()\n            if not route:\n                if '/' in applications:\n                    die(\"Don't know the URL path to use for %s\" % (file))\n                route = '/'\n            applications[route] = application\n\n        if len(applications) == 0:\n            # create an empty application by default, used with output_server typically\n            applications['/'] = Application()\n\n        return applications\n\nclass Serve(ApplicationsSubcommand):\n    \"\"\"Subcommand to launch the Bokeh server.\"\"\"\n\n    name = \"serve\"\n    help = \"Run a Bokeh server hosting one or more applications\"\n\n    def __init__(self, **kwargs):\n        super(Serve, self).__init__(**kwargs)\n        self.parser.add_argument('--develop', action='store_true', help=\"Enable develop-time features that should not be used in production\")\n        self.parser.add_argument('--show', action='store_true', help=\"Open server app(s) in a browser\")\n        self.parser.add_argument('--port', metavar='PORT', type=int, help=\"Port to listen on\", default=-1)\n        self.parser.add_argument('--address', metavar='ADDRESS', type=str, help=\"Address to listen on\", default=None)\n        self.port = 5006\n        self.develop_mode = False\n        self.server = None\n\n    def func(self, args):\n        if args.port >= 0:\n            self.port = args.port\n\n        self.develop_mode = args.develop\n\n        applications = self.build_applications(args)\n\n        # TODO make log level a command line option\n        logging.basicConfig(level=logging.DEBUG)\n\n        server = Server(applications, port=self.port, address=args.address)\n\n        if args.show:\n            # we have to defer opening in browser until\n            # we start up the server\n            def show_callback():\n                for route in applications.keys():\n                    server.show(route)\n            server.io_loop.add_callback(show_callback)\n\n        if self.develop_mode:\n            log.info(\"Using develop mode (do not enable --develop in production)\")\n        address_string = ''\n        if server.address is not None and server.address != '':\n            address_string = ' address ' + server.address\n        log.info(\"Starting Bokeh server on port %d%s with applications at paths %r\",\n                 server.port,\n                 address_string,\n                 sorted(applications.keys()))\n        server.start()\n\nclass Html(ApplicationsSubcommand):\n    \"\"\"Subcommand to output applications as standalone HTML files.\"\"\"\n\n    name = \"html\"\n    help = \"Create standalone HTML files for one or more applications\"\n\n    def __init__(self, **kwargs):\n        super(Html, self).__init__(**kwargs)\n        self.parser.add_argument('--show', action='store_true', help=\"Open generated file(s) in a browser\")\n\n    def func(self, args):\n        applications = self.build_applications(args)\n\n        for (route, app) in applications.items():\n            doc = app.create_document()\n            if route == \"/\":\n                filename = \"index.html\"\n            else:\n                filename = route[1:] + \".html\"\n\n            output_file(filename)\n\n            if args.show:\n                show(doc, new='tab')\n            else:\n                save(doc)\n\nsubcommands = [Serve, Html]\n\ndef main(argv):\n    parser = argparse.ArgumentParser(prog=argv[0])\n    # does this get set by anything other than BOKEH_VERSION env var?\n    version = settings.version()\n    if not version:\n        version = \"unknown version\"\n    parser.add_argument('-v', '--version', action='version', version=version)\n    subs = parser.add_subparsers(help=\"Sub-commands\")\n    for klass in subcommands:\n        c_parser = subs.add_parser(klass.name, help=klass.help)\n        c = klass(parser=c_parser)\n        c_parser.set_defaults(func=c.func)\n\n    args = parser.parse_args(argv[1:])\n    args.func(args)\n", "path": "bokeh/command/__init__.py"}]}