From 9bf085965d20fe31f2f716955825f6d3a53d63d1 2011-06-20 23:39:16 From: MinRK Date: 2011-06-20 23:39:16 Subject: [PATCH] Split generic part of terminal frontend/terminal/ipapp into core/shellapp Now there's a class for IPKernel to inherit from in the qt code --- diff --git a/IPython/config/profile/default/ipython_config.py b/IPython/config/profile/default/ipython_config.py index 9f51229..80ca1fd 100644 --- a/IPython/config/profile/default/ipython_config.py +++ b/IPython/config/profile/default/ipython_config.py @@ -4,34 +4,33 @@ c = get_config() #----------------------------------------------------------------------------- # Application-level options #----------------------------------------------------------------------------- -app = c.IPythonApp -# app.display_banner = True +# c.TerminalIPythonApp.display_banner = True -# app.classic = False +# c.TerminalIPythonApp.classic = False -# app.nosep = True +# c.TerminalIPythonApp.nosep = True # If you still use multiple versions of IPytho on the same machine, # set this to True to suppress warnings about old configuration files -# app.ignore_old_config = False +# c.TerminalIPythonApp.ignore_old_config = False # Set this to determine the detail of what is logged at startup. # The default is 30 and possible values are 0,10,20,30,40,50. -# app.log_level = 20 +# c.Application.log_level = 20 # This should be a list of importable Python modules that have an # load_ipython_extension(ip) method. This method gets called when the extension # is loaded. You can put your extensions anywhere they can be imported # but we add the extensions subdir of the ipython directory to sys.path # during extension loading, so you can put them there as well. -# app.extensions = [ +# c.InteractiveShellApp.extensions = [ # 'myextension' # ] # These lines are run in IPython in the user's namespace after extensions # are loaded. They can contain full IPython syntax with magics etc. -# app.exec_lines = [ +# c.InteractiveShellApp.exec_lines = [ # 'import numpy', # 'a = 10; b = 20', # '1/0' @@ -41,7 +40,7 @@ app = c.IPythonApp # extension need to be pure Python. Files with a .ipy extension can have # custom IPython syntax (like magics, etc.). # These files need to be in the cwd, the ipython_dir or be absolute paths. -# app.exec_files = [ +# c.InteractiveShellApp.exec_files = [ # 'mycode.py', # 'fancy.ipy' # ] @@ -58,9 +57,9 @@ app = c.IPythonApp # c.InteractiveShell.automagic = False -# c.TerminalTerminalInteractiveShell.banner1 = 'This if for overriding the default IPython banner' +# c.TerminalInteractiveShell.banner1 = 'This if for overriding the default IPython banner' -# c.TerminalTerminalInteractiveShell.banner2 = "This is for extra banner text" +# c.TerminalInteractiveShell.banner2 = "This is for extra banner text" # c.InteractiveShell.cache_size = 1000 diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py new file mode 100755 index 0000000..a8fe0fc --- /dev/null +++ b/IPython/core/shellapp.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +A mixin for :class:`~IPython.core.newapplication.Application` classes that +launch InteractiveShell instances, load extensions, etc. + +Authors +------- + +* Min Ragan-Kelley +""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2008-2011 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +from __future__ import absolute_import + +import os +import sys + +from IPython.config.application import boolean_flag +from IPython.config.configurable import Configurable +from IPython.utils.path import filefind +from IPython.utils.traitlets import Unicode, Instance, List + +#----------------------------------------------------------------------------- +# Aliases and Flags +#----------------------------------------------------------------------------- + +shell_flags = {} + +addflag = lambda *args: shell_flags.update(boolean_flag(*args)) +addflag('autoindent', 'InteractiveShell.autoindent', + 'Turn on autoindenting.', 'Turn off autoindenting.' +) +addflag('automagic', 'InteractiveShell.automagic', + """Turn on the auto calling of magic commands. Type %%magic at the + IPython prompt for more information.""", + 'Turn off the auto calling of magic commands.' +) +addflag('pdb', 'InteractiveShell.pdb', + "Enable auto calling the pdb debugger after every exception.", + "Disable auto calling the pdb debugger after every exception." +) +addflag('pprint', 'PlainTextFormatter.pprint', + "Enable auto pretty printing of results.", + "Disable auto auto pretty printing of results." +) +addflag('color-info', 'InteractiveShell.color_info', + """IPython can display information about objects via a set of func- + tions, and optionally can use colors for this, syntax highlighting + source code and various other elements. However, because this + information is passed through a pager (like 'less') and many pagers get + confused with color codes, this option is off by default. You can test + it and turn it on permanently in your ipython_config.py file if it + works for you. Test it and turn it on permanently if it works with + your system. The magic function %%color_info allows you to toggle this + inter- actively for testing.""", + "Disable using colors for info related things." +) +addflag('deep-reload', 'InteractiveShell.deep_reload', + """Enable deep (recursive) reloading by default. IPython can use the + deep_reload module which reloads changes in modules recursively (it + replaces the reload() function, so you don't need to change anything to + use it). deep_reload() forces a full reload of modules whose code may + have changed, which the default reload() function does not. When + deep_reload is off, IPython will use the normal reload(), but + deep_reload will still be available as dreload(). This feature is off + by default [which means that you have both normal reload() and + dreload()].""", + "Disable deep (recursive) reloading by default." +) + +# it's possible we don't want short aliases for *all* of these: +shell_aliases = dict( + autocall='InteractiveShell.autocall', + cache_size='InteractiveShell.cache_size', + colors='InteractiveShell.colors', + logfile='InteractiveShell.logfile', + log_append='InteractiveShell.logappend', + pi1='InteractiveShell.prompt_in1', + pi2='InteractiveShell.prompt_in1', + po='InteractiveShell.prompt_out', + si='InteractiveShell.separate_in', + so='InteractiveShell.separate_out', + so2='InteractiveShell.separate_out2', + xmode='InteractiveShell.xmode', + c='InteractiveShellApp.code_to_run', + ext='InteractiveShellApp.extra_extension', +) + +#----------------------------------------------------------------------------- +# Main classes and functions +#----------------------------------------------------------------------------- + +class InteractiveShellApp(Configurable): + """A Mixin for applications that start InteractiveShell instances. + + Provides configurables for loading extensions and executing files + as part of configuring a Shell environment. + + Provides init_extensions() and init_code() methods, to be called + after init_shell(), which must be implemented by subclasses. + """ + extensions = List(Unicode, config=True, + help="A list of dotted module names of IPython extensions to load." + ) + extra_extension = Unicode('', config=True, + help="dotted module name of an IPython extension to load." + ) + def _extra_extension_changed(self, name, old, new): + if new: + # add to self.extensions + self.extensions.append(new) + + exec_files = List(Unicode, config=True, + help="""List of files to run at IPython startup.""" + ) + file_to_run = Unicode('', config=True, + help="""A file to be run""") + + exec_lines = List(Unicode, config=True, + help="""lines of code to run at IPython startup.""" + ) + code_to_run = Unicode('', config=True, + help="Execute the given command string." + ) + shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') + + def init_shell(self): + raise NotImplementedError("Override in subclasses") + + def init_extensions(self): + """Load all IPython extensions in IPythonApp.extensions. + + This uses the :meth:`ExtensionManager.load_extensions` to load all + the extensions listed in ``self.extensions``. + """ + if not self.extensions: + return + try: + self.log.debug("Loading IPython extensions...") + extensions = self.extensions + for ext in extensions: + try: + self.log.info("Loading IPython extension: %s" % ext) + self.shell.extension_manager.load_extension(ext) + except: + self.log.warn("Error in loading extension: %s" % ext) + self.shell.showtraceback() + except: + self.log.warn("Unknown error in loading extensions:") + self.shell.showtraceback() + + def init_code(self): + """run the pre-flight code, specified via exec_lines""" + self._run_exec_lines() + self._run_exec_files() + self._run_cmd_line_code() + + def _run_exec_lines(self): + """Run lines of code in IPythonApp.exec_lines in the user's namespace.""" + if not self.exec_lines: + return + try: + self.log.debug("Running code from IPythonApp.exec_lines...") + for line in self.exec_lines: + try: + self.log.info("Running code in user namespace: %s" % + line) + self.shell.run_cell(line, store_history=False) + except: + self.log.warn("Error in executing line in user " + "namespace: %s" % line) + self.shell.showtraceback() + except: + self.log.warn("Unknown error in handling IPythonApp.exec_lines:") + self.shell.showtraceback() + + def _exec_file(self, fname): + full_filename = filefind(fname, [u'.', self.ipython_dir]) + if os.path.isfile(full_filename): + if full_filename.endswith(u'.py'): + self.log.info("Running file in user namespace: %s" % + full_filename) + # Ensure that __file__ is always defined to match Python behavior + self.shell.user_ns['__file__'] = fname + try: + self.shell.safe_execfile(full_filename, self.shell.user_ns) + finally: + del self.shell.user_ns['__file__'] + elif full_filename.endswith('.ipy'): + self.log.info("Running file in user namespace: %s" % + full_filename) + self.shell.safe_execfile_ipy(full_filename) + else: + self.log.warn("File does not have a .py or .ipy extension: <%s>" + % full_filename) + + def _run_exec_files(self): + """Run files from IPythonApp.exec_files""" + if not self.exec_files: + return + + self.log.debug("Running files in IPythonApp.exec_files...") + try: + for fname in self.exec_files: + self._exec_file(fname) + except: + self.log.warn("Unknown error in handling IPythonApp.exec_files:") + self.shell.showtraceback() + + def _run_cmd_line_code(self): + """Run code or file specified at the command-line""" + if self.code_to_run: + line = self.code_to_run + try: + self.log.info("Running code given at command line (c=): %s" % + line) + self.shell.run_cell(line, store_history=False) + except: + self.log.warn("Error in executing line in user namespace: %s" % + line) + self.shell.showtraceback() + + # Like Python itself, ignore the second if the first of these is present + elif self.file_to_run: + fname = self.file_to_run + try: + self._exec_file(fname) + except: + self.log.warn("Error in executing file in user namespace: %s" % + fname) + self.shell.showtraceback() + diff --git a/IPython/frontend/terminal/ipapp.py b/IPython/frontend/terminal/ipapp.py index 52401a7..9bbba0b 100755 --- a/IPython/frontend/terminal/ipapp.py +++ b/IPython/frontend/terminal/ipapp.py @@ -40,11 +40,14 @@ from IPython.core.formatters import PlainTextFormatter from IPython.core.newapplication import ( ProfileDir, BaseIPythonApplication, base_flags, base_aliases ) +from IPython.core.shellapp import ( + InteractiveShellApp, shell_flags, shell_aliases +) from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell from IPython.lib import inputhook -from IPython.utils.path import filefind, get_ipython_dir, check_for_old_config +from IPython.utils.path import get_ipython_dir, check_for_old_config from IPython.utils.traitlets import ( - Bool, Unicode, Dict, Instance, List,CaselessStrEnum + Bool, Dict, CaselessStrEnum ) #----------------------------------------------------------------------------- @@ -55,7 +58,6 @@ from IPython.utils.traitlets import ( default_config_file_name = u'ipython_config.py' - #----------------------------------------------------------------------------- # Crash handler for this application #----------------------------------------------------------------------------- @@ -119,69 +121,22 @@ class IPAppCrashHandler(CrashHandler): # Aliases and Flags #----------------------------------------------------------------------------- flags = dict(base_flags) -flags.update({ - - -}) +flags.update(shell_flags) addflag = lambda *args: flags.update(boolean_flag(*args)) -addflag('autoindent', 'InteractiveShell.autoindent', - 'Turn on autoindenting.', 'Turn off autoindenting.' -) -addflag('automagic', 'InteractiveShell.automagic', - """Turn on the auto calling of magic commands. Type %%magic at the - IPython prompt for more information.""", - 'Turn off the auto calling of magic commands.' -) addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax', 'Turn on auto editing of files with syntax errors.', 'Turn off auto editing of files with syntax errors.' ) -addflag('banner', 'IPythonApp.display_banner', +addflag('banner', 'TerminalIPythonApp.display_banner', "Display a banner upon starting IPython.", "Don't display a banner upon starting IPython." ) -addflag('pdb', 'InteractiveShell.pdb', - "Enable auto calling the pdb debugger after every exception.", - "Disable auto calling the pdb debugger after every exception." -) -addflag('pprint', 'PlainTextFormatter.pprint', - "Enable auto pretty printing of results.", - "Disable auto auto pretty printing of results." -) -addflag('color-info', 'InteractiveShell.color_info', - """IPython can display information about objects via a set of func- - tions, and optionally can use colors for this, syntax highlighting - source code and various other elements. However, because this - information is passed through a pager (like 'less') and many pagers get - confused with color codes, this option is off by default. You can test - it and turn it on permanently in your ipython_config.py file if it - works for you. Test it and turn it on permanently if it works with - your system. The magic function %%color_info allows you to toggle this - inter- actively for testing.""", - "Disable using colors for info related things." -) addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit', """Set to confirm when you try to exit IPython with an EOF (Control-D in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', you can force a direct exit without any confirmation.""", "Don't prompt the user when exiting." ) -addflag('deep-reload', 'InteractiveShell.deep_reload', - """Enable deep (recursive) reloading by default. IPython can use the - deep_reload module which reloads changes in modules recursively (it - replaces the reload() function, so you don't need to change anything to - use it). deep_reload() forces a full reload of modules whose code may - have changed, which the default reload() function does not. When - deep_reload is off, IPython will use the normal reload(), but - deep_reload will still be available as dreload(). This feature is off - by default [which means that you have both normal reload() and - dreload()].""", - "Disable deep (recursive) reloading by default." -) -addflag('readline', 'InteractiveShell.readline_use', - "Enable readline for command line usage.", - "Disable readline for command line usage." -) addflag('term-title', 'TerminalInteractiveShell.term_title', "Enable auto setting the terminal title.", "Disable auto setting the terminal title." @@ -209,7 +164,7 @@ flags['classic']=( # # # quick is harder to implement flags['quick']=( - {'IPythonApp' : {'quick' : True}}, + {'TerminalIPythonApp' : {'quick' : True}}, "Enable quick startup with no config files." ) @@ -221,44 +176,31 @@ nosep_config.InteractiveShell.separate_out2 = '' flags['nosep']=(nosep_config, "Eliminate all spacing between prompts.") flags['i'] = ( - {'IPythonApp' : {'force_interact' : True}}, + {'TerminalIPythonApp' : {'force_interact' : True}}, "If running code from the command line, become interactive afterwards." ) flags['pylab'] = ( - {'IPythonApp' : {'pylab' : 'auto'}}, + {'TerminalIPythonApp' : {'pylab' : 'auto'}}, """Pre-load matplotlib and numpy for interactive use with the default matplotlib backend.""" ) aliases = dict(base_aliases) +aliases.update(shell_aliases) # it's possible we don't want short aliases for *all* of these: aliases.update(dict( - autocall='InteractiveShell.autocall', - cache_size='InteractiveShell.cache_size', - colors='InteractiveShell.colors', editor='TerminalInteractiveShell.editor', - logfile='InteractiveShell.logfile', - log_append='InteractiveShell.logappend', - pi1='InteractiveShell.prompt_in1', - pi2='InteractiveShell.prompt_in1', - po='InteractiveShell.prompt_out', sl='TerminalInteractiveShell.screen_length', - si='InteractiveShell.separate_in', - so='InteractiveShell.separate_out', - so2='InteractiveShell.separate_out2', - xmode='InteractiveShell.xmode', - c='IPythonApp.code_to_run', - ext='IPythonApp.extra_extension', - gui='IPythonApp.gui', - pylab='IPythonApp.pylab', + gui='TerminalIPythonApp.gui', + pylab='TerminalIPythonApp.pylab', )) #----------------------------------------------------------------------------- # Main classes and functions #----------------------------------------------------------------------------- -class IPythonApp(BaseIPythonApplication): +class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): name = u'ipython' description = usage.cl_usage # command_line_loader = IPAppConfigLoader @@ -266,7 +208,7 @@ class IPythonApp(BaseIPythonApplication): crash_handler_class = IPAppCrashHandler flags = Dict(flags) aliases = Dict(aliases) - classes = [TerminalInteractiveShell, ProfileDir, PlainTextFormatter] + classes = [InteractiveShellApp, TerminalInteractiveShell, ProfileDir, PlainTextFormatter] # *do* autocreate requested profile auto_create=Bool(True) copy_config_files=Bool(True) @@ -294,16 +236,6 @@ class IPythonApp(BaseIPythonApplication): display_banner = Bool(True, config=True, help="Whether to display a banner upon starting IPython." ) - extensions = List(Unicode, config=True, - help="A list of dotted module names of IPython extensions to load." - ) - extra_extension = Unicode('', config=True, - help="dotted module name of an IPython extension to load." - ) - def _extra_extension_changed(self, name, old, new): - if new: - # add to self.extensions - self.extensions.append(new) # if there is code of files to run from the cmd line, don't interact # unless the --i flag (App.force_interact) is true. @@ -314,22 +246,10 @@ class IPythonApp(BaseIPythonApplication): def _force_interact_changed(self, name, old, new): if new: self.interact = True - - exec_files = List(Unicode, config=True, - help="""List of files to run at IPython startup.""" - ) - file_to_run = Unicode('', config=True, - help="""A file to be run""") + def _file_to_run_changed(self, name, old, new): if new and not self.force_interact: self.interact = False - - exec_lines = List(Unicode, config=True, - help="""lines of code to run at IPython startup.""" - ) - code_to_run = Unicode('', config=True, - help="Execute the given command string." - ) _code_to_run_changed = _file_to_run_changed # internal, not-configurable @@ -338,7 +258,7 @@ class IPythonApp(BaseIPythonApplication): def initialize(self, argv=None): """Do actions after construct, but before starting the app.""" - super(IPythonApp, self).initialize(argv) + super(TerminalIPythonApp, self).initialize(argv) if not self.ignore_old_config: check_for_old_config(self.ipython_dir) @@ -401,110 +321,6 @@ class IPythonApp(BaseIPythonApplication): self.log.warn("Error in enabling GUI event loop integration:") self.shell.showtraceback() - def init_extensions(self): - """Load all IPython extensions in IPythonApp.extensions. - - This uses the :meth:`ExtensionManager.load_extensions` to load all - the extensions listed in ``self.extensions``. - """ - if not self.extensions: - return - try: - self.log.debug("Loading IPython extensions...") - extensions = self.extensions - for ext in extensions: - try: - self.log.info("Loading IPython extension: %s" % ext) - self.shell.extension_manager.load_extension(ext) - except: - self.log.warn("Error in loading extension: %s" % ext) - self.shell.showtraceback() - except: - self.log.warn("Unknown error in loading extensions:") - self.shell.showtraceback() - - def init_code(self): - """run the pre-flight code, specified via exec_lines""" - self._run_exec_lines() - self._run_exec_files() - self._run_cmd_line_code() - - def _run_exec_lines(self): - """Run lines of code in IPythonApp.exec_lines in the user's namespace.""" - if not self.exec_lines: - return - try: - self.log.debug("Running code from IPythonApp.exec_lines...") - for line in self.exec_lines: - try: - self.log.info("Running code in user namespace: %s" % - line) - self.shell.run_cell(line, store_history=False) - except: - self.log.warn("Error in executing line in user " - "namespace: %s" % line) - self.shell.showtraceback() - except: - self.log.warn("Unknown error in handling IPythonApp.exec_lines:") - self.shell.showtraceback() - - def _exec_file(self, fname): - full_filename = filefind(fname, [u'.', self.ipython_dir]) - if os.path.isfile(full_filename): - if full_filename.endswith(u'.py'): - self.log.info("Running file in user namespace: %s" % - full_filename) - # Ensure that __file__ is always defined to match Python behavior - self.shell.user_ns['__file__'] = fname - try: - self.shell.safe_execfile(full_filename, self.shell.user_ns) - finally: - del self.shell.user_ns['__file__'] - elif full_filename.endswith('.ipy'): - self.log.info("Running file in user namespace: %s" % - full_filename) - self.shell.safe_execfile_ipy(full_filename) - else: - self.log.warn("File does not have a .py or .ipy extension: <%s>" - % full_filename) - - def _run_exec_files(self): - """Run files from IPythonApp.exec_files""" - if not self.exec_files: - return - - self.log.debug("Running files in IPythonApp.exec_files...") - try: - for fname in self.exec_files: - self._exec_file(fname) - except: - self.log.warn("Unknown error in handling IPythonApp.exec_files:") - self.shell.showtraceback() - - def _run_cmd_line_code(self): - """Run code or file specified at the command-line""" - if self.code_to_run: - line = self.code_to_run - try: - self.log.info("Running code given at command line (c=): %s" % - line) - self.shell.run_cell(line, store_history=False) - except: - self.log.warn("Error in executing line in user namespace: %s" % - line) - self.shell.showtraceback() - - # Like Python itself, ignore the second if the first of these is present - elif self.file_to_run: - fname = self.file_to_run - try: - self._exec_file(fname) - except: - self.log.warn("Error in executing file in user namespace: %s" % - fname) - self.shell.showtraceback() - - def start(self): # perform any prexec steps: if self.interact: @@ -529,7 +345,7 @@ def load_default_config(ipython_dir=None): def launch_new_instance(): """Create and run a full blown IPython instance""" - app = IPythonApp() + app = TerminalIPythonApp() app.initialize() # print app.config # print app.profile_dir.location