def test_None_conjunction(self): assert bus.nice_join(["one"], conjuction=None) == "one" assert bus.nice_join(["one", "two"], conjuction=None) == "one, two" assert bus.nice_join(["one", "two", "three"], conjuction=None) == "one, two, three" assert bus.nice_join(["one", "two", "three", "four"], conjuction=None) == "one, two, three, four"
def test_string_conjunction(self): assert bus.nice_join(["one"], conjuction="and") == "one" assert bus.nice_join(["one", "two"], conjuction="and") == "one and two" assert bus.nice_join(["one", "two", "three"], conjuction="and") == "one, two and three" assert bus.nice_join(["one", "two", "three", "four"], conjuction="and") == "one, two, three and four"
def test_sep(self): assert bus.nice_join(["one"], sep='; ') == "one" assert bus.nice_join(["one", "two"], sep='; ') == "one or two" assert bus.nice_join(["one", "two", "three"], sep='; ') == "one; two or three" assert bus.nice_join(["one", "two", "three", "four"], sep="; ") == "one; two; three or four"
def main(argv): ''' Execute the Bokeh command. Args: argv (seq[str]) : a list of command line arguments to process Returns: None ''' if len(argv) == 1: die("ERROR: Must specify subcommand, one of: %s" % nice_join(x.name for x in subcommands.all)) parser = argparse.ArgumentParser(prog=argv[0]) # we don't use settings.version() because the point of this option # is to report the actual version of Bokeh, while settings.version() # lets people change the version used for CDN for example. parser.add_argument('-v', '--version', action='version', version=__version__) subs = parser.add_subparsers(help="Sub-commands") for cls in subcommands.all: subparser = subs.add_parser(cls.name, help=cls.help) subcommand = cls(parser=subparser) subparser.set_defaults(invoke=subcommand.invoke) args = parser.parse_args(argv[1:]) try: args.invoke(args) except Exception as e: die(str(e))
def main(argv): ''' Execute the Bokeh command. Args: argv (seq[str]) : a list of command line arguments to process Returns: None ''' if len(argv) == 1: die("ERROR: Must specify subcommand, one of: %s" % nice_join(x.name for x in subcommands.all)) parser = argparse.ArgumentParser(prog=argv[0]) # does this get set by anything other than BOKEH_VERSION env var? version = settings.version() if not version: version = "unknown version" parser.add_argument('-v', '--version', action='version', version=version) subs = parser.add_subparsers(help="Sub-commands") for cls in subcommands.all: subparser = subs.add_parser(cls.name, help=cls.help) subcommand = cls(parser=subparser) subparser.set_defaults(invoke=subcommand.invoke) args = parser.parse_args(argv[1:]) try: args.invoke(args) except Exception as e: die(str(e))
def main(argv): ''' Exectute the Bokeh command. Args: argv (seq[str]) : a list of command line arguments to process Returns: None ''' if len(argv) == 1: die("ERROR: Must specify subcommand, one of: %s" % nice_join(x.name for x in subcommands.all)) parser = argparse.ArgumentParser(prog=argv[0]) # does this get set by anything other than BOKEH_VERSION env var? version = settings.version() if not version: version = "unknown version" parser.add_argument('-v', '--version', action='version', version=version) subs = parser.add_subparsers(help="Sub-commands") for cls in subcommands.all: subparser = subs.add_parser(cls.name, help=cls.help) subcommand = cls(parser=subparser) subparser.set_defaults(invoke=subcommand.invoke) args = parser.parse_args(argv[1:]) try: args.invoke(args) except Exception as e: die(str(e))
def main(argv): ''' Execute the Bokeh command. Args: argv (seq[str]) : a list of command line arguments to process Returns: None The first item in ``argv`` is typically "bokeh", and the second should be the name of one of the available subcommands: * :ref:`html <bokeh.command.subcommands.html>` * :ref:`info <bokeh.command.subcommands.info>` * :ref:`json <bokeh.command.subcommands.json>` * :ref:`png <bokeh.command.subcommands.png>` * :ref:`sampledata <bokeh.command.subcommands.sampledata>` * :ref:`secret <bokeh.command.subcommands.secret>` * :ref:`serve <bokeh.command.subcommands.serve>` * :ref:`static <bokeh.command.subcommands.static>` * :ref:`svg <bokeh.command.subcommands.svg>` ''' if len(argv) == 1: die("ERROR: Must specify subcommand, one of: %s" % nice_join(x.name for x in subcommands.all)) parser = argparse.ArgumentParser( prog=argv[0], epilog="See '<command> --help' to read about a specific subcommand.") # we don't use settings.version() because the point of this option # is to report the actual version of Bokeh, while settings.version() # lets people change the version used for CDN for example. parser.add_argument('-v', '--version', action='version', version=__version__) subs = parser.add_subparsers(help="Sub-commands") for cls in subcommands.all: subparser = subs.add_parser(cls.name, help=cls.help) subcommand = cls(parser=subparser) subparser.set_defaults(invoke=subcommand.invoke) args = parser.parse_args(argv[1:]) try: ret = args.invoke(args) except Exception as e: if settings.dev: raise else: die("ERROR: " + str(e)) if ret is False: sys.exit(1) elif ret is not True and isinstance(ret, int) and ret != 0: sys.exit(ret)
def main(args=None): """Merges commands offered by pyct and bokeh and provides help for both""" from bokeh.command.subcommands import all as bokeh_commands try: import pyct.cmd pyct_commands = ['copy-examples', 'examples'] except Exception: pass parser = argparse.ArgumentParser( prog="panel", epilog="See '<command> --help' to read about a specific subcommand.") parser.add_argument('-v', '--version', action='version', version=__version__) subs = parser.add_subparsers(help="Sub-commands") for cmd in pyct_commands: cmd = cmd.replace('-', '_') fn = getattr(pyct.cmd, cmd) subs.add_parser(cmd, help=fn.__doc__) for cls in bokeh_commands: subs.add_parser(cls.name, help=cls.help) if len(sys.argv) == 1: all_commands = sorted([c.name for c in bokeh_commands] + pyct_commands) die("ERROR: Must specify subcommand, one of: %s" % nice_join(all_commands)) if sys.argv[1] in ('--help', '-h'): args = parser.parse_args(sys.argv[1:]) args.invoke(args) sys.exit() if len(sys.argv) > 1 and any(sys.argv[1] == c.name for c in bokeh_commands): if sys.argv[1] == 'serve' and not any( arg.startswith('--index') for arg in sys.argv): sys.argv = sys.argv + ['--index=%s' % INDEX_HTML] sys.argv = transform_cmds(sys.argv) bokeh_entry_point() elif sys.argv[1] in pyct_commands: try: import pyct.cmd except ImportError: print( "install pyct to enable this command (e.g. `conda install -c pyviz pyct` or `pip install pyct[cmd]`)" ) sys.exit(1) pyct.cmd.substitute_main('panel', cmds=pyct_commands, args=args) else: parser.parse_args(sys.argv[1:]) sys.exit(1)
def test_args(): from bokeh.util.string import nice_join assert scserve.Serve.args == ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help="The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--develop', dict( action='store_true', help="Enable develop-time features that should not be used in production", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--port', dict( metavar='PORT', type=int, help="Port to listen on", default=None )), ('--address', dict( metavar='ADDRESS', type=str, help="Address to listen on", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help="How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--log-level', dict( metavar='LOG-LEVEL', action = 'store', default = 'debug', choices = scserve.LOGLEVELS, help = "One of: %s" % nice_join(scserve.LOGLEVELS), )), )
def main(argv): ''' Execute the Bokeh command. Args: argv (seq[str]) : a list of command line arguments to process Returns: None The first item in ``argv`` is typically "bokeh", and the second should be the name of one of the available subcommands: * :ref:`html <bokeh.command.subcommands.html>` * :ref:`info <bokeh.command.subcommands.info>` * :ref:`json <bokeh.command.subcommands.json>` * :ref:`png <bokeh.command.subcommands.png>` * :ref:`sampledata <bokeh.command.subcommands.sampledata>` * :ref:`secret <bokeh.command.subcommands.secret>` * :ref:`serve <bokeh.command.subcommands.serve>` * :ref:`static <bokeh.command.subcommands.static>` * :ref:`svg <bokeh.command.subcommands.svg>` ''' if len(argv) == 1: die("ERROR: Must specify subcommand, one of: %s" % nice_join(x.name for x in subcommands.all)) parser = argparse.ArgumentParser( prog=argv[0], epilog="See '<command> --help' to read about a specific subcommand.") # we don't use settings.version() because the point of this option # is to report the actual version of Bokeh, while settings.version() # lets people change the version used for CDN for example. parser.add_argument('-v', '--version', action='version', version=__version__) subs = parser.add_subparsers(help="Sub-commands") for cls in subcommands.all: subparser = subs.add_parser(cls.name, help=cls.help) subcommand = cls(parser=subparser) subparser.set_defaults(invoke=subcommand.invoke) args = parser.parse_args(argv[1:]) try: args.invoke(args) except Exception as e: die("ERROR: " + str(e))
def test_args(): from bokeh.util.string import nice_join assert scserve.Serve.args == ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help= "The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--develop', dict( action='store_true', help= "Enable develop-time features that should not be used in production", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--port', dict( metavar='PORT', type=int, help="Port to listen on", default=scserve.DEFAULT_PORT, )), ('--address', dict( metavar='ADDRESS', type=str, help="Address to listen on", default=None, )), ('--log-level', dict( metavar='LOG-LEVEL', action='store', default='debug', choices=scserve.LOGLEVELS, help="One of: %s" % nice_join(scserve.LOGLEVELS), )), )
def main(argv): ''' Execute the Bokeh command. Args: argv (seq[str]) : a list of command line arguments to process Returns: None The first item in ``argv`` is typically "bokeh", and the second should be the name of one of the available subcommands: * {subcmds} ''' if len(argv) == 1: die("ERROR: Must specify subcommand, one of: %s" % nice_join(x.name for x in subcommands.all)) parser = argparse.ArgumentParser(prog=argv[0]) # we don't use settings.version() because the point of this option # is to report the actual version of Bokeh, while settings.version() # lets people change the version used for CDN for example. parser.add_argument('-v', '--version', action='version', version=__version__) subs = parser.add_subparsers(help="Sub-commands") for cls in subcommands.all: subparser = subs.add_parser(cls.name, help=cls.help) subcommand = cls(parser=subparser) subparser.set_defaults(invoke=subcommand.invoke) args = parser.parse_args(argv[1:]) try: args.invoke(args) except Exception as e: die("ERROR:" + str(e))
from bokeh.server.server import Server from bokeh.util.string import nice_join from bokeh.settings import settings from os import getpid from ..subcommand import Subcommand from ..util import build_single_handler_applications, die LOGLEVELS = ('debug', 'info', 'warning', 'error', 'critical') SESSION_ID_MODES = ('unsigned', 'signed', 'external-signed') DEFAULT_LOG_FORMAT = "%(asctime)s %(message)s" __doc__ = __doc__.format( DEFAULT_PORT=DEFAULT_SERVER_PORT, LOGLEVELS=nice_join(LOGLEVELS), SESSION_ID_MODES=nice_join(SESSION_ID_MODES), DEFAULT_LOG_FORMAT=DEFAULT_LOG_FORMAT ) base_serve_args = ( ('--port', dict( metavar = 'PORT', type = int, help = "Port to listen on", default = None )), ('--address', dict( metavar = 'ADDRESS', type = str,
class Serve(Subcommand): ''' Subcommand to launch the Bokeh server. ''' name = "serve" help = "Run a Bokeh server hosting one or more applications" args = base_serve_args + ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help="The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--args', dict( metavar='COMMAND-LINE-ARGS', nargs=argparse.REMAINDER, help="Any command line arguments remaining are passed on to the application handler", )), ('--develop', dict( action='store_true', help="Enable develop-time features that should not be used in production", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--allow-websocket-origin', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames which may connect to the Bokeh websocket", )), ('--host', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames to allow in requests", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help="How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--check-unused-sessions', dict( metavar='MILLISECONDS', type=int, help="How often to check for unused sessions", default=None, )), ('--unused-session-lifetime', dict( metavar='MILLISECONDS', type=int, help="How long unused sessions last", default=None, )), ('--stats-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log stats", default=None, )), ('--use-xheaders', dict( action='store_true', help="Prefer X-headers for IP/protocol information", )), ('--session-ids', dict( metavar='MODE', action = 'store', default = None, choices = SESSION_ID_MODES, help = "One of: %s" % nice_join(SESSION_ID_MODES), )), ) 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("Starting Bokeh server with process id: %d" % getpid()) server.start()
from bokeh.application import Application from bokeh.resources import DEFAULT_SERVER_PORT from bokeh.server.server import Server from bokeh.util.string import nice_join from bokeh.settings import settings from ..subcommand import Subcommand from ..util import build_single_handler_applications, die LOGLEVELS = ('debug', 'info', 'warning', 'error', 'critical') SESSION_ID_MODES = ('unsigned', 'signed', 'external-signed') DEFAULT_LOG_FORMAT = "%(asctime)s %(message)s" __doc__ = __doc__.format(DEFAULT_PORT=DEFAULT_SERVER_PORT, LOGLEVELS=nice_join(LOGLEVELS), SESSION_ID_MODES=nice_join(SESSION_ID_MODES), DEFAULT_LOG_FORMAT=DEFAULT_LOG_FORMAT) class Serve(Subcommand): ''' Subcommand to launch the Bokeh server. ''' name = "serve" help = "Run a Bokeh server hosting one or more applications" args = ( ('files',
from bokeh.util.logconfig import basicConfig from bokeh.util.string import nice_join, format_docstring from bokeh.settings import settings from os import getpid from ..subcommand import Subcommand from ..util import build_single_handler_applications, die, report_server_init_errors LOGLEVELS = ('debug', 'info', 'warning', 'error', 'critical') SESSION_ID_MODES = ('unsigned', 'signed', 'external-signed') DEFAULT_LOG_FORMAT = "%(asctime)s %(message)s" __doc__ = format_docstring(__doc__, DEFAULT_PORT=DEFAULT_SERVER_PORT, LOGLEVELS=nice_join(LOGLEVELS), SESSION_ID_MODES=nice_join(SESSION_ID_MODES), DEFAULT_LOG_FORMAT=DEFAULT_LOG_FORMAT) def _fixup_deprecated_host_args(args): if args.host is not None and len(args.host) > 0: if args.allow_websocket_origin is None: args.allow_websocket_origin = [] args.allow_websocket_origin += args.host args.allow_websocket_origin = list(set(args.allow_websocket_origin)) warnings.warn( "The --host parameter is deprecated because it is no longer needed. " "It will be removed and trigger an error in a future release. " "Values set now will be copied to --allow-websocket-origin. " "Depending on your use case, you may need to set current --host "
from bokeh.application import Application from bokeh.resources import DEFAULT_SERVER_PORT from bokeh.server.server import Server from bokeh.util.string import nice_join from bokeh.settings import settings from ..subcommand import Subcommand from ..util import build_single_handler_applications, die LOGLEVELS = ('debug', 'info', 'warning', 'error', 'critical') SESSION_ID_MODES = ('unsigned', 'signed', 'external-signed') __doc__ = __doc__.format( DEFAULT_PORT=DEFAULT_SERVER_PORT, LOGLEVELS=nice_join(LOGLEVELS), SESSION_ID_MODES=nice_join(SESSION_ID_MODES) ) class Serve(Subcommand): ''' Subcommand to launch the Bokeh server. ''' name = "serve" help = "Run a Bokeh server hosting one or more applications" args = ( ('files', dict(
def test_args(): from bokeh.util.string import nice_join assert scserve.Serve.args == ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help= "The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--develop', dict( action='store_true', help= "Enable develop-time features that should not be used in production", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--port', dict(metavar='PORT', type=int, help="Port to listen on", default=None)), ('--address', dict( metavar='ADDRESS', type=str, help="Address to listen on", default=None, )), ('--allow-websocket-origin', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames which may connect to the Bokeh websocket", )), ('--host', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames to allow in requests", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help= "How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--log-level', dict( metavar='LOG-LEVEL', action='store', default='debug', choices=scserve.LOGLEVELS, help="One of: %s" % nice_join(scserve.LOGLEVELS), )), ('--session-ids', dict( metavar='MODE', action='store', default=None, choices=scserve.SESSION_ID_MODES, help="One of: %s" % nice_join(scserve.SESSION_ID_MODES), )), )
import logging log = logging.getLogger(__name__) from bokeh.application import Application from bokeh.resources import DEFAULT_SERVER_PORT from bokeh.server.server import Server from bokeh.util.string import nice_join from ..subcommand import Subcommand from ..util import build_single_handler_applications LOGLEVELS = ('debug', 'info', 'warning', 'error', 'critical') __doc__ = __doc__.format(DEFAULT_PORT=DEFAULT_SERVER_PORT, LOGLEVELS=nice_join(LOGLEVELS)) class Serve(Subcommand): ''' Subcommand to launch the Bokeh server. ''' name = "serve" help = "Run a Bokeh server hosting one or more applications" args = ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT',
import logging log = logging.getLogger(__name__) from bokeh.application import Application from bokeh.resources import DEFAULT_SERVER_PORT from bokeh.server.server import Server from bokeh.util.string import nice_join from ..subcommand import Subcommand from ..util import build_single_handler_applications LOGLEVELS = ('debug', 'info', 'warning', 'error', 'critical') __doc__ = __doc__.format( DEFAULT_PORT=DEFAULT_SERVER_PORT, LOGLEVELS=nice_join(LOGLEVELS) ) class Serve(Subcommand): ''' Subcommand to launch the Bokeh server. ''' name = "serve" help = "Run a Bokeh server hosting one or more applications" args = ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT',
class Serve(Subcommand): ''' Subcommand to launch the Bokeh server. ''' #: name for this subcommand name = "serve" help = "Run a Bokeh server hosting one or more applications" args = base_serve_args + ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help= "The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--args', dict( metavar='COMMAND-LINE-ARGS', nargs=argparse.REMAINDER, help= "Any command line arguments remaining are passed on to the application handler", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--allow-websocket-origin', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames which may connect to the Bokeh websocket", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help= "How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--check-unused-sessions', dict( metavar='MILLISECONDS', type=int, help="How often to check for unused sessions", default=None, )), ('--unused-session-lifetime', dict( metavar='MILLISECONDS', type=int, help="How long unused sessions last", default=None, )), ('--stats-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log stats", default=None, )), ('--mem-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log memory usage information", default=None, )), ('--use-xheaders', dict( action='store_true', help="Prefer X-headers for IP/protocol information", )), ('--session-ids', dict( metavar='MODE', action='store', default=None, choices=SESSION_ID_MODES, help="One of: %s" % nice_join(SESSION_ID_MODES), )), ('--index', dict( metavar='INDEX', action='store', default=None, help='Path to a template to use for the site index', )), ('--disable-index', dict( action='store_true', help='Do not use the default index on the root path', )), ('--disable-index-redirect', dict( action='store_true', help='Do not redirect to running app from root path', )), ('--num-procs', dict( metavar='N', action='store', help="Number of worker processes for an app. Using " "0 will autodetect number of cores (defaults to 1)", default=1, type=int, )), ('--websocket-max-message-size', dict( metavar='BYTES', action='store', help="Set the Tornado websocket_max_message_size value (defaults " "to 20MB) NOTE: This setting has effect ONLY for Tornado>=4.5", default=DEFAULT_WEBSOCKET_MAX_MESSAGE_SIZE_BYTES, type=int, )), ('--dev', dict( metavar='FILES-TO-WATCH', action='store', default=None, type=str, nargs='*', help="Enable live reloading during app development." "By default it watches all *.py *.html *.css *.yaml files" "in the app directory tree. Additional files can be passed" "as arguments." "NOTE: This setting only works with a single app." "It also restricts the number of processes to 1.", )), ) 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_args(): from bokeh.util.string import nice_join assert scserve.Serve.args == ( ("--port", dict(metavar="PORT", type=int, help="Port to listen on", default=None)), ("--address", dict(metavar="ADDRESS", type=str, help="Address to listen on", default=None)), ( "--log-level", dict( metavar="LOG-LEVEL", action="store", default="info", choices=scserve.LOGLEVELS, help="One of: %s" % nice_join(scserve.LOGLEVELS), ), ), ( "--log-format", dict( metavar="LOG-FORMAT", action="store", default=scserve.DEFAULT_LOG_FORMAT, help="A standard Python logging format string (default: %r)" % scserve.DEFAULT_LOG_FORMAT.replace("%", "%%"), ), ), ( "files", dict( metavar="DIRECTORY-OR-SCRIPT", nargs="*", help="The app directories or scripts to serve (serve empty document if not specified)", default=None, ), ), ( "--args", dict( metavar="COMMAND-LINE-ARGS", nargs=argparse.REMAINDER, help="Any command line arguments remaining are passed on to the application handler", ), ), ( "--develop", dict(action="store_true", help="Enable develop-time features that should not be used in production"), ), ("--show", dict(action="store_true", help="Open server app(s) in a browser")), ( "--allow-websocket-origin", dict( metavar="HOST[:PORT]", action="append", type=str, help="Public hostnames which may connect to the Bokeh websocket", ), ), ( "--host", dict(metavar="HOST[:PORT]", action="append", type=str, help="Public hostnames to allow in requests"), ), ("--prefix", dict(metavar="PREFIX", type=str, help="URL prefix for Bokeh server URLs", default=None)), ( "--keep-alive", dict( metavar="MILLISECONDS", type=int, help="How often to send a keep-alive ping to clients, 0 to disable.", default=None, ), ), ( "--check-unused-sessions", dict(metavar="MILLISECONDS", type=int, help="How often to check for unused sessions", default=None), ), ( "--unused-session-lifetime", dict(metavar="MILLISECONDS", type=int, help="How long unused sessions last", default=None), ), ("--stats-log-frequency", dict(metavar="MILLISECONDS", type=int, help="How often to log stats", default=None)), ("--use-xheaders", dict(action="store_true", help="Prefer X-headers for IP/protocol information")), ( "--session-ids", dict( metavar="MODE", action="store", default=None, choices=scserve.SESSION_ID_MODES, help="One of: %s" % nice_join(scserve.SESSION_ID_MODES), ), ), )
def test_args(): from bokeh.util.string import nice_join assert scserve.Serve.args == ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help= "The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--args', dict( metavar='COMMAND-LINE-ARGS', nargs=argparse.REMAINDER, help= "Any command line arguments remaining are passed on to the application handler", )), ('--develop', dict( action='store_true', help= "Enable develop-time features that should not be used in production", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--port', dict(metavar='PORT', type=int, help="Port to listen on", default=None)), ('--address', dict( metavar='ADDRESS', type=str, help="Address to listen on", default=None, )), ('--allow-websocket-origin', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames which may connect to the Bokeh websocket", )), ('--host', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames to allow in requests", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help= "How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--check-unused-sessions', dict( metavar='MILLISECONDS', type=int, help="How often to check for unused sessions", default=None, )), ('--unused-session-lifetime', dict( metavar='MILLISECONDS', type=int, help="How long unused sessions last", default=None, )), ('--stats-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log stats", default=None, )), ('--use-xheaders', dict( action='store_true', help="Prefer X-headers for IP/protocol information", )), ('--log-level', dict( metavar='LOG-LEVEL', action='store', default='debug', choices=scserve.LOGLEVELS, help="One of: %s" % nice_join(scserve.LOGLEVELS), )), ('--log-format', dict( metavar='LOG-FORMAT', action='store', default=scserve.DEFAULT_LOG_FORMAT, help="A standard Python logging format string (default: %r)" % scserve.DEFAULT_LOG_FORMAT.replace("%", "%%"), )), ('--session-ids', dict( metavar='MODE', action='store', default=None, choices=scserve.SESSION_ID_MODES, help="One of: %s" % nice_join(scserve.SESSION_ID_MODES), )), )
class Serve(Subcommand): ''' Subcommand to launch the Bokeh server. ''' name = "serve" help = "Run a Bokeh server hosting one or more applications" args = ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help= "The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--develop', dict( action='store_true', help= "Enable develop-time features that should not be used in production", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--port', dict( metavar='PORT', type=int, help="Port to listen on", default=DEFAULT_PORT, )), ('--address', dict( metavar='ADDRESS', type=str, help="Address to listen on", default=None, )), ('--log-level', dict( metavar='LOG-LEVEL', action='store', default='debug', choices=LOGLEVELS, help="One of: %s" % nice_join(LOGLEVELS), )), ) def invoke(self, args): applications = build_single_handler_applications(args.files) log_level = getattr(logging, args.log_level.upper()) logging.basicConfig(level=log_level) if len(applications) == 0: # create an empty application by default, typically used with output_server applications['/'] = Application() server = Server(applications, port=args.port, address=args.address) 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())) server.start()
def test_args(): from bokeh.util.string import nice_join assert scserve.Serve.args == ( ('--port', dict(metavar='PORT', type=int, help="Port to listen on", default=DEFAULT_SERVER_PORT)), ('--address', dict( metavar='ADDRESS', type=str, help="Address to listen on", default=None, )), ('--log-level', dict( metavar='LOG-LEVEL', action='store', default='info', choices=scserve.LOGLEVELS, help="One of: %s" % nice_join(scserve.LOGLEVELS), )), ('--log-format', dict( metavar='LOG-FORMAT', action='store', default=scserve.DEFAULT_LOG_FORMAT, help="A standard Python logging format string (default: %r)" % scserve.DEFAULT_LOG_FORMAT.replace("%", "%%"), )), ('--log-file', dict( metavar='LOG-FILE', action='store', default=None, help= "A filename to write logs to, or None to write to the standard stream (default: None)", )), ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help= "The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--args', dict( metavar='COMMAND-LINE-ARGS', nargs=argparse.REMAINDER, help= "Any command line arguments remaining are passed on to the application handler", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--allow-websocket-origin', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames which may connect to the Bokeh websocket", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help= "How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--check-unused-sessions', dict( metavar='MILLISECONDS', type=int, help="How often to check for unused sessions", default=None, )), ('--unused-session-lifetime', dict( metavar='MILLISECONDS', type=int, help="How long unused sessions last", default=None, )), ('--stats-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log stats", default=None, )), ('--mem-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log memory usage information", default=None, )), ('--use-xheaders', dict( action='store_true', help="Prefer X-headers for IP/protocol information", )), ('--session-ids', dict( metavar='MODE', action='store', default=None, choices=scserve.SESSION_ID_MODES, help="One of: %s" % nice_join(scserve.SESSION_ID_MODES), )), ('--index', dict( metavar='INDEX', action='store', default=None, help='Path to a template to use for the site index', )), ('--disable-index', dict( action='store_true', help='Do not use the default index on the root path', )), ('--disable-index-redirect', dict( action='store_true', help='Do not redirect to running app from root path', )), ('--num-procs', dict( metavar='N', action='store', help="Number of worker processes for an app. Using " "0 will autodetect number of cores (defaults to 1)", default=1, type=int, )), ('--websocket-max-message-size', dict( metavar='BYTES', action='store', help="Set the Tornado websocket_max_message_size value (defaults " "to 20MB) NOTE: This setting has effect ONLY for Tornado>=4.5", default=20 * 1024 * 1024, type=int, )), ('--dev', dict( metavar='FILES-TO-WATCH', action='store', default=None, type=str, nargs='*', help="Enable live reloading during app development." "By default it watches all *.py *.html *.css *.yaml files" "in the app directory tree. Additional files can be passed" "as arguments." "NOTE: This setting only works with a single app." "It also restricts the number of processes to 1.", )), )
log = logging.getLogger(__name__) from bokeh.application import Application from bokeh.resources import DEFAULT_SERVER_PORT from bokeh.server.server import Server from bokeh.util.string import nice_join from bokeh.settings import settings from ..subcommand import Subcommand from ..util import build_single_handler_applications, die LOGLEVELS = ("debug", "info", "warning", "error", "critical") SESSION_ID_MODES = ("unsigned", "signed", "external-signed") __doc__ = __doc__.format( DEFAULT_PORT=DEFAULT_SERVER_PORT, LOGLEVELS=nice_join(LOGLEVELS), SESSION_ID_MODES=nice_join(SESSION_ID_MODES) ) class Serve(Subcommand): """ Subcommand to launch the Bokeh server. """ name = "serve" help = "Run a Bokeh server hosting one or more applications" args = ( ( "files",
def test_args(): from bokeh.util.string import nice_join assert scserve.Serve.args == ( ('--port', dict(metavar='PORT', type=int, help="Port to listen on", default=DEFAULT_SERVER_PORT)), ('--address', dict( metavar='ADDRESS', type=str, help="Address to listen on", default=None, )), ('--log-level', dict( metavar='LOG-LEVEL', action='store', default='info', choices=scserve.LOGLEVELS, help="One of: %s" % nice_join(scserve.LOGLEVELS), )), ('--log-format', dict( metavar='LOG-FORMAT', action='store', default=scserve.DEFAULT_LOG_FORMAT, help="A standard Python logging format string (default: %r)" % scserve.DEFAULT_LOG_FORMAT.replace("%", "%%"), )), ('--log-file', dict( metavar='LOG-FILE', action='store', default=None, help= "A filename to write logs to, or None to write to the standard stream (default: None)", )), ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help= "The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--args', dict( metavar='COMMAND-LINE-ARGS', nargs=argparse.REMAINDER, help= "Any command line arguments remaining are passed on to the application handler", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--allow-websocket-origin', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames which may connect to the Bokeh websocket", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help= "How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--check-unused-sessions', dict( metavar='MILLISECONDS', type=int, help="How often to check for unused sessions", default=None, )), ('--unused-session-lifetime', dict( metavar='MILLISECONDS', type=int, help="How long unused sessions last", default=None, )), ('--stats-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log stats", default=None, )), ('--mem-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log memory usage information", default=None, )), ('--use-xheaders', dict( action='store_true', help="Prefer X-headers for IP/protocol information", )), ('--session-ids', dict( metavar='MODE', action='store', default=None, choices=scserve.SESSION_ID_MODES, help="One of: %s" % nice_join(scserve.SESSION_ID_MODES), )), ('--disable-index', dict( action='store_true', help='Do not use the default index on the root path', )), ('--disable-index-redirect', dict( action='store_true', help='Do not redirect to running app from root path', )), ('--num-procs', dict( metavar='N', action='store', help="Number of worker processes for an app. Default to one. Using " "0 will autodetect number of cores", default=1, type=int, )), )
def test_args() -> None: from bokeh.util.string import nice_join assert scserve.Serve.args == ( ('--port', dict( metavar = 'PORT', type = int, help = "Port to listen on", default = DEFAULT_SERVER_PORT )), ('--address', dict( metavar = 'ADDRESS', type = str, help = "Address to listen on", default = None, )), ('--log-level', dict( metavar = 'LOG-LEVEL', action = 'store', default = None, choices = scserve.LOGLEVELS + ("None", ), help = "One of: %s" % nice_join(scserve.LOGLEVELS), )), ('--log-format', dict( metavar ='LOG-FORMAT', action = 'store', default = scserve.DEFAULT_LOG_FORMAT, help = "A standard Python logging format string (default: %r)" % scserve.DEFAULT_LOG_FORMAT.replace("%", "%%"), )), ('--log-file', dict( metavar ='LOG-FILE', action = 'store', default = None, help = "A filename to write logs to, or None to write to the standard stream (default: None)", )), ('--use-config', dict( metavar = 'CONFIG', type = str, help = "Use a YAML config file for settings", default = None, )), ('files', dict( metavar = 'DIRECTORY-OR-SCRIPT', nargs = '*', help = "The app directories or scripts to serve (serve empty document if not specified)", default = None, )), ('--args', dict( metavar = 'COMMAND-LINE-ARGS', nargs = argparse.REMAINDER, help = "Command line arguments remaining to passed on to the application handler. " "NOTE: if this argument precedes DIRECTORY-OR-SCRIPT then some other argument, e.g. " "--show, must be placed before the directory or script. ", )), ('--dev', dict( metavar ='FILES-TO-WATCH', action ='store', default = None, type = str, nargs = '*', help = "Enable live reloading during app development. " "By default it watches all *.py *.html *.css *.yaml files " "in the app directory tree. Additional files can be passed " "as arguments. " "NOTE: if this argument precedes DIRECTORY-OR-SCRIPT then some other argument, e.g " "--show, must be placed before the directory or script. " "NOTE: This setting only works with a single app. " "It also restricts the number of processes to 1. " "NOTE FOR WINDOWS USERS : this option must be invoked using " "'python -m bokeh'. If not Tornado will fail to restart the " "server", )), ('--show', dict( action = 'store_true', help = "Open server app(s) in a browser", )), ('--allow-websocket-origin', dict( metavar = 'HOST[:PORT]', action = 'append', type = str, help = "Public hostnames which may connect to the Bokeh websocket", )), ('--prefix', dict( metavar = 'PREFIX', type = str, help = "URL prefix for Bokeh server URLs", default = None, )), ('--keep-alive', dict( metavar = 'MILLISECONDS', type = int, help = "How often to send a keep-alive ping to clients, 0 to disable.", default = None, )), ('--check-unused-sessions', dict( metavar = 'MILLISECONDS', type = int, help = "How often to check for unused sessions", default = None, )), ('--unused-session-lifetime', dict( metavar = 'MILLISECONDS', type = int, help = "How long unused sessions last", default = None, )), ('--stats-log-frequency', dict( metavar = 'MILLISECONDS', type = int, help = "How often to log stats", default = None, )), ('--mem-log-frequency', dict( metavar = 'MILLISECONDS', type = int, help = "How often to log memory usage information", default = None, )), ('--use-xheaders', dict( action = 'store_true', help = "Prefer X-headers for IP/protocol information", )), ('--ssl-certfile', dict( metavar = 'CERTFILE', action = 'store', default = None, help = 'Absolute path to a certificate file for SSL termination', )), ('--ssl-keyfile', dict( metavar = 'KEYFILE', action = 'store', default = None, help = 'Absolute path to a private key file for SSL termination', )), ('--session-ids', dict( metavar = 'MODE', action = 'store', default = None, choices = scserve.SESSION_ID_MODES, help = "One of: %s" % nice_join(scserve.SESSION_ID_MODES), )), ('--auth-module', dict( metavar = 'AUTH_MODULE', action = 'store', default = None, help = 'Absolute path to a Python module that implements auth hooks', )), ('--enable-xsrf-cookies', dict( action = 'store_true', default = False, help = 'Whether to enable Tornado support for XSRF cookies. All ' 'PUT, POST, or DELETE handlers must be properly instrumented ' 'when this setting is enabled.' )), ('--exclude-headers', dict( action = 'store', default = None, nargs='+', help = 'A list of request headers to exclude from the session ' 'context (by default all headers are included).' )), ('--exclude-cookies', dict( action = 'store', default = None, nargs='+', help = 'A list of request cookies to exclude from the session ' 'context (by default all cookies are included).' )), ('--include-headers', dict( action = 'store', default = None, nargs='+', help = 'A list of request headers to make available in the session ' 'context (by default all headers are included).' )), ('--include-cookies', dict( action = 'store', default = None, nargs='+', help = 'A list of request cookies to make available in the session ' 'context (by default all cookies are included).' )), ('--cookie-secret', dict( metavar = 'COOKIE_SECRET', action = 'store', default = None, help = 'Configure to enable getting/setting secure cookies', )), ('--index', dict( metavar = 'INDEX', action = 'store', default = None, help = 'Path to a template to use for the site index', )), ('--disable-index', dict( action = 'store_true', help = 'Do not use the default index on the root path', )), ('--disable-index-redirect', dict( action = 'store_true', help = 'Do not redirect to running app from root path', )), ('--num-procs', dict( metavar = 'N', action = 'store', help = "Number of worker processes for an app. Using " "0 will autodetect number of cores (defaults to 1)", default = 1, type =int, )), ('--session-token-expiration', dict( metavar = 'N', action = 'store', help = "Duration in seconds that a new session token " "is valid for session creation. After the expiry " "time has elapsed, the token will not be able " "create a new session (defaults to seconds).", default = 300, type = int, )), ('--websocket-max-message-size', dict( metavar = 'BYTES', action = 'store', help = "Set the Tornado websocket_max_message_size value " "(default: 20MB)", default = 20*1024*1024, type = int, )), ('--glob', dict( action='store_true', help='Process all filename arguments as globs', )), )
def test_args(): from bokeh.util.string import nice_join assert scserve.Serve.args == ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help="The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--develop', dict( action='store_true', help="Enable develop-time features that should not be used in production", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--port', dict( metavar='PORT', type=int, help="Port to listen on", default=None )), ('--address', dict( metavar='ADDRESS', type=str, help="Address to listen on", default=None, )), ('--allow-websocket-origin', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames which may connect to the Bokeh websocket", )), ('--host', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames to allow in requests", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help="How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--log-level', dict( metavar='LOG-LEVEL', action = 'store', default = 'debug', choices = scserve.LOGLEVELS, help = "One of: %s" % nice_join(scserve.LOGLEVELS), )), ('--session-ids', dict( metavar='MODE', action = 'store', default = None, choices = scserve.SESSION_ID_MODES, help = "One of: %s" % nice_join(scserve.SESSION_ID_MODES), )), )
def test_default(self): assert bus.nice_join(["one"]) == "one" assert bus.nice_join(["one", "two"]) == "one or two" assert bus.nice_join(["one", "two", "three"]) == "one, two or three" assert bus.nice_join(["one", "two", "three", "four"]) == "one, two, three or four"
class Serve(Subcommand): ''' Subcommand to launch the Bokeh server. ''' #: name for this subcommand name = "serve" help = "Run a Bokeh server hosting one or more applications" args = base_serve_args + ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help= "The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--args', dict( metavar='COMMAND-LINE-ARGS', nargs=argparse.REMAINDER, help= "Command line arguments remaining to passed on to the application handler. " "NOTE: if this argument precedes DIRECTORY-OR-SCRIPT then some other argument, e.g. " "--show, must be placed before the directory or script. ", )), ('--dev', dict( metavar='FILES-TO-WATCH', action='store', default=None, type=str, nargs='*', help="Enable live reloading during app development. " "By default it watches all *.py *.html *.css *.yaml files " "in the app directory tree. Additional files can be passed " "as arguments. " "NOTE: if this argument precedes DIRECTORY-OR-SCRIPT then some other argument, e.g " "--show, must be placed before the directory or script. " "NOTE: This setting only works with a single app. " "It also restricts the number of processes to 1. " "NOTE FOR WINDOWS USERS : this option must be invoked using " "'python -m bokeh'. If not Tornado will fail to restart the " "server", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--allow-websocket-origin', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames which may connect to the Bokeh websocket", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help= "How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--check-unused-sessions', dict( metavar='MILLISECONDS', type=int, help="How often to check for unused sessions", default=None, )), ('--unused-session-lifetime', dict( metavar='MILLISECONDS', type=int, help="How long unused sessions last", default=None, )), ('--stats-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log stats", default=None, )), ('--mem-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log memory usage information", default=None, )), ('--use-xheaders', dict( action='store_true', help="Prefer X-headers for IP/protocol information", )), ('--ssl-certfile', dict( metavar='CERTFILE', action='store', default=None, help='Absolute path to a certificate file for SSL termination', )), ('--ssl-keyfile', dict( metavar='KEYFILE', action='store', default=None, help='Absolute path to a private key file for SSL termination', )), ('--session-ids', dict( metavar='MODE', action='store', default=None, choices=SESSION_ID_MODES, help="One of: %s" % nice_join(SESSION_ID_MODES), )), ('--auth-module', dict( metavar='AUTH_MODULE', action='store', default=None, help='Absolute path to a Python module that implements auth hooks', )), ('--enable-xsrf-cookies', dict(action='store_true', default=False, help='Whether to enable Tornado support for XSRF cookies. All ' 'PUT, POST, or DELETE handlers must be properly instrumented ' 'when this setting is enabled.')), ('--exclude-headers', dict(action='store', default=None, nargs='+', help='A list of request headers to exclude from the session ' 'context (by default all headers are included).')), ('--exclude-cookies', dict(action='store', default=None, nargs='+', help='A list of request cookies to exclude from the session ' 'context (by default all cookies are included).')), ('--include-headers', dict( action='store', default=None, nargs='+', help='A list of request headers to make available in the session ' 'context (by default all headers are included).')), ('--include-cookies', dict( action='store', default=None, nargs='+', help='A list of request cookies to make available in the session ' 'context (by default all cookies are included).')), ('--cookie-secret', dict( metavar='COOKIE_SECRET', action='store', default=None, help='Configure to enable getting/setting secure cookies', )), ('--index', dict( metavar='INDEX', action='store', default=None, help='Path to a template to use for the site index', )), ('--disable-index', dict( action='store_true', help='Do not use the default index on the root path', )), ('--disable-index-redirect', dict( action='store_true', help='Do not redirect to running app from root path', )), ('--num-procs', dict( metavar='N', action='store', help="Number of worker processes for an app. Using " "0 will autodetect number of cores (defaults to 1)", default=1, type=int, )), ('--session-token-expiration', dict( metavar='N', action='store', help="Duration in seconds that a new session token " "is valid for session creation. After the expiry " "time has elapsed, the token will not be able " "create a new session (defaults to seconds).", default=DEFAULT_SESSION_TOKEN_EXPIRATION, type=int, )), ('--websocket-max-message-size', dict( metavar='BYTES', action='store', help="Set the Tornado websocket_max_message_size value " "(default: 20MB)", default=DEFAULT_WEBSOCKET_MAX_MESSAGE_SIZE_BYTES, type=int, )), ('--glob', dict( action='store_true', help='Process all filename arguments as globs', )), ) 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("Using override config file: {}".format(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 = [] 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', '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', '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." ) 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 def find_autoreload_targets(app_path: str) -> None: 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: 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) 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) 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_args(): from bokeh.util.string import nice_join assert scserve.Serve.args == ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help="The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--develop', dict( action='store_true', help="Enable develop-time features that should not be used in production", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--port', dict( metavar='PORT', type=int, help="Port to listen on", default=None )), ('--address', dict( metavar='ADDRESS', type=str, help="Address to listen on", default=None, )), ('--allow-websocket-origin', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames which may connect to the Bokeh websocket", )), ('--host', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames to allow in requests", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help="How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--check-unused-sessions', dict( metavar='MILLISECONDS', type=int, help="How often to check for unused sessions", default=None, )), ('--unused-session-lifetime', dict( metavar='MILLISECONDS', type=int, help="How long unused sessions last", default=None, )), ('--stats-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log stats", default=None, )), ('--use-xheaders', dict( action='store_true', help="Prefer X-headers for IP/protocol information", )), ('--log-level', dict( metavar='LOG-LEVEL', action = 'store', default = 'debug', choices = scserve.LOGLEVELS, help = "One of: %s" % nice_join(scserve.LOGLEVELS), )), ('--log-format', dict( metavar='LOG-FORMAT', action = 'store', default = scserve.DEFAULT_LOG_FORMAT, help = "A standard Python logging format string (default: %r)" % scserve.DEFAULT_LOG_FORMAT.replace("%", "%%"), )), ('--session-ids', dict( metavar='MODE', action = 'store', default = None, choices = scserve.SESSION_ID_MODES, help = "One of: %s" % nice_join(scserve.SESSION_ID_MODES), )), )
def test_args(): from bokeh.util.string import nice_join assert scserve.Serve.args == ( ('--port', dict( metavar = 'PORT', type = int, help = "Port to listen on", default = DEFAULT_SERVER_PORT )), ('--address', dict( metavar = 'ADDRESS', type = str, help = "Address to listen on", default = None, )), ('--log-level', dict( metavar = 'LOG-LEVEL', action = 'store', default = 'info', choices = scserve.LOGLEVELS, help = "One of: %s" % nice_join(scserve.LOGLEVELS), )), ('--log-format', dict( metavar ='LOG-FORMAT', action = 'store', default = scserve.DEFAULT_LOG_FORMAT, help = "A standard Python logging format string (default: %r)" % scserve.DEFAULT_LOG_FORMAT.replace("%", "%%"), )), ('--log-file', dict( metavar ='LOG-FILE', action = 'store', default = None, help = "A filename to write logs to, or None to write to the standard stream (default: None)", )), ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help="The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--args', dict( metavar='COMMAND-LINE-ARGS', nargs=argparse.REMAINDER, help="Any command line arguments remaining are passed on to the application handler", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--allow-websocket-origin', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames which may connect to the Bokeh websocket", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help="How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--check-unused-sessions', dict( metavar='MILLISECONDS', type=int, help="How often to check for unused sessions", default=None, )), ('--unused-session-lifetime', dict( metavar='MILLISECONDS', type=int, help="How long unused sessions last", default=None, )), ('--stats-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log stats", default=None, )), ('--mem-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log memory usage information", default=None, )), ('--use-xheaders', dict( action='store_true', help="Prefer X-headers for IP/protocol information", )), ('--session-ids', dict( metavar='MODE', action = 'store', default = None, choices = scserve.SESSION_ID_MODES, help = "One of: %s" % nice_join(scserve.SESSION_ID_MODES), )), ('--disable-index', dict( action = 'store_true', help = 'Do not use the default index on the root path', )), ('--disable-index-redirect', dict( action = 'store_true', help = 'Do not redirect to running app from root path', )), ('--num-procs', dict( metavar='N', action='store', help="Number of worker processes for an app. Using " "0 will autodetect number of cores (defaults to 1)", default=1, type=int, )), ('--websocket-max-message-size', dict( metavar='BYTES', action='store', help="Set the Tornado websocket_max_message_size value (defaults " "to 20MB) NOTE: This setting has effect ONLY for Tornado>=4.5", default=20*1024*1024, type=int, )), )
class Serve(Subcommand): ''' Subcommand to launch the Bokeh server. ''' name = "serve" help = "Run a Bokeh server hosting one or more applications" args = ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help= "The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--develop', dict( action='store_true', help= "Enable develop-time features that should not be used in production", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--port', dict(metavar='PORT', type=int, help="Port to listen on", default=None)), ('--address', dict( metavar='ADDRESS', type=str, help="Address to listen on", default=None, )), ('--host', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames to allow in requests", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help= "How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--log-level', dict( metavar='LOG-LEVEL', action='store', default='debug', choices=LOGLEVELS, help="One of: %s" % nice_join(LOGLEVELS), )), ) def invoke(self, args): applications = build_single_handler_applications(args.files) log_level = getattr(logging, args.log_level.upper()) logging.basicConfig(level=log_level) 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 server_kwargs = { key: getattr(args, key) for key in ['port', 'address', 'host', 'prefix', 'keep_alive_milliseconds'] if getattr(args, key, None) is not None } 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())) server.start()
class Serve(Subcommand): ''' Subcommand to launch the Bokeh server. ''' name = "serve" help = "Run a Bokeh server hosting one or more applications" args = base_serve_args + ( ('files', dict( metavar='DIRECTORY-OR-SCRIPT', nargs='*', help= "The app directories or scripts to serve (serve empty document if not specified)", default=None, )), ('--args', dict( metavar='COMMAND-LINE-ARGS', nargs=argparse.REMAINDER, help= "Any command line arguments remaining are passed on to the application handler", )), ('--show', dict( action='store_true', help="Open server app(s) in a browser", )), ('--allow-websocket-origin', dict( metavar='HOST[:PORT]', action='append', type=str, help="Public hostnames which may connect to the Bokeh websocket", )), ('--host', dict( metavar='HOST[:PORT]', action='append', type=str, help="*** DEPRECATED ***", )), ('--prefix', dict( metavar='PREFIX', type=str, help="URL prefix for Bokeh server URLs", default=None, )), ('--keep-alive', dict( metavar='MILLISECONDS', type=int, help= "How often to send a keep-alive ping to clients, 0 to disable.", default=None, )), ('--check-unused-sessions', dict( metavar='MILLISECONDS', type=int, help="How often to check for unused sessions", default=None, )), ('--unused-session-lifetime', dict( metavar='MILLISECONDS', type=int, help="How long unused sessions last", default=None, )), ('--stats-log-frequency', dict( metavar='MILLISECONDS', type=int, help="How often to log stats", default=None, )), ('--use-xheaders', dict( action='store_true', help="Prefer X-headers for IP/protocol information", )), ('--session-ids', dict( metavar='MODE', action='store', default=None, choices=SESSION_ID_MODES, help="One of: %s" % nice_join(SESSION_ID_MODES), )), ('--disable-index', dict( action='store_true', help='Do not use the default index on the root path', )), ('--disable-index-redirect', dict( action='store_true', help='Do not redirect to running app from root path', )), ('--num-procs', dict( metavar='N', action='store', help="Number of worker processes for an app. Default to one. Using " "0 will autodetect number of cores", default=1, type=int, )), ) 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()) 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 main(args=None): """Merges commands offered by pyct and bokeh and provides help for both""" from bokeh.command.subcommands import all as bokeh_commands bokeh_commands = bokeh_commands + [OAuthSecret] try: import pyct.cmd pyct_commands = ['copy-examples', 'examples'] except Exception: pass parser = argparse.ArgumentParser( prog="panel", epilog="See '<command> --help' to read about a specific subcommand.") parser.add_argument('-v', '--version', action='version', version=__version__) subs = parser.add_subparsers(help="Sub-commands") for cmd in pyct_commands: cmd = cmd.replace('-', '_') fn = getattr(pyct.cmd, cmd) subs.add_parser(cmd, help=fn.__doc__) for cls in bokeh_commands: if cls is BkServe: subparser = subs.add_parser(Serve.name, help=Serve.help) subcommand = Serve(parser=subparser) subparser.set_defaults(invoke=subcommand.invoke) else: subs.add_parser(cls.name, help=cls.help) if len(sys.argv) == 1: all_commands = sorted([c.name for c in bokeh_commands] + pyct_commands) die("ERROR: Must specify subcommand, one of: %s" % nice_join(all_commands)) if sys.argv[1] in ('--help', '-h'): args = parser.parse_args(sys.argv[1:]) args.invoke(args) sys.exit() if len(sys.argv) > 1 and any(sys.argv[1] == c.name for c in bokeh_commands): sys.argv = transform_cmds(sys.argv) if sys.argv[1] == 'serve': args = parser.parse_args(sys.argv[1:]) try: ret = args.invoke(args) except Exception as e: die("ERROR: " + str(e)) elif sys.argv[1] == 'oauth-secret': ret = OAuthSecret(parser).invoke(args) else: ret = bokeh_entry_point() elif sys.argv[1] in pyct_commands: try: import pyct.cmd except ImportError: print( "install pyct to enable this command (e.g. `conda install -c pyviz pyct` or `pip install pyct[cmd]`)" ) sys.exit(1) pyct.cmd.substitute_main('panel', cmds=pyct_commands, args=args) else: parser.parse_args(sys.argv[1:]) sys.exit(1) if ret is False: sys.exit(1) elif ret is not True and isinstance(ret, int) and ret != 0: sys.exit(ret)