def build_applications(self, args): if args.files: files = args.files else: files = [] applications = {} for file in files: file = os.path.abspath(file) if os.path.isdir(file): handler = DirectoryHandler(filename=file) else: handler = ScriptHandler(filename=file) application = Application() application.add(handler) route = handler.url_path() if not route: if '/' in applications: die("Don't know the URL path to use for %s" % (file)) route = '/' applications[route] = application if len(applications) == 0: # create an empty application by default, used with output_server typically applications['/'] = Application() return applications
def test_pull_document(self): application = Application() def add_roots(doc): doc.add_root(AnotherModelInTestClientServer(bar=43)) doc.add_root(SomeModelInTestClientServer(foo=42)) handler = FunctionHandler(add_roots) application.add(handler) with ManagedServerLoop(application) as server: client_session = pull_session(session_id='test_pull_document', url=server.ws_url, io_loop=server.io_loop) assert len(client_session.document.roots) == 2 server_session = server.get_session('/', client_session.id) assert len(server_session.document.roots) == 2 results = {} for r in server_session.document.roots: if hasattr(r, 'foo'): results['foo'] = r.foo if hasattr(r, 'bar'): results['bar'] = r.bar assert results['foo'] == 42 assert results['bar'] == 43 client_session.close() client_session.loop_until_closed() assert not client_session.connected
def test_application_doesnt_validate_document_due_to_env_var(check_integrity, monkeypatch): monkeypatch.setenv("BOKEH_VALIDATE_DOC", "false") a = Application() d = Document() d.add_root(figure()) a.initialize_document(d) assert not check_integrity.called
def test_one_handler(self): a = Application() def add_roots(doc): doc.add_root(AnotherModelInTestApplication()) doc.add_root(SomeModelInTestApplication()) handler = FunctionHandler(add_roots) a.add(handler) doc = a.create_document() assert len(doc.roots) == 2
def test_no_static_path(): a = Application() def add_roots(doc): doc.add_root(AnotherModelInTestApplication()) doc.add_root(SomeModelInTestApplication()) def add_one_root(doc): doc.add_root(AnotherModelInTestApplication()) handler = FunctionHandler(add_roots) a.add(handler) handler2 = FunctionHandler(add_one_root) a.add(handler2) assert a.static_path == None
def test_excess_static_path(): a = Application() def add_roots(doc): doc.add_root(AnotherModelInTestApplication()) doc.add_root(SomeModelInTestApplication()) def add_one_root(doc): doc.add_root(AnotherModelInTestApplication()) handler = FunctionHandler(add_roots) handler._static = "foo" a.add(handler) handler2 = FunctionHandler(add_one_root) handler2._static = "bar" with pytest.raises(RuntimeError): a.add(handler2)
def test_lots_of_concurrent_messages(self, ManagedServerLoop) -> None: application = Application() def setup_stuff(doc): m1 = AnotherModelInTestClientServer(bar=43, name='m1') m2 = SomeModelInTestClientServer(foo=42, name='m2') m3 = SomeModelInTestClientServer(foo=68, name='m3') doc.add_root(m1) doc.add_root(m2) doc.add_root(m3) def timeout1(): m1.bar += 1 timeout1_cb_id = doc.add_timeout_callback(timeout1, 1) def timeout2(): m2.foo +=1 timeout2_cb_id = doc.add_timeout_callback(timeout2, 3) def periodic1(): m1.bar += 1 doc.remove_timeout_callback(timeout1_cb_id) doc.add_timeout_callback(timeout1, m1.bar % 7) doc.add_periodic_callback(periodic1, 3) def periodic2(): m2.foo += 1 doc.remove_timeout_callback(timeout2_cb_id) doc.add_timeout_callback(timeout2, m2.foo % 7) doc.add_periodic_callback(periodic2, 1) def server_on_change(event): if isinstance(event, ModelChangedEvent) and event.model is m3: return m3.foo += 1 doc.on_change(server_on_change) handler = FunctionHandler(setup_stuff) application.add(handler) # keep_alive_milliseconds=1 sends pings as fast as the OS will let us with ManagedServerLoop(application, keep_alive_milliseconds=1) as server: session = pull_session(session_id='test_lots_of_concurrent_messages', url=url(server), io_loop=server.io_loop) assert session.connected server_session = server.get_session('/', session.id) def client_timeout(): m = session.document.roots[0] m.name = m.name[::-1] cb_id = session.document.add_timeout_callback(client_timeout, 3) def client_periodic(): m = session.document.roots[1] m.name = m.name[::-1] session.document.remove_timeout_callback(cb_id) session.document.add_timeout_callback(client_timeout, 3) session.document.add_periodic_callback(client_periodic, 1) result = {} def end_test(): result['connected'] = session.connected result['server_connection_count'] = server_session.connection_count result['server_close_code'] = next(iter(server._tornado._clients))._socket.close_code result['doc'] = session.document.to_json() session.close() # making this longer is more likely to trigger bugs, but it also # makes the test take however much time you put here session.document.add_timeout_callback(end_test, 250) def client_on_change(event): if not isinstance(event, TitleChangedEvent): session.document.title = session.document.title[::-1] session.document.on_change(client_on_change) session._loop_until_closed() assert not session.connected # we should have still been connected at the end, # if we didn't have any crazy protocol errors assert 'connected' in result assert result['connected'] # server should also still have been connected assert result['server_connection_count'] == 1 assert result['server_close_code'] is None
def test__lifecycle_hooks(): application = Application() handler = HookTestHandler() application.add(handler) with ManagedServerLoop(application, check_unused_sessions_milliseconds=30) as server: # wait for server callbacks to run before we mix in the # session, this keeps the test deterministic def check_done(): if len(handler.hooks) == 4: server.io_loop.stop() server_load_checker = PeriodicCallback(check_done, 1) server_load_checker.start() server.io_loop.start() server_load_checker.stop() # now we create a session client_session = pull_session(session_id='test__lifecycle_hooks', url=url(server), io_loop=server.io_loop) client_doc = client_session.document assert len(client_doc.roots) == 1 server_session = server.get_session('/', client_session.id) server_doc = server_session.document assert len(server_doc.roots) == 1 # we have to capture these here for examination later, since after # the session is closed, doc.roots will be emptied client_hook_list = client_doc.roots[0] server_hook_list = server_doc.roots[0] client_session.close() # expire the session quickly rather than after the # usual timeout server_session.request_expiration() def on_done(): server.io_loop.stop() server.io_loop.call_later(0.1, on_done) server.io_loop.start() assert handler.hooks == ["server_loaded", "next_tick_server", "timeout_server", "periodic_server", "session_created", "next_tick_session", "modify", "timeout_session", "periodic_session", "session_destroyed", "server_unloaded"] assert handler.load_count == 1 assert handler.unload_count == 1 # this is 3 instead of 6 because locked callbacks on destroyed sessions # are turned into no-ops assert handler.session_creation_async_value == 3 assert client_doc.title == "Modified" assert server_doc.title == "Modified" # only the handler sees the event that adds "session_destroyed" since # the session is shut down at that point. assert client_hook_list.hooks == ["session_created", "modify"] assert server_hook_list.hooks == ["session_created", "modify"]
def test__existing_ioloop_with_multiple_processes_exception(ManagedServerLoop, event_loop) -> None: application = Application() loop = IOLoop.current() with pytest.raises(RuntimeError): with ManagedServerLoop(application, io_loop=loop, num_procs=3): pass
def invoke(self, args: argparse.Namespace) -> None: ''' ''' basicConfig(format=args.log_format, filename=args.log_file) # This is a bit of a fudge. We want the default log level for non-server # cases to be None, i.e. we don't set a log level. But for the server we # do want to set the log level to INFO if nothing else overrides that. log_level = settings.py_log_level(args.log_level) if log_level is None: log_level = logging.INFO logging.getLogger('bokeh').setLevel(log_level) if args.use_config is not None: log.info(f"Using override config file: {args.use_config}") settings.load_config(args.use_config) # protect this import inside a function so that "bokeh info" can work # even if Tornado is not installed from bokeh.server.server import Server files: List[str] = [] for f in args.files: if args.glob: files.extend(glob(f)) else: files.append(f) argvs = {f: args.args for f in files} applications = build_single_handler_applications(files, argvs) if len(applications) == 0: # create an empty application by default applications['/'] = Application() # rename args to be compatible with Server if args.keep_alive is not None: args.keep_alive_milliseconds = args.keep_alive if args.check_unused_sessions is not None: args.check_unused_sessions_milliseconds = args.check_unused_sessions if args.unused_session_lifetime is not None: args.unused_session_lifetime_milliseconds = args.unused_session_lifetime if args.stats_log_frequency is not None: args.stats_log_frequency_milliseconds = args.stats_log_frequency if args.mem_log_frequency is not None: args.mem_log_frequency_milliseconds = args.mem_log_frequency server_kwargs = { key: getattr(args, key) for key in [ 'port', 'address', 'unix_socket', 'allow_websocket_origin', 'num_procs', 'prefix', 'index', 'keep_alive_milliseconds', 'check_unused_sessions_milliseconds', 'unused_session_lifetime_milliseconds', 'stats_log_frequency_milliseconds', 'mem_log_frequency_milliseconds', 'use_xheaders', 'websocket_max_message_size', 'websocket_compression_level', 'websocket_compression_mem_level', 'include_cookies', 'include_headers', 'exclude_cookies', 'exclude_headers', 'session_token_expiration', ] if getattr(args, key, None) is not None } server_kwargs['sign_sessions'] = settings.sign_sessions() server_kwargs['secret_key'] = settings.secret_key_bytes() server_kwargs['ssl_certfile'] = settings.ssl_certfile( getattr(args, 'ssl_certfile', None)) server_kwargs['ssl_keyfile'] = settings.ssl_keyfile( getattr(args, 'ssl_keyfile', None)) server_kwargs['ssl_password'] = settings.ssl_password() server_kwargs['generate_session_ids'] = True if args.session_ids is None: # no --session-ids means use the env vars pass elif args.session_ids == 'unsigned': server_kwargs['sign_sessions'] = False elif args.session_ids == 'signed': server_kwargs['sign_sessions'] = True elif args.session_ids == 'external-signed': server_kwargs['sign_sessions'] = True server_kwargs['generate_session_ids'] = False else: raise RuntimeError( "argparse should have filtered out --session-ids mode " + args.session_ids) if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']: die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; " + "the `bokeh secret` command can be used to generate a new key." ) if 'unix_socket' in server_kwargs: if server_kwargs['port'] != DEFAULT_SERVER_PORT: die("--port arg is not supported with a unix socket") invalid_args = [ 'address', 'allow_websocket_origin', 'ssl_certfile', 'ssl_keyfile' ] if any(server_kwargs.get(x) for x in invalid_args): die(f"{invalid_args + ['port']} args are not supported with a unix socket" ) auth_module_path = settings.auth_module( getattr(args, 'auth_module', None)) if auth_module_path: server_kwargs['auth_provider'] = AuthModule(auth_module_path) else: server_kwargs['auth_provider'] = NullAuth() server_kwargs['xsrf_cookies'] = settings.xsrf_cookies( getattr(args, 'enable_xsrf_cookies', False)) server_kwargs['cookie_secret'] = settings.cookie_secret( getattr(args, 'cookie_secret', None)) server_kwargs['use_index'] = not args.disable_index server_kwargs['redirect_root'] = not args.disable_index_redirect server_kwargs['autoreload'] = args.dev is not None server_kwargs['ico_path'] = settings.ico_path( getattr(args, 'ico_path', None)) def find_autoreload_targets(app_path: str) -> None: path = os.path.abspath(app_path) if not os.path.isdir(path): return for path, _, files in os.walk(path): for name in files: if (fnmatch(name, '*.html') or fnmatch(name, '*.css') or fnmatch(name, '*.yaml')): log.info("Watching: " + os.path.join(path, name)) watch(os.path.join(path, name)) def add_optional_autoreload_files(file_list: List[str]) -> None: for filen in file_list: if os.path.isdir(filen): log.warning("Cannot watch directory " + filen) continue log.info("Watching: " + filen) watch(filen) if server_kwargs['autoreload']: if len(applications.keys()) != 1: die("--dev can only support a single app.") if server_kwargs['num_procs'] != 1: log.info("Running in --dev mode. --num-procs is limited to 1.") server_kwargs['num_procs'] = 1 find_autoreload_targets(args.files[0]) add_optional_autoreload_files(args.dev) applications = self.customize_applications(args, applications) server_kwargs = self.customize_kwargs(args, server_kwargs) with report_server_init_errors(**server_kwargs): server = Server(applications, **server_kwargs) if args.show: # we have to defer opening in browser until we start up the server def show_callback() -> None: for route in applications.keys(): server.show(route) server.io_loop.add_callback(show_callback) # Server may not have a port when bound to a unix socket if server.port: address_string = 'localhost' if server.address is not None and server.address != '': address_string = server.address if server_kwargs['ssl_certfile'] and ( server_kwargs['ssl_certfile'].endswith('.pem') or server_kwargs['ssl_keyfile']): protocol = 'https' else: protocol = 'http' for route in sorted(applications.keys()): url = f"{protocol}://{address_string}:{server.port}{server.prefix}{route}" log.info("Bokeh app running at: %s" % url) log.info("Starting Bokeh server with process id: %d" % os.getpid()) server.run_until_shutdown()
def run_server(filename, path='/', port=5000): apps = {path: Application(FunctionHandler(make_makedoc(filename)))} server = Server(apps, port=port, allow_websocket_origin=['*']) server.run_until_shutdown()
def test_use_xheaders(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application, use_xheaders=True) as server: assert server._http.xheaders == True
def test_address(self): loop = IOLoop() loop.make_current() server = Server(Application(), address='0.0.0.0') assert server.address == '0.0.0.0'
y='Lon', text='code', level='glyph', x_offset=5, y_offset=5, source=flight_source, render_mode='canvas', background_fill_color='red', text_font_size="8pt") p.add_tile(STAMEN_TONER) p.circle('y', 'x', source=flight_source, fill_color={ 'field': 'country', 'transform': color_mapper }, hover_color='yellow', size=10, fill_alpha=0.8, line_width=0.5) p.add_tools(my_hover) p.add_layout(labels) doc.title = 'REAL TIME FLIGHT TRACKING WITH PANDAS AND BOKEH' doc.add_root(p) # SERVER CODE apps = {'/': Application(FunctionHandler(flight_track))} server = Server(apps, port=5000) #define an unused port server.start()
def invoke(self, args): argvs = {f: args.args for f in args.files} applications = build_single_handler_applications(args.files, argvs) log_level = getattr(logging, args.log_level.upper()) logging.basicConfig(level=log_level, format=args.log_format) if len(applications) == 0: # create an empty application by default, typically used with output_server applications['/'] = Application() if args.keep_alive is not None: if args.keep_alive == 0: log.info("Keep-alive ping disabled") else: log.info("Keep-alive ping configured every %d milliseconds", args.keep_alive) # rename to be compatible with Server args.keep_alive_milliseconds = args.keep_alive if args.check_unused_sessions is not None: log.info("Check for unused sessions every %d milliseconds", args.check_unused_sessions) # rename to be compatible with Server args.check_unused_sessions_milliseconds = args.check_unused_sessions if args.unused_session_lifetime is not None: log.info("Unused sessions last for %d milliseconds", args.unused_session_lifetime) # rename to be compatible with Server args.unused_session_lifetime_milliseconds = args.unused_session_lifetime if args.stats_log_frequency is not None: log.info("Log statistics every %d milliseconds", args.stats_log_frequency) # rename to be compatible with Server args.stats_log_frequency_milliseconds = args.stats_log_frequency server_kwargs = { key: getattr(args, key) for key in [ 'port', 'address', 'allow_websocket_origin', 'host', 'prefix', 'develop', 'keep_alive_milliseconds', 'check_unused_sessions_milliseconds', 'unused_session_lifetime_milliseconds', 'stats_log_frequency_milliseconds', 'use_xheaders', ] if getattr(args, key, None) is not None } server_kwargs['sign_sessions'] = settings.sign_sessions() server_kwargs['secret_key'] = settings.secret_key_bytes() server_kwargs['generate_session_ids'] = True if args.session_ids is None: # no --session-ids means use the env vars pass elif args.session_ids == 'unsigned': server_kwargs['sign_sessions'] = False elif args.session_ids == 'signed': server_kwargs['sign_sessions'] = True elif args.session_ids == 'external-signed': server_kwargs['sign_sessions'] = True server_kwargs['generate_session_ids'] = False else: raise RuntimeError( "argparse should have filtered out --session-ids mode " + args.session_ids) if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']: die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; " + "the `bokeh secret` command can be used to generate a new key." ) server = Server(applications, **server_kwargs) if args.show: # we have to defer opening in browser until we start up the server def show_callback(): for route in applications.keys(): server.show(route) server.io_loop.add_callback(show_callback) if args.develop: log.info( "Using develop mode (do not enable --develop in production)") 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())) log.info("Staring Bokeh server with process id: %d" % getpid()) server.start()
def test_port(self): loop = IOLoop() loop.make_current() server = Server(Application(), port=1234) assert server.port == 1234
def disss(abc): handler = FunctionHandler(modify_doc) app = Application(handler) show(app) make_plot(abc)
initial_crimes = option_selection # Put controls in a single element controls = WidgetBox(option_selection) # Create a row layout layout = row(controls) # Make a tab with the layout doc.add_root(layout) # Set up an application handler = FunctionHandler(modify_doc) app = Application(handler) show(app) # In[22]: from IPython.display import HTML HTML('''<script> code_show=true; function code_toggle() { if (code_show){ $('div.input').hide(); } else { $('div.input').show(); } code_show = !code_show }
def test__existing_ioloop_with_multiple_processes_exception(): application = Application() ioloop_instance = IOLoop.instance() ; ioloop_instance # silence flake8 with pytest.raises(RuntimeError): with ManagedServerLoop(application, num_procs=3): pass
# Put all the tabs into one application tabs = Tabs(tabs=[tab1]) doc.title = "World Development Indicator" doc.add_root(tabs) ''' def form_menu_group(list): return [(x,x) for x in list] def country_change_handler(attr, old, new): print (country_selection.value) def indicator_change_handler(attr, old, new): print(indicator_selection.value) form_menu_group(available_countries) ''' # show(layout) # curdoc().add_root(layout) # curdoc().title="World Development Indicator" # if __init__='__main__': apps = {'/': Application(FunctionHandler(modify_doc))} server = Server(apps, port=5000) server.start()
action='append', type=str, metavar='HOST[:PORT]', help="""Public hostnames which may connect to the Bokeh websocket""", default=None) args = parser.parse_args() # This should remain here until --host is removed entirely _fixup_deprecated_host_args(args) applications = {} main_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'plot_app') handler = DirectoryHandler(filename=main_path) applications['/plot_app'] = Application(handler) server_kwargs = {} if args.port != None: server_kwargs['port'] = args.port if args.use_xheaders: server_kwargs['use_xheaders'] = args.use_xheaders server_kwargs['num_procs'] = args.numprocs if args.address != None: server_kwargs['address'] = args.address if args.host != None: server_kwargs['host'] = args.host if args.allow_websocket_origin != None: server_kwargs['allow_websocket_origin'] = args.allow_websocket_origin # increase the maximum upload size (default is 100MB) server_kwargs['http_server_kwargs'] = {'max_buffer_size': 300 * 1024 * 1024} show_ulog_file = False show_3d_page = False
# other stuff if (not isdir(server.config['UPLOAD_FOLDER'])): mkdir(server.config['UPLOAD_FOLDER']) # start Bokeh server if "gunicorn" in environ.get("SERVER_SOFTWARE", ""): forcedPort = getpid() sockets, port = bind_sockets("localhost", forcedPort) server.config['PORT'] = port + 20 server.logger.info("STARTED LISTENING INTERNALLY ON %d AND EXTERNALLY ON %d" % (port, server.config['PORT'])) else: sockets, port = bind_sockets("localhost", 0) server.config['PORT'] = port from graphion.visualise import modify_doc bkapp = Application(FunctionHandler(modify_doc)) def bk_worker(): set_event_loop(new_event_loop()) bokeh_tornado = BokehTornado({'/bkapp': bkapp}, extra_websocket_origins=["localhost:5000", "graphion.uddi.ng:*"]) bokeh_http = HTTPServer(bokeh_tornado) bokeh_http.add_sockets(sockets) server = BaseServer(IOLoop.current(), bokeh_tornado, bokeh_http) server.start() server.io_loop.start() from threading import Thread Thread(target=bk_worker).start()
def test__lifecycle_hooks(): application = Application() handler = HookTestHandler() application.add(handler) with ManagedServerLoop(application, check_unused_sessions_milliseconds=30) as server: # wait for server callbacks to run before we mix in the # session, this keeps the test deterministic def check_done(): if len(handler.hooks) == 4: server.io_loop.stop() server_load_checker = PeriodicCallback(check_done, 1, io_loop=server.io_loop) server_load_checker.start() server.io_loop.start() server_load_checker.stop() # now we create a session client_session = pull_session(session_id='test__lifecycle_hooks', url=url(server), io_loop=server.io_loop) client_doc = client_session.document assert len(client_doc.roots) == 1 server_session = server.get_session('/', client_session.id) server_doc = server_session.document assert len(server_doc.roots) == 1 client_session.close() # expire the session quickly rather than after the # usual timeout server_session.request_expiration() def on_done(): server.io_loop.stop() server.io_loop.call_later(0.1, on_done) server.io_loop.start() assert handler.hooks == [ "server_loaded", "next_tick_server", "timeout_server", "periodic_server", "session_created", "next_tick_session", "modify", "timeout_session", "periodic_session", "session_destroyed", "server_unloaded" ] client_hook_list = client_doc.roots[0] server_hook_list = server_doc.roots[0] assert handler.load_count == 1 assert handler.unload_count == 1 assert handler.session_creation_async_value == 6 assert client_doc.title == "Modified" assert server_doc.title == "Modified" # the client session doesn't see the event that adds "session_destroyed" since # we shut down at that point. assert client_hook_list.hooks == ["session_created", "modify"] assert server_hook_list.hooks == [ "session_created", "modify", "session_destroyed" ]
def invoke(self, args): ''' ''' # protect this import inside a function so that "bokeh info" can work # even if Tornado is not installed from bokeh.server.server import Server argvs = {f: args.args for f in args.files} applications = build_single_handler_applications(args.files, argvs) log_level = getattr(logging, args.log_level.upper()) basicConfig(level=log_level, format=args.log_format, filename=args.log_file) if len(applications) == 0: # create an empty application by default applications['/'] = Application() # rename args to be compatible with Server if args.keep_alive is not None: args.keep_alive_milliseconds = args.keep_alive if args.check_unused_sessions is not None: args.check_unused_sessions_milliseconds = args.check_unused_sessions if args.unused_session_lifetime is not None: args.unused_session_lifetime_milliseconds = args.unused_session_lifetime if args.stats_log_frequency is not None: args.stats_log_frequency_milliseconds = args.stats_log_frequency if args.mem_log_frequency is not None: args.mem_log_frequency_milliseconds = args.mem_log_frequency server_kwargs = { key: getattr(args, key) for key in [ 'port', 'address', 'allow_websocket_origin', 'num_procs', 'prefix', 'index', 'keep_alive_milliseconds', 'check_unused_sessions_milliseconds', 'unused_session_lifetime_milliseconds', 'stats_log_frequency_milliseconds', 'mem_log_frequency_milliseconds', 'use_xheaders', 'websocket_max_message_size', ] if getattr(args, key, None) is not None } server_kwargs['sign_sessions'] = settings.sign_sessions() server_kwargs['secret_key'] = settings.secret_key_bytes() server_kwargs['generate_session_ids'] = True if args.session_ids is None: # no --session-ids means use the env vars pass elif args.session_ids == 'unsigned': server_kwargs['sign_sessions'] = False elif args.session_ids == 'signed': server_kwargs['sign_sessions'] = True elif args.session_ids == 'external-signed': server_kwargs['sign_sessions'] = True server_kwargs['generate_session_ids'] = False else: raise RuntimeError( "argparse should have filtered out --session-ids mode " + args.session_ids) if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']: die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; " + "the `bokeh secret` command can be used to generate a new key." ) server_kwargs['use_index'] = not args.disable_index server_kwargs['redirect_root'] = not args.disable_index_redirect server_kwargs['autoreload'] = args.dev is not None def find_autoreload_targets(app_path): path = os.path.abspath(app_path) if not os.path.isdir(path): return for path, subdirs, files in os.walk(path): for name in files: if (fnmatch(name, '*.html') or fnmatch(name, '*.css') or fnmatch(name, '*.yaml')): log.info("Watching: " + os.path.join(path, name)) watch(os.path.join(path, name)) def add_optional_autoreload_files(file_list): for filen in file_list: if os.path.isdir(filen): log.warning("Cannot watch directory " + filen) continue log.info("Watching: " + filen) watch(filen) if server_kwargs['autoreload']: if len(applications.keys()) != 1: die("--dev can only support a single app.") if server_kwargs['num_procs'] != 1: log.info("Running in --dev mode. --num-procs is limited to 1.") server_kwargs['num_procs'] = 1 find_autoreload_targets(args.files[0]) add_optional_autoreload_files(args.dev) with report_server_init_errors(**server_kwargs): server = Server(applications, **server_kwargs) if args.show: # we have to defer opening in browser until we start up the server def show_callback(): for route in applications.keys(): server.show(route) server.io_loop.add_callback(show_callback) address_string = 'localhost' if server.address is not None and server.address != '': address_string = server.address for route in sorted(applications.keys()): url = "http://%s:%d%s%s" % (address_string, server.port, server.prefix, route) log.info("Bokeh app running at: %s" % url) log.info("Starting Bokeh server with process id: %d" % os.getpid()) server.run_until_shutdown()
def test_empty(self): a = Application() doc = a.create_document() assert not doc.roots
# Bokeh runner import tornado.web from bokeh.application import Application from bokeh.application.handlers import FunctionHandler from bokeh.server.server import Server from src import robot, inverse server = Server( { '/robot': Application(FunctionHandler(robot.main)), '/inversek': Application(FunctionHandler(inverse.main)) }, extra_patterns=[ #('/api', api.ApiHandler), (r'/my_static/(.*)', tornado.web.StaticFileHandler, { "path": "my_static/" }) ], allow_websocket_origin=["localhost:5006"]) server.start() if __name__ == '__main__': print( 'Opening Tornado app with embedded Bokeh application on http://localhost:5006/' ) server.io_loop.start()
def create_ready_app(): return Application(ReadyHandler())
def test__lifecycle_hooks(ManagedServerLoop) -> None: application = Application() handler = HookTestHandler() application.add(handler) with ManagedServerLoop(application, check_unused_sessions_milliseconds=30) as server: # wait for server callbacks to run before we mix in the # session, this keeps the test deterministic def check_done(): if len(handler.hooks) == 4: server.io_loop.stop() server_load_checker = PeriodicCallback(check_done, 1) server_load_checker.start() server.io_loop.start() server_load_checker.stop() # now we create a session client_session = pull_session(session_id='test__lifecycle_hooks', url=url(server), io_loop=server.io_loop) client_doc = client_session.document assert len(client_doc.roots) == 1 server_session = server.get_session('/', client_session.id) server_doc = server_session.document assert len(server_doc.roots) == 1 # we have to capture these here for examination later, since after # the session is closed, doc.roots will be emptied client_hook_list = client_doc.roots[0] server_hook_list = server_doc.roots[0] client_session.close() # expire the session quickly rather than after the # usual timeout server_session.request_expiration() def on_done(): server.io_loop.stop() server.io_loop.call_later(0.1, on_done) server.io_loop.start() assert handler.hooks == ["server_loaded", "next_tick_server", "timeout_server", "periodic_server", "session_created", "modify", "next_tick_session", "timeout_session", "periodic_session", "session_destroyed", "server_unloaded"] assert handler.load_count == 1 assert handler.unload_count == 1 # this is 3 instead of 6 because locked callbacks on destroyed sessions # are turned into no-ops assert handler.session_creation_async_value == 3 assert client_doc.title == "Modified" assert server_doc.title == "Modified" # only the handler sees the event that adds "session_destroyed" since # the session is shut down at that point. assert client_hook_list.hooks == ["session_created", "modify"] assert server_hook_list.hooks == ["session_created", "modify"]
def test_unit_spec_changes_do_not_boomerang(monkeypatch): application = Application() with ManagedServerLoop(application) as server: doc = document.Document() client_root = UnitsSpecModel() doc.add_root(client_root) client_session = push_session( doc, session_id='test_unit_spec_changes_do_not_boomerang', url=url(server), io_loop=server.io_loop) server_session = server.get_session('/', client_session.id) assert len(server_session.document.roots) == 1 server_root = next(iter(server_session.document.roots)) assert client_root.distance == 42 assert server_root.angle == 0 def change_to(new_distance, new_angle): got_angry = {} got_angry['result'] = None # trap any boomerang def get_angry(message): got_angry['result'] = message monkeypatch.setattr(client_session, '_handle_patch', get_angry) server_previous_distance = server_root.distance server_previous_angle = server_root.angle # Now modify the client document client_root.distance = new_distance client_root.angle = new_angle # wait until server side change made ... but we may not have the # boomerang yet def server_change_made(): return server_root.distance != server_previous_distance and \ server_root.angle != server_previous_angle client_session._connection._loop_until(server_change_made) # force a round trip to be sure we get the boomerang if we're going to client_session.force_roundtrip() assert got_angry['result'] is None change_to(57, 1) change_to({'value': 58}, {'value': 2}) change_to({'field': 'foo'}, {'field': 'bar'}) change_to({ 'value': 59, 'units': 'screen' }, { 'value': 30, 'units': 'deg' }) client_session.close() client_session.loop_until_closed(suppress_warning=True) assert not client_session.connected server.unlisten() # clean up so next test can run
async def test__actual_port_number(ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application, port=0) as server: port = server.port assert port > 0 await http_get(server.io_loop, url(server))
def app(self_or_cls, plot, show=False, new_window=False, websocket_origin=None, port=0): """ Creates a bokeh app from a HoloViews object or plot. By default simply attaches the plot to bokeh's curdoc and returns the Document, if show option is supplied creates an Application instance and displays it either in a browser window or inline if notebook extension has been loaded. Using the new_window option the app may be displayed in a new browser tab once the notebook extension has been loaded. A websocket origin is required when launching from an existing tornado server (such as the notebook) and it is not on the default port ('localhost:8888'). """ if not isinstance(self_or_cls, BokehRenderer) or self_or_cls.mode != 'server': renderer = self_or_cls.instance(mode='server') else: renderer = self_or_cls def modify_doc(doc): renderer(plot, doc=doc) handler = FunctionHandler(modify_doc) app = Application(handler) if not show: # If not showing and in notebook context return app return app elif self_or_cls.notebook_context and not new_window: # If in notebook, show=True and no new window requested # display app inline if isinstance(websocket_origin, list): if len(websocket_origin) > 1: raise ValueError( 'In the notebook only a single websocket origin ' 'may be defined, which must match the URL of the ' 'notebook server.') websocket_origin = websocket_origin[0] opts = dict( notebook_url=websocket_origin) if websocket_origin else {} return bkshow(app, **opts) # If app shown outside notebook or new_window requested # start server and open in new browser tab from tornado.ioloop import IOLoop loop = IOLoop.current() if websocket_origin and not isinstance(websocket_origin, list): websocket_origin = [websocket_origin] opts = dict(allow_websocket_origin=websocket_origin ) if websocket_origin else {} opts['io_loop'] = loop server = Server({'/': app}, port=port, **opts) def show_callback(): server.show('/') server.io_loop.add_callback(show_callback) server.start() def sig_exit(*args, **kwargs): loop.add_callback_from_signal(do_stop) def do_stop(*args, **kwargs): loop.stop() signal.signal(signal.SIGINT, sig_exit) try: loop.start() except RuntimeError: pass return server
def test_server_changes_go_to_client(self, ManagedServerLoop) -> None: application = Application() with ManagedServerLoop(application) as server: doc = document.Document() client_session = push_session(doc, session_id='test_server_changes_go_to_client', url=url(server), io_loop=server.io_loop) server_session = server.get_session('/', client_session.id) assert len(client_session.document.roots) == 0 server_root = SomeModelInTestClientServer(foo=42) def do_add_server_root(): server_session.document.add_root(server_root) server.io_loop.spawn_callback(server_session.with_document_locked, do_add_server_root) def client_has_root(): return len(doc.roots) > 0 client_session._connection._loop_until(client_has_root) client_root = next(iter(client_session.document.roots)) assert client_root.foo == 42 assert server_root.foo == 42 # Now try setting title on server side def do_set_server_title(): server_session.document.title = "Server Title" server.io_loop.spawn_callback(server_session.with_document_locked, do_set_server_title) def client_title_set(): return client_session.document.title != document.DEFAULT_TITLE client_session._connection._loop_until(client_title_set) assert client_session.document.title == "Server Title" # Now modify a model within the server document def do_set_property_on_server(): server_root.foo = 57 server.io_loop.spawn_callback(server_session.with_document_locked, do_set_property_on_server) # there is no great way to block until the server # has applied changes, since patches are sent # asynchronously. We use internal _loop_until API. def client_change_made(): return client_root.foo == 57 client_session._connection._loop_until(client_change_made) assert client_root.foo == 57 def do_remove_server_root(): server_session.document.remove_root(server_root) server.io_loop.spawn_callback(server_session.with_document_locked, do_remove_server_root) def client_lacks_root(): return len(doc.roots) == 0 client_session._connection._loop_until(client_lacks_root) assert len(client_session.document.roots) == 0 client_session.close() client_session._loop_until_closed() assert not client_session.connected
def test_application_validates_document_by_default(check_integrity): a = Application() d = Document() d.add_root(figure()) a.initialize_document(d) assert check_integrity.called
ytmp = 100 * tmp new = { 'x': [tmp], 'y': [ytmp // (tmp + 1)], 'color': [random.choice(['red', 'blue', 'green'])] } source.stream(new) doc.add_periodic_callback(update, 500) fig = figure(title='Simulation playback!', sizing_mode='scale_height', x_range=[0, 100], y_range=[0, 100]) fig.line(source=source, x='x', y='y', color='red') # size=10) doc.title = "Now with live updating!" doc.add_root(fig) apps = {'/': Application(FunctionHandler(make_document))} server = Server(apps, port=5000) server.start() if __name__ == '__main__': print('Opening Bokeh application on http://localhost:5006/') server.io_loop.add_callback(server.show, "/") server.io_loop.start()
def _fixup(self, app: Application) -> Application: if not any( isinstance(handler, DocumentLifecycleHandler) for handler in app.handlers): app.add(DocumentLifecycleHandler()) return app
def invoke(self, args): ''' ''' # protect this import inside a function so that "bokeh info" can work # even if Tornado is not installed from bokeh.server.server import Server argvs = { f : args.args for f in args.files} applications = build_single_handler_applications(args.files, argvs) log_level = getattr(logging, args.log_level.upper()) basicConfig(level=log_level, format=args.log_format) # This should remain here until --host is removed entirely _fixup_deprecated_host_args(args) if len(applications) == 0: # create an empty application by default applications['/'] = Application() if args.keep_alive is not None: if args.keep_alive == 0: log.info("Keep-alive ping disabled") else: log.info("Keep-alive ping configured every %d milliseconds", args.keep_alive) # rename to be compatible with Server args.keep_alive_milliseconds = args.keep_alive if args.check_unused_sessions is not None: log.info("Check for unused sessions every %d milliseconds", args.check_unused_sessions) # rename to be compatible with Server args.check_unused_sessions_milliseconds = args.check_unused_sessions if args.unused_session_lifetime is not None: log.info("Unused sessions last for %d milliseconds", args.unused_session_lifetime) # rename to be compatible with Server args.unused_session_lifetime_milliseconds = args.unused_session_lifetime if args.stats_log_frequency is not None: log.info("Log statistics every %d milliseconds", args.stats_log_frequency) # rename to be compatible with Server args.stats_log_frequency_milliseconds = args.stats_log_frequency server_kwargs = { key: getattr(args, key) for key in ['port', 'address', 'allow_websocket_origin', 'num_procs', 'prefix', 'keep_alive_milliseconds', 'check_unused_sessions_milliseconds', 'unused_session_lifetime_milliseconds', 'stats_log_frequency_milliseconds', 'use_xheaders', ] if getattr(args, key, None) is not None } server_kwargs['sign_sessions'] = settings.sign_sessions() server_kwargs['secret_key'] = settings.secret_key_bytes() server_kwargs['generate_session_ids'] = True if args.session_ids is None: # no --session-ids means use the env vars pass elif args.session_ids == 'unsigned': server_kwargs['sign_sessions'] = False elif args.session_ids == 'signed': server_kwargs['sign_sessions'] = True elif args.session_ids == 'external-signed': server_kwargs['sign_sessions'] = True server_kwargs['generate_session_ids'] = False else: raise RuntimeError("argparse should have filtered out --session-ids mode " + args.session_ids) if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']: die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; " + "the `bokeh secret` command can be used to generate a new key.") server_kwargs['use_index'] = not args.disable_index server_kwargs['redirect_root'] = not args.disable_index_redirect with report_server_init_errors(**server_kwargs): server = Server(applications, **server_kwargs) if args.show: # we have to defer opening in browser until we start up the server def show_callback(): for route in applications.keys(): server.show(route) server.io_loop.add_callback(show_callback) address_string = 'localhost' if server.address is not None and server.address != '': address_string = server.address for route in sorted(applications.keys()): url = "http://%s:%d%s%s" % (address_string, server.port, server.prefix, route) log.info("Bokeh app running at: %s" % url) log.info("Starting Bokeh server with process id: %d" % getpid()) server.run_until_shutdown()
def get_bokeh_app(cls): if cls._bokeh_app is None: cls._bokeh_app = Application(FunctionHandler(cls.modify_doc)) return cls._bokeh_app
def test_lots_of_concurrent_messages(self): application = Application() def setup_stuff(doc): m1 = AnotherModelInTestClientServer(bar=43, name='m1') m2 = SomeModelInTestClientServer(foo=42, name='m2') m3 = SomeModelInTestClientServer(foo=68, name='m3') doc.add_root(m1) doc.add_root(m2) doc.add_root(m3) def timeout1(): m1.bar += 1 doc.add_timeout_callback(timeout1, 1) def timeout2(): m2.foo +=1 doc.add_timeout_callback(timeout2, 3) def periodic1(): m1.bar += 1 doc.remove_timeout_callback(timeout1) doc.add_timeout_callback(timeout1, m1.bar % 7) doc.add_periodic_callback(periodic1, 3) def periodic2(): m2.foo += 1 doc.remove_timeout_callback(timeout2) doc.add_timeout_callback(timeout2, m2.foo % 7) doc.add_periodic_callback(periodic2, 1) def server_on_change(event): if isinstance(event, ModelChangedEvent) and event.model is m3: return m3.foo += 1 doc.on_change(server_on_change) handler = FunctionHandler(setup_stuff) application.add(handler) # keep_alive_milliseconds=1 sends pings as fast as the OS will let us with ManagedServerLoop(application, keep_alive_milliseconds=1) as server: session = pull_session(session_id='test_lots_of_concurrent_messages', url=url(server), io_loop=server.io_loop) assert session.connected server_session = server.get_session('/', session.id) def client_timeout(): m = session.document.roots[0] m.name = m.name[::-1] session.document.add_timeout_callback(client_timeout, 3) def client_periodic(): m = session.document.roots[1] m.name = m.name[::-1] session.document.remove_timeout_callback(client_timeout) session.document.add_timeout_callback(client_timeout, 3) session.document.add_periodic_callback(client_periodic, 1) result = {} def end_test(): result['connected'] = session.connected result['server_connection_count'] = server_session.connection_count result['server_close_code'] = next(iter(server._tornado._clients))._socket.close_code result['doc'] = session.document.to_json() session.close() # making this longer is more likely to trigger bugs, but it also # makes the test take however much time you put here session.document.add_timeout_callback(end_test, 250) def client_on_change(event): if not isinstance(event, TitleChangedEvent): session.document.title = session.document.title[::-1] session.document.on_change(client_on_change) session.loop_until_closed() assert not session.connected # we should have still been connected at the end, # if we didn't have any crazy protocol errors assert 'connected' in result assert result['connected'] # server should also still have been connected assert result['server_connection_count'] == 1 assert result['server_close_code'] is None
def start(self, event=None, block=False): try: ioloop.IOLoop.current() except RuntimeError: if six.PY3: import asyncio asyncio.set_event_loop(asyncio.new_event_loop()) loop = None try: loop = ioloop.IOLoop.current() except: pass if loop is None: raise else: raise if self._scheduler_ip is None: kv_store = kvstore.get(options.kv_store) try: schedulers = [s.key.rsplit('/', 1)[1] for s in kv_store.read('/schedulers').children] self._scheduler_ip = random.choice(schedulers) except KeyError: raise KeyError('No scheduler is available') static_path = os.path.join(os.path.dirname(__file__), 'static') handlers = dict() for p, h in _ui_handlers.items(): handlers[p] = Application(FunctionHandler(functools.partial(h, self._scheduler_ip))) extra_patterns = [ ('/static/(.*)', BokehStaticFileHandler, {'path': static_path}) ] for p, h in _api_handlers.items(): extra_patterns.append((p, h, {'scheduler_ip': self._scheduler_ip})) retrial = 5 while retrial: try: if self._port is None: use_port = get_next_port() else: use_port = self._port self._server = Server( handlers, allow_websocket_origin=['*'], address='0.0.0.0', port=use_port, extra_patterns=extra_patterns, ) self._server.start() self._port = use_port logger.info('Mars UI started at 0.0.0.0:%d', self._port) break except: if self._port is not None: raise retrial -= 1 if retrial == 0: raise if not block: self._server_thread = threading.Thread(target=self._server.io_loop.start) self._server_thread.daemon = True self._server_thread.start() if event: event.set() else: if event: event.set() self._server.io_loop.start()
def on_transfer_function_change(self, attr, old, new): self.model.transfer_function = self.model.transfer_functions[new] self.update_image() def on_opacity_slider_change(self, attr, old, new): for renderer in self.fig.renderers: if hasattr(renderer, 'image_source'): renderer.alpha = new / 100 if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--config', help='yaml config file (e.g. nyc_taxi.yml)', required=True) args = vars(parser.parse_args()) def add_roots(doc): model = AppState(args['config']) view = AppView(model) GetDataset.model = model doc.add_root(view.layout) app = Application() app.add(FunctionHandler(add_roots)) # Start server object wired to bokeh client. Instantiating ``Server`` # directly is used to add custom http endpoint into ``extra_patterns``. server = Server(app, io_loop=IOLoop(), extra_patterns=[(r"/datashader", GetDataset)], port=5000) print('Starting server at http://localhost:5000/...') server.start()
line_width=1, hover_line_color='color', hover_line_alpha=1.0, source=source) def modify_doc(doc): def x_range_change_cb(attr, old, new): new_range = (plot.x_range.start, plot.x_range.end) if None in new_range: return new_data = down_sample(data=data, npoints=screenwidth, limits=new_range) source.data = ColumnDataSource(data=new_data).data print('change detected!') plot.x_range.on_change('start', x_range_change_cb) plot.x_range.on_change('end', x_range_change_cb) doc.add_root(column(plot)) server = Server({'/': Application(FunctionHandler(modify_doc))}, io_loop=io_loop) server.start() if __name__ == '__main__': io_loop.add_callback(server.show, "/") io_loop.start()