Python 以编程方式运行bokeh服务器以在本地浏览器中显示

Python 以编程方式运行bokeh服务器以在本地浏览器中显示,python,python-3.x,tornado,bokeh,Python,Python 3.x,Tornado,Bokeh,我正在使用将在包中部署的bokeh(0.12.6)实用程序进行交互式数据操作。其思想是用户可以运行某个例程module.utility(),该例程将启动bokeh服务器,在浏览器中启动应用程序,当选项卡或浏览器关闭时,服务器将停止 如果我运行bokeh-service--show myapp,我的应用程序可以正常启动,但是当使用下面描述的方法连接到本地主机时,它会挂起。我已经检查了处理程序,一切都正常 这样做合理吗?我做得对吗 目录格式 <installed module path>

我正在使用将在包中部署的
bokeh
0.12.6
)实用程序进行交互式数据操作。其思想是用户可以运行某个例程
module.utility()
,该例程将启动bokeh服务器,在浏览器中启动应用程序,当选项卡或浏览器关闭时,服务器将停止

如果我运行
bokeh-service--show myapp
,我的应用程序可以正常启动,但是当使用下面描述的方法连接到本地主机时,它会挂起。我已经检查了处理程序,一切都正常

这样做合理吗?我做得对吗

目录格式

<installed module path>/myapp
└── main.py
def run_single_server(abs_app_path, port=5000):
    '''Run bokeh application for single session from server`'''
    from bokeh.application import Application
    from bokeh.application.handlers import DirectoryHandler
    from bokeh.server.server import Server
    import os

    app_name = os.path.split(abs_app_path)[1]
    url = '/{}'.format(app_name)

    # Start a bokeh server
    apps = {url:Application(DirectoryHandler(filename=abs_app_path))}
    server = Server(apps, port=port)
    server.start()
    server.show(url)

    # somehow wait for session to end, perhaps using `server_lifecycle.py`

    server.stop()

    return

def utility():
    import mymodule

    module_path = os.path.split(mymodule.__file__)[0]
    abs_app_path = os.path.join(module_path, 'myapp')

    run_single_server(abs_app_path, port=5000)

    return
运行脚本

<installed module path>/myapp
└── main.py
def run_single_server(abs_app_path, port=5000):
    '''Run bokeh application for single session from server`'''
    from bokeh.application import Application
    from bokeh.application.handlers import DirectoryHandler
    from bokeh.server.server import Server
    import os

    app_name = os.path.split(abs_app_path)[1]
    url = '/{}'.format(app_name)

    # Start a bokeh server
    apps = {url:Application(DirectoryHandler(filename=abs_app_path))}
    server = Server(apps, port=port)
    server.start()
    server.show(url)

    # somehow wait for session to end, perhaps using `server_lifecycle.py`

    server.stop()

    return

def utility():
    import mymodule

    module_path = os.path.split(mymodule.__file__)[0]
    abs_app_path = os.path.join(module_path, 'myapp')

    run_single_server(abs_app_path, port=5000)

    return
也许在主
\uuuu init\uuuu.py
中有该例程,并使其按如下方式工作:

import mymodule
mymodule.utility()

# 1. Browser launches
# 2. user does stuff
# 3. user closes window
# 4. bokeh server is shutdown

更新 我找到了常规并尝试了,但它似乎也挂起了

from bokeh.command.util import build_single_handler_application
import os

app_name = os.path.split(abs_app_path)[1]
url = '/{}'.format(app_name)

# Start a bokeh server
apps = build_single_handler_application(abs_app_path)

看起来我有几个问题。我最终找到并修改了我在邮件组中找到的一些代码,以用于我的用例

通过使用单独的过程,我成功地使一切正常工作:1)启动服务器,2)使用
webbrowser
启动应用程序URL,以及3)检查关闭的连接并关闭

我想我也许可以取消启动
tornado
服务器实例,就像在我改编的flask示例中所做的那样,但我很高兴在这里

