"""A tornado based IPython notebook server.""" #----------------------------------------------------------------------------- # Copyright (C) 2011 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING.txt, distributed as part of this software. #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Imports #----------------------------------------------------------------------------- import logging import os import signal import sys import zmq # Install the pyzmq ioloop. This has to be done before anything else from # tornado is imported. from zmq.eventloop import ioloop import tornado.ioloop tornado.ioloop = ioloop from tornado import httpserver from tornado import web from .kernelmanager import KernelManager, RoutingKernelManager from .sessionmanager import SessionManager from .handlers import ( NBBrowserHandler, NewHandler, NamedNotebookHandler, MainKernelHandler, KernelHandler, KernelActionHandler, ZMQStreamHandler, NotebookRootHandler, NotebookHandler ) from .notebookmanager import NotebookManager from IPython.core.application import BaseIPythonApplication from IPython.core.profiledir import ProfileDir from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget from IPython.zmq.session import Session from IPython.zmq.zmqshell import ZMQInteractiveShell from IPython.zmq.ipkernel import ( flags as ipkernel_flags, aliases as ipkernel_aliases, IPKernelApp ) from IPython.utils.traitlets import Dict, Unicode, Int, Any, List, Enum #----------------------------------------------------------------------------- # Module globals #----------------------------------------------------------------------------- _kernel_id_regex = r"(?P\w+-\w+-\w+-\w+-\w+)" _kernel_action_regex = r"(?Prestart|interrupt)" _notebook_id_regex = r"(?P\w+-\w+-\w+-\w+-\w+)" LOCALHOST = '127.0.0.1' #----------------------------------------------------------------------------- # The Tornado web application #----------------------------------------------------------------------------- class NotebookWebApplication(web.Application): def __init__(self, routing_kernel_manager, notebook_manager, log): handlers = [ (r"/", NBBrowserHandler), (r"/new", NewHandler), (r"/%s" % _notebook_id_regex, NamedNotebookHandler), (r"/kernels", MainKernelHandler), (r"/kernels/%s" % _kernel_id_regex, KernelHandler), (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler), (r"/kernels/%s/iopub" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='iopub')), (r"/kernels/%s/shell" % _kernel_id_regex, ZMQStreamHandler, dict(stream_name='shell')), (r"/notebooks", NotebookRootHandler), (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler) ] settings = dict( template_path=os.path.join(os.path.dirname(__file__), "templates"), static_path=os.path.join(os.path.dirname(__file__), "static"), ) web.Application.__init__(self, handlers, **settings) self.routing_kernel_manager = routing_kernel_manager self.log = log self.notebook_manager = notebook_manager #----------------------------------------------------------------------------- # Aliases and Flags #----------------------------------------------------------------------------- flags = dict(ipkernel_flags) # the flags that are specific to the frontend # these must be scrubbed before being passed to the kernel, # or it will raise an error on unrecognized flags notebook_flags = [] aliases = dict(ipkernel_aliases) aliases.update(dict( ip = 'IPythonNotebookApp.ip', port = 'IPythonNotebookApp.port', colors = 'ZMQInteractiveShell.colors', editor = 'RichIPythonWidget.editor', )) #----------------------------------------------------------------------------- # IPythonNotebookApp #----------------------------------------------------------------------------- class IPythonNotebookApp(BaseIPythonApplication): name = 'ipython-notebook' default_config_file_name='ipython_notebook_config.py' description = """ The IPython HTML Notebook. This launches a Tornado based HTML Notebook Server that serves up an HTML5/Javascript Notebook client. """ classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session, RoutingKernelManager, NotebookManager, KernelManager, SessionManager, RichIPythonWidget] flags = Dict(flags) aliases = Dict(aliases) kernel_argv = List(Unicode) log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'), default_value=logging.INFO, config=True, help="Set the log level by value or name.") # connection info: ip = Unicode(LOCALHOST, config=True, help="The IP address the notebook server will listen on." ) port = Int(8888, config=True, help="The port the notebook server will listen on." ) # the factory for creating a widget widget_factory = Any(RichIPythonWidget) def parse_command_line(self, argv=None): super(IPythonNotebookApp, self).parse_command_line(argv) if argv is None: argv = sys.argv[1:] self.kernel_argv = list(argv) # copy # kernel should inherit default config file from frontend self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name) # scrub frontend-specific flags for a in argv: if a.startswith('-') and a.lstrip('-') in notebook_flags: self.kernel_argv.remove(a) def init_configurables(self): # Don't let Qt or ZMQ swallow KeyboardInterupts. signal.signal(signal.SIGINT, signal.SIG_DFL) # Create a KernelManager and start a kernel. self.kernel_manager = KernelManager(config=self.config, log=self.log) self.routing_kernel_manager = RoutingKernelManager(config=self.config, log=self.log, kernel_manager=self.kernel_manager, kernel_argv=self.kernel_argv ) self.notebook_manager = NotebookManager(config=self.config, log=self.log) def init_logging(self): super(IPythonNotebookApp, self).init_logging() # This prevents double log messages because tornado use a root logger that # self.log is a child of. The logging module dipatches log messages to a log # and all of its ancenstors until propagate is set to False. self.log.propagate = False def initialize(self, argv=None): super(IPythonNotebookApp, self).initialize(argv) self.init_configurables() self.web_app = NotebookWebApplication( self.routing_kernel_manager, self.notebook_manager, self.log ) self.http_server = httpserver.HTTPServer(self.web_app) self.http_server.listen(self.port) def start(self): self.log.info("The IPython Notebook is running at: http://%s:%i" % (self.ip, self.port)) ioloop.IOLoop.instance().start() #----------------------------------------------------------------------------- # Main entry point #----------------------------------------------------------------------------- def launch_new_instance(): app = IPythonNotebookApp() app.initialize() app.start()