diff --git a/IPython/config/default/ipython_config.py b/IPython/config/default/ipython_config.py index c366614..67098c7 100644 --- a/IPython/config/default/ipython_config.py +++ b/IPython/config/default/ipython_config.py @@ -47,15 +47,15 @@ c = get_config() # c.InteractiveShell.autocall = 1 -# c.InteractiveShell.autoedit_syntax = False +# c.TerminalInteractiveShell.autoedit_syntax = False -# c.InteractiveShell.autoindent = True +# c.TerminalInteractiveShell.autoindent = True # c.InteractiveShell.automagic = False -# c.InteractiveShell.banner1 = 'This if for overriding the default IPython banner' +# c.TerminalTerminalInteractiveShell.banner1 = 'This if for overriding the default IPython banner' -# c.InteractiveShell.banner2 = "This is for extra banner text" +# c.TerminalTerminalInteractiveShell.banner2 = "This is for extra banner text" # c.InteractiveShell.cache_size = 1000 @@ -63,11 +63,11 @@ c = get_config() # c.InteractiveShell.color_info = True -# c.InteractiveShell.confirm_exit = True +# c.TerminalInteractiveShell.confirm_exit = True # c.InteractiveShell.deep_reload = False -# c.InteractiveShell.editor = 'nano' +# c.TerminalInteractiveShell.editor = 'nano' # c.InteractiveShell.logstart = True @@ -77,7 +77,7 @@ c = get_config() # c.InteractiveShell.object_info_string_level = 0 -# c.InteractiveShell.pager = 'less' +# c.TerminalInteractiveShell.pager = 'less' # c.InteractiveShell.pdb = False @@ -114,17 +114,17 @@ c = get_config() # c.InteractiveShell.readline_merge_completions = True # c.InteractiveShell.readline_omit__names = 0 -# c.InteractiveShell.screen_length = 0 +# c.TerminalInteractiveShell.screen_length = 0 -# c.InteractiveShell.separate_in = '\n' -# c.InteractiveShell.separate_out = '' -# c.InteractiveShell.separate_out2 = '' +# c.TerminalInteractiveShell.separate_in = '\n' +# c.TerminalInteractiveShell.separate_out = '' +# c.TerminalInteractiveShell.separate_out2 = '' # c.InteractiveShell.system_header = "IPython system call: " # c.InteractiveShell.system_verbose = True -# c.InteractiveShell.term_title = False +# c.TerminalInteractiveShell.term_title = False # c.InteractiveShell.wildcards_case_sensitive = True diff --git a/IPython/config/profile/ipython_config_pysh.py b/IPython/config/profile/ipython_config_pysh.py index ba20354..437f202 100644 --- a/IPython/config/profile/ipython_config_pysh.py +++ b/IPython/config/profile/ipython_config_pysh.py @@ -10,9 +10,9 @@ c.InteractiveShell.prompt_out = '<\#> ' c.InteractiveShell.prompts_pad_left = True -c.InteractiveShell.separate_in = '' -c.InteractiveShell.separate_out = '' -c.InteractiveShell.separate_out2 = '' +c.TerminalInteractiveShell.separate_in = '' +c.TerminalInteractiveShell.separate_out = '' +c.TerminalInteractiveShell.separate_out2 = '' c.PrefilterManager.multi_line_specials = True diff --git a/IPython/core/inputlist.py b/IPython/core/inputlist.py new file mode 100644 index 0000000..1e2a3e8 --- /dev/null +++ b/IPython/core/inputlist.py @@ -0,0 +1,14 @@ +class InputList(list): + """Class to store user input. + + It's basically a list, but slices return a string instead of a list, thus + allowing things like (assuming 'In' is an instance): + + exec In[4:7] + + or + + exec In[5:9] + In[14] + In[21:25]""" + + def __getslice__(self,i,j): + return ''.join(list.__getslice__(self,i,j)) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index a098db6..e585e35 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -19,7 +19,6 @@ from __future__ import absolute_import import __builtin__ import abc -import bdb import codeop import exceptions import new @@ -39,35 +38,27 @@ from IPython.core.alias import AliasManager from IPython.core.builtin_trap import BuiltinTrap from IPython.config.configurable import Configurable from IPython.core.display_trap import DisplayTrap -from IPython.core.error import TryNext, UsageError +from IPython.core.error import UsageError from IPython.core.extensions import ExtensionManager from IPython.core.fakemodule import FakeModule, init_fakemod_dict +from IPython.core.inputlist import InputList from IPython.core.logger import Logger from IPython.core.magic import Magic from IPython.core.plugin import PluginManager from IPython.core.prefilter import PrefilterManager from IPython.core.prompts import CachedOutput -from IPython.core.usage import interactive_usage, default_banner import IPython.core.hooks from IPython.external.Itpl import ItplNS -from IPython.lib.inputhook import enable_gui -from IPython.lib.backgroundjobs import BackgroundJobManager -from IPython.lib.pylabtools import pylab_activate from IPython.utils import PyColorize from IPython.utils import pickleshare from IPython.utils.doctestreload import doctest_reload from IPython.utils.ipstruct import Struct from IPython.utils.io import Term, ask_yes_no from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError -from IPython.utils.process import ( - abbrev_cwd, - getoutput, - getoutputerror -) -# import IPython.utils.rlineimpl as readline +from IPython.utils.process import getoutput, getoutputerror from IPython.utils.strdispatch import StrDispatch from IPython.utils.syspathcontext import prepended_to_syspath -from IPython.utils.terminal import toggle_set_term_title, set_term_title +from IPython.utils.text import num_ini_spaces from IPython.utils.warn import warn, error, fatal from IPython.utils.traitlets import ( Int, Str, CBool, CaselessStrEnum, Enum, List, Unicode, Instance @@ -80,10 +71,6 @@ from IPython.utils.traitlets import ( # Globals #----------------------------------------------------------------------------- -# store the builtin raw_input globally, and use this always, in case user code -# overwrites it (like wx.py.PyShell does) -raw_input_original = raw_input - # compiled regexps for autoindent management dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass') @@ -91,18 +78,9 @@ dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass') # Utilities #----------------------------------------------------------------------------- -ini_spaces_re = re.compile(r'^(\s+)') - - -def num_ini_spaces(strng): - """Return the number of initial spaces in a string""" - - ini_spaces = ini_spaces_re.match(strng) - if ini_spaces: - return ini_spaces.end() - else: - return 0 - +# store the builtin raw_input globally, and use this always, in case user code +# overwrites it (like wx.py.PyShell does) +raw_input_original = raw_input def softspace(file, newvalue): """Copied from code.py, to remove the dependency""" @@ -126,22 +104,6 @@ class SpaceInInput(exceptions.Exception): pass class Bunch: pass -class InputList(list): - """Class to store user input. - - It's basically a list, but slices return a string instead of a list, thus - allowing things like (assuming 'In' is an instance): - - exec In[4:7] - - or - - exec In[5:9] + In[14] + In[21:25]""" - - def __getslice__(self,i,j): - return ''.join(list.__getslice__(self,i,j)) - - class SyntaxTB(ultratb.ListTB): """Extension which holds some state: the last exception value""" @@ -160,17 +122,6 @@ class SyntaxTB(ultratb.ListTB): return e -def get_default_editor(): - try: - ed = os.environ['EDITOR'] - except KeyError: - if os.name == 'posix': - ed = 'vi' # the only one guaranteed to be there! - else: - ed = 'notepad' # same in Windows! - return ed - - def get_default_colors(): if sys.platform=='darwin': return "LightBG" @@ -180,18 +131,6 @@ def get_default_colors(): return 'Linux' -class SeparateStr(Str): - """A Str subclass to validate separate_in, separate_out, etc. - - This is a Str based trait that converts '0'->'' and '\\n'->'\n'. - """ - - def validate(self, obj, value): - if value == '0': value = '' - value = value.replace('\\n','\n') - return super(SeparateStr, self).validate(obj, value) - - #----------------------------------------------------------------------------- # Main IPython class #----------------------------------------------------------------------------- @@ -201,28 +140,13 @@ class InteractiveShell(Configurable, Magic): """An enhanced, interactive shell for Python.""" autocall = Enum((0,1,2), default_value=1, config=True) - autoedit_syntax = CBool(False, config=True) - autoindent = CBool(True, config=True) automagic = CBool(True, config=True) - banner = Str('') - banner1 = Str(default_banner, config=True) - banner2 = Str('', config=True) cache_size = Int(1000, config=True) color_info = CBool(True, config=True) colors = CaselessStrEnum(('NoColor','LightBG','Linux'), default_value=get_default_colors(), config=True) - confirm_exit = CBool(True, config=True) debug = CBool(False, config=True) deep_reload = CBool(False, config=True) - # This display_banner only controls whether or not self.show_banner() - # is called when mainloop/interact are called. The default is False - # because for the terminal based application, the banner behavior - # is controlled by Global.display_banner, which IPythonApp looks at - # to determine if *it* should call show_banner() by hand or not. - display_banner = CBool(False) # This isn't configurable! - embedded = CBool(False) - embedded_active = CBool(False) - editor = Str(get_default_editor(), config=True) filename = Str("") ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__ logstart = CBool(False, config=True) @@ -230,7 +154,6 @@ class InteractiveShell(Configurable, Magic): logappend = Str('', config=True) object_info_string_level = Enum((0,1,2), default_value=0, config=True) - pager = Str('less', config=True) pdb = CBool(False, config=True) pprint = CBool(True, config=True) profile = Str('', config=True) @@ -240,6 +163,8 @@ class InteractiveShell(Configurable, Magic): prompts_pad_left = CBool(True, config=True) quiet = CBool(False, config=True) + # The readline stuff will eventually be moved to the terminal subclass + # but for now, we can't do that as readline is welded in everywhere. readline_use = CBool(True, config=True) readline_merge_completions = CBool(True, config=True) readline_omit__names = Enum((0,1,2), default_value=0, config=True) @@ -262,26 +187,12 @@ class InteractiveShell(Configurable, Magic): '"\C-u": unix-line-discard', ], allow_none=False, config=True) - screen_length = Int(0, config=True) - - # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n' - separate_in = SeparateStr('\n', config=True) - separate_out = SeparateStr('', config=True) - separate_out2 = SeparateStr('', config=True) - system_header = Str('IPython system call: ', config=True) system_verbose = CBool(False, config=True) - term_title = CBool(False, config=True) wildcards_case_sensitive = CBool(True, config=True) xmode = CaselessStrEnum(('Context','Plain', 'Verbose'), default_value='Context', config=True) - autoexec = List(allow_none=False) - - # class attribute to indicate whether the class supports threads or not. - # Subclasses with thread support should override this as needed. - isthreaded = False - # Subcomponents of InteractiveShell alias_manager = Instance('IPython.core.alias.AliasManager') prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager') @@ -290,9 +201,8 @@ class InteractiveShell(Configurable, Magic): extension_manager = Instance('IPython.core.extensions.ExtensionManager') plugin_manager = Instance('IPython.core.plugin.PluginManager') - def __init__(self, config=None, ipython_dir=None, usage=None, + def __init__(self, config=None, ipython_dir=None, user_ns=None, user_global_ns=None, - banner1=None, banner2=None, display_banner=None, custom_exceptions=((),None)): # This is where traits with a config_key argument are updated @@ -302,9 +212,6 @@ class InteractiveShell(Configurable, Magic): # These are relatively independent and stateless self.init_ipython_dir(ipython_dir) self.init_instance_attrs() - self.init_term_title() - self.init_usage(usage) - self.init_banner(banner1, banner2, display_banner) # Create namespaces (user_ns, user_global_ns, etc.) self.init_create_namespaces(user_ns, user_global_ns) @@ -366,27 +273,10 @@ class InteractiveShell(Configurable, Magic): # Trait changed handlers #------------------------------------------------------------------------- - def _banner1_changed(self): - self.compute_banner() - - def _banner2_changed(self): - self.compute_banner() - def _ipython_dir_changed(self, name, new): if not os.path.isdir(new): os.makedirs(new, mode = 0777) - @property - def usable_screen_length(self): - if self.screen_length == 0: - return 0 - else: - num_lines_bot = self.separate_in.count('\n')+1 - return self.screen_length - num_lines_bot - - def _term_title_changed(self, name, new_value): - self.init_term_title() - def set_autoindent(self,value=None): """Set the autoindent flag, checking for readline support. @@ -421,7 +311,6 @@ class InteractiveShell(Configurable, Magic): self.config.Global.ipython_dir = self.ipython_dir def init_instance_attrs(self): - self.jobs = BackgroundJobManager() self.more = False # command compiler @@ -443,9 +332,6 @@ class InteractiveShell(Configurable, Magic): # item which gets cleared once run. self.code_to_run = None - # Flag to mark unconditional exit - self.exit_now = False - # Temporary files used for various purposes. Deleted at exit. self.tempfiles = [] @@ -459,20 +345,6 @@ class InteractiveShell(Configurable, Magic): # Indentation management self.indent_current_nsp = 0 - def init_term_title(self): - # Enable or disable the terminal title. - if self.term_title: - toggle_set_term_title(True) - set_term_title('IPython: ' + abbrev_cwd()) - else: - toggle_set_term_title(False) - - def init_usage(self, usage=None): - if usage is None: - self.usage = interactive_usage - else: - self.usage = usage - def init_encoding(self): # Get system encoding at startup time. Certain terminals (like Emacs # under Win32 have it set to None, and we need to have a known valid @@ -550,31 +422,6 @@ class InteractiveShell(Configurable, Magic): warn("doctest module does not exist.") #------------------------------------------------------------------------- - # Things related to the banner - #------------------------------------------------------------------------- - - def init_banner(self, banner1, banner2, display_banner): - if banner1 is not None: - self.banner1 = banner1 - if banner2 is not None: - self.banner2 = banner2 - if display_banner is not None: - self.display_banner = display_banner - self.compute_banner() - - def show_banner(self, banner=None): - if banner is None: - banner = self.banner - self.write(banner) - - def compute_banner(self): - self.banner = self.banner1 + '\n' - if self.profile: - self.banner += '\nIPython profile: %s\n' % self.profile - if self.banner2: - self.banner += '\n' + self.banner2 + '\n' - - #------------------------------------------------------------------------- # Things related to injections into the sys module #------------------------------------------------------------------------- @@ -762,11 +609,6 @@ class InteractiveShell(Configurable, Magic): # notify the actual exception handlers self.InteractiveTB.call_pdb = val - if self.isthreaded: - try: - self.sys_excepthook.call_pdb = val - except: - warn('Failed to activate pdb for threaded exception handler') call_pdb = property(_get_call_pdb,_set_call_pdb,None, 'Control auto-activation of pdb at exceptions') @@ -1404,64 +1246,6 @@ class InteractiveShell(Configurable, Magic): value = msg, (filename, lineno, offset, line) self.SyntaxTB(etype,value,[]) - def edit_syntax_error(self): - """The bottom half of the syntax error handler called in the main loop. - - Loop until syntax error is fixed or user cancels. - """ - - while self.SyntaxTB.last_syntax_error: - # copy and clear last_syntax_error - err = self.SyntaxTB.clear_err_state() - if not self._should_recompile(err): - return - try: - # may set last_syntax_error again if a SyntaxError is raised - self.safe_execfile(err.filename,self.user_ns) - except: - self.showtraceback() - else: - try: - f = file(err.filename) - try: - # This should be inside a display_trap block and I - # think it is. - sys.displayhook(f.read()) - finally: - f.close() - except: - self.showtraceback() - - def _should_recompile(self,e): - """Utility routine for edit_syntax_error""" - - if e.filename in ('','','', - '','', - None): - - return False - try: - if (self.autoedit_syntax and - not self.ask_yes_no('Return to editor to correct syntax error? ' - '[Y/n] ','y')): - return False - except EOFError: - return False - - def int0(x): - try: - return int(x) - except TypeError: - return 0 - # always pass integer line and offset values to editor hook - try: - self.hooks.fix_error_editor(e.filename, - int0(e.lineno),int0(e.offset),e.msg) - except TryNext: - warn('Could not open editor') - return False - return True - #------------------------------------------------------------------------- # Things related to tab completion #------------------------------------------------------------------------- @@ -1641,13 +1425,12 @@ class InteractiveShell(Configurable, Magic): self.rl_next_input = s + # Maybe move this to the terminal subclass? def pre_readline(self): """readline hook to be used at the start of each line. Currently it handles auto-indent only.""" - #debugx('self.indent_current_nsp','pre_readline:') - if self.rl_do_indent: self.readline.insert_text(self._indent_current_str()) if self.rl_next_input is not None: @@ -1773,6 +1556,17 @@ class InteractiveShell(Configurable, Magic): self.plugin_manager = PluginManager(config=self.config) #------------------------------------------------------------------------- + # Things related to the prefilter + #------------------------------------------------------------------------- + + def init_prefilter(self): + self.prefilter_manager = PrefilterManager(shell=self, config=self.config) + # Ultimately this will be refactored in the new interpreter code, but + # for now, we should expose the main prefilter method (there's legacy + # code out there that may rely on this). + self.prefilter = self.prefilter_manager.prefilter_lines + + #------------------------------------------------------------------------- # Things related to the running of code #------------------------------------------------------------------------- @@ -1789,177 +1583,6 @@ class InteractiveShell(Configurable, Magic): with nested(self.builtin_trap,): return eval(expr, self.user_global_ns, self.user_ns) - def mainloop(self, display_banner=None): - """Start the mainloop. - - If an optional banner argument is given, it will override the - internally created default banner. - """ - - with nested(self.builtin_trap, self.display_trap): - - # if you run stuff with -c , raw hist is not updated - # ensure that it's in sync - if len(self.input_hist) != len (self.input_hist_raw): - self.input_hist_raw = InputList(self.input_hist) - - while 1: - try: - self.interact(display_banner=display_banner) - #self.interact_with_readline() - # XXX for testing of a readline-decoupled repl loop, call - # interact_with_readline above - break - except KeyboardInterrupt: - # this should not be necessary, but KeyboardInterrupt - # handling seems rather unpredictable... - self.write("\nKeyboardInterrupt in interact()\n") - - def interact_prompt(self): - """ Print the prompt (in read-eval-print loop) - - Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not - used in standard IPython flow. - """ - if self.more: - try: - prompt = self.hooks.generate_prompt(True) - except: - self.showtraceback() - if self.autoindent: - self.rl_do_indent = True - - else: - try: - prompt = self.hooks.generate_prompt(False) - except: - self.showtraceback() - self.write(prompt) - - def interact_handle_input(self,line): - """ Handle the input line (in read-eval-print loop) - - Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not - used in standard IPython flow. - """ - if line.lstrip() == line: - self.shadowhist.add(line.strip()) - lineout = self.prefilter_manager.prefilter_lines(line,self.more) - - if line.strip(): - if self.more: - self.input_hist_raw[-1] += '%s\n' % line - else: - self.input_hist_raw.append('%s\n' % line) - - - self.more = self.push_line(lineout) - if (self.SyntaxTB.last_syntax_error and - self.autoedit_syntax): - self.edit_syntax_error() - - def interact_with_readline(self): - """ Demo of using interact_handle_input, interact_prompt - - This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI), - it should work like this. - """ - self.readline_startup_hook(self.pre_readline) - while not self.exit_now: - self.interact_prompt() - if self.more: - self.rl_do_indent = True - else: - self.rl_do_indent = False - line = raw_input_original().decode(self.stdin_encoding) - self.interact_handle_input(line) - - def interact(self, display_banner=None): - """Closely emulate the interactive Python console.""" - - # batch run -> do not interact - if self.exit_now: - return - - if display_banner is None: - display_banner = self.display_banner - if display_banner: - self.show_banner() - - more = 0 - - # Mark activity in the builtins - __builtin__.__dict__['__IPYTHON__active'] += 1 - - if self.has_readline: - self.readline_startup_hook(self.pre_readline) - # exit_now is set by a call to %Exit or %Quit, through the - # ask_exit callback. - - while not self.exit_now: - self.hooks.pre_prompt_hook() - if more: - try: - prompt = self.hooks.generate_prompt(True) - except: - self.showtraceback() - if self.autoindent: - self.rl_do_indent = True - - else: - try: - prompt = self.hooks.generate_prompt(False) - except: - self.showtraceback() - try: - line = self.raw_input(prompt, more) - if self.exit_now: - # quick exit on sys.std[in|out] close - break - if self.autoindent: - self.rl_do_indent = False - - except KeyboardInterrupt: - #double-guard against keyboardinterrupts during kbdint handling - try: - self.write('\nKeyboardInterrupt\n') - self.resetbuffer() - # keep cache in sync with the prompt counter: - self.outputcache.prompt_count -= 1 - - if self.autoindent: - self.indent_current_nsp = 0 - more = 0 - except KeyboardInterrupt: - pass - except EOFError: - if self.autoindent: - self.rl_do_indent = False - if self.has_readline: - self.readline_startup_hook(None) - self.write('\n') - self.exit() - except bdb.BdbQuit: - warn('The Python debugger has exited with a BdbQuit exception.\n' - 'Because of how pdb handles the stack, it is impossible\n' - 'for IPython to properly format this particular exception.\n' - 'IPython will resume normal operation.') - except: - # exceptions here are VERY RARE, but they can be triggered - # asynchronously by signal handlers, for example. - self.showtraceback() - else: - more = self.push_line(line) - if (self.SyntaxTB.last_syntax_error and - self.autoedit_syntax): - self.edit_syntax_error() - - # We are off again... - __builtin__.__dict__['__IPYTHON__active'] -= 1 - - # Turn off the exit flag, so the mainloop can be restarted if desired - self.exit_now = False - def safe_execfile(self, fname, *where, **kw): """A safe version of the builtin execfile(). @@ -2057,43 +1680,6 @@ class InteractiveShell(Configurable, Magic): except: self.showtraceback() warn('Unknown failure executing file: <%s>' % fname) - - def _is_secondary_block_start(self, s): - if not s.endswith(':'): - return False - if (s.startswith('elif') or - s.startswith('else') or - s.startswith('except') or - s.startswith('finally')): - return True - - def cleanup_ipy_script(self, script): - """Make a script safe for self.runlines() - - Currently, IPython is lines based, with blocks being detected by - empty lines. This is a problem for block based scripts that may - not have empty lines after blocks. This script adds those empty - lines to make scripts safe for running in the current line based - IPython. - """ - res = [] - lines = script.splitlines() - level = 0 - - for l in lines: - lstripped = l.lstrip() - stripped = l.strip() - if not stripped: - continue - newlevel = len(l) - len(lstripped) - if level > 0 and newlevel == 0 and \ - not self._is_secondary_block_start(stripped): - # add empty line - res.append('') - res.append(l) - level = newlevel - - return '\n'.join(res) + '\n' def runlines(self, lines, clean=False): """Run a string of one or more lines of source. @@ -2108,7 +1694,7 @@ class InteractiveShell(Configurable, Magic): lines = '\n'.join(lines) if clean: - lines = self.cleanup_ipy_script(lines) + lines = self._cleanup_ipy_script(lines) # We must start with a clean buffer, in case this is run from an # interactive IPython session (via a magic, for example). @@ -2272,6 +1858,47 @@ class InteractiveShell(Configurable, Magic): self.resetbuffer() return more + def resetbuffer(self): + """Reset the input buffer.""" + self.buffer[:] = [] + + def _is_secondary_block_start(self, s): + if not s.endswith(':'): + return False + if (s.startswith('elif') or + s.startswith('else') or + s.startswith('except') or + s.startswith('finally')): + return True + + def _cleanup_ipy_script(self, script): + """Make a script safe for self.runlines() + + Currently, IPython is lines based, with blocks being detected by + empty lines. This is a problem for block based scripts that may + not have empty lines after blocks. This script adds those empty + lines to make scripts safe for running in the current line based + IPython. + """ + res = [] + lines = script.splitlines() + level = 0 + + for l in lines: + lstripped = l.lstrip() + stripped = l.strip() + if not stripped: + continue + newlevel = len(l) - len(lstripped) + if level > 0 and newlevel == 0 and \ + not self._is_secondary_block_start(stripped): + # add empty line + res.append('') + res.append(l) + level = newlevel + + return '\n'.join(res) + '\n' + def _autoindent_update(self,line): """Keep track of the indent level.""" @@ -2290,91 +1917,12 @@ class InteractiveShell(Configurable, Magic): else: self.indent_current_nsp = 0 - def resetbuffer(self): - """Reset the input buffer.""" - self.buffer[:] = [] - - def raw_input(self,prompt='',continue_prompt=False): - """Write a prompt and read a line. - - The returned line does not include the trailing newline. - When the user enters the EOF key sequence, EOFError is raised. - - Optional inputs: - - - prompt(''): a string to be printed to prompt the user. - - - continue_prompt(False): whether this line is the first one or a - continuation in a sequence of inputs. - """ - # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt)) - - # Code run by the user may have modified the readline completer state. - # We must ensure that our completer is back in place. - - if self.has_readline: - self.set_completer() - - try: - line = raw_input_original(prompt).decode(self.stdin_encoding) - except ValueError: - warn("\n********\nYou or a %run:ed script called sys.stdin.close()" - " or sys.stdout.close()!\nExiting IPython!") - self.ask_exit() - return "" - - # Try to be reasonably smart about not re-indenting pasted input more - # than necessary. We do this by trimming out the auto-indent initial - # spaces, if the user's actual input started itself with whitespace. - #debugx('self.buffer[-1]') - - if self.autoindent: - if num_ini_spaces(line) > self.indent_current_nsp: - line = line[self.indent_current_nsp:] - self.indent_current_nsp = 0 - - # store the unfiltered input before the user has any chance to modify - # it. - if line.strip(): - if continue_prompt: - self.input_hist_raw[-1] += '%s\n' % line - if self.has_readline and self.readline_use: - try: - histlen = self.readline.get_current_history_length() - if histlen > 1: - newhist = self.input_hist_raw[-1].rstrip() - self.readline.remove_history_item(histlen-1) - self.readline.replace_history_item(histlen-2, - newhist.encode(self.stdin_encoding)) - except AttributeError: - pass # re{move,place}_history_item are new in 2.4. - else: - self.input_hist_raw.append('%s\n' % line) - # only entries starting at first column go to shadow history - if line.lstrip() == line: - self.shadowhist.add(line.strip()) - elif not continue_prompt: - self.input_hist_raw.append('\n') - try: - lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt) - except: - # blanket except, in case a user-defined prefilter crashes, so it - # can't take all of ipython with it. - self.showtraceback() - return '' - else: - return lineout - #------------------------------------------------------------------------- - # Things related to the prefilter + # Things related to GUI support and pylab #------------------------------------------------------------------------- - def init_prefilter(self): - self.prefilter_manager = PrefilterManager(shell=self, config=self.config) - # Ultimately this will be refactored in the new interpreter code, but - # for now, we should expose the main prefilter method (there's legacy - # code out there that may rely on this). - self.prefilter = self.prefilter_manager.prefilter_lines + def enable_pylab(self, gui=None): + raise NotImplementedError('Implement enable_pylab in a subclass') #------------------------------------------------------------------------- # Utilities @@ -2426,10 +1974,12 @@ class InteractiveShell(Configurable, Magic): tmp_file.close() return filename + # TODO: This should be removed when Term is refactored. def write(self,data): """Write a string to the default output""" Term.cout.write(data) + # TODO: This should be removed when Term is refactored. def write_err(self,data): """Write a string to the default error output""" Term.cerr.write(data) @@ -2440,58 +1990,9 @@ class InteractiveShell(Configurable, Magic): return ask_yes_no(prompt,default) #------------------------------------------------------------------------- - # Things related to GUI support and pylab - #------------------------------------------------------------------------- - - def enable_pylab(self, gui=None): - """Activate pylab support at runtime. - - This turns on support for matplotlib, preloads into the interactive - namespace all of numpy and pylab, and configures IPython to correcdtly - interact with the GUI event loop. The GUI backend to be used can be - optionally selected with the optional :param:`gui` argument. - - Parameters - ---------- - gui : optional, string - - If given, dictates the choice of matplotlib GUI backend to use - (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or - 'gtk'), otherwise we use the default chosen by matplotlib (as - dictated by the matplotlib build-time options plus the user's - matplotlibrc configuration file). - """ - # We want to prevent the loading of pylab to pollute the user's - # namespace as shown by the %who* magics, so we execute the activation - # code in an empty namespace, and we update *both* user_ns and - # user_ns_hidden with this information. - ns = {} - gui = pylab_activate(ns, gui) - self.user_ns.update(ns) - self.user_ns_hidden.update(ns) - # Now we must activate the gui pylab wants to use, and fix %run to take - # plot updates into account - enable_gui(gui) - self.magic_run = self._pylab_magic_run - - #------------------------------------------------------------------------- # Things related to IPython exiting #------------------------------------------------------------------------- - def ask_exit(self): - """ Ask the shell to exit. Can be overiden and used as a callback. """ - self.exit_now = True - - def exit(self): - """Handle interactive exit. - - This method calls the ask_exit callback.""" - if self.confirm_exit: - if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'): - self.ask_exit() - else: - self.ask_exit() - def atexit_operations(self): """This will be executed at the time of exit. diff --git a/IPython/core/ipapi.py b/IPython/core/ipapi.py index 0d79aa0..8e5fef8 100644 --- a/IPython/core/ipapi.py +++ b/IPython/core/ipapi.py @@ -25,6 +25,6 @@ has been made into a component, this module will be sent to deathrow. def get(): """Get the global InteractiveShell instance.""" - from IPython.core.interactiveshell import InteractiveShell - return InteractiveShell.instance() + from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell + return TerminalInteractiveShell.instance() diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 7e1c0be..fad3f6b 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -2524,13 +2524,6 @@ Currently the magic system has the following functions:\n""" except: xmode_switch_err('user') - # threaded shells use a special handler in sys.excepthook - if shell.isthreaded: - try: - shell.sys_excepthook.set_mode(mode=new_mode) - except: - xmode_switch_err('threaded') - def magic_colors(self,parameter_s = ''): """Switch color scheme for prompts, info system and exception handlers. @@ -2585,13 +2578,6 @@ Defaulting color scheme to 'NoColor'""" except: color_switch_err('exception') - # threaded shells use a verbose traceback in sys.excepthook - if shell.isthreaded: - try: - shell.sys_excepthook.set_colors(scheme=new_scheme) - except: - color_switch_err('system exception handler') - # Set info (for 'object?') colors if shell.color_info: try: @@ -3160,49 +3146,6 @@ Defaulting color scheme to 'NoColor'""" print >> Term.cerr,err return SList(out.split('\n')) - def magic_bg(self, parameter_s=''): - """Run a job in the background, in a separate thread. - - For example, - - %bg myfunc(x,y,z=1) - - will execute 'myfunc(x,y,z=1)' in a background thread. As soon as the - execution starts, a message will be printed indicating the job - number. If your job number is 5, you can use - - myvar = jobs.result(5) or myvar = jobs[5].result - - to assign this result to variable 'myvar'. - - IPython has a job manager, accessible via the 'jobs' object. You can - type jobs? to get more information about it, and use jobs. to see - its attributes. All attributes not starting with an underscore are - meant for public use. - - In particular, look at the jobs.new() method, which is used to create - new jobs. This magic %bg function is just a convenience wrapper - around jobs.new(), for expression-based jobs. If you want to create a - new job with an explicit function object and arguments, you must call - jobs.new() directly. - - The jobs.new docstring also describes in detail several important - caveats associated with a thread-based model for background job - execution. Type jobs.new? for details. - - You can check the status of all jobs with jobs.status(). - - The jobs variable is set by IPython into the Python builtin namespace. - If you ever declare a variable named 'jobs', you will shadow this - name. You can either delete your global jobs variable to regain - access to the job manager, or make a new name and assign it manually - to the manager (stored in IPython's namespace). For example, to - assign the job manager to the Jobs name, use: - - Jobs = __builtins__.jobs""" - - self.shell.jobs.new(parameter_s,self.shell.user_ns) - def magic_r(self, parameter_s=''): """Repeat previous input. diff --git a/IPython/core/tests/test_imports.py b/IPython/core/tests/test_imports.py index a5e47cc..7f72a1b 100644 --- a/IPython/core/tests/test_imports.py +++ b/IPython/core/tests/test_imports.py @@ -40,9 +40,6 @@ def test_import_magic(): def test_import_oinspect(): from IPython.core import oinspect -def test_import_outputtrap(): - from IPython.core import outputtrap - def test_import_prefilter(): from IPython.core import prefilter diff --git a/IPython/core/outputtrap.py b/IPython/deathrow/outputtrap.py similarity index 100% rename from IPython/core/outputtrap.py rename to IPython/deathrow/outputtrap.py diff --git a/IPython/frontend/terminal/embed.py b/IPython/frontend/terminal/embed.py index eaf8c87..94a271f 100755 --- a/IPython/frontend/terminal/embed.py +++ b/IPython/frontend/terminal/embed.py @@ -30,7 +30,7 @@ import sys from contextlib import nested from IPython.core import ultratb -from IPython.core.interactiveshell import InteractiveShell +from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell from IPython.frontend.terminal.ipapp import load_default_config from IPython.utils.traitlets import Bool, Str, CBool @@ -59,7 +59,7 @@ def kill_embedded(self,parameter_s=''): print "This embedded IPython will not reactivate anymore once you exit." -class InteractiveShellEmbed(InteractiveShell): +class InteractiveShellEmbed(TerminalInteractiveShell): dummy_mode = Bool(False) exit_msg = Str('') @@ -69,18 +69,19 @@ class InteractiveShellEmbed(InteractiveShell): # is True by default. display_banner = CBool(True) - def __init__(self, parent=None, config=None, ipython_dir=None, usage=None, - user_ns=None, user_global_ns=None, - banner1=None, banner2=None, display_banner=None, - custom_exceptions=((),None), exit_msg=''): + def __init__(self, config=None, ipython_dir=None, user_ns=None, + user_global_ns=None, custom_exceptions=((),None), + usage=None, banner1=None, banner2=None, + display_banner=None, exit_msg=u''): self.save_sys_ipcompleter() super(InteractiveShellEmbed,self).__init__( - parent=parent, config=config, ipython_dir=ipython_dir, usage=usage, - user_ns=user_ns, user_global_ns=user_global_ns, - banner1=banner1, banner2=banner2, display_banner=display_banner, - custom_exceptions=custom_exceptions) + config=config, ipython_dir=ipython_dir, user_ns=user_ns, + user_global_ns=user_global_ns, custom_exceptions=custom_exceptions, + usage=usage, banner1=banner1, banner2=banner2, + display_banner=display_banner + ) self.exit_msg = exit_msg self.define_magic("kill_embedded", kill_embedded) @@ -240,8 +241,7 @@ class InteractiveShellEmbed(InteractiveShell): _embedded_shell = None -def embed(header='', config=None, usage=None, banner1=None, banner2=None, - display_banner=True, exit_msg=''): +def embed(**kwargs): """Call this to embed IPython at the current point in your program. The first invocation of this will create an :class:`InteractiveShellEmbed` @@ -261,15 +261,12 @@ def embed(header='', config=None, usage=None, banner1=None, banner2=None, Full customization can be done by passing a :class:`Struct` in as the config argument. """ + config = kwargs.get('config') + header = kwargs.pop('header', u'') if config is None: config = load_default_config() - config.InteractiveShellEmbed = config.InteractiveShell + config.InteractiveShellEmbed = config.TerminalInteractiveShell global _embedded_shell if _embedded_shell is None: - _embedded_shell = InteractiveShellEmbed( - config=config, usage=usage, - banner1=banner1, banner2=banner2, - display_banner=display_banner, exit_msg=exit_msg - ) + _embedded_shell = InteractiveShellEmbed(**kwargs) _embedded_shell(header=header, stack_depth=2) - diff --git a/IPython/frontend/terminal/interactiveshell.py b/IPython/frontend/terminal/interactiveshell.py new file mode 100644 index 0000000..5bf2770 --- /dev/null +++ b/IPython/frontend/terminal/interactiveshell.py @@ -0,0 +1,541 @@ +# -*- coding: utf-8 -*- +"""Subclass of InteractiveShell for terminal based frontends.""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2001 Janko Hauser +# Copyright (C) 2001-2007 Fernando Perez. +# Copyright (C) 2008-2010 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 +#----------------------------------------------------------------------------- + +import __builtin__ +import bdb +from contextlib import nested +import os +import re +import sys + +from IPython.core.error import TryNext +from IPython.core.usage import interactive_usage, default_banner +from IPython.core.inputlist import InputList +from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC +from IPython.lib.inputhook import enable_gui +from IPython.lib.pylabtools import pylab_activate +from IPython.utils.terminal import toggle_set_term_title, set_term_title +from IPython.utils.process import abbrev_cwd +from IPython.utils.warn import warn +from IPython.utils.text import num_ini_spaces +from IPython.utils.traitlets import Int, Str, CBool + + +#----------------------------------------------------------------------------- +# Utilities +#----------------------------------------------------------------------------- + + +def get_default_editor(): + try: + ed = os.environ['EDITOR'] + except KeyError: + if os.name == 'posix': + ed = 'vi' # the only one guaranteed to be there! + else: + ed = 'notepad' # same in Windows! + return ed + + +# store the builtin raw_input globally, and use this always, in case user code +# overwrites it (like wx.py.PyShell does) +raw_input_original = raw_input + + +class SeparateStr(Str): + """A Str subclass to validate separate_in, separate_out, etc. + + This is a Str based trait that converts '0'->'' and '\\n'->'\n'. + """ + + def validate(self, obj, value): + if value == '0': value = '' + value = value.replace('\\n','\n') + return super(SeparateStr, self).validate(obj, value) + + +#----------------------------------------------------------------------------- +# Main class +#----------------------------------------------------------------------------- + + +class TerminalInteractiveShell(InteractiveShell): + + autoedit_syntax = CBool(False, config=True) + autoindent = CBool(True, config=True) + banner = Str('') + banner1 = Str(default_banner, config=True) + banner2 = Str('', config=True) + confirm_exit = CBool(True, config=True) + # This display_banner only controls whether or not self.show_banner() + # is called when mainloop/interact are called. The default is False + # because for the terminal based application, the banner behavior + # is controlled by Global.display_banner, which IPythonApp looks at + # to determine if *it* should call show_banner() by hand or not. + display_banner = CBool(False) # This isn't configurable! + embedded = CBool(False) + embedded_active = CBool(False) + editor = Str(get_default_editor(), config=True) + exit_now = CBool(False) + pager = Str('less', config=True) + + screen_length = Int(0, config=True) + + # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n' + separate_in = SeparateStr('\n', config=True) + separate_out = SeparateStr('', config=True) + separate_out2 = SeparateStr('', config=True) + term_title = CBool(False, config=True) + + def __init__(self, config=None, ipython_dir=None, user_ns=None, + user_global_ns=None, custom_exceptions=((),None), + usage=None, banner1=None, banner2=None, + display_banner=None): + + super(TerminalInteractiveShell, self).__init__( + config=config, ipython_dir=ipython_dir, user_ns=user_ns, + user_global_ns=user_global_ns, custom_exceptions=custom_exceptions + ) + self.init_term_title() + self.init_usage(usage) + self.init_banner(banner1, banner2, display_banner) + + #------------------------------------------------------------------------- + # Things related to the terminal + #------------------------------------------------------------------------- + + @property + def usable_screen_length(self): + if self.screen_length == 0: + return 0 + else: + num_lines_bot = self.separate_in.count('\n')+1 + return self.screen_length - num_lines_bot + + def init_term_title(self): + # Enable or disable the terminal title. + if self.term_title: + toggle_set_term_title(True) + set_term_title('IPython: ' + abbrev_cwd()) + else: + toggle_set_term_title(False) + + #------------------------------------------------------------------------- + # Things related to the banner and usage + #------------------------------------------------------------------------- + + def _banner1_changed(self): + self.compute_banner() + + def _banner2_changed(self): + self.compute_banner() + + def _term_title_changed(self, name, new_value): + self.init_term_title() + + def init_banner(self, banner1, banner2, display_banner): + if banner1 is not None: + self.banner1 = banner1 + if banner2 is not None: + self.banner2 = banner2 + if display_banner is not None: + self.display_banner = display_banner + self.compute_banner() + + def show_banner(self, banner=None): + if banner is None: + banner = self.banner + self.write(banner) + + def compute_banner(self): + self.banner = self.banner1 + '\n' + if self.profile: + self.banner += '\nIPython profile: %s\n' % self.profile + if self.banner2: + self.banner += '\n' + self.banner2 + '\n' + + def init_usage(self, usage=None): + if usage is None: + self.usage = interactive_usage + else: + self.usage = usage + + #------------------------------------------------------------------------- + # Mainloop and code execution logic + #------------------------------------------------------------------------- + + def mainloop(self, display_banner=None): + """Start the mainloop. + + If an optional banner argument is given, it will override the + internally created default banner. + """ + + with nested(self.builtin_trap, self.display_trap): + + # if you run stuff with -c , raw hist is not updated + # ensure that it's in sync + if len(self.input_hist) != len (self.input_hist_raw): + self.input_hist_raw = InputList(self.input_hist) + + while 1: + try: + self.interact(display_banner=display_banner) + #self.interact_with_readline() + # XXX for testing of a readline-decoupled repl loop, call + # interact_with_readline above + break + except KeyboardInterrupt: + # this should not be necessary, but KeyboardInterrupt + # handling seems rather unpredictable... + self.write("\nKeyboardInterrupt in interact()\n") + + def interact(self, display_banner=None): + """Closely emulate the interactive Python console.""" + + # batch run -> do not interact + if self.exit_now: + return + + if display_banner is None: + display_banner = self.display_banner + if display_banner: + self.show_banner() + + more = 0 + + # Mark activity in the builtins + __builtin__.__dict__['__IPYTHON__active'] += 1 + + if self.has_readline: + self.readline_startup_hook(self.pre_readline) + # exit_now is set by a call to %Exit or %Quit, through the + # ask_exit callback. + + while not self.exit_now: + self.hooks.pre_prompt_hook() + if more: + try: + prompt = self.hooks.generate_prompt(True) + except: + self.showtraceback() + if self.autoindent: + self.rl_do_indent = True + + else: + try: + prompt = self.hooks.generate_prompt(False) + except: + self.showtraceback() + try: + line = self.raw_input(prompt, more) + if self.exit_now: + # quick exit on sys.std[in|out] close + break + if self.autoindent: + self.rl_do_indent = False + + except KeyboardInterrupt: + #double-guard against keyboardinterrupts during kbdint handling + try: + self.write('\nKeyboardInterrupt\n') + self.resetbuffer() + # keep cache in sync with the prompt counter: + self.outputcache.prompt_count -= 1 + + if self.autoindent: + self.indent_current_nsp = 0 + more = 0 + except KeyboardInterrupt: + pass + except EOFError: + if self.autoindent: + self.rl_do_indent = False + if self.has_readline: + self.readline_startup_hook(None) + self.write('\n') + self.exit() + except bdb.BdbQuit: + warn('The Python debugger has exited with a BdbQuit exception.\n' + 'Because of how pdb handles the stack, it is impossible\n' + 'for IPython to properly format this particular exception.\n' + 'IPython will resume normal operation.') + except: + # exceptions here are VERY RARE, but they can be triggered + # asynchronously by signal handlers, for example. + self.showtraceback() + else: + more = self.push_line(line) + if (self.SyntaxTB.last_syntax_error and + self.autoedit_syntax): + self.edit_syntax_error() + + # We are off again... + __builtin__.__dict__['__IPYTHON__active'] -= 1 + + # Turn off the exit flag, so the mainloop can be restarted if desired + self.exit_now = False + + def raw_input(self,prompt='',continue_prompt=False): + """Write a prompt and read a line. + + The returned line does not include the trailing newline. + When the user enters the EOF key sequence, EOFError is raised. + + Optional inputs: + + - prompt(''): a string to be printed to prompt the user. + + - continue_prompt(False): whether this line is the first one or a + continuation in a sequence of inputs. + """ + # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt)) + + # Code run by the user may have modified the readline completer state. + # We must ensure that our completer is back in place. + + if self.has_readline: + self.set_completer() + + try: + line = raw_input_original(prompt).decode(self.stdin_encoding) + except ValueError: + warn("\n********\nYou or a %run:ed script called sys.stdin.close()" + " or sys.stdout.close()!\nExiting IPython!") + self.ask_exit() + return "" + + # Try to be reasonably smart about not re-indenting pasted input more + # than necessary. We do this by trimming out the auto-indent initial + # spaces, if the user's actual input started itself with whitespace. + #debugx('self.buffer[-1]') + + if self.autoindent: + if num_ini_spaces(line) > self.indent_current_nsp: + line = line[self.indent_current_nsp:] + self.indent_current_nsp = 0 + + # store the unfiltered input before the user has any chance to modify + # it. + if line.strip(): + if continue_prompt: + self.input_hist_raw[-1] += '%s\n' % line + if self.has_readline and self.readline_use: + try: + histlen = self.readline.get_current_history_length() + if histlen > 1: + newhist = self.input_hist_raw[-1].rstrip() + self.readline.remove_history_item(histlen-1) + self.readline.replace_history_item(histlen-2, + newhist.encode(self.stdin_encoding)) + except AttributeError: + pass # re{move,place}_history_item are new in 2.4. + else: + self.input_hist_raw.append('%s\n' % line) + # only entries starting at first column go to shadow history + if line.lstrip() == line: + self.shadowhist.add(line.strip()) + elif not continue_prompt: + self.input_hist_raw.append('\n') + try: + lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt) + except: + # blanket except, in case a user-defined prefilter crashes, so it + # can't take all of ipython with it. + self.showtraceback() + return '' + else: + return lineout + + # TODO: The following three methods are an early attempt to refactor + # the main code execution logic. We don't use them, but they may be + # helpful when we refactor the code execution logic further. + # def interact_prompt(self): + # """ Print the prompt (in read-eval-print loop) + # + # Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not + # used in standard IPython flow. + # """ + # if self.more: + # try: + # prompt = self.hooks.generate_prompt(True) + # except: + # self.showtraceback() + # if self.autoindent: + # self.rl_do_indent = True + # + # else: + # try: + # prompt = self.hooks.generate_prompt(False) + # except: + # self.showtraceback() + # self.write(prompt) + # + # def interact_handle_input(self,line): + # """ Handle the input line (in read-eval-print loop) + # + # Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not + # used in standard IPython flow. + # """ + # if line.lstrip() == line: + # self.shadowhist.add(line.strip()) + # lineout = self.prefilter_manager.prefilter_lines(line,self.more) + # + # if line.strip(): + # if self.more: + # self.input_hist_raw[-1] += '%s\n' % line + # else: + # self.input_hist_raw.append('%s\n' % line) + # + # + # self.more = self.push_line(lineout) + # if (self.SyntaxTB.last_syntax_error and + # self.autoedit_syntax): + # self.edit_syntax_error() + # + # def interact_with_readline(self): + # """ Demo of using interact_handle_input, interact_prompt + # + # This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI), + # it should work like this. + # """ + # self.readline_startup_hook(self.pre_readline) + # while not self.exit_now: + # self.interact_prompt() + # if self.more: + # self.rl_do_indent = True + # else: + # self.rl_do_indent = False + # line = raw_input_original().decode(self.stdin_encoding) + # self.interact_handle_input(line) + + #------------------------------------------------------------------------- + # Methods to support auto-editing of SyntaxErrors. + #------------------------------------------------------------------------- + + def edit_syntax_error(self): + """The bottom half of the syntax error handler called in the main loop. + + Loop until syntax error is fixed or user cancels. + """ + + while self.SyntaxTB.last_syntax_error: + # copy and clear last_syntax_error + err = self.SyntaxTB.clear_err_state() + if not self._should_recompile(err): + return + try: + # may set last_syntax_error again if a SyntaxError is raised + self.safe_execfile(err.filename,self.user_ns) + except: + self.showtraceback() + else: + try: + f = file(err.filename) + try: + # This should be inside a display_trap block and I + # think it is. + sys.displayhook(f.read()) + finally: + f.close() + except: + self.showtraceback() + + def _should_recompile(self,e): + """Utility routine for edit_syntax_error""" + + if e.filename in ('','','', + '','', + None): + + return False + try: + if (self.autoedit_syntax and + not self.ask_yes_no('Return to editor to correct syntax error? ' + '[Y/n] ','y')): + return False + except EOFError: + return False + + def int0(x): + try: + return int(x) + except TypeError: + return 0 + # always pass integer line and offset values to editor hook + try: + self.hooks.fix_error_editor(e.filename, + int0(e.lineno),int0(e.offset),e.msg) + except TryNext: + warn('Could not open editor') + return False + return True + + #------------------------------------------------------------------------- + # Things related to GUI support and pylab + #------------------------------------------------------------------------- + + def enable_pylab(self, gui=None): + """Activate pylab support at runtime. + + This turns on support for matplotlib, preloads into the interactive + namespace all of numpy and pylab, and configures IPython to correcdtly + interact with the GUI event loop. The GUI backend to be used can be + optionally selected with the optional :param:`gui` argument. + + Parameters + ---------- + gui : optional, string + + If given, dictates the choice of matplotlib GUI backend to use + (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or + 'gtk'), otherwise we use the default chosen by matplotlib (as + dictated by the matplotlib build-time options plus the user's + matplotlibrc configuration file). + """ + # We want to prevent the loading of pylab to pollute the user's + # namespace as shown by the %who* magics, so we execute the activation + # code in an empty namespace, and we update *both* user_ns and + # user_ns_hidden with this information. + ns = {} + gui = pylab_activate(ns, gui) + self.user_ns.update(ns) + self.user_ns_hidden.update(ns) + # Now we must activate the gui pylab wants to use, and fix %run to take + # plot updates into account + enable_gui(gui) + self.magic_run = self._pylab_magic_run + + #------------------------------------------------------------------------- + # Things related to exiting + #------------------------------------------------------------------------- + + def ask_exit(self): + """ Ask the shell to exit. Can be overiden and used as a callback. """ + self.exit_now = True + + def exit(self): + """Handle interactive exit. + + This method calls the ask_exit callback.""" + if self.confirm_exit: + if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'): + self.ask_exit() + else: + self.ask_exit() + + +InteractiveShellABC.register(TerminalInteractiveShell) diff --git a/IPython/frontend/terminal/ipapp.py b/IPython/frontend/terminal/ipapp.py index 0062332..6f93507 100755 --- a/IPython/frontend/terminal/ipapp.py +++ b/IPython/frontend/terminal/ipapp.py @@ -31,7 +31,7 @@ import sys from IPython.core import release from IPython.core.crashhandler import CrashHandler from IPython.core.application import Application, BaseAppConfigLoader -from IPython.core.interactiveshell import InteractiveShell +from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell from IPython.config.loader import ( Config, PyFileConfigLoader @@ -85,10 +85,10 @@ class IPAppConfigLoader(BaseAppConfigLoader): The default is '1'.""", metavar='InteractiveShell.autocall') paa('--autoindent', - action='store_true', dest='InteractiveShell.autoindent', + action='store_true', dest='TerminalInteractiveShell.autoindent', help='Turn on autoindenting.') paa('--no-autoindent', - action='store_false', dest='InteractiveShell.autoindent', + action='store_false', dest='TerminalInteractiveShell.autoindent', help='Turn off autoindenting.') paa('--automagic', action='store_true', dest='InteractiveShell.automagic', @@ -99,10 +99,10 @@ class IPAppConfigLoader(BaseAppConfigLoader): action='store_false', dest='InteractiveShell.automagic', help='Turn off the auto calling of magic commands.') paa('--autoedit-syntax', - action='store_true', dest='InteractiveShell.autoedit_syntax', + action='store_true', dest='TerminalInteractiveShell.autoedit_syntax', help='Turn on auto editing of files with syntax errors.') paa('--no-autoedit-syntax', - action='store_false', dest='InteractiveShell.autoedit_syntax', + action='store_false', dest='TerminalInteractiveShell.autoedit_syntax', help='Turn off auto editing of files with syntax errors.') paa('--banner', action='store_true', dest='Global.display_banner', @@ -143,13 +143,13 @@ class IPAppConfigLoader(BaseAppConfigLoader): action='store_false', dest='InteractiveShell.color_info', help="Disable using colors for info related things.") paa('--confirm-exit', - action='store_true', dest='InteractiveShell.confirm_exit', + action='store_true', dest='TerminalInteractiveShell.confirm_exit', help= """Set to confirm when you try to exit IPython with an EOF (Control-D in Unix, Control-Z/Enter in Windows). By typing 'exit', 'quit' or '%%Exit', you can force a direct exit without any confirmation.""") paa('--no-confirm-exit', - action='store_false', dest='InteractiveShell.confirm_exit', + action='store_false', dest='TerminalInteractiveShell.confirm_exit', help="Don't prompt the user when exiting.") paa('--deep-reload', action='store_true', dest='InteractiveShell.deep_reload', @@ -167,9 +167,9 @@ class IPAppConfigLoader(BaseAppConfigLoader): action='store_false', dest='InteractiveShell.deep_reload', help="Disable deep (recursive) reloading by default.") paa('--editor', - type=str, dest='InteractiveShell.editor', + type=str, dest='TerminalInteractiveShell.editor', help="Set the editor used by IPython (default to $EDITOR/vi/notepad).", - metavar='InteractiveShell.editor') + metavar='TerminalInteractiveShell.editor') paa('--log','-l', action='store_true', dest='InteractiveShell.logstart', help="Start logging to the default log file (./ipython_log.py).") @@ -228,7 +228,7 @@ class IPAppConfigLoader(BaseAppConfigLoader): action='store_false', dest='InteractiveShell.readline_use', help="Disable readline for command line usage.") paa('--screen-length','-sl', - type=int, dest='InteractiveShell.screen_length', + type=int, dest='TerminalInteractiveShell.screen_length', help= """Number of lines of your screen, used to control printing of very long strings. Strings longer than this number of lines will be sent @@ -239,27 +239,27 @@ class IPAppConfigLoader(BaseAppConfigLoader): internally). If for some reason this isn't working well (it needs curses support), specify it yourself. Otherwise don't change the default.""", - metavar='InteractiveShell.screen_length') + metavar='TerminalInteractiveShell.screen_length') paa('--separate-in','-si', - type=str, dest='InteractiveShell.separate_in', + type=str, dest='TerminalInteractiveShell.separate_in', help="Separator before input prompts. Default '\\n'.", - metavar='InteractiveShell.separate_in') + metavar='TerminalInteractiveShell.separate_in') paa('--separate-out','-so', - type=str, dest='InteractiveShell.separate_out', + type=str, dest='TerminalInteractiveShell.separate_out', help="Separator before output prompts. Default 0 (nothing).", - metavar='InteractiveShell.separate_out') + metavar='TerminalInteractiveShell.separate_out') paa('--separate-out2','-so2', - type=str, dest='InteractiveShell.separate_out2', + type=str, dest='TerminalInteractiveShell.separate_out2', help="Separator after output prompts. Default 0 (nonight).", - metavar='InteractiveShell.separate_out2') + metavar='TerminalInteractiveShell.separate_out2') paa('--no-sep', action='store_true', dest='Global.nosep', help="Eliminate all spacing between prompts.") paa('--term-title', - action='store_true', dest='InteractiveShell.term_title', + action='store_true', dest='TerminalInteractiveShell.term_title', help="Enable auto setting the terminal title.") paa('--no-term-title', - action='store_false', dest='InteractiveShell.term_title', + action='store_false', dest='TerminalInteractiveShell.term_title', help="Disable auto setting the terminal title.") paa('--xmode', type=str, dest='InteractiveShell.xmode', @@ -448,17 +448,17 @@ class IPythonApp(Application): config.InteractiveShell.prompt_in1 = '>>> ' config.InteractiveShell.prompt_in2 = '... ' config.InteractiveShell.prompt_out = '' - config.InteractiveShell.separate_in = \ - config.InteractiveShell.separate_out = \ - config.InteractiveShell.separate_out2 = '' + config.TerminalInteractiveShell.separate_in = \ + config.TerminalInteractiveShell.separate_out = \ + config.TerminalInteractiveShell.separate_out2 = '' config.InteractiveShell.colors = 'NoColor' config.InteractiveShell.xmode = 'Plain' if hasattr(config.Global, 'nosep'): if config.Global.nosep: - config.InteractiveShell.separate_in = \ - config.InteractiveShell.separate_out = \ - config.InteractiveShell.separate_out2 = '' + config.TerminalInteractiveShell.separate_in = \ + config.TerminalInteractiveShell.separate_out = \ + config.TerminalInteractiveShell.separate_out2 = '' # if there is code of files to run from the cmd line, don't interact # unless the -i flag (Global.force_interact) is true. @@ -476,7 +476,7 @@ class IPythonApp(Application): sys.path.insert(0, '') # Create an InteractiveShell instance. - self.shell = InteractiveShell.instance(config=self.master_config) + self.shell = TerminalInteractiveShell.instance(config=self.master_config) def post_construct(self): """Do actions after construct, but before starting the app.""" diff --git a/IPython/testing/globalipapp.py b/IPython/testing/globalipapp.py index f41cf6a..d508d55 100644 --- a/IPython/testing/globalipapp.py +++ b/IPython/testing/globalipapp.py @@ -114,8 +114,7 @@ def start_ipython(): return start_ipython.already_called = True - # Ok, first time we're called, go ahead - from IPython.core import interactiveshell + from IPython.frontend.terminal import interactiveshell def xsys(cmd): """Execute a command and print its output. @@ -136,7 +135,7 @@ def start_ipython(): config = tools.default_config() # Create and initialize our test-friendly IPython instance. - shell = interactiveshell.InteractiveShell.instance( + shell = interactiveshell.TerminalInteractiveShell.instance( config=config, user_ns=ipnsdict(), user_global_ns={} ) diff --git a/IPython/testing/tools.py b/IPython/testing/tools.py index a6dc9da..8622a6b 100644 --- a/IPython/testing/tools.py +++ b/IPython/testing/tools.py @@ -164,9 +164,9 @@ def default_argv(): def default_config(): """Return a config object with good defaults for testing.""" config = Config() - config.InteractiveShell.colors = 'NoColor' - config.InteractiveShell.term_title = False, - config.InteractiveShell.autocall = 0 + config.TerminalInteractiveShell.colors = 'NoColor' + config.TerminalTerminalInteractiveShell.term_title = False, + config.TerminalInteractiveShell.autocall = 0 return config diff --git a/IPython/utils/text.py b/IPython/utils/text.py index e354574..169a0e4 100644 --- a/IPython/utils/text.py +++ b/IPython/utils/text.py @@ -471,3 +471,14 @@ def marquee(txt='',width=78,mark='*'): return '%s %s %s' % (marks,txt,marks) +ini_spaces_re = re.compile(r'^(\s+)') + +def num_ini_spaces(strng): + """Return the number of initial spaces in a string""" + + ini_spaces = ini_spaces_re.match(strng) + if ini_spaces: + return ini_spaces.end() + else: + return 0 +