diff --git a/IPython/frontend/kernelmixinapp.py b/IPython/frontend/kernelmixinapp.py index 44b1822..6483528 100644 --- a/IPython/frontend/kernelmixinapp.py +++ b/IPython/frontend/kernelmixinapp.py @@ -63,13 +63,13 @@ from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS #----------------------------------------------------------------------------- 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 app_flags = { 'existing' : ({'IPythonMixinConsoleApp' : {'existing' : 'kernel*.json'}}, "Connect to an existing kernel. If no argument specified, guess most recent"), - 'pure' : ({'IPythonMixinConsoleApp' : {'pure' : True}}, - "Use a pure Python kernel instead of an IPython kernel."), - 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}}, - "Disable rich text support."), } app_flags.update(boolean_flag( 'confirm-exit', 'IPythonMixinConsoleApp.confirm_exit', @@ -84,6 +84,7 @@ flags.update(app_flags) aliases = dict(ipkernel_aliases) +# also scrub aliases from the frontend app_aliases = dict( hb = 'IPythonMixinConsoleApp.hb_port', shell = 'IPythonMixinConsoleApp.shell_port', @@ -135,6 +136,8 @@ class IPythonMixinConsoleApp(Configurable): kernel_argv = List(Unicode) + pure = CBool(False, config=True, + help="Use a pure Python kernel instead of an IPython kernel.") # create requested profiles by default, if they don't exist: auto_create = CBool(True) # connection info: @@ -176,13 +179,16 @@ class IPythonMixinConsoleApp(Configurable): Set to display confirmation dialog on exit. You can always use 'exit' or 'quit', to force a direct exit without any confirmation.""", ) - + def parse_command_line(self, argv=None): - super(PythonBaseConsoleApp, self).parse_command_line(argv) + #super(PythonBaseConsoleApp, self).parse_command_line(argv) # make this stuff after this a function, in case the super stuff goes # away. Also, Min notes that this functionality should be moved to a # generic library of kernel stuff + self.swallow_args(app_aliases,app_flags,argv=argv) + + def swallow_args(self, aliases,flags, argv=None): if argv is None: argv = sys.argv[1:] self.kernel_argv = list(argv) # copy @@ -205,15 +211,15 @@ class IPythonMixinConsoleApp(Configurable): if a.startswith('-'): split = a.lstrip('-').split('=') alias = split[0] - if alias in qt_aliases: + if alias in aliases: self.kernel_argv.remove(a) if len(split) == 1: # alias passed with arg via space swallow_next = True # could have been a flag that matches an alias, e.g. `existing` # in which case, we might not swallow the next arg - was_flag = alias in qt_flags - elif alias in qt_flags: + was_flag = alias in flags + elif alias in flags: # strip flag, but don't swallow next, as flags don't take args self.kernel_argv.remove(a) @@ -347,20 +353,12 @@ class IPythonMixinConsoleApp(Configurable): def initialize(self, argv=None): - super(IPythonMixinConsoleApp, self).initialize(argv) + """ + Classes which mix this class in should call: + IPythonMixinConsoleApp.initialize(self,argv) + """ self.init_connection_file() default_secure(self.config) self.init_ssh() self.init_kernel_manager() - self.init_colors() - -#----------------------------------------------------------------------------- -# Main entry point -#----------------------------------------------------------------------------- - -def main(): - raise NotImplementedError - -if __name__ == '__main__': - main() diff --git a/IPython/frontend/qt/console/qtconsoleapp.py b/IPython/frontend/qt/console/qtconsoleapp.py index 0ce49ab..5e5b72c 100644 --- a/IPython/frontend/qt/console/qtconsoleapp.py +++ b/IPython/frontend/qt/console/qtconsoleapp.py @@ -48,6 +48,7 @@ from IPython.utils.traitlets import ( from IPython.zmq.ipkernel import IPKernelApp from IPython.zmq.session import Session, default_secure from IPython.zmq.zmqshell import ZMQInteractiveShell + from IPython.frontend.kernelmixinapp import ( IPythonMixinConsoleApp, app_aliases, app_flags ) @@ -71,10 +72,9 @@ ipython qtconsole --pylab=inline # start with pylab in inline plotting mode # Aliases and Flags #----------------------------------------------------------------------------- +# XXX: the app_flags should really be flags from the mixin flags = dict(app_flags) qt_flags = { - #'existing' : ({'IPythonQtConsoleApp' : {'existing' : 'kernel*.json'}}, - # "Connect to an existing kernel. If no argument specified, guess most recent"), 'pure' : ({'IPythonQtConsoleApp' : {'pure' : True}}, "Use a pure Python kernel instead of an IPython kernel."), 'plain' : ({'ConsoleWidget' : {'kind' : 'plain'}}, @@ -90,8 +90,6 @@ flags.update(qt_flags) aliases = dict(app_aliases) qt_aliases = dict( - existing = 'IPythonQtConsoleApp.existing', - f = 'IPythonQtConsoleApp.connection_file', style = 'IPythonWidget.syntax_style', stylesheet = 'IPythonQtConsoleApp.stylesheet', @@ -113,7 +111,6 @@ aliases.update(qt_aliases) class IPythonQtConsoleApp(BaseIPythonApplication, IPythonMixinConsoleApp): name = 'ipython-qtconsole' - default_config_file_name='ipython_config.py' description = """ The IPython QtConsole. @@ -140,8 +137,6 @@ class IPythonQtConsoleApp(BaseIPythonApplication, IPythonMixinConsoleApp): stylesheet = Unicode('', config=True, help="path to a custom CSS stylesheet") - pure = CBool(False, config=True, - help="Use a pure Python kernel instead of an IPython kernel.") plain = CBool(False, config=True, help="Use a plaintext widget instead of rich text (plain can't print/save).") @@ -157,50 +152,14 @@ class IPythonQtConsoleApp(BaseIPythonApplication, IPythonMixinConsoleApp): _plain_changed = _pure_changed - confirm_exit = CBool(True, config=True, - help=""" - Set to display confirmation dialog on exit. You can always use 'exit' or 'quit', - to force a direct exit without any confirmation.""", - ) - # the factory for creating a widget widget_factory = Any(RichIPythonWidget) def parse_command_line(self, argv=None): super(IPythonQtConsoleApp, 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 - swallow_next = False - was_flag = False - # copy again, in case some aliases have the same name as a flag - # argv = list(self.kernel_argv) - for a in argv: - if swallow_next: - swallow_next = False - # last arg was an alias, remove the next one - # *unless* the last alias has a no-arg flag version, in which - # case, don't swallow the next arg if it's also a flag: - if not (was_flag and a.startswith('-')): - self.kernel_argv.remove(a) - continue - if a.startswith('-'): - split = a.lstrip('-').split('=') - alias = split[0] - if alias in qt_aliases: - self.kernel_argv.remove(a) - if len(split) == 1: - # alias passed with arg via space - swallow_next = True - # could have been a flag that matches an alias, e.g. `existing` - # in which case, we might not swallow the next arg - was_flag = alias in qt_flags - elif alias in qt_flags: - # strip flag, but don't swallow next, as flags don't take args - self.kernel_argv.remove(a) + IPythonMixinConsoleApp.parse_command_line(self,argv) + self.swallow_args(qt_aliases,qt_flags,argv=argv) + @@ -342,10 +301,7 @@ class IPythonQtConsoleApp(BaseIPythonApplication, IPythonMixinConsoleApp): @catch_config_error def initialize(self, argv=None): super(IPythonQtConsoleApp, self).initialize(argv) - self.init_connection_file() - default_secure(self.config) - self.init_ssh() - self.init_kernel_manager() + IPythonMixinConsoleApp.initialize(self,argv) self.init_qt_elements() self.init_colors() diff --git a/IPython/frontend/zmqterminal/app.py b/IPython/frontend/zmqterminal/app.py index 216d170..ebb99bf 100644 --- a/IPython/frontend/zmqterminal/app.py +++ b/IPython/frontend/zmqterminal/app.py @@ -1,5 +1,18 @@ -from __future__ import print_function +""" A minimal application using the ZMQ-based terminal IPython frontend. +This is not a complete console app, as subprocess will not be able to receive +input, there is no real readline support, among other limitations. + +Authors: + +* Min RK +* Paul Ivanov + +""" + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- import signal import sys import time @@ -9,144 +22,71 @@ from IPython.frontend.terminal.ipapp import TerminalIPythonApp from IPython.utils.traitlets import ( Dict, List, Unicode, Int, CaselessStrEnum, CBool, Any ) -from IPython.zmq.ipkernel import ( - flags as ipkernel_flags, - aliases as ipkernel_aliases, - IPKernelApp -) -from IPython.zmq.session import Session +from IPython.zmq.ipkernel import IPKernelApp +from IPython.zmq.session import Session, default_secure from IPython.zmq.zmqshell import ZMQInteractiveShell -from IPython.zmq.blockingkernelmanager import BlockingKernelManager -from IPython.zmq.ipkernel import ( - flags as ipkernel_flags, - aliases as ipkernel_aliases, - IPKernelApp -) +from IPython.frontend.kernelmixinapp import ( + IPythonMixinConsoleApp, app_aliases, app_flags + ) + from IPython.frontend.zmqterminal.interactiveshell import ZMQTerminalInteractiveShell #----------------------------------------------------------------------------- -# Network Constants +# Globals #----------------------------------------------------------------------------- -from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS +_examples = """ +ipython console # start the ZMQ-based console +ipython console --pylab # start with pylab plotting mode +""" #----------------------------------------------------------------------------- # Flags and Aliases #----------------------------------------------------------------------------- - -flags = dict(ipkernel_flags) -frontend_flags = { - 'existing' : ({'ZMQTerminalIPythonApp' : {'existing' : True}}, - "Connect to an existing kernel."), -} +# XXX: the app_flags should really be flags from the mixin +flags = dict(app_flags) +frontend_flags = { } flags.update(frontend_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 + frontend_flags = frontend_flags.keys() -aliases = dict(ipkernel_aliases) +aliases = dict(app_aliases) + +frontend_aliases = dict() -frontend_aliases = dict( - hb = 'ZMQTerminalIPythonApp.hb_port', - shell = 'ZMQTerminalIPythonApp.shell_port', - iopub = 'ZMQTerminalIPythonApp.iopub_port', - stdin = 'ZMQTerminalIPythonApp.stdin_port', - ip = 'ZMQTerminalIPythonApp.ip', -) aliases.update(frontend_aliases) -# also scrub aliases from the frontend -frontend_flags.extend(frontend_aliases.keys()) #----------------------------------------------------------------------------- # Classes #----------------------------------------------------------------------------- -class ZMQTerminalIPythonApp(TerminalIPythonApp): +class ZMQTerminalIPythonApp(TerminalIPythonApp, IPythonMixinConsoleApp): """Start a terminal frontend to the IPython zmq kernel.""" - kernel_argv = List(Unicode) + classes = List([IPKernelApp, ZMQTerminalInteractiveShell]) flags = Dict(flags) aliases = Dict(aliases) - classes = List([IPKernelApp, ZMQTerminalInteractiveShell]) - - # connection info: - ip = Unicode(LOCALHOST, config=True, - help="""Set the kernel\'s IP address [default localhost]. - If the IP address is something other than localhost, then - Consoles on other machines will be able to connect - to the Kernel, so be careful!""" - ) - pure = False - hb_port = Int(0, config=True, - help="set the heartbeat port [default: random]") - shell_port = Int(0, config=True, - help="set the shell (XREP) port [default: random]") - iopub_port = Int(0, config=True, - help="set the iopub (PUB) port [default: random]") - stdin_port = Int(0, config=True, - help="set the stdin (XREQ) port [default: random]") - - existing = CBool(False, config=True, - help="Whether to connect to an already running Kernel.") - - # from qtconsoleapp: def parse_command_line(self, argv=None): super(ZMQTerminalIPythonApp, 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('-'): - key = a.lstrip('-').split('=')[0] - if key in frontend_flags: - self.kernel_argv.remove(a) - - def init_kernel_manager(self): - """init kernel manager (from qtconsole)""" - # 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 = BlockingKernelManager( - shell_address=(self.ip, self.shell_port), - sub_address=(self.ip, self.iopub_port), - stdin_address=(self.ip, self.stdin_port), - hb_address=(self.ip, self.hb_port), - config=self.config - ) - # start the kernel - if not self.existing: - kwargs = dict(ip=self.ip, ipython=not self.pure) - kwargs['extra_arguments'] = self.kernel_argv - self.kernel_manager.start_kernel(**kwargs) - # wait for kernel to start - time.sleep(0.5) - self.kernel_manager.start_channels() - # relay sigint to kernel - signal.signal(signal.SIGINT, self.handle_sigint) + IPythonMixinConsoleApp.parse_command_line(self,argv) + self.swallow_args(frontend_aliases,frontend_flags,argv=argv) def init_shell(self): - self.init_kernel_manager() + IPythonMixinConsoleApp.initialize(self) + #self.init_kernel_manager() self.shell = ZMQTerminalInteractiveShell.instance(config=self.config, display_banner=False, profile_dir=self.profile_dir, ipython_dir=self.ipython_dir, kernel_manager=self.kernel_manager) - + def handle_sigint(self, *args): self.shell.write('KeyboardInterrupt\n') self.kernel_manager.interrupt_kernel() - + def init_code(self): # no-op in the frontend, code gets run in the backend pass - def launch_new_instance(): """Create and run a full blown IPython instance"""