注意:此示例使用单文件应用程序,但您也可以传递目录格式应用程序的路径

def create_bokeh_server(io_loop, files, argvs, host, port):
    '''Start bokeh server with applications paths'''
    from bokeh.server.server import Server
    from bokeh.command.util import build_single_handler_applications

    # Turn file paths into bokeh apps
    apps = build_single_handler_applications(files, argvs)

    # kwargs lifted from bokeh serve call to Server, with created io_loop
    kwargs = {
        'io_loop':io_loop,
        'generate_session_ids':True,
        'redirect_root':True,
        'use_x_headers':False,
        'secret_key':None,
        'num_procs':1,
        'host': host,
        'sign_sessions':False,
        'develop':False,
        'port':port,
        'use_index':True
    }
    server = Server(apps,**kwargs)

    return server


def run_single_app(files, port=5000, new='tab'):

    def start_bokeh(io_loop):
        '''Start the `io_loop`'''
        io_loop.start()
        return None

    def launch_app(host, app_name, new):
        '''Lauch app in browser

        Ideally this would `bokeh.util.browser.view()`, but it doesn't work
        '''
        import webbrowser

        # Map method strings to webbrowser method
        options = {'current':0, 'window':1, 'tab':2}

        # Concatenate url and open in browser, creating a session
        app_url = 'http://{}/{}'.format(host, app_name)
        print('Opening `{}` in browser'.format(app_url))
        webbrowser.open(app_url, new=options[new])

        return None

    def server_loop(server, io_loop):
        '''Check connections once session created and close on disconnect'''
        import time

        connected = [True,]
        session_loaded = False
        while any(connected):

            # Check if no session started on server
            sessions = server.get_sessions()
            if not session_loaded:
                if sessions:
                    session_loaded = True
            # Once 1+ sessions started, check for no connections
            else:
                # List of bools for each session
                connected = [True,]*len(sessions)
                # Set `connected` item false no connections on session
                for i in range(len(sessions)):
                    if sessions[i].connection_count == 0:
                        connected[i] = False
            # Keep the pace down
            time.sleep(2)

        # Stop server once opened session connections closed
        io_loop.stop()

        return None

    import os
    import threading
    import tornado.ioloop
    import tornado.autoreload
    import time

    # Initialize some values, sanatize the paths to the bokeh plots
    argvs = {}
    app_names = []
    for path in files:
        argvs[path] = None
        app_names.append(os.path.splitext(os.path.split(path)[1])[0])

    # Concate hostname/port for creating handlers, launching apps
    host = 'localhost:{}'.format(port)

    # Initialize the tornado server
    io_loop = tornado.ioloop.IOLoop.instance()
    tornado.autoreload.start(io_loop)

    # Add the io_loop to the bokeh server
    server = run_bokeh_server(io_loop, files, argvs, host, port)

    print('Starting the server on {}'.format(host))
    args = (io_loop,)
    th_startup = threading.Thread(target=start_bokeh, args=args)
    th_startup.start()

    # Launch each application in own tab or window
    th_launch = [None,]*len(app_names)
    for i in range(len(app_names)):
        args = (host, app_names[i], new)
        th_launch[i] = threading.Thread(target=launch_app, args=args)
        th_launch[i].start()
        # Delay to allow tabs to open in same browser window
        time.sleep(2)

    # Run session connection test, then stop `io_loop`
    args = (server, io_loop)
    th_shutdown = threading.Thread(target=server_loop, args=args)
    th_shutdown.start()

    return None

if __name__ == "__main__":

import os
files = [os.path.join('bokeh', fname) for fname in ['ex1.py','ex2.py']]
run_single_app(files, port=5006)

您在哪里找到“use_x_头”的文档:False?经过大量的谷歌搜索,这是我发现的唯一一个提到它的页面。我不记得了,但我猜我是从我在谷歌邮件列表中找到的代码中得到的。