diff --git a/IPython/Shell.py b/IPython/Shell.py index 7f650ed..7bdd833 100644 --- a/IPython/Shell.py +++ b/IPython/Shell.py @@ -19,11 +19,24 @@ the new code in IPython.core.shell. from warnings import warn msg = """ -This module (IPython.Shell) has been moved to a new location -(IPython.core.shell) and is being refactored. Please update your code -to use the new IPython.core.shell module""" +This module (IPython.Shell) is deprecated. The classes that were in this +module have been replaced by: + +IPShell->IPython.core.iplib.InteractiveShell +IPShellEmbed->IPython.core.embed.InteractiveShellEmbed + +Please migrate your code to use these classes instead. +""" warn(msg, category=DeprecationWarning, stacklevel=1) -from IPython.core.shell import start, IPShell, IPShellEmbed +from IPython.core.iplib import InteractiveShell as IPShell +from IPython.core.embed import InteractiveShellEmbed as IPShellEmbed + +def start(user_ns=None, embedded=False): + """Return an instance of :class:`InteractiveShell`.""" + if embedded: + return InteractiveShellEmbed(user_ns=user_ns) + else: + return InteractiveShell(user_ns=user_ns) diff --git a/IPython/__init__.py b/IPython/__init__.py index 632c5fa..a3d3030 100644 --- a/IPython/__init__.py +++ b/IPython/__init__.py @@ -1,67 +1,47 @@ - # -*- coding: utf-8 -*- +#!/usr/bin/env python +# encoding: utf-8 """ -IPython -- An enhanced Interactive Python +IPython. -One of Python's nicest features is its interactive interpreter. This allows -very fast testing of ideas without the overhead of creating test files as is -typical in most programming languages. However, the interpreter supplied with -the standard Python distribution is fairly primitive (and IDLE isn't really -much better). - -IPython tries to: - - i - provide an efficient environment for interactive work in Python - programming. It tries to address what we see as shortcomings of the standard - Python prompt, and adds many features to make interactive work much more - efficient. - - ii - offer a flexible framework so that it can be used as the base - environment for other projects and problems where Python can be the - underlying language. Specifically scientific environments like Mathematica, - IDL and Mathcad inspired its design, but similar ideas can be useful in many - fields. Python is a fabulous language for implementing this kind of system - (due to its dynamic and introspective features), and with suitable libraries - entire systems could be built leveraging Python's power. - - iii - serve as an embeddable, ready to go interpreter for your own programs. - -IPython requires Python 2.4 or newer. +IPython is a set of tools for interactive and exploratory computing in Python. """ -#***************************************************************************** -# Copyright (C) 2008-2009 The IPython Development Team -# Copyright (C) 2001-2007 Fernando Perez. +#----------------------------------------------------------------------------- +# Copyright (C) 2008-2009 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 +#----------------------------------------------------------------------------- -# Enforce proper version requirements +import os import sys +from IPython.core import release + +#----------------------------------------------------------------------------- +# Setup everything +#----------------------------------------------------------------------------- + if sys.version[0:3] < '2.4': raise ImportError('Python Version 2.4 or above is required for IPython.') + # Make it easy to import extensions - they are always directly on pythonpath. # Therefore, non-IPython modules can be added to extensions directory -import os sys.path.append(os.path.join(os.path.dirname(__file__), "extensions")) -# Define what gets imported with a 'from IPython import *' -__all__ = ['IPython.core.ipapi','utils.generics','utils.ipstruct', - 'core.release','core.shell'] - -# Load __all__ in IPython namespace so that a simple 'import IPython' gives -# access to them via IPython. -glob,loc = globals(),locals() -for name in __all__: - #print 'Importing: ',name # dbg - __import__(name,glob,loc,[]) +#----------------------------------------------------------------------------- +# Setup the top level names +#----------------------------------------------------------------------------- -from IPython.core import shell -Shell = shell -from IPython.core import ipapi -from IPython.core import iplib +# In some cases, these are causing circular imports. +from IPython.core.iplib import InteractiveShell +from IPython.core.embed import embed +from IPython.core.error import TryNext from IPython.lib import ( enable_wx, disable_wx, @@ -75,13 +55,10 @@ from IPython.lib import ( ) # Release data -from IPython.core import release # do it explicitly so pydoc can see it - pydoc bug -__author__ = '%s <%s>\n%s <%s>\n%s <%s>' % \ - ( release.authors['Fernando'] + release.authors['Janko'] + \ - release.authors['Nathan'] ) +__author__ = '' +for author, email in release.authors.values(): + __author__ += author + ' <' + email + '>\n' __license__ = release.license __version__ = release.version __revision__ = release.revision -# Namespace cleanup -del name,glob,loc diff --git a/IPython/config/configloader.py b/IPython/config/configloader.py deleted file mode 100644 index c8aeb37..0000000 --- a/IPython/config/configloader.py +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: utf-8 -*- -"""Configuration loader -""" - -#***************************************************************************** -# Copyright (C) 2001-2006 Fernando Perez. -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#***************************************************************************** - -import exceptions -import os -from pprint import pprint - -from IPython.core import ultratb -from IPython.utils.ipstruct import Struct -from IPython.utils.genutils import * - -class ConfigLoaderError(exceptions.Exception): - """Exception for ConfigLoader class.""" - - def __init__(self,args=None): - self.args = args - -class ConfigLoader: - - """Configuration file loader capable of handling recursive inclusions and - with parametrized conflict resolution for multiply found keys.""" - - def __init__(self,conflict=None,field_sep=None,reclimit=15): - - """The reclimit parameter controls the number of recursive - configuration file inclusions. This way we can stop early on (before - python's own recursion limit is hit) if there is a circular - inclusion. - - - conflict: dictionary for conflict resolutions (see Struct.merge()) - - """ - self.conflict = conflict - self.field_sep = field_sep - self.reset(reclimit) - - def reset(self,reclimit=15): - self.reclimit = reclimit - self.recdepth = 0 - self.included = [] - - def load(self,fname,convert=None,recurse_key='',incpath = '.',**kw): - """Load a configuration file, return the resulting Struct. - - Call: load_config(fname,convert=None,conflict=None,recurse_key='') - - - fname: file to load from. - - convert: dictionary of type conversions (see read_dict()) - - recurse_key: keyword in dictionary to trigger recursive file - inclusions. - """ - - if self.recdepth > self.reclimit: - raise ConfigLoaderError, 'maximum recursive inclusion of rcfiles '+\ - 'exceeded: ' + `self.recdepth` + \ - '.\nMaybe you have a circular chain of inclusions?' - self.recdepth += 1 - fname = filefind(fname,incpath) - data = Struct() - # avoid including the same file more than once - if fname in self.included: - return data - Xinfo = ultratb.AutoFormattedTB(color_scheme='NoColor') - if convert==None and recurse_key : convert = {qwflat:recurse_key} - # for production, change warn to 0: - data.merge(read_dict(fname,convert,fs=self.field_sep,strip=1, - warn=0,no_empty=0,**kw)) - # keep track of successfully loaded files - self.included.append(fname) - if recurse_key in data: - for incfilename in data[recurse_key]: - found=0 - try: - incfile = filefind(incfilename,incpath) - except IOError: - if os.name in ['nt','dos']: - try: - # Try again with '.ini' extension - incfilename += '.ini' - incfile = filefind(incfilename,incpath) - except IOError: - found = 0 - else: - found = 1 - else: - found = 0 - else: - found = 1 - if found: - try: - data.merge(self.load(incfile,convert,recurse_key, - incpath,**kw), - self.conflict) - except: - Xinfo() - warn('Problem loading included file: '+ - `incfilename` + '. Ignoring it...') - else: - warn('File `%s` not found. Included by %s' % (incfilename,fname)) - - return data - -# end ConfigLoader diff --git a/IPython/config/loader.py b/IPython/config/loader.py index 679d921..c77b1b8 100644 --- a/IPython/config/loader.py +++ b/IPython/config/loader.py @@ -163,7 +163,7 @@ class ArgParseConfigLoader(CommandLineConfigLoader): self._add_arguments() self._add_other_arguments() - def _add_other_arguments(): + def _add_other_arguments(self): pass def _add_arguments(self): @@ -189,12 +189,15 @@ class ArgParseConfigLoader(CommandLineConfigLoader): class IPythonArgParseConfigLoader(ArgParseConfigLoader): def _add_other_arguments(self): - self.parser.add_argument('--ipythondir',dest='IPYTHONDIR',type=str, - help='set to override default location of IPYTHONDIR', + self.parser.add_argument('-ipythondir',dest='IPYTHONDIR',type=str, + help='Set to override default location of IPYTHONDIR.', + default=NoDefault) + self.parser.add_argument('-p','-profile',dest='PROFILE',type=str, + help='The string name of the ipython profile to be used.', + default=NoDefault) + self.parser.add_argument('-debug',dest="DEBUG",action='store_true', + help='Debug the application startup process.', default=NoDefault) - self.parser.add_argument('-p','--p',dest='PROFILE_NAME',type=str, - help='the string name of the ipython profile to be used', - default=None) - self.parser.add_argument('--debug',dest="DEBUG",action='store_true', - help='debug the application startup process', + self.parser.add_argument('-config_file',dest='CONFIG_FILE',type=str, + help='Set the config file name to override default.', default=NoDefault) diff --git a/IPython/config/tests/test_imports.py b/IPython/config/tests/test_imports.py index 7987b88..192149a 100644 --- a/IPython/config/tests/test_imports.py +++ b/IPython/config/tests/test_imports.py @@ -1,9 +1,6 @@ #!/usr/bin/env python # encoding: utf-8 -def test_import_configloader(): - from IPython.config import configloader - def test_import_userconfig(): from IPython.config import userconfig diff --git a/IPython/core/application.py b/IPython/core/application.py index 82cc86c..5c528ff 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -59,7 +59,7 @@ class Application(object): """Start the application.""" self.attempt(self.create_default_config) self.attempt(self.pre_load_command_line_config) - self.attempt(self.load_command_line_config, action='exit') + self.attempt(self.load_command_line_config, action='abort') self.attempt(self.post_load_command_line_config) self.attempt(self.find_ipythondir) self.attempt(self.find_config_file_name) @@ -137,11 +137,18 @@ class Application(object): loader where they are resolved to an absolute path. """ - if self.command_line_config.PROFILE_NAME is not None: - self.profile_name = self.command_line_config.PROFILE_NAME + try: + self.config_file_name = self.command_line_config.CONFIG_FILE + except AttributeError: + pass + + try: + self.profile_name = self.command_line_config.PROFILE name_parts = self.config_file_name.split('.') name_parts.insert(1, '_' + self.profile_name + '.') self.config_file_name = ''.join(name_parts) + except AttributeError: + pass def find_config_file_paths(self): """Set the search paths for resolving the config file.""" @@ -168,7 +175,8 @@ class Application(object): self.config_file_name) self.file_config = Struct() else: - self.log("Config file loaded: %s" % loader.full_filename) + self.log("Config file loaded: %s" % loader.full_filename, + self.file_config) def post_load_file_config(self): """Do actions after the config file is loaded.""" @@ -178,8 +186,8 @@ class Application(object): """Merge the default, command line and file config objects.""" config = Struct() config.update(self.default_config) - config.update(self.command_line_config) config.update(self.file_config) + config.update(self.command_line_config) self.master_config = config self.log("Master config created:", self.master_config) diff --git a/IPython/core/autocall.py b/IPython/core/autocall.py new file mode 100644 index 0000000..ff2d3a6 --- /dev/null +++ b/IPython/core/autocall.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Autocall capabilities for IPython.core. + +Authors: + +* Brian Granger +* Fernando Perez + +Notes +----- +""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2008-2009 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 +#----------------------------------------------------------------------------- + + +#----------------------------------------------------------------------------- +# Code +#----------------------------------------------------------------------------- + +class IPyAutocall(object): + """ Instances of this class are always autocalled + + This happens regardless of 'autocall' variable state. Use this to + develop macro-like mechanisms. + """ + + def set_ip(self,ip): + """ Will be used to set _ip point to current ipython instance b/f call + + Override this method if you don't want this to happen. + + """ + self._ip = ip + diff --git a/IPython/core/builtin_trap.py b/IPython/core/builtin_trap.py new file mode 100644 index 0000000..d3b2eba --- /dev/null +++ b/IPython/core/builtin_trap.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +A context manager for managing things injected into :mod:`__builtin__`. + +Authors: + +* Brian Granger +""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2008-2009 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__ + +from IPython.core.component import Component +from IPython.core.quitter import Quitter + +#----------------------------------------------------------------------------- +# Classes and functions +#----------------------------------------------------------------------------- + + +class BuiltinUndefined(object): pass +BuiltinUndefined = BuiltinUndefined() + + +class BuiltinTrap(Component): + + def __init__(self, parent, name=None, config=None): + super(BuiltinTrap, self).__init__(parent, name, config) + # Don't just grab parent!!! + from IPython.core.iplib import InteractiveShell + self.shell = InteractiveShell.get_instances(root=self.root)[0] + self._orig_builtins = {} + + def __enter__(self): + self.set() + # I return self, so callers can use add_builtin in a with clause. + return self + + def __exit__(self, type, value, traceback): + self.unset() + return True + + def add_builtin(self, key, value): + """Add a builtin and save the original.""" + orig = __builtin__.__dict__.get(key, BuiltinUndefined) + self._orig_builtins[key] = orig + __builtin__.__dict__[key] = value + + def remove_builtin(self, key): + """Remove an added builtin and re-set the original.""" + try: + orig = self._orig_builtins.pop(key) + except KeyError: + pass + else: + if orig is BuiltinUndefined: + del __builtin__.__dict__[key] + else: + __builtin__.__dict__[key] = orig + + def set(self): + """Store ipython references in the __builtin__ namespace.""" + self.add_builtin('exit', Quitter(self.shell, 'exit')) + self.add_builtin('quit', Quitter(self.shell, 'quit')) + + # Recursive reload function + try: + from IPython.lib import deepreload + if self.shell.deep_reload: + self.add_builtin('reload', deepreload.reload) + else: + self.add_builtin('dreload', deepreload.reload) + del deepreload + except ImportError: + pass + + # Keep in the builtins a flag for when IPython is active. We set it + # with setdefault so that multiple nested IPythons don't clobber one + # another. Each will increase its value by one upon being activated, + # which also gives us a way to determine the nesting level. + __builtin__.__dict__.setdefault('__IPYTHON__active',0) + + def unset(self): + """Remove any builtins which might have been added by add_builtins, or + restore overwritten ones to their previous values.""" + for key in self._orig_builtins.keys(): + self.remove_builtin(key) + self._orig_builtins.clear() + self._builtins_added = False + try: + del __builtin__.__dict__['__IPYTHON__active'] + except KeyError: + pass \ No newline at end of file diff --git a/IPython/core/completer.py b/IPython/core/completer.py index fcf8262..f7daa34 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -70,12 +70,13 @@ import os import re import shlex import sys -import IPython.utils.rlineimpl as readline import itertools +import types + +from IPython.core.error import TryNext +import IPython.utils.rlineimpl as readline from IPython.utils.ipstruct import Struct -from IPython.core import ipapi from IPython.utils import generics -import types # Python 2.4 offers sets as a builtin try: @@ -195,7 +196,7 @@ class Completer: try: words = generics.complete_object(obj, words) - except ipapi.TryNext: + except TryNext: pass # Build match list to return n = len(attr) @@ -241,7 +242,7 @@ class IPCompleter(Completer): self.get_line_buffer = self.readline.get_line_buffer self.get_endidx = self.readline.get_endidx self.omit__names = omit__names - self.merge_completions = shell.rc.readline_merge_completions + self.merge_completions = shell.readline_merge_completions if alias_table is None: alias_table = {} self.alias_table = alias_table @@ -553,7 +554,7 @@ class IPCompleter(Completer): return withcase # if none, then case insensitive ones are ok too return [r for r in res if r.lower().startswith(text.lower())] - except ipapi.TryNext: + except TryNext: pass return None diff --git a/IPython/core/component.py b/IPython/core/component.py index bc33324..bc914cd 100644 --- a/IPython/core/component.py +++ b/IPython/core/component.py @@ -21,6 +21,7 @@ Authors: #----------------------------------------------------------------------------- from copy import deepcopy +import datetime from weakref import WeakValueDictionary from IPython.utils.ipstruct import Struct @@ -51,15 +52,19 @@ class MetaComponentTracker(type): When a Component or subclass is instantiated, this is called and the instance is saved in a WeakValueDictionary for tracking. """ - - instance = super(MetaComponentTracker, cls).__call__(*args, **kw) + instance = cls.__new__(cls, *args, **kw) + # Do this before __init__ is called so get_instances works inside + # __init__ methods! for c in cls.__mro__: if issubclass(cls, c) and issubclass(c, Component): c.__numcreated += 1 c.__instance_refs[c.__numcreated] = instance + if isinstance(instance, cls): + cls.__init__(instance, *args, **kw) + return instance - def get_instances(cls, name=None, root=None): + def get_instances(cls, name=None, root=None, classname=None): """Get all instances of cls and its subclasses. Parameters @@ -68,21 +73,26 @@ class MetaComponentTracker(type): Limit to components with this name. root : Component or subclass Limit to components having this root. + classname : str + The string name of a class to match exactly. """ instances = cls.__instance_refs.values() if name is not None: instances = [i for i in instances if i.name == name] + if classname is not None: + instances = [i for i in instances if i.__class__.__name__ == classname] if root is not None: instances = [i for i in instances if i.root == root] return instances - def get_instances_by_condition(cls, call, name=None, root=None): + def get_instances_by_condition(cls, call, name=None, root=None, + classname=None): """Get all instances of cls, i such that call(i)==True. - This also takes the ``name`` and ``root`` arguments of - :meth:`get_instance` + This also takes the ``name`` and ``root`` and ``classname`` + arguments of :meth:`get_instance` """ - return [i for i in cls.get_instances(name, root) if call(i)] + return [i for i in cls.get_instances(name, root, classname) if call(i)] class ComponentNameGenerator(object): @@ -118,6 +128,7 @@ class Component(HasTraitlets): config = Instance(Struct,(),{}) parent = This() root = This() + created = None def __init__(self, parent, name=None, config=None): """Create a component given a parent and possibly and name and config. @@ -159,13 +170,15 @@ class Component(HasTraitlets): else: self.name = name self.root = self # This is the default, it is set when parent is set - self.parent = parent + self.parent = parent if config is not None: self.config = deepcopy(config) else: if self.parent is not None: self.config = deepcopy(self.parent.config) + self.created = datetime.datetime.now() + #------------------------------------------------------------------------- # Static traitlet notifiations #------------------------------------------------------------------------- diff --git a/IPython/core/crashhandler.py b/IPython/core/crashhandler.py index 128389f..285ce02 100644 --- a/IPython/core/crashhandler.py +++ b/IPython/core/crashhandler.py @@ -124,7 +124,7 @@ $self.bug_tracker #color_scheme = 'Linux' # dbg try: - rptdir = self.IP.rc.ipythondir + rptdir = self.IP.config.IPYTHONDIR except: rptdir = os.getcwd() if not os.path.isdir(rptdir): @@ -171,7 +171,7 @@ $self.bug_tracker rpt_add('Platform info : os.name -> %s, sys.platform -> %s' % (os.name,sys.platform) ) rpt_add(sec_sep+'Current user configuration structure:\n\n') - rpt_add(pformat(self.IP.rc.dict())) + rpt_add(pformat(self.IP.dict())) rpt_add(sec_sep+'Crash traceback:\n\n' + traceback) try: rpt_add(sec_sep+"History of session input:") @@ -215,7 +215,7 @@ class IPythonCrashHandler(CrashHandler): rpt_add('Platform info : os.name -> %s, sys.platform -> %s' % (os.name,sys.platform) ) rpt_add(sec_sep+'Current user configuration structure:\n\n') - rpt_add(pformat(self.IP.rc.dict())) + # rpt_add(pformat(self.IP.dict())) rpt_add(sec_sep+'Crash traceback:\n\n' + traceback) try: rpt_add(sec_sep+"History of session input:") diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index e61e662..694d6e1 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -110,7 +110,7 @@ class Tracer(object): __IPYTHON__ except NameError: # Outside of ipython, we set our own exception hook manually - __IPYTHON__ = ipapi.get(True,False) + __IPYTHON__ = ipapi.get() BdbQuit_excepthook.excepthook_ori = sys.excepthook sys.excepthook = BdbQuit_excepthook def_colors = 'NoColor' @@ -123,7 +123,7 @@ class Tracer(object): else: # In ipython, we use its custom exception handler mechanism ip = ipapi.get() - def_colors = ip.options.colors + def_colors = ip.colors ip.set_custom_exc((bdb.BdbQuit,),BdbQuit_IPython_excepthook) if colors is None: diff --git a/IPython/core/embed.py b/IPython/core/embed.py new file mode 100644 index 0000000..6ee1aa4 --- /dev/null +++ b/IPython/core/embed.py @@ -0,0 +1,282 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +An embedded IPython shell. + +Authors: + +* Brian Granger +* Fernando Perez + +Notes +----- +""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2008-2009 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 with_statement + +import sys + +from IPython.core import ultratb +from IPython.core.iplib import InteractiveShell + +from IPython.utils.traitlets import Bool, Str, CBool +from IPython.utils.genutils import ask_yes_no + +#----------------------------------------------------------------------------- +# Classes and functions +#----------------------------------------------------------------------------- + +# This is an additional magic that is exposed in embedded shells. +def kill_embedded(self,parameter_s=''): + """%kill_embedded : deactivate for good the current embedded IPython. + + This function (after asking for confirmation) sets an internal flag so that + an embedded IPython will never activate again. This is useful to + permanently disable a shell that is being called inside a loop: once you've + figured out what you needed from it, you may then kill it and the program + will then continue to run without the interactive shell interfering again. + """ + + kill = ask_yes_no("Are you sure you want to kill this embedded instance " + "(y/n)? [y/N] ",'n') + if kill: + self.embedded_active = False + print "This embedded IPython will not reactivate anymore once you exit." + + +class InteractiveShellEmbed(InteractiveShell): + + dummy_mode = Bool(False) + exit_msg = Str('') + embedded = CBool(True) + embedded_active = CBool(True) + + def __init__(self, parent=None, config=None, ipythondir=None, usage=None, + user_ns=None, user_global_ns=None, + banner1=None, banner2=None, + custom_exceptions=((),None), exit_msg=''): + + # First we need to save the state of sys.displayhook and + # sys.ipcompleter so we can restore it when we are done. + self.save_sys_displayhook() + self.save_sys_ipcompleter() + + super(InteractiveShellEmbed,self).__init__( + parent=parent, config=config, ipythondir=ipythondir, usage=usage, + user_ns=user_ns, user_global_ns=user_global_ns, + banner1=banner1, banner2=banner2, + custom_exceptions=custom_exceptions) + + self.save_sys_displayhook_embed() + self.exit_msg = exit_msg + self.define_magic("kill_embedded", kill_embedded) + + # don't use the ipython crash handler so that user exceptions aren't + # trapped + sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors, + mode=self.xmode, + call_pdb=self.pdb) + + self.restore_sys_displayhook() + self.restore_sys_ipcompleter() + + def init_sys_modules(self): + pass + + def save_sys_displayhook(self): + # sys.displayhook is a global, we need to save the user's original + # Don't rely on __displayhook__, as the user may have changed that. + self.sys_displayhook_orig = sys.displayhook + + def save_sys_ipcompleter(self): + """Save readline completer status.""" + try: + #print 'Save completer',sys.ipcompleter # dbg + self.sys_ipcompleter_orig = sys.ipcompleter + except: + pass # not nested with IPython + + def restore_sys_displayhook(self): + sys.displayhook = self.sys_displayhook_orig + + def restore_sys_ipcompleter(self): + """Restores the readline completer which was in place. + + This allows embedded IPython within IPython not to disrupt the + parent's completion. + """ + try: + self.readline.set_completer(self.sys_ipcompleter_orig) + sys.ipcompleter = self.sys_ipcompleter_orig + except: + pass + + def save_sys_displayhook_embed(self): + self.sys_displayhook_embed = sys.displayhook + + def restore_sys_displayhook_embed(self): + sys.displayhook = self.sys_displayhook_embed + + def __call__(self, header='', local_ns=None, global_ns=None, dummy=None, + stack_depth=1): + """Activate the interactive interpreter. + + __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start + the interpreter shell with the given local and global namespaces, and + optionally print a header string at startup. + + The shell can be globally activated/deactivated using the + set/get_dummy_mode methods. This allows you to turn off a shell used + for debugging globally. + + However, *each* time you call the shell you can override the current + state of dummy_mode with the optional keyword parameter 'dummy'. For + example, if you set dummy mode on with IPShell.set_dummy_mode(1), you + can still have a specific call work by making it as IPShell(dummy=0). + + The optional keyword parameter dummy controls whether the call + actually does anything. + """ + + # If the user has turned it off, go away + if not self.embedded_active: + return + + # Normal exits from interactive mode set this flag, so the shell can't + # re-enter (it checks this variable at the start of interactive mode). + self.exit_now = False + + # Allow the dummy parameter to override the global __dummy_mode + if dummy or (dummy != 0 and self.dummy_mode): + return + + self.restore_sys_displayhook_embed() + + if self.has_readline: + self.set_completer() + + if self.banner and header: + format = '%s\n%s\n' + else: + format = '%s%s\n' + banner = format % (self.banner,header) + + # Call the embedding code with a stack depth of 1 so it can skip over + # our call and get the original caller's namespaces. + self.mainloop(banner, local_ns, global_ns, + stack_depth=stack_depth) + + if self.exit_msg is not None: + print self.exit_msg + + # Restore global systems (display, completion) + self.restore_sys_displayhook() + self.restore_sys_ipcompleter() + + def mainloop(self,header='',local_ns=None,global_ns=None,stack_depth=0): + """Embeds IPython into a running python program. + + Input: + + - header: An optional header message can be specified. + + - local_ns, global_ns: working namespaces. If given as None, the + IPython-initialized one is updated with __main__.__dict__, so that + program variables become visible but user-specific configuration + remains possible. + + - stack_depth: specifies how many levels in the stack to go to + looking for namespaces (when local_ns and global_ns are None). This + allows an intermediate caller to make sure that this function gets + the namespace from the intended level in the stack. By default (0) + it will get its locals and globals from the immediate caller. + + Warning: it's possible to use this in a program which is being run by + IPython itself (via %run), but some funny things will happen (a few + globals get overwritten). In the future this will be cleaned up, as + there is no fundamental reason why it can't work perfectly.""" + + # Get locals and globals from caller + if local_ns is None or global_ns is None: + call_frame = sys._getframe(stack_depth).f_back + + if local_ns is None: + local_ns = call_frame.f_locals + if global_ns is None: + global_ns = call_frame.f_globals + + # Update namespaces and fire up interpreter + + # The global one is easy, we can just throw it in + self.user_global_ns = global_ns + + # but the user/local one is tricky: ipython needs it to store internal + # data, but we also need the locals. We'll copy locals in the user + # one, but will track what got copied so we can delete them at exit. + # This is so that a later embedded call doesn't see locals from a + # previous call (which most likely existed in a separate scope). + local_varnames = local_ns.keys() + self.user_ns.update(local_ns) + #self.user_ns['local_ns'] = local_ns # dbg + + # Patch for global embedding to make sure that things don't overwrite + # user globals accidentally. Thanks to Richard + # FIXME. Test this a bit more carefully (the if.. is new) + if local_ns is None and global_ns is None: + self.user_global_ns.update(__main__.__dict__) + + # make sure the tab-completer has the correct frame information, so it + # actually completes using the frame's locals/globals + self.set_completer_frame() + + with self.builtin_trap: + self.interact(header) + + # now, purge out the user namespace from anything we might have added + # from the caller's local namespace + delvar = self.user_ns.pop + for var in local_varnames: + delvar(var,None) + + +_embedded_shell = None + + +def embed(header='', config=None, usage=None, banner1=None, banner2=None, + exit_msg=''): + """Call this to embed IPython at the current point in your program. + + The first invocation of this will create an :class:`InteractiveShellEmbed` + instance and then call it. Consecutive calls just call the already + created instance. + + Here is a simple example:: + + from IPython import embed + a = 10 + b = 20 + embed('First time') + c = 30 + d = 40 + embed + + Full customization can be done by passing a :class:`Struct` in as the + config argument. + """ + global _embedded_shell + if _embedded_shell is None: + _embedded_shell = InteractiveShellEmbed(config=config, + usage=usage, banner1=banner1, banner2=banner2, exit_msg=exit_msg) + _embedded_shell(header=header, stack_depth=2) + diff --git a/IPython/core/error.py b/IPython/core/error.py new file mode 100644 index 0000000..8d20ea8 --- /dev/null +++ b/IPython/core/error.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Global exception classes for IPython.core. + +Authors: + +* Brian Granger +* Fernando Perez + +Notes +----- +""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2008-2009 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 +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Exception classes +#----------------------------------------------------------------------------- + +class IPythonCoreError(Exception): + pass + + +class TryNext(IPythonCoreError): + """Try next hook exception. + + Raise this in your hook function to indicate that the next hook handler + should be used to handle the operation. If you pass arguments to the + constructor those arguments will be used by the next hook instead of the + original ones. + """ + + def __init__(self, *args, **kwargs): + self.args = args + self.kwargs = kwargs + +class UsageError(IPythonCoreError): + """Error in magic function arguments, etc. + + Something that probably won't warrant a full traceback, but should + nevertheless interrupt a macro / batch file. + """ \ No newline at end of file diff --git a/IPython/core/history.py b/IPython/core/history.py index f03f3b8..a85bf01 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -47,9 +47,7 @@ def magic_history(self, parameter_s = ''): confirmation first if it already exists. """ - ip = self.api - shell = self.shell - if not shell.outputcache.do_full_cache: + if not self.outputcache.do_full_cache: print 'This feature is only available if numbered prompts are in use.' return opts,args = self.parse_options(parameter_s,'gntsrf:',mode='list') @@ -71,11 +69,11 @@ def magic_history(self, parameter_s = ''): close_at_end = True if 't' in opts: - input_hist = shell.input_hist + input_hist = self.input_hist elif 'r' in opts: - input_hist = shell.input_hist_raw + input_hist = self.input_hist_raw else: - input_hist = shell.input_hist + input_hist = self.input_hist default_length = 40 pattern = None @@ -105,7 +103,7 @@ def magic_history(self, parameter_s = ''): found = False if pattern is not None: - sh = ip.IP.shadowhist.all() + sh = self.shadowhist.all() for idx, s in sh: if fnmatch.fnmatch(s, pattern): print "0%d: %s" %(idx, s) @@ -168,9 +166,8 @@ def rep_f(self, arg): """ opts,args = self.parse_options(arg,'',mode='list') - ip = self.api if not args: - ip.set_next_input(str(ip.user_ns["_"])) + self.set_next_input(str(self.user_ns["_"])) return if len(args) == 1 and not '-' in args[0]: @@ -179,33 +176,33 @@ def rep_f(self, arg): # get from shadow hist num = int(arg[1:]) line = self.shadowhist.get(num) - ip.set_next_input(str(line)) + self.set_next_input(str(line)) return try: num = int(args[0]) - ip.set_next_input(str(ip.IP.input_hist_raw[num]).rstrip()) + self.set_next_input(str(self.input_hist_raw[num]).rstrip()) return except ValueError: pass - for h in reversed(self.shell.input_hist_raw): + for h in reversed(self.input_hist_raw): if 'rep' in h: continue if fnmatch.fnmatch(h,'*' + arg + '*'): - ip.set_next_input(str(h).rstrip()) + self.set_next_input(str(h).rstrip()) return try: lines = self.extract_input_slices(args, True) print "lines",lines - ip.runlines(lines) + self.runlines(lines) except ValueError: print "Not found in recent history:", args _sentinel = object() -class ShadowHist: +class ShadowHist(object): def __init__(self,db): # cmd => idx mapping self.curidx = 0 @@ -228,7 +225,7 @@ class ShadowHist: #print "new",newidx # dbg self.db.hset('shadowhist',ent, newidx) except: - ipapi.get().IP.showtraceback() + ipapi.get().showtraceback() print "WARNING: disabling shadow history" self.disabled = True @@ -250,8 +247,8 @@ class ShadowHist: def init_ipython(ip): import ipy_completers - ip.expose_magic("rep",rep_f) - ip.expose_magic("hist",magic_hist) - ip.expose_magic("history",magic_history) + ip.define_magic("rep",rep_f) + ip.define_magic("hist",magic_hist) + ip.define_magic("history",magic_history) ipy_completers.quick_completer('%hist' ,'-g -t -r -n') diff --git a/IPython/core/hooks.py b/IPython/core/hooks.py index 97cce7c..60e7687 100644 --- a/IPython/core/hooks.py +++ b/IPython/core/hooks.py @@ -26,7 +26,7 @@ def calljed(self,filename, linenum): "My editor hook calls the jed editor directly." print "Calling my own editor, jed ..." if os.system('jed +%d %s' % (linenum,filename)) != 0: - raise ipapi.TryNext() + raise TryNext() ip.set_hook('editor', calljed) @@ -41,22 +41,21 @@ somewhere in your configuration files or ipython command line. # the file COPYING, distributed as part of this software. #***************************************************************************** -from IPython.core import ipapi - import os, bisect import sys from IPython.utils.genutils import Term, shell from pprint import PrettyPrinter +from IPython.core.error import TryNext + # List here all the default hooks. For now it's just the editor functions # but over time we'll move here all the public API for user-accessible things. -# vds: >> + __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', 'result_display', 'input_prefilter', 'shutdown_hook', 'late_startup_hook', 'generate_prompt', 'generate_output_prompt','shell_hook', 'show_in_pager','pre_prompt_hook', 'pre_runcode_hook', 'clipboard_get'] -# vds: << pformat = PrettyPrinter().pformat @@ -69,7 +68,7 @@ def editor(self,filename, linenum=None): # IPython configures a default editor at startup by reading $EDITOR from # the environment, and falling back on vi (unix) or notepad (win32). - editor = self.rc.editor + editor = self.editor # marker for at which line to open the file (for existing objects) if linenum is None or editor=='notepad': @@ -83,7 +82,7 @@ def editor(self,filename, linenum=None): # Call the actual editor if os.system('%s %s %s' % (editor,linemark,filename)) != 0: - raise ipapi.TryNext() + raise TryNext() import tempfile def fix_error_editor(self,filename,linenum,column,msg): @@ -99,20 +98,20 @@ def fix_error_editor(self,filename,linenum,column,msg): t.write('%s:%d:%d:%s\n' % (filename,linenum,column,msg)) t.flush() return t - if os.path.basename(self.rc.editor) != 'vim': + if os.path.basename(self.editor) != 'vim': self.hooks.editor(filename,linenum) return t = vim_quickfix_file() try: if os.system('vim --cmd "set errorformat=%f:%l:%c:%m" -q ' + t.name): - raise ipapi.TryNext() + raise TryNext() finally: t.close() -# vds: >> + def synchronize_with_editor(self, filename, linenum, column): pass -# vds: << + class CommandChainDispatcher: """ Dispatch calls to a chain of commands until some func can handle it @@ -140,12 +139,12 @@ class CommandChainDispatcher: try: ret = cmd(*args, **kw) return ret - except ipapi.TryNext, exc: + except TryNext, exc: if exc.args or exc.kwargs: args = exc.args kw = exc.kwargs # if no function will accept it, raise TryNext up to the caller - raise ipapi.TryNext + raise TryNext def __str__(self): return str(self.chain) @@ -160,14 +159,15 @@ class CommandChainDispatcher: Handy if the objects are not callable. """ return iter(self.chain) - + + def result_display(self,arg): """ Default display hook. Called for displaying the result to the user. """ - if self.rc.pprint: + if self.pprint: out = pformat(arg) if '\n' in out: # So that multi-line strings line up with the left column of @@ -183,6 +183,7 @@ def result_display(self,arg): # the default display hook doesn't manipulate the value to put in history return None + def input_prefilter(self,line): """ Default input prefilter @@ -197,6 +198,7 @@ def input_prefilter(self,line): #print "attempt to rewrite",line #dbg return line + def shutdown_hook(self): """ default shutdown hook @@ -206,32 +208,36 @@ def shutdown_hook(self): #print "default shutdown hook ok" # dbg return + def late_startup_hook(self): """ Executed after ipython has been constructed and configured """ #print "default startup hook ok" # dbg + def generate_prompt(self, is_continuation): """ calculate and return a string with the prompt to display """ - ip = self.api if is_continuation: - return str(ip.IP.outputcache.prompt2) - return str(ip.IP.outputcache.prompt1) + return str(self.outputcache.prompt2) + return str(self.outputcache.prompt1) + def generate_output_prompt(self): - ip = self.api - return str(ip.IP.outputcache.prompt_out) + return str(self.outputcache.prompt_out) + def shell_hook(self,cmd): """ Run system/shell command a'la os.system() """ - shell(cmd, header=self.rc.system_header, verbose=self.rc.system_verbose) + shell(cmd, header=self.system_header, verbose=self.system_verbose) + def show_in_pager(self,s): """ Run a string through pager """ # raising TryNext here will use the default paging functionality - raise ipapi.TryNext + raise TryNext + def pre_prompt_hook(self): """ Run before displaying the next prompt @@ -242,10 +248,12 @@ def pre_prompt_hook(self): return None + def pre_runcode_hook(self): """ Executed before running the (prefiltered) code in IPython """ return None + def clipboard_get(self): """ Get text from the clipboard. """ diff --git a/IPython/core/ipapi.py b/IPython/core/ipapi.py index fbf3cfc..e4d2df2 100644 --- a/IPython/core/ipapi.py +++ b/IPython/core/ipapi.py @@ -1,685 +1,58 @@ -"""IPython customization API - -Your one-stop module for configuring & extending ipython - -The API will probably break when ipython 1.0 is released, but so -will the other configuration method (rc files). - -All names prefixed by underscores are for internal use, not part -of the public api. - -Below is an example that you can just put to a module and import from ipython. - -A good practice is to install the config script below as e.g. - -~/.ipython/my_private_conf.py - -And do - -import_mod my_private_conf - -in ~/.ipython/ipythonrc - -That way the module is imported at startup and you can have all your -personal configuration (as opposed to boilerplate ipythonrc-PROFILENAME -stuff) in there. - -from IPython.core import ipapi -ip = ipapi.get() - -def ankka_f(self, arg): - print 'Ankka',self,'says uppercase:',arg.upper() - -ip.expose_magic('ankka',ankka_f) - -ip.magic('alias sayhi echo "Testing, hi ok"') -ip.magic('alias helloworld echo "Hello world"') -ip.system('pwd') - -ip.ex('import re') -ip.ex(''' -def funcci(a,b): - print a+b -print funcci(3,4) -''') -ip.ex('funcci(348,9)') +#!/usr/bin/env python +# encoding: utf-8 +""" +Oh my @#*%, where did ipapi go? -def jed_editor(self,filename, linenum=None): - print 'Calling my own editor, jed ... via hook!' - import os - if linenum is None: linenum = 0 - os.system('jed +%d %s' % (linenum, filename)) - print 'exiting jed' +Originally, this module was designed to be a public api for IPython. It is +now deprecated and replaced by :class:`IPython.core.Interactive` shell. +Almost all of the methods that were here are now there, but possibly renamed. -ip.set_hook('editor',jed_editor) +During our transition, we will keep this simple module with its :func:`get` +function. It too will eventually go away when the new component querying +interface is fully used. -o = ip.options -o.autocall = 2 # FULL autocall mode +Authors: -print 'done!' +* Brian Granger """ #----------------------------------------------------------------------------- -# Modules and globals - -# stdlib imports -import __builtin__ -import sys - -# contains the most recently instantiated IPApi -_RECENT_IP = None - +# Copyright (C) 2008-2009 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. #----------------------------------------------------------------------------- -# Code begins - -class TryNext(Exception): - """Try next hook exception. - - Raise this in your hook function to indicate that the next hook handler - should be used to handle the operation. If you pass arguments to the - constructor those arguments will be used by the next hook instead of the - original ones. - """ - - def __init__(self, *args, **kwargs): - self.args = args - self.kwargs = kwargs - - -class UsageError(Exception): - """ Error in magic function arguments, etc. - - Something that probably won't warrant a full traceback, but should - nevertheless interrupt a macro / batch file. - """ - - -class IPyAutocall: - """ Instances of this class are always autocalled - - This happens regardless of 'autocall' variable state. Use this to - develop macro-like mechanisms. - """ - - def set_ip(self,ip): - """ Will be used to set _ip point to current ipython instance b/f call - - Override this method if you don't want this to happen. - - """ - self._ip = ip - - -class IPythonNotRunning: - """Dummy do-nothing class. - - Instances of this class return a dummy attribute on all accesses, which - can be called and warns. This makes it easier to write scripts which use - the ipapi.get() object for informational purposes to operate both with and - without ipython. Obviously code which uses the ipython object for - computations will not work, but this allows a wider range of code to - transparently work whether ipython is being used or not.""" - - def __init__(self,warn=True): - if warn: - self.dummy = self._dummy_warn - else: - self.dummy = self._dummy_silent - - def __str__(self): - return "" - - __repr__ = __str__ - - def __getattr__(self,name): - return self.dummy - - def _dummy_warn(self,*args,**kw): - """Dummy function, which doesn't do anything but warn.""" - - print ("IPython is not running, this is a dummy no-op function") - - def _dummy_silent(self,*args,**kw): - """Dummy function, which doesn't do anything and emits no warnings.""" - pass - - -def get(allow_dummy=False,dummy_warn=True): - """Get an IPApi object. - - If allow_dummy is true, returns an instance of IPythonNotRunning - instead of None if not running under IPython. - - If dummy_warn is false, the dummy instance will be completely silent. - - Running this should be the first thing you do when writing extensions that - can be imported as normal modules. You can then direct all the - configuration operations against the returned object. - """ - global _RECENT_IP - if allow_dummy and not _RECENT_IP: - _RECENT_IP = IPythonNotRunning(dummy_warn) - return _RECENT_IP - - -class IPApi(object): - """ The actual API class for configuring IPython - - You should do all of the IPython configuration by getting an IPApi object - with IPython.ipapi.get() and using the attributes and methods of the - returned object.""" - - def __init__(self,ip): - - global _RECENT_IP - - # All attributes exposed here are considered to be the public API of - # IPython. As needs dictate, some of these may be wrapped as - # properties. - - self.magic = ip.ipmagic - - self.system = ip.system - - self.set_hook = ip.set_hook - - self.set_custom_exc = ip.set_custom_exc - - self.user_ns = ip.user_ns - - self.set_crash_handler = ip.set_crash_handler - - # Session-specific data store, which can be used to store - # data that should persist through the ipython session. - self.meta = ip.meta - - # The ipython instance provided - self.IP = ip - - self.extensions = {} - - self.dbg = DebugTools(self) - - _RECENT_IP = self - - # Use a property for some things which are added to the instance very - # late. I don't have time right now to disentangle the initialization - # order issues, so a property lets us delay item extraction while - # providing a normal attribute API. - def get_db(self): - """A handle to persistent dict-like database (a PickleShareDB object)""" - return self.IP.db - - db = property(get_db,None,None,get_db.__doc__) - def get_options(self): - """All configurable variables.""" - - # catch typos by disabling new attribute creation. If new attr creation - # is in fact wanted (e.g. when exposing new options), do - # allow_new_attr(True) for the received rc struct. - - self.IP.rc.allow_new_attr(False) - return self.IP.rc - - options = property(get_options,None,None,get_options.__doc__) - - def expose_magic(self,magicname, func): - """Expose own function as magic function for ipython - - def foo_impl(self,parameter_s=''): - 'My very own magic!. (Use docstrings, IPython reads them).' - print 'Magic function. Passed parameter is between < >:' - print '<%s>' % parameter_s - print 'The self object is:',self - - ipapi.expose_magic('foo',foo_impl) - """ - - import new - im = new.instancemethod(func,self.IP, self.IP.__class__) - old = getattr(self.IP, "magic_" + magicname, None) - if old: - self.dbg.debug_stack("Magic redefinition '%s', old %s" % - (magicname,old) ) - - setattr(self.IP, "magic_" + magicname, im) - - def ex(self,cmd): - """ Execute a normal python statement in user namespace """ - exec cmd in self.user_ns - - def ev(self,expr): - """ Evaluate python expression expr in user namespace - - Returns the result of evaluation""" - return eval(expr,self.user_ns) - - def runlines(self,lines): - """ Run the specified lines in interpreter, honoring ipython directives. - - This allows %magic and !shell escape notations. - - Takes either all lines in one string or list of lines. - """ - - def cleanup_ipy_script(script): - """ Make a script safe for _ip.runlines() - - - Removes empty lines Suffixes all indented blocks that end with - - unindented lines with empty lines - """ - - 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) - def is_secondary_block_start(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 - - if level > 0 and newlevel == 0 and \ - not is_secondary_block_start(stripped): - # add empty line - res.append('') - - res.append(l) - level = newlevel - return '\n'.join(res) + '\n' - - if isinstance(lines,basestring): - script = lines - else: - script = '\n'.join(lines) - clean=cleanup_ipy_script(script) - # print "_ip.runlines() script:\n",clean # dbg - self.IP.runlines(clean) - - def to_user_ns(self,vars, interactive = True): - """Inject a group of variables into the IPython user namespace. - - Inputs: - - - vars: string with variable names separated by whitespace, or a - dict with name/value pairs. - - - interactive: if True (default), the var will be listed with - %whos et. al. - - This utility routine is meant to ease interactive debugging work, - where you want to easily propagate some internal variable in your code - up to the interactive namespace for further exploration. - - When you run code via %run, globals in your script become visible at - the interactive prompt, but this doesn't happen for locals inside your - own functions and methods. Yet when debugging, it is common to want - to explore some internal variables further at the interactive propmt. - - Examples: - - To use this, you first must obtain a handle on the ipython object as - indicated above, via: - - from IPython.core import ipapi - ip = ipapi.get() - - Once this is done, inside a routine foo() where you want to expose - variables x and y, you do the following: - - def foo(): - ... - x = your_computation() - y = something_else() - - # This pushes x and y to the interactive prompt immediately, even - # if this routine crashes on the next line after: - ip.to_user_ns('x y') - ... - - # To expose *ALL* the local variables from the function, use: - ip.to_user_ns(locals()) - - ... - # return - - - If you need to rename variables, the dict input makes it easy. For - example, this call exposes variables 'foo' as 'x' and 'bar' as 'y' - in IPython user namespace: - - ip.to_user_ns(dict(x=foo,y=bar)) - """ - - # print 'vars given:',vars # dbg - - # We need a dict of name/value pairs to do namespace updates. - if isinstance(vars,dict): - # If a dict was given, no need to change anything. - vdict = vars - elif isinstance(vars,basestring): - # If a string with names was given, get the caller's frame to - # evaluate the given names in - cf = sys._getframe(1) - vdict = {} - for name in vars.split(): - try: - vdict[name] = eval(name,cf.f_globals,cf.f_locals) - except: - print ('could not get var. %s from %s' % - (name,cf.f_code.co_name)) - else: - raise ValueError('vars must be a string or a dict') - - # Propagate variables to user namespace - self.user_ns.update(vdict) - - # And configure interactive visibility - config_ns = self.IP.user_config_ns - if interactive: - for name,val in vdict.iteritems(): - config_ns.pop(name,None) - else: - for name,val in vdict.iteritems(): - config_ns[name] = val - - def expand_alias(self,line): - """ Expand an alias in the command line - - Returns the provided command line, possibly with the first word - (command) translated according to alias expansion rules. - - [ipython]|16> _ip.expand_aliases("np myfile.txt") - <16> 'q:/opt/np/notepad++.exe myfile.txt' - """ - - pre,fn,rest = self.IP.split_user_input(line) - res = pre + self.IP.expand_aliases(fn,rest) - return res - - def itpl(self, s, depth = 1): - """ Expand Itpl format string s. - - Only callable from command line (i.e. prefilter results); - If you use in your scripts, you need to use a bigger depth! - """ - return self.IP.var_expand(s, depth) - - def defalias(self, name, cmd): - """ Define a new alias - - _ip.defalias('bb','bldmake bldfiles') - - Creates a new alias named 'bb' in ipython user namespace - """ - - self.dbg.check_hotname(name) - - if name in self.IP.alias_table: - self.dbg.debug_stack("Alias redefinition: '%s' => '%s' (old '%s')" - % (name, cmd, self.IP.alias_table[name])) - - if callable(cmd): - self.IP.alias_table[name] = cmd - from IPython.core import shadowns - setattr(shadowns, name,cmd) - return - - if isinstance(cmd,basestring): - nargs = cmd.count('%s') - if nargs>0 and cmd.find('%l')>=0: - raise Exception('The %s and %l specifiers are mutually ' - 'exclusive in alias definitions.') - - self.IP.alias_table[name] = (nargs,cmd) - return - - # just put it in - it's probably (0,'foo') - self.IP.alias_table[name] = cmd - - def defmacro(self, *args): - """ Define a new macro - - 2 forms of calling: - - mac = _ip.defmacro('print "hello"\nprint "world"') - - (doesn't put the created macro on user namespace) - - _ip.defmacro('build', 'bldmake bldfiles\nabld build winscw udeb') - - (creates a macro named 'build' in user namespace) - """ - - from IPython.core import macro - - if len(args) == 1: - return macro.Macro(args[0]) - elif len(args) == 2: - self.user_ns[args[0]] = macro.Macro(args[1]) - else: - return Exception("_ip.defmacro must be called with 1 or 2 arguments") - - def set_next_input(self, s): - """ Sets the 'default' input string for the next command line. - - Requires readline. - - Example: - - [D:\ipython]|1> _ip.set_next_input("Hello Word") - [D:\ipython]|2> Hello Word_ # cursor is here - """ - - self.IP.rl_next_input = s - - def load(self, mod): - """ Load an extension. - - Some modules should (or must) be 'load()':ed, rather than just imported. - - Loading will do: - - - run init_ipython(ip) - - run ipython_firstrun(ip) - """ - - if mod in self.extensions: - # just to make sure we don't init it twice - # note that if you 'load' a module that has already been - # imported, init_ipython gets run anyway - - return self.extensions[mod] - __import__(mod) - m = sys.modules[mod] - if hasattr(m,'init_ipython'): - m.init_ipython(self) - - if hasattr(m,'ipython_firstrun'): - already_loaded = self.db.get('firstrun_done', set()) - if mod not in already_loaded: - m.ipython_firstrun(self) - already_loaded.add(mod) - self.db['firstrun_done'] = already_loaded - - self.extensions[mod] = m - return m - - -class DebugTools: - """ Used for debugging mishaps in api usage - - So far, tracing redefinitions is supported. - """ - - def __init__(self, ip): - self.ip = ip - self.debugmode = False - self.hotnames = set() - - def hotname(self, name_to_catch): - self.hotnames.add(name_to_catch) - - def debug_stack(self, msg = None): - if not self.debugmode: - return - - import traceback - if msg is not None: - print '====== %s ========' % msg - traceback.print_stack() - - def check_hotname(self,name): - if name in self.hotnames: - self.debug_stack( "HotName '%s' caught" % name) - - -def launch_new_instance(user_ns = None,shellclass = None): - """ Make and start a new ipython instance. - - This can be called even without having an already initialized - ipython session running. - - This is also used as the egg entry point for the 'ipython' script. - - """ - ses = make_session(user_ns,shellclass) - ses.mainloop() - - -def make_user_ns(user_ns = None): - """Return a valid user interactive namespace. - - This builds a dict with the minimal information needed to operate as a - valid IPython user namespace, which you can pass to the various embedding - classes in ipython. - - This API is currently deprecated. Use ipapi.make_user_namespaces() instead - to make both the local and global namespace objects simultaneously. - - :Parameters: - user_ns : dict-like, optional - The current user namespace. The items in this namespace should be - included in the output. If None, an appropriate blank namespace - should be created. - - :Returns: - A dictionary-like object to be used as the local namespace of the - interpreter. - """ - - raise NotImplementedError - - -def make_user_global_ns(ns = None): - """Return a valid user global namespace. - - Similar to make_user_ns(), but global namespaces are really only needed in - embedded applications, where there is a distinction between the user's - interactive namespace and the global one where ipython is running. - - This API is currently deprecated. Use ipapi.make_user_namespaces() instead - to make both the local and global namespace objects simultaneously. - - :Parameters: - ns : dict, optional - The current user global namespace. The items in this namespace - should be included in the output. If None, an appropriate blank - namespace should be created. - - :Returns: - A true dict to be used as the global namespace of the interpreter. - """ - - raise NotImplementedError - -# Record the true objects in order to be able to test if the user has overridden -# these API functions. -_make_user_ns = make_user_ns -_make_user_global_ns = make_user_global_ns - - -def make_user_namespaces(user_ns = None,user_global_ns = None): - """Return a valid local and global user interactive namespaces. +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- - This builds a dict with the minimal information needed to operate as a - valid IPython user namespace, which you can pass to the various embedding - classes in ipython. The default implementation returns the same dict for - both the locals and the globals to allow functions to refer to variables in - the namespace. Customized implementations can return different dicts. The - locals dictionary can actually be anything following the basic mapping - protocol of a dict, but the globals dict must be a true dict, not even - a subclass. It is recommended that any custom object for the locals - namespace synchronize with the globals dict somehow. +from IPython.core.error import TryNext, UsageError - Raises TypeError if the provided globals namespace is not a true dict. +#----------------------------------------------------------------------------- +# Classes and functions +#----------------------------------------------------------------------------- - :Parameters: - user_ns : dict-like, optional - The current user namespace. The items in this namespace should be - included in the output. If None, an appropriate blank namespace - should be created. - user_global_ns : dict, optional - The current user global namespace. The items in this namespace - should be included in the output. If None, an appropriate blank - namespace should be created. +def get(): + """Get the most recently created InteractiveShell instance.""" + from IPython.core.iplib import InteractiveShell + insts = InteractiveShell.get_instances() + most_recent = insts[0] + for inst in insts[1:]: + if inst.created > most_recent.created: + most_recent = inst + return most_recent - :Returns: - A tuple pair of dictionary-like object to be used as the local namespace - of the interpreter and a dict to be used as the global namespace. - """ +def launch_new_instance(): + """Create a run a full blown IPython instance""" + from IPython.core.ipapp import IPythonApp + app = IPythonApp() + app.start() - if user_ns is None: - if make_user_ns is not _make_user_ns: - # Old API overridden. - # FIXME: Issue DeprecationWarning, or just let the old API live on? - user_ns = make_user_ns(user_ns) - else: - # Set __name__ to __main__ to better match the behavior of the - # normal interpreter. - user_ns = {'__name__' :'__main__', - '__builtins__' : __builtin__, - } - else: - user_ns.setdefault('__name__','__main__') - user_ns.setdefault('__builtins__',__builtin__) - if user_global_ns is None: - if make_user_global_ns is not _make_user_global_ns: - # Old API overridden. - user_global_ns = make_user_global_ns(user_global_ns) - else: - user_global_ns = user_ns - if type(user_global_ns) is not dict: - raise TypeError("user_global_ns must be a true dict; got %r" - % type(user_global_ns)) - return user_ns, user_global_ns -def make_session(user_ns = None, shellclass = None): - """Makes, but does not launch an IPython session. - - Later on you can call obj.mainloop() on the returned object. - Inputs: - - user_ns(None): a dict to be used as the user's namespace with initial - data. - - WARNING: This should *not* be run when a session exists already.""" - import IPython.core.shell - if shellclass is None: - return IPython.core.shell.start(user_ns) - return shellclass(user_ns = user_ns) diff --git a/IPython/core/ipapp.py b/IPython/core/ipapp.py new file mode 100644 index 0000000..155d36f --- /dev/null +++ b/IPython/core/ipapp.py @@ -0,0 +1,317 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +The main IPython application object + +Authors: + +* Brian Granger +* Fernando Perez + +Notes +----- +""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2008-2009 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 os +import sys +import warnings + +from IPython.core.application import Application +from IPython.core import release +from IPython.core.iplib import InteractiveShell +from IPython.config.loader import IPythonArgParseConfigLoader, NoDefault + +from IPython.utils.ipstruct import Struct + + +#----------------------------------------------------------------------------- +# Utilities and helpers +#----------------------------------------------------------------------------- + + +ipython_desc = """ +A Python shell with automatic history (input and output), dynamic object +introspection, easier configuration, command completion, access to the system +shell and more. +""" + +def threaded_shell_warning(): + msg = """ + +The IPython threaded shells and their associated command line +arguments (pylab/wthread/gthread/qthread/q4thread) have been +deprecated. See the %gui magic for information on the new interface. +""" + warnings.warn(msg, category=DeprecationWarning, stacklevel=1) + + +#----------------------------------------------------------------------------- +# Main classes and functions +#----------------------------------------------------------------------------- + +cl_args = ( + (('-autocall',), dict( + type=int, dest='AUTOCALL', default=NoDefault, + help='Set the autocall value (0,1,2).') + ), + (('-autoindent',), dict( + action='store_true', dest='AUTOINDENT', default=NoDefault, + help='Turn on autoindenting.') + ), + (('-noautoindent',), dict( + action='store_false', dest='AUTOINDENT', default=NoDefault, + help='Turn off autoindenting.') + ), + (('-automagic',), dict( + action='store_true', dest='AUTOMAGIC', default=NoDefault, + help='Turn on the auto calling of magic commands.') + ), + (('-noautomagic',), dict( + action='store_false', dest='AUTOMAGIC', default=NoDefault, + help='Turn off the auto calling of magic commands.') + ), + (('-autoedit_syntax',), dict( + action='store_true', dest='AUTOEDIT_SYNTAX', default=NoDefault, + help='Turn on auto editing of files with syntax errors.') + ), + (('-noautoedit_syntax',), dict( + action='store_false', dest='AUTOEDIT_SYNTAX', default=NoDefault, + help='Turn off auto editing of files with syntax errors.') + ), + (('-banner',), dict( + action='store_true', dest='DISPLAY_BANNER', default=NoDefault, + help='Display a banner upon starting IPython.') + ), + (('-nobanner',), dict( + action='store_false', dest='DISPLAY_BANNER', default=NoDefault, + help="Don't display a banner upon starting IPython.") + ), + (('-c',), dict( + type=str, dest='C', default=NoDefault, + help="Execute the given command string.") + ), + (('-cache_size',), dict( + type=int, dest='CACHE_SIZE', default=NoDefault, + help="Set the size of the output cache.") + ), + (('-classic',), dict( + action='store_true', dest='CLASSIC', default=NoDefault, + help="Gives IPython a similar feel to the classic Python prompt.") + ), + (('-colors',), dict( + type=str, dest='COLORS', default=NoDefault, + help="Set the color scheme (NoColor, Linux, and LightBG).") + ), + (('-color_info',), dict( + action='store_true', dest='COLOR_INFO', default=NoDefault, + help="Enable using colors for info related things.") + ), + (('-nocolor_info',), dict( + action='store_false', dest='COLOR_INFO', default=NoDefault, + help="Disable using colors for info related things.") + ), + (('-confirm_exit',), dict( + action='store_true', dest='CONFIRM_EXIT', default=NoDefault, + help="Prompt the user when existing.") + ), + (('-noconfirm_exit',), dict( + action='store_false', dest='CONFIRM_EXIT', default=NoDefault, + help="Don't prompt the user when existing.") + ), + (('-deep_reload',), dict( + action='store_true', dest='DEEP_RELOAD', default=NoDefault, + help="Enable deep (recursive) reloading by default.") + ), + (('-nodeep_reload',), dict( + action='store_false', dest='DEEP_RELOAD', default=NoDefault, + help="Disable deep (recursive) reloading by default.") + ), + (('-editor',), dict( + type=str, dest='EDITOR', default=NoDefault, + help="Set the editor used by IPython (default to $EDITOR/vi/notepad).") + ), + (('-log','-l'), dict( + action='store_true', dest='LOGSTART', default=NoDefault, + help="Start logging to the default file (./ipython_log.py).") + ), + (('-logfile','-lf'), dict( + type=str, dest='LOGFILE', default=NoDefault, + help="Specify the name of your logfile.") + ), + (('-logplay','-lp'), dict( + type=str, dest='LOGPLAY', default=NoDefault, + help="Re-play a log file and then append to it.") + ), + (('-pdb',), dict( + action='store_true', dest='PDB', default=NoDefault, + help="Enable auto calling the pdb debugger after every exception.") + ), + (('-nopdb',), dict( + action='store_false', dest='PDB', default=NoDefault, + help="Disable auto calling the pdb debugger after every exception.") + ), + (('-pprint',), dict( + action='store_true', dest='PPRINT', default=NoDefault, + help="Enable auto pretty printing of results.") + ), + (('-nopprint',), dict( + action='store_false', dest='PPRINT', default=NoDefault, + help="Disable auto auto pretty printing of results.") + ), + (('-prompt_in1','-pi1'), dict( + type=str, dest='PROMPT_IN1', default=NoDefault, + help="Set the main input prompt ('In [\#]: ')") + ), + (('-prompt_in2','-pi2'), dict( + type=str, dest='PROMPT_IN2', default=NoDefault, + help="Set the secondary input prompt (' .\D.: ')") + ), + (('-prompt_out','-po'), dict( + type=str, dest='PROMPT_OUT', default=NoDefault, + help="Set the output prompt ('Out[\#]:')") + ), + (('-quick',), dict( + action='store_true', dest='QUICK', default=NoDefault, + help="Enable quick startup with no config files.") + ), + (('-readline',), dict( + action='store_true', dest='READLINE_USE', default=NoDefault, + help="Enable readline for command line usage.") + ), + (('-noreadline',), dict( + action='store_false', dest='READLINE_USE', default=NoDefault, + help="Disable readline for command line usage.") + ), + (('-screen_length','-sl'), dict( + type=int, dest='SCREEN_LENGTH', default=NoDefault, + help='Number of lines on screen, used to control printing of long strings.') + ), + (('-separate_in','-si'), dict( + type=str, dest='SEPARATE_IN', default=NoDefault, + help="Separator before input prompts. Default '\n'.") + ), + (('-separate_out','-so'), dict( + type=str, dest='SEPARATE_OUT', default=NoDefault, + help="Separator before output prompts. Default 0 (nothing).") + ), + (('-separate_out2','-so2'), dict( + type=str, dest='SEPARATE_OUT2', default=NoDefault, + help="Separator after output prompts. Default 0 (nonight).") + ), + (('-nosep',), dict( + action='store_true', dest='NOSEP', default=NoDefault, + help="Eliminate all spacing between prompts.") + ), + (('-term_title',), dict( + action='store_true', dest='TERM_TITLE', default=NoDefault, + help="Enable auto setting the terminal title.") + ), + (('-noterm_title',), dict( + action='store_false', dest='TERM_TITLE', default=NoDefault, + help="Disable auto setting the terminal title.") + ), + (('-xmode',), dict( + type=str, dest='XMODE', default=NoDefault, + help="Exception mode ('Plain','Context','Verbose')") + ), + # These are only here to get the proper deprecation warnings + (('-pylab','-wthread','-qthread','-q4thread','-gthread'), dict( + action='store_true', dest='THREADED_SHELL', default=NoDefault, + help="These command line flags are deprecated, see the 'gui' magic.") + ), +) + + +class IPythonAppCLConfigLoader(IPythonArgParseConfigLoader): + + arguments = cl_args + + +class IPythonApp(Application): + name = 'ipython' + config_file_name = 'ipython_config.py' + + def create_command_line_config(self): + """Create and return a command line config loader.""" + return IPythonAppCLConfigLoader( + description=ipython_desc, + version=release.version) + + def post_load_command_line_config(self): + """Do actions after loading cl config.""" + clc = self.command_line_config + + # This needs to be set here, the rest are set in pre_construct. + if hasattr(clc, 'CLASSIC'): + if clc.CLASSIC: clc.QUICK = 1 + + # Display the deprecation warnings about threaded shells + if hasattr(clc, 'THREADED_SHELL'): + threaded_shell_warning() + del clc['THREADED_SHELL'] + + def load_file_config(self): + if hasattr(self.command_line_config, 'QUICK'): + if self.command_line_config.QUICK: + self.file_config = Struct() + return + super(IPythonApp, self).load_file_config() + + def post_load_file_config(self): + """Logic goes here.""" + + def pre_construct(self): + config = self.master_config + + if hasattr(config, 'CLASSIC'): + if config.CLASSIC: + config.QUICK = 1 + config.CACHE_SIZE = 0 + config.PPRINT = 0 + config.PROMPT_IN1 = '>>> ' + config.PROMPT_IN2 = '... ' + config.PROMPT_OUT = '' + config.SEPARATE_IN = config.SEPARATE_OUT = config.SEPARATE_OUT2 = '' + config.COLORS = 'NoColor' + config.XMODE = 'Plain' + + # All this should be moved to traitlet handlers in InteractiveShell + # But, currently InteractiveShell doesn't have support for changing + # these values at runtime. Once we support that, this should + # be moved there!!! + if hasattr(config, 'NOSEP'): + if config.NOSEP: + config.SEPARATE_IN = config.SEPARATE_OUT = config.SEPARATE_OUT2 = '0' + + def construct(self): + # I am a little hesitant to put these into InteractiveShell itself. + # But that might be the place for them + sys.path.insert(0, '') + # add personal ipythondir to sys.path so that users can put things in + # there for customization + sys.path.append(os.path.abspath(self.ipythondir)) + + # Create an InteractiveShell instance + self.shell = InteractiveShell( + parent=None, + config=self.master_config + ) + + def start_app(self): + self.shell.mainloop() + + +if __name__ == '__main__': + app = IPythonApp() + app.start() \ No newline at end of file diff --git a/IPython/core/iplib.py b/IPython/core/iplib.py index 85fcfec..68efdce 100644 --- a/IPython/core/iplib.py +++ b/IPython/core/iplib.py @@ -1,32 +1,23 @@ # -*- coding: utf-8 -*- """ -IPython -- An enhanced Interactive Python - -Requires Python 2.4 or newer. - -This file contains all the classes and helper functions specific to IPython. +Main IPython Component """ -#***************************************************************************** -# Copyright (C) 2001 Janko Hauser and -# Copyright (C) 2001-2006 Fernando Perez. +#----------------------------------------------------------------------------- +# Copyright (C) 2001 Janko Hauser +# Copyright (C) 2001-2007 Fernando Perez. +# Copyright (C) 2008-2009 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. -# -# Note: this code originally subclassed code.InteractiveConsole from the -# Python standard library. Over time, all of that class has been copied -# verbatim here for modifications which could not be accomplished by -# subclassing. At this point, there are no dependencies at all on the code -# module anymore (it is not even imported). The Python License (sec. 2) -# allows for this, but it's always nice to acknowledge credit where credit is -# due. -#***************************************************************************** - -#**************************************************************************** -# Modules and globals - -# Python standard modules +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +from __future__ import with_statement + import __main__ import __builtin__ import StringIO @@ -43,26 +34,40 @@ import string import sys import tempfile -# IPython's own modules -#import IPython from IPython.core import ultratb -from IPython.utils import PyColorize from IPython.core import debugger, oinspect -from IPython.extensions import pickleshare +from IPython.core import shadowns +from IPython.core import history as ipcorehist +from IPython.core import prefilter +from IPython.core.autocall import IPyAutocall +from IPython.core.builtin_trap import BuiltinTrap from IPython.core.fakemodule import FakeModule, init_fakemod_dict -from IPython.external.Itpl import ItplNS from IPython.core.logger import Logger from IPython.core.magic import Magic from IPython.core.prompts import CachedOutput -from IPython.utils.ipstruct import Struct +from IPython.core.page import page +from IPython.core.component import Component +from IPython.core.oldusersetup import user_setup +from IPython.core.usage import interactive_usage, default_banner +from IPython.core.error import TryNext, UsageError + +from IPython.extensions import pickleshare +from IPython.external.Itpl import ItplNS from IPython.lib.backgroundjobs import BackgroundJobManager +from IPython.utils.ipstruct import Struct +from IPython.utils import PyColorize from IPython.utils.genutils import * from IPython.utils.strdispatch import StrDispatch -from IPython.core import ipapi -import IPython.core.history -import IPython.core.prefilter as prefilter -from IPython.core import shadowns +from IPython.utils.platutils import toggle_set_term_title, set_term_title + +from IPython.utils.traitlets import ( + Int, Float, Str, CBool, CaselessStrEnum, Enum, List, Unicode +) + +#----------------------------------------------------------------------------- # Globals +#----------------------------------------------------------------------------- + # store the builtin raw_input globally, and use this always, in case user code # overwrites it (like wx.py.PyShell does) @@ -72,11 +77,14 @@ raw_input_original = raw_input dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass') -#**************************************************************************** -# Some utility function definitions +#----------------------------------------------------------------------------- +# Utilities +#----------------------------------------------------------------------------- + ini_spaces_re = re.compile(r'^(\s+)') + def num_ini_spaces(strng): """Return the number of initial spaces in a string""" @@ -86,6 +94,7 @@ def num_ini_spaces(strng): else: return 0 + def softspace(file, newvalue): """Copied from code.py, to remove the dependency""" @@ -102,229 +111,10 @@ def softspace(file, newvalue): return oldvalue -def user_setup(ipythondir,rc_suffix,mode='install',interactive=True): - """Install or upgrade the user configuration directory. - - Can be called when running for the first time or to upgrade the user's - .ipython/ directory. - - Parameters - ---------- - ipythondir : path - The directory to be used for installation/upgrade. In 'install' mode, - if this path already exists, the function exits immediately. - - rc_suffix : str - Extension for the config files. On *nix platforms it is typically the - empty string, while Windows normally uses '.ini'. - - mode : str, optional - Valid modes are 'install' and 'upgrade'. - - interactive : bool, optional - If False, do not wait for user input on any errors. Normally after - printing its status information, this function waits for the user to - hit Return before proceeding. This is because the default use case is - when first installing the IPython configuration, so we want the user to - acknowledge the initial message, which contains some useful - information. - """ - - # For automatic use, deactivate all i/o - if interactive: - def wait(): - try: - raw_input("Please press to start IPython.") - except EOFError: - print >> Term.cout - print '*'*70 - - def printf(s): - print s - else: - wait = lambda : None - printf = lambda s : None - - # Install mode should be re-entrant: if the install dir already exists, - # bail out cleanly. - # XXX. This is too hasty to return. We need to check to make sure that - # all the expected config files and directories are actually there. We - # currently have a failure mode if someone deletes a needed config file - # but still has the ipythondir. - if mode == 'install' and os.path.isdir(ipythondir): - return - - cwd = os.getcwd() # remember where we started - glb = glob.glob - - printf('*'*70) - if mode == 'install': - printf( -"""Welcome to IPython. I will try to create a personal configuration directory -where you can customize many aspects of IPython's functionality in:\n""") - else: - printf('I am going to upgrade your configuration in:') - - printf(ipythondir) - - rcdirend = os.path.join('IPython','config','userconfig') - cfg = lambda d: os.path.join(d,rcdirend) - try: - rcdir = filter(os.path.isdir,map(cfg,sys.path))[0] - printf("Initializing from configuration: %s" % rcdir) - except IndexError: - warning = """ -Installation error. IPython's directory was not found. - -Check the following: - -The ipython/IPython directory should be in a directory belonging to your -PYTHONPATH environment variable (that is, it should be in a directory -belonging to sys.path). You can copy it explicitly there or just link to it. - -IPython will create a minimal default configuration for you. - -""" - warn(warning) - wait() - - if sys.platform =='win32': - inif = 'ipythonrc.ini' - else: - inif = 'ipythonrc' - minimal_setup = {'ipy_user_conf.py' : 'import ipy_defaults', - inif : '# intentionally left blank' } - os.makedirs(ipythondir, mode = 0777) - for f, cont in minimal_setup.items(): - # In 2.5, this can be more cleanly done using 'with' - fobj = file(ipythondir + '/' + f,'w') - fobj.write(cont) - fobj.close() - - return - - if mode == 'install': - try: - shutil.copytree(rcdir,ipythondir) - os.chdir(ipythondir) - rc_files = glb("ipythonrc*") - for rc_file in rc_files: - os.rename(rc_file,rc_file+rc_suffix) - except: - warning = """ - -There was a problem with the installation: -%s -Try to correct it or contact the developers if you think it's a bug. -IPython will proceed with builtin defaults.""" % sys.exc_info()[1] - warn(warning) - wait() - return - - elif mode == 'upgrade': - try: - os.chdir(ipythondir) - except: - printf(""" -Can not upgrade: changing to directory %s failed. Details: -%s -""" % (ipythondir,sys.exc_info()[1]) ) - wait() - return - else: - sources = glb(os.path.join(rcdir,'[A-Za-z]*')) - for new_full_path in sources: - new_filename = os.path.basename(new_full_path) - if new_filename.startswith('ipythonrc'): - new_filename = new_filename + rc_suffix - # The config directory should only contain files, skip any - # directories which may be there (like CVS) - if os.path.isdir(new_full_path): - continue - if os.path.exists(new_filename): - old_file = new_filename+'.old' - if os.path.exists(old_file): - os.remove(old_file) - os.rename(new_filename,old_file) - shutil.copy(new_full_path,new_filename) - else: - raise ValueError('unrecognized mode for install: %r' % mode) - - # Fix line-endings to those native to each platform in the config - # directory. - try: - os.chdir(ipythondir) - except: - printf(""" -Problem: changing to directory %s failed. -Details: -%s - -Some configuration files may have incorrect line endings. This should not -cause any problems during execution. """ % (ipythondir,sys.exc_info()[1]) ) - wait() - else: - for fname in glb('ipythonrc*'): - try: - native_line_ends(fname,backup=0) - except IOError: - pass - - if mode == 'install': - printf(""" -Successful installation! - -Please read the sections 'Initial Configuration' and 'Quick Tips' in the -IPython manual (there are both HTML and PDF versions supplied with the -distribution) to make sure that your system environment is properly configured -to take advantage of IPython's features. - -Important note: the configuration system has changed! The old system is -still in place, but its setting may be partly overridden by the settings in -"~/.ipython/ipy_user_conf.py" config file. Please take a look at the file -if some of the new settings bother you. - -""") - else: - printf(""" -Successful upgrade! - -All files in your directory: -%(ipythondir)s -which would have been overwritten by the upgrade were backed up with a .old -extension. If you had made particular customizations in those files you may -want to merge them back into the new files.""" % locals() ) - wait() - os.chdir(cwd) - -#**************************************************************************** -# Local use exceptions class SpaceInInput(exceptions.Exception): pass - -#**************************************************************************** -# Local use classes class Bunch: pass -class Undefined: pass - -class Quitter(object): - """Simple class to handle exit, similar to Python 2.5's. - - It handles exiting in an ipython-safe manner, which the one in Python 2.5 - doesn't do (obviously, since it doesn't know about ipython).""" - - def __init__(self,shell,name): - self.shell = shell - self.name = name - - def __repr__(self): - return 'Type %s() to exit.' % self.name - __str__ = __repr__ - - def __call__(self): - self.shell.exit() - class InputList(list): """Class to store user input. @@ -340,6 +130,7 @@ class InputList(list): 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""" @@ -357,55 +148,229 @@ class SyntaxTB(ultratb.ListTB): self.last_syntax_error = None return e -#**************************************************************************** -# Main IPython class -# FIXME: the Magic class is a mixin for now, and will unfortunately remain so -# until a full rewrite is made. I've cleaned all cross-class uses of -# attributes and methods, but too much user code out there relies on the -# equlity %foo == __IP.magic_foo, so I can't actually remove the mixin usage. -# -# But at least now, all the pieces have been separated and we could, in -# principle, stop using the mixin. This will ease the transition to the -# chainsaw branch. +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 + + +class SeparateStr(Str): + """A Str subclass to validate separate_in, separate_out, etc. -# For reference, the following is the list of 'self.foo' uses in the Magic -# class as of 2005-12-28. These are names we CAN'T use in the main ipython -# class, to prevent clashes. + This is a Str based traitlet that converts '0'->'' and '\\n'->'\n'. + """ -# ['self.__class__', 'self.__dict__', 'self._inspect', 'self._ofind', -# 'self.arg_err', 'self.extract_input', 'self.format_', 'self.lsmagic', -# 'self.magic_', 'self.options_table', 'self.parse', 'self.shell', -# 'self.value'] + def validate(self, obj, value): + if value == '0': value = '' + value = value.replace('\\n','\n') + return super(SeparateStr, self).validate(obj, value) -class InteractiveShell(object,Magic): - """An enhanced console for Python.""" + +#----------------------------------------------------------------------------- +# Main IPython class +#----------------------------------------------------------------------------- + + +class InteractiveShell(Component, Magic): + """An enhanced, interactive shell for Python.""" + + autocall = Enum((0,1,2), config_key='AUTOCALL') + autoedit_syntax = CBool(False, config_key='AUTOEDIT_SYNTAX') + autoindent = CBool(True, config_key='AUTOINDENT') + automagic = CBool(True, config_key='AUTOMAGIC') + display_banner = CBool(True, config_key='DISPLAY_BANNER') + banner = Str('') + banner1 = Str(default_banner, config_key='BANNER1') + banner2 = Str('', config_key='BANNER2') + c = Str('', config_key='C') + cache_size = Int(1000, config_key='CACHE_SIZE') + classic = CBool(False, config_key='CLASSIC') + color_info = CBool(True, config_key='COLOR_INFO') + colors = CaselessStrEnum(('NoColor','LightBG','Linux'), + default_value='LightBG', config_key='COLORS') + confirm_exit = CBool(True, config_key='CONFIRM_EXIT') + debug = CBool(False, config_key='DEBUG') + deep_reload = CBool(False, config_key='DEEP_RELOAD') + embedded = CBool(False) + embedded_active = CBool(False) + editor = Str(get_default_editor(), config_key='EDITOR') + filename = Str("") + interactive = CBool(False, config_key='INTERACTIVE') + ipythondir= Unicode('', config_key='IPYTHONDIR') # Set to os.getcwd() in __init__ + logstart = CBool(False, config_key='LOGSTART') + logfile = Str('', config_key='LOGFILE') + logplay = Str('', config_key='LOGPLAY') + multi_line_specials = CBool(True, config_key='MULTI_LINE_SPECIALS') + object_info_string_level = Enum((0,1,2), default_value=0, + config_keys='OBJECT_INFO_STRING_LEVEL') + pager = Str('less', config_key='PAGER') + pdb = CBool(False, config_key='PDB') + pprint = CBool(True, config_key='PPRINT') + profile = Str('', config_key='PROFILE') + prompt_in1 = Str('In [\\#]: ', config_key='PROMPT_IN1') + prompt_in2 = Str(' .\\D.: ', config_key='PROMPT_IN2') + prompt_out = Str('Out[\\#]: ', config_key='PROMPT_OUT1') + prompts_pad_left = CBool(True, config_key='PROMPTS_PAD_LEFT') + quiet = CBool(False, config_key='QUIET') + + readline_use = CBool(True, config_key='READLINE_USE') + readline_merge_completions = CBool(True, + config_key='READLINE_MERGE_COMPLETIONS') + readline_omit__names = Enum((0,1,2), default_value=0, + config_key='READLINE_OMIT_NAMES') + readline_remove_delims = Str('-/~', config_key='READLINE_REMOVE_DELIMS') + readline_parse_and_bind = List([ + 'tab: complete', + '"\C-l": possible-completions', + 'set show-all-if-ambiguous on', + '"\C-o": tab-insert', + '"\M-i": " "', + '"\M-o": "\d\d\d\d"', + '"\M-I": "\d\d\d\d"', + '"\C-r": reverse-search-history', + '"\C-s": forward-search-history', + '"\C-p": history-search-backward', + '"\C-n": history-search-forward', + '"\e[A": history-search-backward', + '"\e[B": history-search-forward', + '"\C-k": kill-line', + '"\C-u": unix-line-discard', + ], allow_none=False, config_key='READLINE_PARSE_AND_BIND' + ) + + screen_length = Int(0, config_key='SCREEN_LENGTH') + + # Use custom TraitletTypes that convert '0'->'' and '\\n'->'\n' + separate_in = SeparateStr('\n', config_key='SEPARATE_IN') + separate_out = SeparateStr('', config_key='SEPARATE_OUT') + separate_out2 = SeparateStr('', config_key='SEPARATE_OUT2') + + system_header = Str('IPython system call: ', config_key='SYSTEM_HEADER') + system_verbose = CBool(False, config_key='SYSTEM_VERBOSE') + term_title = CBool(False, config_key='TERM_TITLE') + wildcards_case_sensitive = CBool(True, config_key='WILDCARDS_CASE_SENSITIVE') + xmode = CaselessStrEnum(('Context','Plain', 'Verbose'), + default_value='Context', config_key='XMODE') + + alias = List(allow_none=False, config_key='ALIAS') + 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 - def __init__(self,name,usage=None,rc=Struct(opts=None,args=None), - user_ns=None,user_global_ns=None,banner2='', - custom_exceptions=((),None),embedded=False): + def __init__(self, parent=None, config=None, ipythondir=None, usage=None, + user_ns=None, user_global_ns=None, + banner1=None, banner2=None, + custom_exceptions=((),None)): + + # This is where traitlets with a config_key argument are updated + # from the values on config. + super(InteractiveShell, self).__init__(parent, config=config, name='__IP') + + # These are relatively independent and stateless + self.init_ipythondir(ipythondir) + self.init_instance_attrs() + self.init_term_title() + self.init_usage(usage) + self.init_banner(banner1, banner2) + + # Create namespaces (user_ns, user_global_ns, alias_table, etc.) + self.init_create_namespaces(user_ns, user_global_ns) + # This has to be done after init_create_namespaces because it uses + # something in self.user_ns, but before init_sys_modules, which + # is the first thing to modify sys. + self.save_sys_module_state() + self.init_sys_modules() + + self.init_history() + self.init_encoding() + self.init_handlers() + + Magic.__init__(self, self) + + self.init_syntax_highlighting() + self.init_hooks() + self.init_pushd_popd_magic() + self.init_traceback_handlers(custom_exceptions) + self.init_user_ns() + self.init_logger() + self.init_aliases() + self.init_builtins() + + # pre_config_initialization + self.init_shadow_hist() + + # The next section should contain averything that was in ipmaker. + self.init_logstart() + + # The following was in post_config_initialization + self.init_inspector() + self.init_readline() + self.init_prompts() + self.init_displayhook() + self.init_reload_doctest() + self.init_magics() + self.init_pdb() + self.hooks.late_startup_hook() - # log system - self.logger = Logger(self,logfname='ipython_log.py',logmode='rotate') - - # Job manager (for jobs run as background threads) - self.jobs = BackgroundJobManager() + def cleanup(self): + self.restore_sys_module_state() - # Store the actual shell's name - self.name = name - self.more = False + #------------------------------------------------------------------------- + # Traitlet changed handlers + #------------------------------------------------------------------------- - # We need to know whether the instance is meant for embedding, since - # global/local namespaces need to be handled differently in that case - self.embedded = embedded - if embedded: - # Control variable so users can, from within the embedded instance, - # permanently deactivate it. - self.embedded_active = True + def _banner1_changed(self): + self.compute_banner() + + def _banner2_changed(self): + self.compute_banner() + + @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() + + #------------------------------------------------------------------------- + # init_* methods called by __init__ + #------------------------------------------------------------------------- + + def init_ipythondir(self, ipythondir): + if ipythondir is not None: + self.ipythondir = ipythondir + self.config.IPYTHONDIR = self.ipythondir + return + + if hasattr(self.config, 'IPYTHONDIR'): + self.ipythondir = self.config.IPYTHONDIR + if not hasattr(self.config, 'IPYTHONDIR'): + # cdw is always defined + self.ipythondir = os.getcwd() + + # The caller must make sure that ipythondir exists. We should + # probably handle this using a Dir traitlet. + if not os.path.isdir(self.ipythondir): + raise IOError('IPython dir does not exist: %s' % self.ipythondir) + + # All children can just read this + self.config.IPYTHONDIR = self.ipythondir + + def init_instance_attrs(self): + self.jobs = BackgroundJobManager() + self.more = False # command compiler self.compile = codeop.CommandCompiler() @@ -413,14 +378,6 @@ class InteractiveShell(object,Magic): # User input buffer self.buffer = [] - # Default name given in compilation of code - self.filename = '' - - # Install our own quitter instead of the builtins. For python2.3-2.4, - # this brings in behavior like 2.5, and for 2.5 it's identical. - __builtin__.exit = Quitter(self,'exit') - __builtin__.quit = Quitter(self,'quit') - # Make an empty namespace, which extension writers can rely on both # existing and NEVER being used by ipython itself. This gives them a # convenient location for storing additional information and state @@ -428,6 +385,59 @@ class InteractiveShell(object,Magic): # ipython names that may develop later. self.meta = Struct() + # Object variable to store code object waiting execution. This is + # used mainly by the multithreaded shells, but it can come in handy in + # other situations. No need to use a Queue here, since it's a single + # 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 = [] + + # Keep track of readline usage (later set by init_readline) + self.has_readline = False + + # keep track of where we started running (mainly for crash post-mortem) + # This is not being used anywhere currently. + self.starting_dir = os.getcwd() + + # 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_banner(self, banner1, banner2): + if self.c: # regular python doesn't print the banner with -c + self.display_banner = False + if banner1 is not None: + self.banner1 = banner1 + if banner2 is not None: + self.banner2 = banner2 + self.compute_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_create_namespaces(self, user_ns=None, user_global_ns=None): # Create the namespace where the user will operate. user_ns is # normally the only one used, and it is passed to the exec calls as # the locals argument. But we do carry a user_global_ns namespace @@ -464,7 +474,7 @@ class InteractiveShell(object,Magic): # These routines return properly built dicts as needed by the rest of # the code, and can also be used by extension writers to generate # properly initialized namespaces. - user_ns, user_global_ns = ipapi.make_user_namespaces(user_ns, + user_ns, user_global_ns = self.make_user_namespaces(user_ns, user_global_ns) # Assign namespaces @@ -532,6 +542,7 @@ class InteractiveShell(object,Magic): self.alias_table, self.internal_ns, self._main_ns_cache ] + def init_sys_modules(self): # We need to insert into sys.modules something that looks like a # module but which accesses the IPython namespace, for shelve and # pickle to work interactively. Normally they rely on getting @@ -547,16 +558,65 @@ class InteractiveShell(object,Magic): # shouldn't overtake the execution environment of the script they're # embedded in). - if not embedded: - try: - main_name = self.user_ns['__name__'] - except KeyError: - raise KeyError,'user_ns dictionary MUST have a "__name__" key' - else: - #print "pickle hack in place" # dbg - #print 'main_name:',main_name # dbg - sys.modules[main_name] = FakeModule(self.user_ns) - + # This is overridden in the InteractiveShellEmbed subclass to a no-op. + + try: + main_name = self.user_ns['__name__'] + except KeyError: + raise KeyError('user_ns dictionary MUST have a "__name__" key') + else: + sys.modules[main_name] = FakeModule(self.user_ns) + + def make_user_namespaces(self, user_ns=None, user_global_ns=None): + """Return a valid local and global user interactive namespaces. + + This builds a dict with the minimal information needed to operate as a + valid IPython user namespace, which you can pass to the various + embedding classes in ipython. The default implementation returns the + same dict for both the locals and the globals to allow functions to + refer to variables in the namespace. Customized implementations can + return different dicts. The locals dictionary can actually be anything + following the basic mapping protocol of a dict, but the globals dict + must be a true dict, not even a subclass. It is recommended that any + custom object for the locals namespace synchronize with the globals + dict somehow. + + Raises TypeError if the provided globals namespace is not a true dict. + + :Parameters: + user_ns : dict-like, optional + The current user namespace. The items in this namespace should + be included in the output. If None, an appropriate blank + namespace should be created. + user_global_ns : dict, optional + The current user global namespace. The items in this namespace + should be included in the output. If None, an appropriate + blank namespace should be created. + + :Returns: + A tuple pair of dictionary-like object to be used as the local namespace + of the interpreter and a dict to be used as the global namespace. + """ + + if user_ns is None: + # Set __name__ to __main__ to better match the behavior of the + # normal interpreter. + user_ns = {'__name__' :'__main__', + '__builtins__' : __builtin__, + } + else: + user_ns.setdefault('__name__','__main__') + user_ns.setdefault('__builtins__',__builtin__) + + if user_global_ns is None: + user_global_ns = user_ns + if type(user_global_ns) is not dict: + raise TypeError("user_global_ns must be a true dict; got %r" + % type(user_global_ns)) + + return user_ns, user_global_ns + + def init_history(self): # List of input with multi-line handling. self.input_hist = InputList() # This one will hold the 'raw' input history, without any @@ -573,6 +633,18 @@ class InteractiveShell(object,Magic): # dict of output history self.output_hist = {} + # Now the history file + try: + histfname = 'history-%s' % self.profile + except AttributeError: + histfname = 'history' + self.histfile = os.path.join(self.config.IPYTHONDIR, histfname) + + # Fill the history zero entry, user counter starts at 1 + self.input_hist.append('\n') + self.input_hist_raw.append('\n') + + 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 # encoding to use in the raw_input() method @@ -581,20 +653,7 @@ class InteractiveShell(object,Magic): except AttributeError: self.stdin_encoding = 'ascii' - # dict of things NOT to alias (keywords, builtins and some magics) - no_alias = {} - no_alias_magics = ['cd','popd','pushd','dhist','alias','unalias'] - for key in keyword.kwlist + no_alias_magics: - no_alias[key] = 1 - no_alias.update(__builtin__.__dict__) - self.no_alias = no_alias - - # Object variable to store code object waiting execution. This is - # used mainly by the multithreaded shells, but it can come in handy in - # other situations. No need to use a Queue here, since it's a single - # item which gets cleared once run. - self.code_to_run = None - + def init_handlers(self): # escapes for automatic behavior on the command line self.ESC_SHELL = '!' self.ESC_SH_CAP = '!!' @@ -614,13 +673,12 @@ class InteractiveShell(object,Magic): self.ESC_SH_CAP : self.handle_shell_escape, } - # class initializations - Magic.__init__(self,self) - + def init_syntax_highlighting(self): # Python source parser/formatter for syntax highlighting pyformat = PyColorize.Parser().format - self.pycolorize = lambda src: pyformat(src,'str',self.rc['colors']) + self.pycolorize = lambda src: pyformat(src,'str',self.colors) + def init_hooks(self): # hooks holds pointers used for user-side customizations self.hooks = Struct() @@ -633,81 +691,17 @@ class InteractiveShell(object,Magic): # default hooks have priority 100, i.e. low; user hooks should have # 0-100 priority self.set_hook(hook_name,getattr(hooks,hook_name), 100) - #print "bound hook",hook_name - - # Flag to mark unconditional exit - self.exit_now = False - - self.usage_min = """\ - An enhanced console for Python. - Some of its features are: - - Readline support if the readline library is present. - - Tab completion in the local namespace. - - Logging of input, see command-line options. - - System shell escape via ! , eg !ls. - - Magic commands, starting with a % (like %ls, %pwd, %cd, etc.) - - Keeps track of locally defined variables via %who, %whos. - - Show object information with a ? eg ?x or x? (use ?? for more info). - """ - if usage: self.usage = usage - else: self.usage = self.usage_min - - # Storage - self.rc = rc # This will hold all configuration information - self.pager = 'less' - # temporary files used for various purposes. Deleted at exit. - self.tempfiles = [] - # Keep track of readline usage (later set by init_readline) - self.has_readline = False - - # template for logfile headers. It gets resolved at runtime by the - # logstart method. - self.loghead_tpl = \ -"""#log# Automatic Logger file. *** THIS MUST BE THE FIRST LINE *** -#log# DO NOT CHANGE THIS LINE OR THE TWO BELOW -#log# opts = %s -#log# args = %s -#log# It is safe to make manual edits below here. -#log#----------------------------------------------------------------------- -""" + def init_pushd_popd_magic(self): # for pushd/popd management try: self.home_dir = get_home_dir() - except HomeDirError,msg: + except HomeDirError, msg: fatal(msg) self.dir_stack = [] - # Functions to call the underlying shell. - - # The first is similar to os.system, but it doesn't return a value, - # and it allows interpolation of variables in the user's namespace. - self.system = lambda cmd: \ - self.hooks.shell_hook(self.var_expand(cmd,depth=2)) - - # These are for getoutput and getoutputerror: - self.getoutput = lambda cmd: \ - getoutput(self.var_expand(cmd,depth=2), - header=self.rc.system_header, - verbose=self.rc.system_verbose) - - self.getoutputerror = lambda cmd: \ - getoutputerror(self.var_expand(cmd,depth=2), - header=self.rc.system_header, - verbose=self.rc.system_verbose) - - - # keep track of where we started running (mainly for crash post-mortem) - self.starting_dir = os.getcwd() - - # Various switches which can be set - self.CACHELENGTH = 5000 # this is cheap, it's just text - self.BANNER = "Python %(version)s on %(platform)s\n" % sys.__dict__ - self.banner2 = banner2 - - # TraceBack handlers: - + def init_traceback_handlers(self, custom_exceptions): # Syntax error handler. self.SyntaxTB = SyntaxTB(color_scheme='NoColor') @@ -734,9 +728,37 @@ class InteractiveShell(object,Magic): # and add any custom exception handlers the user may have specified self.set_custom_exc(*custom_exceptions) - # indentation management - self.autoindent = False - self.indent_current_nsp = 0 + def init_logger(self): + self.logger = Logger(self, logfname='ipython_log.py', logmode='rotate') + # local shortcut, this is used a LOT + self.log = self.logger.log + # template for logfile headers. It gets resolved at runtime by the + # logstart method. + self.loghead_tpl = \ +"""#log# Automatic Logger file. *** THIS MUST BE THE FIRST LINE *** +#log# DO NOT CHANGE THIS LINE OR THE TWO BELOW +#log# opts = %s +#log# args = %s +#log# It is safe to make manual edits below here. +#log#----------------------------------------------------------------------- +""" + + def init_logstart(self): + if self.logplay: + self.magic_logstart(self.logplay + ' append') + elif self.logfile: + self.magic_logstart(self.logfile) + elif self.logstart: + self.magic_logstart() + + def init_aliases(self): + # dict of things NOT to alias (keywords, builtins and some magics) + no_alias = {} + no_alias_magics = ['cd','popd','pushd','dhist','alias','unalias'] + for key in keyword.kwlist + no_alias_magics: + no_alias[key] = 1 + no_alias.update(__builtin__.__dict__) + self.no_alias = no_alias # Make some aliases automatically # Prepare list of shell aliases to auto-define @@ -783,93 +805,133 @@ class InteractiveShell(object,Magic): auto_alias = () self.auto_alias = [s.split(None,1) for s in auto_alias] - # Produce a public API instance - self.api = ipapi.IPApi(self) - - # Initialize all user-visible namespaces - self.init_namespaces() - - # Call the actual (public) initializer - self.init_auto_alias() - - # track which builtins we add, so we can clean up later - self.builtins_added = {} - # This method will add the necessary builtins for operation, but - # tracking what it did via the builtins_added dict. - - #TODO: remove this, redundant - self.add_builtins() - # end __init__ - - def var_expand(self,cmd,depth=0): - """Expand python variables in a string. - - The depth argument indicates how many frames above the caller should - be walked to look for the local namespace where to expand variables. - - The global namespace for expansion is always the user's interactive - namespace. - """ + # Load default aliases + for alias, cmd in self.auto_alias: + self.define_alias(alias,cmd) - return str(ItplNS(cmd, - self.user_ns, # globals - # Skip our own frame in searching for locals: - sys._getframe(depth+1).f_locals # locals - )) + # Load user aliases + for alias in self.alias: + self.magic_alias(alias) - def pre_config_initialization(self): - """Pre-configuration init method + def init_builtins(self): + self.builtin_trap = BuiltinTrap(self) - This is called before the configuration files are processed to - prepare the services the config files might need. - - self.rc already has reasonable default values at this point. - """ - rc = self.rc + def init_shadow_hist(self): try: - self.db = pickleshare.PickleShareDB(rc.ipythondir + "/db") + self.db = pickleshare.PickleShareDB(self.config.IPYTHONDIR + "/db") except exceptions.UnicodeDecodeError: print "Your ipythondir can't be decoded to unicode!" print "Please set HOME environment variable to something that" print r"only has ASCII characters, e.g. c:\home" - print "Now it is",rc.ipythondir + print "Now it is", self.config.IPYTHONDIR sys.exit() - self.shadowhist = IPython.core.history.ShadowHist(self.db) - - def post_config_initialization(self): - """Post configuration init method - - This is called after the configuration files have been processed to - 'finalize' the initialization.""" - - rc = self.rc + self.shadowhist = ipcorehist.ShadowHist(self.db) + def init_inspector(self): # Object inspector self.inspector = oinspect.Inspector(oinspect.InspectColors, PyColorize.ANSICodeColors, 'NoColor', - rc.object_info_string_level) - + self.object_info_string_level) + + def init_readline(self): + """Command history completion/saving/reloading.""" + self.rl_next_input = None self.rl_do_indent = False - # Load readline proper - if rc.readline: - self.init_readline() - - # local shortcut, this is used a LOT - self.log = self.logger.log + if not self.readline_use: + return + + import IPython.utils.rlineimpl as readline + + if not readline.have_readline: + self.has_readline = 0 + self.readline = None + # no point in bugging windows users with this every time: + warn('Readline services not available on this platform.') + else: + sys.modules['readline'] = readline + import atexit + from IPython.core.completer import IPCompleter + self.Completer = IPCompleter(self, + self.user_ns, + self.user_global_ns, + self.readline_omit__names, + self.alias_table) + sdisp = self.strdispatchers.get('complete_command', StrDispatch()) + self.strdispatchers['complete_command'] = sdisp + self.Completer.custom_completers = sdisp + # Platform-specific configuration + if os.name == 'nt': + self.readline_startup_hook = readline.set_pre_input_hook + else: + self.readline_startup_hook = readline.set_startup_hook + + # Load user's initrc file (readline config) + # Or if libedit is used, load editrc. + inputrc_name = os.environ.get('INPUTRC') + if inputrc_name is None: + home_dir = get_home_dir() + if home_dir is not None: + inputrc_name = '.inputrc' + if readline.uses_libedit: + inputrc_name = '.editrc' + inputrc_name = os.path.join(home_dir, inputrc_name) + if os.path.isfile(inputrc_name): + try: + readline.read_init_file(inputrc_name) + except: + warn('Problems reading readline initialization file <%s>' + % inputrc_name) + + self.has_readline = 1 + self.readline = readline + # save this in sys so embedded copies can restore it properly + sys.ipcompleter = self.Completer.complete + self.set_completer() + + # Configure readline according to user's prefs + # This is only done if GNU readline is being used. If libedit + # is being used (as on Leopard) the readline config is + # not run as the syntax for libedit is different. + if not readline.uses_libedit: + for rlcommand in self.readline_parse_and_bind: + #print "loading rl:",rlcommand # dbg + readline.parse_and_bind(rlcommand) + + # Remove some chars from the delimiters list. If we encounter + # unicode chars, discard them. + delims = readline.get_completer_delims().encode("ascii", "ignore") + delims = delims.translate(string._idmap, + self.readline_remove_delims) + readline.set_completer_delims(delims) + # otherwise we end up with a monster history after a while: + readline.set_history_length(1000) + try: + #print '*** Reading readline history' # dbg + readline.read_history_file(self.histfile) + except IOError: + pass # It doesn't exist yet. + + atexit.register(self.atexit_operations) + del atexit + + # Configure auto-indent for all platforms + self.set_autoindent(self.autoindent) + + def init_prompts(self): # Initialize cache, set in/out prompts and printing system self.outputcache = CachedOutput(self, - rc.cache_size, - rc.pprint, - input_sep = rc.separate_in, - output_sep = rc.separate_out, - output_sep2 = rc.separate_out2, - ps1 = rc.prompt_in1, - ps2 = rc.prompt_in2, - ps_out = rc.prompt_out, - pad_left = rc.prompts_pad_left) + self.cache_size, + self.pprint, + input_sep = self.separate_in, + output_sep = self.separate_out, + output_sep2 = self.separate_out2, + ps1 = self.prompt_in1, + ps2 = self.prompt_in2, + ps_out = self.prompt_out, + pad_left = self.prompts_pad_left) # user may have over-ridden the default print hook: try: @@ -877,6 +939,7 @@ class InteractiveShell(object,Magic): except AttributeError: pass + def init_displayhook(self): # I don't like assigning globally to sys, because it means when # embedding instances, each embedded instance overrides the previous # choice. But sys.displayhook seems to be called internally by exec, @@ -885,43 +948,75 @@ class InteractiveShell(object,Magic): self.sys_displayhook = sys.displayhook sys.displayhook = self.outputcache + def init_reload_doctest(self): # Do a proper resetting of doctest, including the necessary displayhook # monkeypatching try: doctest_reload() except ImportError: warn("doctest module does not exist.") - + + def init_magics(self): # Set user colors (don't do it in the constructor above so that it # doesn't crash if colors option is invalid) - self.magic_colors(rc.colors) + self.magic_colors(self.colors) + def init_pdb(self): # Set calling of pdb on exceptions - self.call_pdb = rc.pdb - - # Load user aliases - for alias in rc.alias: - self.magic_alias(alias) - - self.hooks.late_startup_hook() - - for cmd in self.rc.autoexec: - #print "autoexec>",cmd #dbg - self.api.runlines(cmd) - - batchrun = False - for batchfile in [path(arg) for arg in self.rc.args - if arg.lower().endswith('.ipy')]: - if not batchfile.isfile(): - print "No such batch file:", batchfile - continue - self.api.runlines(batchfile.text()) - batchrun = True - # without -i option, exit after running the batch file - if batchrun and not self.rc.interact: - self.ask_exit() - - def init_namespaces(self): + # self.call_pdb is a property + self.call_pdb = self.pdb + + # def init_exec_commands(self): + # for cmd in self.config.EXECUTE: + # print "execute:", cmd + # self.api.runlines(cmd) + # + # batchrun = False + # if self.config.has_key('EXECFILE'): + # for batchfile in [path(arg) for arg in self.config.EXECFILE + # if arg.lower().endswith('.ipy')]: + # if not batchfile.isfile(): + # print "No such batch file:", batchfile + # continue + # self.api.runlines(batchfile.text()) + # batchrun = True + # # without -i option, exit after running the batch file + # if batchrun and not self.interactive: + # self.ask_exit() + + # def load(self, mod): + # """ Load an extension. + # + # Some modules should (or must) be 'load()':ed, rather than just imported. + # + # Loading will do: + # + # - run init_ipython(ip) + # - run ipython_firstrun(ip) + # """ + # + # if mod in self.extensions: + # # just to make sure we don't init it twice + # # note that if you 'load' a module that has already been + # # imported, init_ipython gets run anyway + # + # return self.extensions[mod] + # __import__(mod) + # m = sys.modules[mod] + # if hasattr(m,'init_ipython'): + # m.init_ipython(self) + # + # if hasattr(m,'ipython_firstrun'): + # already_loaded = self.db.get('firstrun_done', set()) + # if mod not in already_loaded: + # m.ipython_firstrun(self) + # already_loaded.add(mod) + # self.db['firstrun_done'] = already_loaded + # + # self.extensions[mod] = m + # return m + + def init_user_ns(self): """Initialize all user-visible namespaces to their minimum defaults. Certain history lists are also initialized here, as they effectively @@ -936,8 +1031,8 @@ class InteractiveShell(object,Magic): # The user namespace MUST have a pointer to the shell itself. self.user_ns[self.name] = self - # Store the public api instance - self.user_ns['_ip'] = self.api + # Store myself as the public api!!! + self.user_ns['_ip'] = self # make global variables for user access to the histories self.user_ns['_ih'] = self.input_hist @@ -950,51 +1045,46 @@ class InteractiveShell(object,Magic): self.user_ns['_sh'] = shadowns - # Fill the history zero entry, user counter starts at 1 - self.input_hist.append('\n') - self.input_hist_raw.append('\n') + # Put 'help' in the user namespace + try: + from site import _Helper + self.user_ns['help'] = _Helper() + except ImportError: + warn('help() not available - check site.py') + + def save_sys_module_state(self): + """Save the state of hooks in the sys module. + + This has to be called after self.user_ns is created. + """ + self._orig_sys_module_state = {} + self._orig_sys_module_state['stdin'] = sys.stdin + self._orig_sys_module_state['stdout'] = sys.stdout + self._orig_sys_module_state['stderr'] = sys.stderr + self._orig_sys_module_state['displayhook'] = sys.displayhook + self._orig_sys_module_state['excepthook'] = sys.excepthook + try: + self._orig_sys_modules_main_name = self.user_ns['__name__'] + except KeyError: + pass + + def restore_sys_module_state(self): + """Restore the state of the sys module.""" + try: + for k, v in self._orig_sys_module_state.items(): + setattr(sys, k, v) + except AttributeError: + pass + try: + delattr(sys, 'ipcompleter') + except AttributeError: + pass + # Reset what what done in self.init_sys_modules + try: + sys.modules[self.user_ns['__name__']] = self._orig_sys_modules_main_name + except (AttributeError, KeyError): + pass - def add_builtins(self): - """Store ipython references into the builtin namespace. - - Some parts of ipython operate via builtins injected here, which hold a - reference to IPython itself.""" - - # TODO: deprecate all of these, they are unsafe - builtins_new = dict(__IPYTHON__ = self, - ip_set_hook = self.set_hook, - jobs = self.jobs, - ipmagic = wrap_deprecated(self.ipmagic,'_ip.magic()'), - ipalias = wrap_deprecated(self.ipalias), - ipsystem = wrap_deprecated(self.ipsystem,'_ip.system()'), - #_ip = self.api - ) - for biname,bival in builtins_new.items(): - try: - # store the orignal value so we can restore it - self.builtins_added[biname] = __builtin__.__dict__[biname] - except KeyError: - # or mark that it wasn't defined, and we'll just delete it at - # cleanup - self.builtins_added[biname] = Undefined - __builtin__.__dict__[biname] = bival - - # Keep in the builtins a flag for when IPython is active. We set it - # with setdefault so that multiple nested IPythons don't clobber one - # another. Each will increase its value by one upon being activated, - # which also gives us a way to determine the nesting level. - __builtin__.__dict__.setdefault('__IPYTHON__active',0) - - def clean_builtins(self): - """Remove any builtins which might have been added by add_builtins, or - restore overwritten ones to their previous values.""" - for biname,bival in self.builtins_added.items(): - if bival is Undefined: - del __builtin__.__dict__[biname] - else: - __builtin__.__dict__[biname] = bival - self.builtins_added.clear() - def set_hook(self,name,hook, priority = 50, str_key = None, re_key = None): """set_hook(name,hook) -> sets an internal IPython hook. @@ -1033,11 +1123,8 @@ class InteractiveShell(object,Magic): dp = f setattr(self.hooks,name, dp) - - - #setattr(self.hooks,name,new.instancemethod(hook,self,self.__class__)) - def set_crash_handler(self,crashHandler): + def set_crash_handler(self, crashHandler): """Set the IPython crash handler. This must be a callable with a signature suitable for use as @@ -1052,7 +1139,6 @@ class InteractiveShell(object,Magic): # frameworks). self.sys_excepthook = sys.excepthook - def set_custom_exc(self,exc_tuple,handler): """set_custom_exc(exc_tuple,handler) @@ -1133,33 +1219,24 @@ class InteractiveShell(object,Magic): call_pdb = property(_get_call_pdb,_set_call_pdb,None, 'Control auto-activation of pdb at exceptions') - - # These special functions get installed in the builtin namespace, to - # provide programmatic (pure python) access to magics, aliases and system - # calls. This is important for logging, user scripting, and more. - # We are basically exposing, via normal python functions, the three - # mechanisms in which ipython offers special call modes (magics for - # internal control, aliases for direct system access via pre-selected - # names, and !cmd for calling arbitrary system commands). - - def ipmagic(self,arg_s): + def magic(self,arg_s): """Call a magic function by name. Input: a string containing the name of the magic function to call and any additional arguments to be passed to the magic. - ipmagic('name -opt foo bar') is equivalent to typing at the ipython + magic('name -opt foo bar') is equivalent to typing at the ipython prompt: In[1]: %name -opt foo bar - To call a magic without arguments, simply use ipmagic('name'). + To call a magic without arguments, simply use magic('name'). This provides a proper Python function to call IPython's magics in any valid Python code you can type at the interpreter, including loops and - compound statements. It is added by IPython to the Python builtin - namespace upon initialization.""" + compound statements. + """ args = arg_s.split(' ',1) magic_name = args[0] @@ -1174,7 +1251,67 @@ class InteractiveShell(object,Magic): error("Magic function `%s` not found." % magic_name) else: magic_args = self.var_expand(magic_args,1) - return fn(magic_args) + with self.builtin_trap: + result = fn(magic_args) + return result + + def define_magic(self, magicname, func): + """Expose own function as magic function for ipython + + def foo_impl(self,parameter_s=''): + 'My very own magic!. (Use docstrings, IPython reads them).' + print 'Magic function. Passed parameter is between < >:' + print '<%s>' % parameter_s + print 'The self object is:',self + + self.define_magic('foo',foo_impl) + """ + + import new + im = new.instancemethod(func,self, self.__class__) + old = getattr(self, "magic_" + magicname, None) + setattr(self, "magic_" + magicname, im) + return old + + def define_macro(self, name, themacro): + """Define a new macro + + Parameters + ---------- + name : str + The name of the macro. + themacro : str or Macro + The action to do upon invoking the macro. If a string, a new + Macro object is created by passing the string to it. + """ + + from IPython.core import macro + + if isinstance(themacro, basestring): + themacro = macro.Macro(themacro) + if not isinstance(themacro, macro.Macro): + raise ValueError('A macro must be a string or a Macro instance.') + self.user_ns[name] = themacro + + def define_alias(self, name, cmd): + """ Define a new alias.""" + + if callable(cmd): + self.alias_table[name] = cmd + from IPython.core import shadowns + setattr(shadowns, name, cmd) + return + + if isinstance(cmd, basestring): + nargs = cmd.count('%s') + if nargs>0 and cmd.find('%l')>=0: + raise Exception('The %s and %l specifiers are mutually ' + 'exclusive in alias definitions.') + + self.alias_table[name] = (nargs,cmd) + return + + self.alias_table[name] = cmd def ipalias(self,arg_s): """Call an alias by name. @@ -1205,12 +1342,35 @@ class InteractiveShell(object,Magic): else: error("Alias `%s` not found." % alias_name) - def ipsystem(self,arg_s): + def system(self, cmd): """Make a system call, using IPython.""" + return self.hooks.shell_hook(self.var_expand(cmd, depth=2)) + + def ex(self, cmd): + """Execute a normal python statement in user namespace.""" + with self.builtin_trap: + exec cmd in self.user_global_ns, self.user_ns - self.system(arg_s) + def ev(self, expr): + """Evaluate python expression expr in user namespace. - def complete(self,text): + Returns the result of evaluation + """ + with self.builtin_trap: + result = eval(expr, self.user_global_ns, self.user_ns) + return result + + def getoutput(self, cmd): + return getoutput(self.var_expand(cmd,depth=2), + header=self.system_header, + verbose=self.system_verbose) + + def getoutputerror(self, cmd): + return getoutputerror(self.var_expand(cmd,depth=2), + header=self.system_header, + verbose=self.system_verbose) + + def complete(self, text): """Return a sorted list of all possible completions on text. Inputs: @@ -1232,26 +1392,28 @@ class InteractiveShell(object,Magic): In [9]: print x hello - In [10]: _ip.IP.complete('x.l') + In [10]: _ip.complete('x.l') Out[10]: ['x.ljust', 'x.lower', 'x.lstrip'] """ - - complete = self.Completer.complete - state = 0 - # use a dict so we get unique keys, since ipyhton's multiple - # completers can return duplicates. When we make 2.4 a requirement, - # start using sets instead, which are faster. - comps = {} - while True: - newcomp = complete(text,state,line_buffer=text) - if newcomp is None: - break - comps[newcomp] = 1 - state += 1 - outcomps = comps.keys() - outcomps.sort() - #print "T:",text,"OC:",outcomps # dbg - #print "vars:",self.user_ns.keys() + + # Inject names into __builtin__ so we can complete on the added names. + with self.builtin_trap: + complete = self.Completer.complete + state = 0 + # use a dict so we get unique keys, since ipyhton's multiple + # completers can return duplicates. When we make 2.4 a requirement, + # start using sets instead, which are faster. + comps = {} + while True: + newcomp = complete(text,state,line_buffer=text) + if newcomp is None: + break + comps[newcomp] = 1 + state += 1 + outcomps = comps.keys() + outcomps.sort() + #print "T:",text,"OC:",outcomps # dbg + #print "vars:",self.user_ns.keys() return outcomps def set_completer_frame(self, frame=None): @@ -1268,8 +1430,7 @@ class InteractiveShell(object,Magic): These are ALL parameter-less aliases""" for alias,cmd in self.auto_alias: - self.getapi().defalias(alias,cmd) - + self.define_alias(alias,cmd) def alias_table_validate(self,verbose=0): """Update information about the alias table. @@ -1283,7 +1444,20 @@ class InteractiveShell(object,Magic): if verbose: print ("Deleting alias <%s>, it's a Python " "keyword or builtin." % k) - + + def set_next_input(self, s): + """ Sets the 'default' input string for the next command line. + + Requires readline. + + Example: + + [D:\ipython]|1> _ip.set_next_input("Hello Word") + [D:\ipython]|2> Hello Word_ # cursor is here + """ + + self.rl_next_input = s + def set_autoindent(self,value=None): """Set the autoindent flag, checking for readline support. @@ -1299,28 +1473,6 @@ class InteractiveShell(object,Magic): else: self.autoindent = value - def rc_set_toggle(self,rc_field,value=None): - """Set or toggle a field in IPython's rc config. structure. - - If called with no arguments, it acts as a toggle. - - If called with a non-existent field, the resulting AttributeError - exception will propagate out.""" - - rc_val = getattr(self.rc,rc_field) - if value is None: - value = not rc_val - setattr(self.rc,rc_field,value) - - def user_setup(self,ipythondir,rc_suffix,mode='install'): - """Install the user configuration directory. - - Notes - ----- - DEPRECATED: use the top-level user_setup() function instead. - """ - return user_setup(ipythondir,rc_suffix,mode) - def atexit_operations(self): """This will be executed at the time of exit. @@ -1357,7 +1509,7 @@ class InteractiveShell(object,Magic): self.input_hist_raw[:] = [] self.output_hist.clear() # Restore the user namespaces to minimal usability - self.init_namespaces() + self.init_user_ns() def savehist(self): """Save input history to a file (via readline library).""" @@ -1412,89 +1564,8 @@ class InteractiveShell(object,Magic): self.readline.insert_text(self.rl_next_input) self.rl_next_input = None - def init_readline(self): - """Command history completion/saving/reloading.""" - - - import IPython.utils.rlineimpl as readline - - if not readline.have_readline: - self.has_readline = 0 - self.readline = None - # no point in bugging windows users with this every time: - warn('Readline services not available on this platform.') - else: - sys.modules['readline'] = readline - import atexit - from IPython.core.completer import IPCompleter - self.Completer = IPCompleter(self, - self.user_ns, - self.user_global_ns, - self.rc.readline_omit__names, - self.alias_table) - sdisp = self.strdispatchers.get('complete_command', StrDispatch()) - self.strdispatchers['complete_command'] = sdisp - self.Completer.custom_completers = sdisp - # Platform-specific configuration - if os.name == 'nt': - self.readline_startup_hook = readline.set_pre_input_hook - else: - self.readline_startup_hook = readline.set_startup_hook - - # Load user's initrc file (readline config) - # Or if libedit is used, load editrc. - inputrc_name = os.environ.get('INPUTRC') - if inputrc_name is None: - home_dir = get_home_dir() - if home_dir is not None: - inputrc_name = '.inputrc' - if readline.uses_libedit: - inputrc_name = '.editrc' - inputrc_name = os.path.join(home_dir, inputrc_name) - if os.path.isfile(inputrc_name): - try: - readline.read_init_file(inputrc_name) - except: - warn('Problems reading readline initialization file <%s>' - % inputrc_name) - - self.has_readline = 1 - self.readline = readline - # save this in sys so embedded copies can restore it properly - sys.ipcompleter = self.Completer.complete - self.set_completer() - - # Configure readline according to user's prefs - # This is only done if GNU readline is being used. If libedit - # is being used (as on Leopard) the readline config is - # not run as the syntax for libedit is different. - if not readline.uses_libedit: - for rlcommand in self.rc.readline_parse_and_bind: - #print "loading rl:",rlcommand # dbg - readline.parse_and_bind(rlcommand) - - # Remove some chars from the delimiters list. If we encounter - # unicode chars, discard them. - delims = readline.get_completer_delims().encode("ascii", "ignore") - delims = delims.translate(string._idmap, - self.rc.readline_remove_delims) - readline.set_completer_delims(delims) - # otherwise we end up with a monster history after a while: - readline.set_history_length(1000) - try: - #print '*** Reading readline history' # dbg - readline.read_history_file(self.histfile) - except IOError: - pass # It doesn't exist yet. - - atexit.register(self.atexit_operations) - del atexit - - # Configure auto-indent for all platforms - self.set_autoindent(self.rc.autoindent) - def ask_yes_no(self,prompt,default=True): - if self.rc.quiet: + if self.quiet: return True return ask_yes_no(prompt,default) @@ -1539,9 +1610,9 @@ class InteractiveShell(object,Magic): In [10]: import IPython - In [11]: _ip.IP.cache_main_mod(IPython.__dict__,IPython.__file__) + In [11]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__) - In [12]: IPython.__file__ in _ip.IP._main_ns_cache + In [12]: IPython.__file__ in _ip._main_ns_cache Out[12]: True """ self._main_ns_cache[os.path.abspath(fname)] = ns.copy() @@ -1556,14 +1627,14 @@ class InteractiveShell(object,Magic): In [15]: import IPython - In [16]: _ip.IP.cache_main_mod(IPython.__dict__,IPython.__file__) + In [16]: _ip.cache_main_mod(IPython.__dict__,IPython.__file__) - In [17]: len(_ip.IP._main_ns_cache) > 0 + In [17]: len(_ip._main_ns_cache) > 0 Out[17]: True - In [18]: _ip.IP.clear_main_mod_cache() + In [18]: _ip.clear_main_mod_cache() - In [19]: len(_ip.IP._main_ns_cache) == 0 + In [19]: len(_ip._main_ns_cache) == 0 Out[19]: True """ self._main_ns_cache.clear() @@ -1577,7 +1648,7 @@ class InteractiveShell(object,Magic): return False try: - if (self.rc.autoedit_syntax and + if (self.autoedit_syntax and not self.ask_yes_no('Return to editor to correct syntax error? ' '[Y/n] ','y')): return False @@ -1593,7 +1664,7 @@ class InteractiveShell(object,Magic): try: self.hooks.fix_error_editor(e.filename, int0(e.lineno),int0(e.offset),e.msg) - except ipapi.TryNext: + except TryNext: warn('Could not open editor') return False return True @@ -1707,7 +1778,7 @@ class InteractiveShell(object,Magic): if etype is SyntaxError: self.showsyntaxerror(filename) - elif etype is ipapi.UsageError: + elif etype is UsageError: print "UsageError:", value else: # WARNING: these variables are somewhat deprecated and not @@ -1728,41 +1799,37 @@ class InteractiveShell(object,Magic): except KeyboardInterrupt: self.write("\nKeyboardInterrupt\n") - def mainloop(self,banner=None): - """Creates the local namespace and starts the mainloop. + def mainloop(self, banner=None): + """Start the mainloop. If an optional banner argument is given, it will override the - internally created default banner.""" - - if self.rc.c: # Emulate Python's -c option - self.exec_init_cmd() - if banner is None: - if not self.rc.banner: - banner = '' - # banner is string? Use it directly! - elif isinstance(self.rc.banner,basestring): - banner = self.rc.banner - else: - banner = self.BANNER+self.banner2 - - # 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) + internally created default banner. + """ + + with self.builtin_trap: + if self.c: # Emulate Python's -c option + self.exec_init_cmd() - while 1: - try: - self.interact(banner) - #self.interact_with_readline() + if self.display_banner: + if banner is None: + banner = self.banner - # XXX for testing of a readline-decoupled repl loop, call - # interact_with_readline above + # 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) - break - except KeyboardInterrupt: - # this should not be necessary, but KeyboardInterrupt - # handling seems rather unpredictable... - self.write("\nKeyboardInterrupt in interact()\n") + while 1: + try: + self.interact() + #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 exec_init_cmd(self): """Execute a command given at the command line. @@ -1770,81 +1837,10 @@ class InteractiveShell(object,Magic): This emulates Python's -c option.""" #sys.argv = ['-c'] - self.push(self.prefilter(self.rc.c, False)) - if not self.rc.interact: + self.push_line(self.prefilter(self.c, False)) + if not self.interactive: self.ask_exit() - def embed_mainloop(self,header='',local_ns=None,global_ns=None,stack_depth=0): - """Embeds IPython into a running python program. - - Input: - - - header: An optional header message can be specified. - - - local_ns, global_ns: working namespaces. If given as None, the - IPython-initialized one is updated with __main__.__dict__, so that - program variables become visible but user-specific configuration - remains possible. - - - stack_depth: specifies how many levels in the stack to go to - looking for namespaces (when local_ns and global_ns are None). This - allows an intermediate caller to make sure that this function gets - the namespace from the intended level in the stack. By default (0) - it will get its locals and globals from the immediate caller. - - Warning: it's possible to use this in a program which is being run by - IPython itself (via %run), but some funny things will happen (a few - globals get overwritten). In the future this will be cleaned up, as - there is no fundamental reason why it can't work perfectly.""" - - # Get locals and globals from caller - if local_ns is None or global_ns is None: - call_frame = sys._getframe(stack_depth).f_back - - if local_ns is None: - local_ns = call_frame.f_locals - if global_ns is None: - global_ns = call_frame.f_globals - - # Update namespaces and fire up interpreter - - # The global one is easy, we can just throw it in - self.user_global_ns = global_ns - - # but the user/local one is tricky: ipython needs it to store internal - # data, but we also need the locals. We'll copy locals in the user - # one, but will track what got copied so we can delete them at exit. - # This is so that a later embedded call doesn't see locals from a - # previous call (which most likely existed in a separate scope). - local_varnames = local_ns.keys() - self.user_ns.update(local_ns) - #self.user_ns['local_ns'] = local_ns # dbg - - # Patch for global embedding to make sure that things don't overwrite - # user globals accidentally. Thanks to Richard - # FIXME. Test this a bit more carefully (the if.. is new) - if local_ns is None and global_ns is None: - self.user_global_ns.update(__main__.__dict__) - - # make sure the tab-completer has the correct frame information, so it - # actually completes using the frame's locals/globals - self.set_completer_frame() - - # before activating the interactive mode, we need to make sure that - # all names in the builtin namespace needed by ipython point to - # ourselves, and not to other instances. - self.add_builtins() - - self.interact(header) - - # now, purge out the user namespace from anything we might have added - # from the caller's local namespace - delvar = self.user_ns.pop - for var in local_varnames: - delvar(var,None) - # and clean builtins we may have overridden - self.clean_builtins() - def interact_prompt(self): """ Print the prompt (in read-eval-print loop) @@ -1883,9 +1879,9 @@ class InteractiveShell(object,Magic): self.input_hist_raw.append('%s\n' % line) - self.more = self.push(lineout) + self.more = self.push_line(lineout) if (self.SyntaxTB.last_syntax_error and - self.rc.autoedit_syntax): + self.autoedit_syntax): self.edit_syntax_error() def interact_with_readline(self): @@ -1904,28 +1900,16 @@ class InteractiveShell(object,Magic): line = raw_input_original().decode(self.stdin_encoding) self.interact_handle_input(line) - def interact(self, banner=None): - """Closely emulate the interactive Python console. + """Closely emulate the interactive Python console.""" - The optional banner argument specify the banner to print - before the first interaction; by default it prints a banner - similar to the one printed by the real Python interpreter, - followed by the current class name in parentheses (so as not - to confuse this with the real interpreter -- since it's so - close!). - - """ - + # batch run -> do not interact if self.exit_now: - # batch run -> do not interact return - cprt = 'Type "copyright", "credits" or "license" for more information.' - if banner is None: - self.write("Python %s on %s\n%s\n(%s)\n" % - (sys.version, sys.platform, cprt, - self.__class__.__name__)) - else: + + if self.display_banner: + if banner is None: + banner = self.banner self.write(banner) more = 0 @@ -1954,7 +1938,7 @@ class InteractiveShell(object,Magic): except: self.showtraceback() try: - line = self.raw_input(prompt,more) + line = self.raw_input(prompt, more) if self.exit_now: # quick exit on sys.std[in|out] close break @@ -1990,9 +1974,9 @@ class InteractiveShell(object,Magic): # asynchronously by signal handlers, for example. self.showtraceback() else: - more = self.push(line) + more = self.push_line(line) if (self.SyntaxTB.last_syntax_error and - self.rc.autoedit_syntax): + self.autoedit_syntax): self.edit_syntax_error() # We are off again... @@ -2022,8 +2006,22 @@ class InteractiveShell(object,Magic): """ self.showtraceback((etype,value,tb),tb_offset=0) - def expand_aliases(self,fn,rest): - """ Expand multiple levels of aliases: + def expand_alias(self, line): + """ Expand an alias in the command line + + Returns the provided command line, possibly with the first word + (command) translated according to alias expansion rules. + + [ipython]|16> _ip.expand_aliases("np myfile.txt") + <16> 'q:/opt/np/notepad++.exe myfile.txt' + """ + + pre,fn,rest = self.split_user_input(line) + res = pre + self.expand_aliases(fn, rest) + return res + + def expand_aliases(self, fn, rest): + """Expand multiple levels of aliases: if: @@ -2130,40 +2128,137 @@ class InteractiveShell(object,Magic): else: self.indent_current_nsp = 0 - def runlines(self,lines): + def push(self, variables, interactive=True): + """Inject a group of variables into the IPython user namespace. + + Parameters + ---------- + variables : dict, str or list/tuple of str + The variables to inject into the user's namespace. If a dict, + a simple update is done. If a str, the string is assumed to + have variable names separated by spaces. A list/tuple of str + can also be used to give the variable names. If just the variable + names are give (list/tuple/str) then the variable values looked + up in the callers frame. + interactive : bool + If True (default), the variables will be listed with the ``who`` + magic. + """ + vdict = None + + # We need a dict of name/value pairs to do namespace updates. + if isinstance(variables, dict): + vdict = variables + elif isinstance(variables, (basestring, list, tuple)): + if isinstance(variables, basestring): + vlist = variables.split() + else: + vlist = variables + vdict = {} + cf = sys._getframe(1) + for name in vlist: + try: + vdict[name] = eval(name, cf.f_globals, cf.f_locals) + except: + print ('Could not get variable %s from %s' % + (name,cf.f_code.co_name)) + else: + raise ValueError('variables must be a dict/str/list/tuple') + + # Propagate variables to user namespace + self.user_ns.update(vdict) + + # And configure interactive visibility + config_ns = self.user_config_ns + if interactive: + for name, val in vdict.iteritems(): + config_ns.pop(name, None) + else: + for name,val in vdict.iteritems(): + config_ns[name] = val + + def cleanup_ipy_script(self, script): + """Make a script safe for self.runlines() + + Notes + ----- + This was copied over from the old ipapi and probably can be done + away with once we move to block based interpreter. + + - Removes empty lines Suffixes all indented blocks that end with + - unindented lines with empty lines + """ + + 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) + def is_secondary_block_start(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 + + if level > 0 and newlevel == 0 and \ + not 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. This method is capable of running a string containing multiple source lines, as if they had been entered at the IPython prompt. Since it exposes IPython's processing machinery, the given strings can contain - magic calls (%magic), special shell access (!cmd), etc.""" + magic calls (%magic), special shell access (!cmd), etc. + """ + + if isinstance(lines, (list, tuple)): + lines = '\n'.join(lines) + + if clean: + 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). self.resetbuffer() - lines = lines.split('\n') + lines = lines.splitlines() more = 0 - - for line in lines: - # skip blank lines so we don't mess up the prompt counter, but do - # NOT skip even a blank line if we are in a code block (more is - # true) + + with self.builtin_trap: + for line in lines: + # skip blank lines so we don't mess up the prompt counter, but do + # NOT skip even a blank line if we are in a code block (more is + # true) - if line or more: - # push to raw history, so hist line numbers stay in sync - self.input_hist_raw.append("# " + line + "\n") - more = self.push(self.prefilter(line,more)) - # IPython's runsource returns None if there was an error - # compiling the code. This allows us to stop processing right - # away, so the user gets the error message at the right place. - if more is None: - break - else: - self.input_hist_raw.append("\n") - # final newline in case the input didn't have it, so that the code - # actually does get executed - if more: - self.push('\n') + if line or more: + # push to raw history, so hist line numbers stay in sync + self.input_hist_raw.append("# " + line + "\n") + more = self.push_line(self.prefilter(line,more)) + # IPython's runsource returns None if there was an error + # compiling the code. This allows us to stop processing right + # away, so the user gets the error message at the right place. + if more is None: + break + else: + self.input_hist_raw.append("\n") + # final newline in case the input didn't have it, so that the code + # actually does get executed + if more: + self.push_line('\n') def runsource(self, source, filename='', symbol='single'): """Compile and run some source in the interpreter. @@ -2271,7 +2366,7 @@ class InteractiveShell(object,Magic): self.code_to_run = None return outflag - def push(self, line): + def push_line(self, line): """Push a line to the interpreter. The line should not have a trailing newline; it may have @@ -2419,7 +2514,7 @@ class InteractiveShell(object,Magic): # print '***cont',continue_prompt # dbg # special handlers are only allowed for single line statements - if continue_prompt and not self.rc.multi_line_specials: + if continue_prompt and not self.multi_line_specials: return self.handle_normal(line_info) @@ -2481,7 +2576,7 @@ class InteractiveShell(object,Magic): # print "=>",tgt #dbg if callable(tgt): if '$' in line_info.line: - call_meth = '(_ip, _ip.itpl(%s))' + call_meth = '(_ip, _ip.var_expand(%s))' else: call_meth = '(_ip,%s)' line_out = ("%s_sh.%s" + call_meth) % (line_info.preWhitespace, @@ -2549,7 +2644,7 @@ class InteractiveShell(object,Magic): self.log(line,line,continue_prompt) return line - force_auto = isinstance(obj, ipapi.IPyAutocall) + force_auto = isinstance(obj, IPyAutocall) auto_rewrite = True if pre == self.ESC_QUOTE: @@ -2565,7 +2660,7 @@ class InteractiveShell(object,Magic): # We only apply it to argument-less calls if the autocall # parameter is set to 2. We only need to check that autocall is < # 2, since this function isn't called unless it's at least 1. - if not theRest and (self.rc.autocall < 2) and not force_auto: + if not theRest and (self.autocall < 2) and not force_auto: newcmd = '%s %s' % (iFun,theRest) auto_rewrite = False else: @@ -2623,7 +2718,7 @@ class InteractiveShell(object,Magic): #print 'line:<%r>' % line # dbg self.magic_pinfo(line) else: - page(self.usage,screen_lines=self.rc.screen_length) + page(self.usage,screen_lines=self.usable_screen_length) return '' # Empty string is needed here! except: # Pass any other exceptions through to the normal handler @@ -2632,18 +2727,6 @@ class InteractiveShell(object,Magic): # If the code compiles ok, we should handle it normally return self.handle_normal(line_info) - def getapi(self): - """ Get an IPApi object for this shell instance - - Getting an IPApi object is always preferable to accessing the shell - directly, but this holds true especially for extensions. - - It should always be possible to implement an extension with IPApi - alone. If not, contact maintainer to request an addition. - - """ - return self.api - def handle_emacs(self, line_info): """Handle input lines marked by python-mode.""" @@ -2653,6 +2736,21 @@ class InteractiveShell(object,Magic): # The input cache shouldn't be updated return line_info.line + def var_expand(self,cmd,depth=0): + """Expand python variables in a string. + + The depth argument indicates how many frames above the caller should + be walked to look for the local namespace where to expand variables. + + The global namespace for expansion is always the user's interactive + namespace. + """ + + return str(ItplNS(cmd, + self.user_ns, # globals + # Skip our own frame in searching for locals: + sys._getframe(depth+1).f_locals # locals + )) def mktempfile(self,data=None): """Make a new tempfile and return its filename. @@ -2690,8 +2788,7 @@ class InteractiveShell(object,Magic): """Handle interactive exit. This method calls the ask_exit callback.""" - - if self.rc.confirm_exit: + if self.confirm_exit: if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'): self.ask_exit() else: diff --git a/IPython/core/ipmaker.py b/IPython/core/ipmaker.py deleted file mode 100644 index e277821..0000000 --- a/IPython/core/ipmaker.py +++ /dev/null @@ -1,792 +0,0 @@ -# -*- coding: utf-8 -*- -""" -IPython -- An enhanced Interactive Python - -Requires Python 2.1 or better. - -This file contains the main make_IPython() starter function. -""" - -#***************************************************************************** -# Copyright (C) 2008-2009 The IPython Development Team -# Copyright (C) 2001-2007 Fernando Perez. -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#***************************************************************************** - -try: - credits._Printer__data = """ - Python: %s - - IPython: The IPython Development Team. - See http://ipython.scipy.org for more information.""" \ - % credits._Printer__data - - copyright._Printer__data += """ - - Copyright (c) 2008-2009 The IPython Development Team. - Copyright (c) 2001-2007 Fernando Perez, Janko Hauser, Nathan Gray. - All Rights Reserved.""" -except NameError: - # Can happen if ipython was started with 'python -S', so that site.py is - # not loaded - pass - -#**************************************************************************** -# Required modules - -# From the standard library -import __main__ -import __builtin__ -import os -import sys -from pprint import pprint -import warnings - -# Our own -from IPython.utils import DPyGetOpt -from IPython.core import release -from IPython.utils.ipstruct import Struct -from IPython.core.outputtrap import OutputTrap -from IPython.config.configloader import ConfigLoader -from IPython.core.iplib import InteractiveShell -from IPython.core.usage import cmd_line_usage, interactive_usage -from IPython.utils.genutils import * - - -def force_import(modname,force_reload=False): - if modname in sys.modules and force_reload: - info("reloading: %s" % modname) - reload(sys.modules[modname]) - else: - __import__(modname) - - -def threaded_shell_warning(): - msg = """ - -The IPython threaded shells and their associated command line -arguments (pylab/wthread/gthread/qthread/q4thread) have been -deprecated. See the %gui magic for information on the new interface. -""" - warnings.warn(msg, category=DeprecationWarning, stacklevel=1) - - -#----------------------------------------------------------------------------- -def make_IPython(argv=None,user_ns=None,user_global_ns=None,debug=1, - rc_override=None,shell_class=InteractiveShell, - embedded=False,**kw): - """This is a dump of IPython into a single function. - - Later it will have to be broken up in a sensible manner. - - Arguments: - - - argv: a list similar to sys.argv[1:]. It should NOT contain the desired - script name, b/c DPyGetOpt strips the first argument only for the real - sys.argv. - - - user_ns: a dict to be used as the user's namespace.""" - - #---------------------------------------------------------------------- - # Defaults and initialization - - # For developer debugging, deactivates crash handler and uses pdb. - DEVDEBUG = True - - if argv is None: - argv = sys.argv - - # __IP is the main global that lives throughout and represents the whole - # application. If the user redefines it, all bets are off as to what - # happens. - - # __IP is the name of he global which the caller will have accessible as - # __IP.name. We set its name via the first parameter passed to - # InteractiveShell: - - IP = shell_class('__IP',user_ns=user_ns,user_global_ns=user_global_ns, - embedded=embedded,**kw) - - # Put 'help' in the user namespace - try: - from site import _Helper - IP.user_ns['help'] = _Helper() - except ImportError: - warn('help() not available - check site.py') - - if DEVDEBUG: - # For developer debugging only (global flag) - from IPython.core import ultratb - sys.excepthook = ultratb.VerboseTB(call_pdb=1) - - IP.BANNER_PARTS = ['Python %s\n' - 'Type "copyright", "credits" or "license" ' - 'for more information.\n' - % (sys.version.split('\n')[0],), - "IPython %s -- An enhanced Interactive Python." - % (release.version,), -"""\ -? -> Introduction and overview of IPython's features. -%quickref -> Quick reference. -help -> Python's own help system. -object? -> Details about 'object'. ?object also works, ?? prints more. -""" ] - - IP.usage = interactive_usage - - # Platform-dependent suffix. - if os.name == 'posix': - rc_suffix = '' - else: - rc_suffix = '.ini' - - # default directory for configuration - ipythondir_def = get_ipython_dir() - - sys.path.insert(0, '') # add . to sys.path. Fix from Prabhu Ramachandran - - # we need the directory where IPython itself is installed - import IPython - IPython_dir = os.path.dirname(IPython.__file__) - del IPython - - #------------------------------------------------------------------------- - # Command line handling - - # Valid command line options (uses DPyGetOpt syntax, like Perl's - # GetOpt::Long) - - # Any key not listed here gets deleted even if in the file (like session - # or profile). That's deliberate, to maintain the rc namespace clean. - - # Each set of options appears twice: under _conv only the names are - # listed, indicating which type they must be converted to when reading the - # ipythonrc file. And under DPyGetOpt they are listed with the regular - # DPyGetOpt syntax (=s,=i,:f,etc). - - # Make sure there's a space before each end of line (they get auto-joined!) - cmdline_opts = ('autocall=i autoindent! automagic! banner! cache_size|cs=i ' - 'c=s classic|cl color_info! colors=s confirm_exit! ' - 'debug! deep_reload! editor=s log|l messages! nosep ' - 'object_info_string_level=i pdb! ' - 'pprint! prompt_in1|pi1=s prompt_in2|pi2=s prompt_out|po=s ' - 'pydb! ' - 'pylab_import_all! ' - 'quick screen_length|sl=i prompts_pad_left=i ' - 'logfile|lf=s logplay|lp=s profile|p=s ' - 'readline! readline_merge_completions! ' - 'readline_omit__names! ' - 'rcfile=s separate_in|si=s separate_out|so=s ' - 'separate_out2|so2=s xmode=s wildcards_case_sensitive! ' - 'magic_docstrings system_verbose! ' - 'multi_line_specials! ' - 'term_title! wxversion=s ' - 'autoedit_syntax!') - - # Options that can *only* appear at the cmd line (not in rcfiles). - - cmdline_only = ('help interact|i ipythondir=s Version upgrade ' - 'gthread! qthread! q4thread! wthread! tkthread! pylab! tk! ' - # 'twisted!' # disabled for now. - ) - - # Build the actual name list to be used by DPyGetOpt - opts_names = qw(cmdline_opts) + qw(cmdline_only) - - # Set sensible command line defaults. - # This should have everything from cmdline_opts and cmdline_only - opts_def = Struct(autocall = 1, - autoedit_syntax = 0, - autoindent = 0, - automagic = 1, - autoexec = [], - banner = 1, - c = '', - cache_size = 1000, - classic = 0, - color_info = 0, - colors = 'NoColor', - confirm_exit = 1, - debug = 0, - deep_reload = 0, - editor = '0', - gthread = 0, - help = 0, - interact = 0, - ipythondir = ipythondir_def, - log = 0, - logfile = '', - logplay = '', - messages = 1, - multi_line_specials = 1, - nosep = 0, - object_info_string_level = 0, - pdb = 0, - pprint = 0, - profile = '', - prompt_in1 = 'In [\\#]: ', - prompt_in2 = ' .\\D.: ', - prompt_out = 'Out[\\#]: ', - prompts_pad_left = 1, - pydb = 0, - pylab = 0, - pylab_import_all = 1, - q4thread = 0, - qthread = 0, - quick = 0, - quiet = 0, - rcfile = 'ipythonrc' + rc_suffix, - readline = 1, - readline_merge_completions = 1, - readline_omit__names = 0, - screen_length = 0, - separate_in = '\n', - separate_out = '\n', - separate_out2 = '', - system_header = 'IPython system call: ', - system_verbose = 0, - term_title = 1, - tk = 0, - #twisted= 0, # disabled for now - upgrade = 0, - Version = 0, - wildcards_case_sensitive = 1, - wthread = 0, - wxversion = '0', - xmode = 'Context', - magic_docstrings = 0, # undocumented, for doc generation - ) - - # Things that will *only* appear in rcfiles (not at the command line). - # Make sure there's a space before each end of line (they get auto-joined!) - rcfile_opts = { qwflat: 'include import_mod import_all execfile ', - qw_lol: 'import_some ', - # for things with embedded whitespace: - list_strings:'execute alias readline_parse_and_bind ', - # Regular strings need no conversion: - None:'readline_remove_delims ', - } - # Default values for these - rc_def = Struct(include = [], - import_mod = [], - import_all = [], - import_some = [[]], - execute = [], - execfile = [], - alias = [], - readline_parse_and_bind = [], - readline_remove_delims = '', - ) - - # Build the type conversion dictionary from the above tables: - typeconv = rcfile_opts.copy() - typeconv.update(optstr2types(cmdline_opts)) - - # FIXME: the None key appears in both, put that back together by hand. Ugly! - typeconv[None] += ' ' + rcfile_opts[None] - - # Remove quotes at ends of all strings (used to protect spaces) - typeconv[unquote_ends] = typeconv[None] - del typeconv[None] - - # Build the list we'll use to make all config decisions with defaults: - opts_all = opts_def.copy() - opts_all.update(rc_def) - - # Build conflict resolver for recursive loading of config files: - # - preserve means the outermost file maintains the value, it is not - # overwritten if an included file has the same key. - # - add_flip applies + to the two values, so it better make sense to add - # those types of keys. But it flips them first so that things loaded - # deeper in the inclusion chain have lower precedence. - conflict = {'preserve': ' '.join([ typeconv[int], - typeconv[unquote_ends] ]), - 'add_flip': ' '.join([ typeconv[qwflat], - typeconv[qw_lol], - typeconv[list_strings] ]) - } - - # Now actually process the command line - getopt = DPyGetOpt.DPyGetOpt() - getopt.setIgnoreCase(0) - - getopt.parseConfiguration(opts_names) - - try: - getopt.processArguments(argv) - except DPyGetOpt.ArgumentError, exc: - print cmd_line_usage - warn('\nError in Arguments: "%s"' % exc) - sys.exit(1) - - # convert the options dict to a struct for much lighter syntax later - opts = Struct(getopt.optionValues) - args = getopt.freeValues - - # this is the struct (which has default values at this point) with which - # we make all decisions: - opts_all.update(opts) - - # Options that force an immediate exit - if opts_all.help: - page(cmd_line_usage) - sys.exit() - - if opts_all.Version: - print release.version - sys.exit() - - if opts_all.magic_docstrings: - IP.magic_magic('-latex') - sys.exit() - - # Display the deprecation warnings about threaded shells - if opts_all.pylab == 1: threaded_shell_warning() - if opts_all.wthread == 1: threaded_shell_warning() - if opts_all.qthread == 1: threaded_shell_warning() - if opts_all.q4thread == 1: threaded_shell_warning() - if opts_all.gthread == 1: threaded_shell_warning() - - # add personal ipythondir to sys.path so that users can put things in - # there for customization - sys.path.append(os.path.abspath(opts_all.ipythondir)) - - # Create user config directory if it doesn't exist. This must be done - # *after* getting the cmd line options. - if not os.path.isdir(opts_all.ipythondir): - IP.user_setup(opts_all.ipythondir,rc_suffix,'install') - - # upgrade user config files while preserving a copy of the originals - if opts_all.upgrade: - IP.user_setup(opts_all.ipythondir,rc_suffix,'upgrade') - - # check mutually exclusive options in the *original* command line - mutex_opts(opts,[qw('log logfile'),qw('rcfile profile'), - qw('classic profile'),qw('classic rcfile')]) - - #--------------------------------------------------------------------------- - # Log replay - - # if -logplay, we need to 'become' the other session. That basically means - # replacing the current command line environment with that of the old - # session and moving on. - - # this is needed so that later we know we're in session reload mode, as - # opts_all will get overwritten: - load_logplay = 0 - - if opts_all.logplay: - load_logplay = opts_all.logplay - opts_debug_save = opts_all.debug - try: - logplay = open(opts_all.logplay) - except IOError: - if opts_all.debug: IP.InteractiveTB() - warn('Could not open logplay file '+`opts_all.logplay`) - # restore state as if nothing had happened and move on, but make - # sure that later we don't try to actually load the session file - logplay = None - load_logplay = 0 - del opts_all.logplay - else: - try: - logplay.readline() - logplay.readline(); - # this reloads that session's command line - cmd = logplay.readline()[6:] - exec cmd - # restore the true debug flag given so that the process of - # session loading itself can be monitored. - opts.debug = opts_debug_save - # save the logplay flag so later we don't overwrite the log - opts.logplay = load_logplay - # now we must update our own structure with defaults - opts_all.update(opts) - # now load args - cmd = logplay.readline()[6:] - exec cmd - logplay.close() - except: - logplay.close() - if opts_all.debug: IP.InteractiveTB() - warn("Logplay file lacking full configuration information.\n" - "I'll try to read it, but some things may not work.") - - #------------------------------------------------------------------------- - # set up output traps: catch all output from files, being run, modules - # loaded, etc. Then give it to the user in a clean form at the end. - - msg_out = 'Output messages. ' - msg_err = 'Error messages. ' - msg_sep = '\n' - msg = Struct(config = OutputTrap('Configuration Loader',msg_out, - msg_err,msg_sep,debug, - quiet_out=1), - user_exec = OutputTrap('User File Execution',msg_out, - msg_err,msg_sep,debug), - logplay = OutputTrap('Log Loader',msg_out, - msg_err,msg_sep,debug), - summary = '' - ) - - #------------------------------------------------------------------------- - # Process user ipythonrc-type configuration files - - # turn on output trapping and log to msg.config - # remember that with debug on, trapping is actually disabled - msg.config.trap_all() - - # look for rcfile in current or default directory - try: - opts_all.rcfile = filefind(opts_all.rcfile,opts_all.ipythondir) - except IOError: - if opts_all.debug: IP.InteractiveTB() - warn('Configuration file %s not found. Ignoring request.' - % (opts_all.rcfile) ) - - print opts_all.rcfile, opts_all.ipythondir - - # 'profiles' are a shorthand notation for config filenames - profile_handled_by_legacy = False - if opts_all.profile: - - try: - opts_all.rcfile = filefind('ipythonrc-' + opts_all.profile - + rc_suffix, - opts_all.ipythondir) - profile_handled_by_legacy = True - except IOError: - if opts_all.debug: IP.InteractiveTB() - opts.profile = '' # remove profile from options if invalid - # We won't warn anymore, primary method is ipy_profile_PROFNAME - # which does trigger a warning. - - # load the config file - rcfiledata = None - if opts_all.quick: - print 'Launching IPython in quick mode. No config file read.' - elif opts_all.rcfile: - try: - cfg_loader = ConfigLoader(conflict) - rcfiledata = cfg_loader.load(opts_all.rcfile,typeconv, - 'include',opts_all.ipythondir, - purge = 1, - unique = conflict['preserve']) - except: - IP.InteractiveTB() - warn('Problems loading configuration file '+ - `opts_all.rcfile`+ - '\nStarting with default -bare bones- configuration.') - else: - warn('No valid configuration file found in either currrent directory\n'+ - 'or in the IPython config. directory: '+`opts_all.ipythondir`+ - '\nProceeding with internal defaults.') - - #------------------------------------------------------------------------ - # Set exception handlers in mode requested by user. - otrap = OutputTrap(trap_out=1) # trap messages from magic_xmode - IP.magic_xmode(opts_all.xmode) - otrap.release_out() - - #------------------------------------------------------------------------ - # Execute user config - - # Create a valid config structure with the right precedence order: - # defaults < rcfile < command line. This needs to be in the instance, so - # that method calls below that rely on it find it. - IP.rc = rc_def.copy() - - # Work with a local alias inside this routine to avoid unnecessary - # attribute lookups. - IP_rc = IP.rc - - IP_rc.update(opts_def) - if rcfiledata: - IP_rc.update(rcfiledata) - IP_rc.update(opts) - if rc_override is not None: - IP_rc.update(rc_override) - - # Store the original cmd line for reference: - IP_rc.opts = opts - IP_rc.args = args - - # create a *runtime* Struct like rc for holding parameters which may be - # created and/or modified by runtime user extensions. - IP.runtime_rc = Struct() - - # from this point on, all config should be handled through IP_rc, - # opts* shouldn't be used anymore. - - - # update IP_rc with some special things that need manual - # tweaks. Basically options which affect other options. I guess this - # should just be written so that options are fully orthogonal and we - # wouldn't worry about this stuff! - - if IP_rc.classic: - IP_rc.quick = 1 - IP_rc.cache_size = 0 - IP_rc.pprint = 0 - IP_rc.prompt_in1 = '>>> ' - IP_rc.prompt_in2 = '... ' - IP_rc.prompt_out = '' - IP_rc.separate_in = IP_rc.separate_out = IP_rc.separate_out2 = '0' - IP_rc.colors = 'NoColor' - IP_rc.xmode = 'Plain' - - IP.pre_config_initialization() - # configure readline - - # update exception handlers with rc file status - otrap.trap_out() # I don't want these messages ever. - IP.magic_xmode(IP_rc.xmode) - otrap.release_out() - - # activate logging if requested and not reloading a log - if IP_rc.logplay: - IP.magic_logstart(IP_rc.logplay + ' append') - elif IP_rc.logfile: - IP.magic_logstart(IP_rc.logfile) - elif IP_rc.log: - IP.magic_logstart() - - # find user editor so that it we don't have to look it up constantly - if IP_rc.editor.strip()=='0': - 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! - IP_rc.editor = ed - - # Keep track of whether this is an embedded instance or not (useful for - # post-mortems). - IP_rc.embedded = IP.embedded - - # Recursive reload - try: - from IPython.lib import deepreload - if IP_rc.deep_reload: - __builtin__.reload = deepreload.reload - else: - __builtin__.dreload = deepreload.reload - del deepreload - except ImportError: - pass - - # Save the current state of our namespace so that the interactive shell - # can later know which variables have been created by us from config files - # and loading. This way, loading a file (in any way) is treated just like - # defining things on the command line, and %who works as expected. - - # DON'T do anything that affects the namespace beyond this point! - IP.internal_ns.update(__main__.__dict__) - - #IP.internal_ns.update(locals()) # so our stuff doesn't show up in %who - - # Now run through the different sections of the users's config - if IP_rc.debug: - print 'Trying to execute the following configuration structure:' - print '(Things listed first are deeper in the inclusion tree and get' - print 'loaded first).\n' - pprint(IP_rc.__dict__) - - for mod in IP_rc.import_mod: - try: - exec 'import '+mod in IP.user_ns - except : - IP.InteractiveTB() - import_fail_info(mod) - - for mod_fn in IP_rc.import_some: - if not mod_fn == []: - mod,fn = mod_fn[0],','.join(mod_fn[1:]) - try: - exec 'from '+mod+' import '+fn in IP.user_ns - except : - IP.InteractiveTB() - import_fail_info(mod,fn) - - for mod in IP_rc.import_all: - try: - exec 'from '+mod+' import *' in IP.user_ns - except : - IP.InteractiveTB() - import_fail_info(mod) - - for code in IP_rc.execute: - try: - exec code in IP.user_ns - except: - IP.InteractiveTB() - warn('Failure executing code: ' + `code`) - - # Execute the files the user wants in ipythonrc - for file in IP_rc.execfile: - try: - file = filefind(file,sys.path+[IPython_dir]) - except IOError: - warn(itpl('File $file not found. Skipping it.')) - else: - IP.safe_execfile(os.path.expanduser(file),IP.user_ns) - - # finally, try importing ipy_*_conf for final configuration - try: - import ipy_system_conf - except ImportError: - if opts_all.debug: IP.InteractiveTB() - warn("Could not import 'ipy_system_conf'") - except: - IP.InteractiveTB() - import_fail_info('ipy_system_conf') - - # only import prof module if ipythonrc-PROF was not found - if opts_all.profile and not profile_handled_by_legacy: - profmodname = 'ipy_profile_' + opts_all.profile - try: - force_import(profmodname) - except: - IP.InteractiveTB() - print "Error importing",profmodname,\ - "- perhaps you should run %upgrade?" - import_fail_info(profmodname) - else: - opts.profile = opts_all.profile - else: - force_import('ipy_profile_none') - # XXX - this is wrong: ipy_user_conf should not be loaded unconditionally, - # since the user could have specified a config file path by hand. - try: - force_import('ipy_user_conf') - except: - conf = opts_all.ipythondir + "/ipy_user_conf.py" - IP.InteractiveTB() - if not os.path.isfile(conf): - warn(conf + ' does not exist, please run %upgrade!') - - import_fail_info("ipy_user_conf") - - # Define the history file for saving commands in between sessions - try: - histfname = 'history-%s' % opts.profile - except AttributeError: - histfname = 'history' - IP.histfile = os.path.join(opts_all.ipythondir,histfname) - - # finally, push the argv to options again to ensure highest priority - IP_rc.update(opts) - - # release stdout and stderr and save config log into a global summary - msg.config.release_all() - if IP_rc.messages: - msg.summary += msg.config.summary_all() - - #------------------------------------------------------------------------ - # Setup interactive session - - # Now we should be fully configured. We can then execute files or load - # things only needed for interactive use. Then we'll open the shell. - - # Take a snapshot of the user namespace before opening the shell. That way - # we'll be able to identify which things were interactively defined and - # which were defined through config files. - IP.user_config_ns.update(IP.user_ns) - - # Force reading a file as if it were a session log. Slower but safer. - if load_logplay: - print 'Replaying log...' - try: - if IP_rc.debug: - logplay_quiet = 0 - else: - logplay_quiet = 1 - - msg.logplay.trap_all() - IP.safe_execfile(load_logplay,IP.user_ns, - islog = 1, quiet = logplay_quiet) - msg.logplay.release_all() - if IP_rc.messages: - msg.summary += msg.logplay.summary_all() - except: - warn('Problems replaying logfile %s.' % load_logplay) - IP.InteractiveTB() - - # Load remaining files in command line - msg.user_exec.trap_all() - - # Do NOT execute files named in the command line as scripts to be loaded - # by embedded instances. Doing so has the potential for an infinite - # recursion if there are exceptions thrown in the process. - - # XXX FIXME: the execution of user files should be moved out to after - # ipython is fully initialized, just as if they were run via %run at the - # ipython prompt. This would also give them the benefit of ipython's - # nice tracebacks. - - if (not embedded and IP_rc.args and - not IP_rc.args[0].lower().endswith('.ipy')): - name_save = IP.user_ns['__name__'] - IP.user_ns['__name__'] = '__main__' - # Set our own excepthook in case the user code tries to call it - # directly. This prevents triggering the IPython crash handler. - old_excepthook,sys.excepthook = sys.excepthook, IP.excepthook - - save_argv = sys.argv[1:] # save it for later restoring - - sys.argv = args - - try: - IP.safe_execfile(args[0], IP.user_ns) - finally: - # Reset our crash handler in place - sys.excepthook = old_excepthook - sys.argv[:] = save_argv - IP.user_ns['__name__'] = name_save - - msg.user_exec.release_all() - - if IP_rc.messages: - msg.summary += msg.user_exec.summary_all() - - # since we can't specify a null string on the cmd line, 0 is the equivalent: - if IP_rc.nosep: - IP_rc.separate_in = IP_rc.separate_out = IP_rc.separate_out2 = '0' - if IP_rc.separate_in == '0': IP_rc.separate_in = '' - if IP_rc.separate_out == '0': IP_rc.separate_out = '' - if IP_rc.separate_out2 == '0': IP_rc.separate_out2 = '' - IP_rc.separate_in = IP_rc.separate_in.replace('\\n','\n') - IP_rc.separate_out = IP_rc.separate_out.replace('\\n','\n') - IP_rc.separate_out2 = IP_rc.separate_out2.replace('\\n','\n') - - # Determine how many lines at the bottom of the screen are needed for - # showing prompts, so we can know wheter long strings are to be printed or - # paged: - num_lines_bot = IP_rc.separate_in.count('\n')+1 - IP_rc.screen_length = IP_rc.screen_length - num_lines_bot - - # configure startup banner - if IP_rc.c: # regular python doesn't print the banner with -c - IP_rc.banner = 0 - if IP_rc.banner: - BANN_P = IP.BANNER_PARTS - else: - BANN_P = [] - - if IP_rc.profile: BANN_P.append('IPython profile: %s\n' % IP_rc.profile) - - # add message log (possibly empty) - if msg.summary: BANN_P.append(msg.summary) - # Final banner is a string - IP.BANNER = '\n'.join(BANN_P) - - # Finalize the IPython instance. This assumes the rc structure is fully - # in place. - IP.post_config_initialization() - - return IP -#************************ end of file ************************** diff --git a/IPython/core/macro.py b/IPython/core/macro.py index 6e89276..7ca39ed 100644 --- a/IPython/core/macro.py +++ b/IPython/core/macro.py @@ -7,10 +7,8 @@ # the file COPYING, distributed as part of this software. #***************************************************************************** -from IPython.core import ipapi - from IPython.utils.genutils import Term -from IPython.core.ipapi import IPyAutocall +from IPython.core.autocall import IPyAutocall class Macro(IPyAutocall): """Simple class to store the value of macros as strings. diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 539656c..b7d1398 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -45,16 +45,17 @@ except ImportError: import IPython from IPython.utils import wildcard from IPython.core import debugger, oinspect +from IPython.core.error import TryNext from IPython.core.fakemodule import FakeModule from IPython.external.Itpl import Itpl, itpl, printpl,itplns from IPython.utils.PyColorize import Parser from IPython.utils.ipstruct import Struct from IPython.core.macro import Macro from IPython.utils.genutils import * +from IPython.core.page import page from IPython.utils import platutils import IPython.utils.generics -from IPython.core import ipapi -from IPython.core.ipapi import UsageError +from IPython.core.error import UsageError from IPython.testing import decorators as testdec #*************************************************************************** @@ -378,7 +379,7 @@ python-profiler package from non-free.""") mesc = self.shell.ESC_MAGIC print 'Available magic functions:\n'+mesc+\ (' '+mesc).join(self.lsmagic()) - print '\n' + Magic.auto_status[self.shell.rc.automagic] + print '\n' + Magic.auto_status[self.shell.automagic] return None def magic_magic(self, parameter_s = ''): @@ -470,8 +471,8 @@ ipythonrc file, placing a line like: will define %pf as a new name for %profile. -You can also call magics in code using the ipmagic() function, which IPython -automatically adds to the builtin namespace. Type 'ipmagic?' for details. +You can also call magics in code using the magic() function, which IPython +automatically adds to the builtin namespace. Type 'magic?' for details. For a list of the available magic functions, use %lsmagic. For a description of any of them, type %magic_name?, e.g. '%cd?'. @@ -483,9 +484,9 @@ Currently the magic system has the following functions:\n""" "\n\n%s%s\n\n%s" % (outmsg, magic_docs,mesc,mesc, (' '+mesc).join(self.lsmagic()), - Magic.auto_status[self.shell.rc.automagic] ) ) + Magic.auto_status[self.shell.automagic] ) ) - page(outmsg,screen_lines=self.shell.rc.screen_length) + page(outmsg,screen_lines=self.shell.usable_screen_length) def magic_autoindent(self, parameter_s = ''): @@ -512,15 +513,14 @@ Currently the magic system has the following functions:\n""" delete the variable (del var), the previously shadowed magic function becomes visible to automagic again.""" - rc = self.shell.rc arg = parameter_s.lower() if parameter_s in ('on','1','true'): - rc.automagic = True + self.shell.automagic = True elif parameter_s in ('off','0','false'): - rc.automagic = False + self.shell.automagic = False else: - rc.automagic = not rc.automagic - print '\n' + Magic.auto_status[rc.automagic] + self.shell.automagic = not self.shell.automagic + print '\n' + Magic.auto_status[self.shell.automagic] @testdec.skip_doctest def magic_autocall(self, parameter_s = ''): @@ -566,8 +566,6 @@ Currently the magic system has the following functions:\n""" # all-random (note for auto-testing) """ - rc = self.shell.rc - if parameter_s: arg = int(parameter_s) else: @@ -578,18 +576,18 @@ Currently the magic system has the following functions:\n""" return if arg in (0,1,2): - rc.autocall = arg + self.shell.autocall = arg else: # toggle - if rc.autocall: - self._magic_state.autocall_save = rc.autocall - rc.autocall = 0 + if self.shell.autocall: + self._magic_state.autocall_save = self.shell.autocall + self.shell.autocall = 0 else: try: - rc.autocall = self._magic_state.autocall_save + self.shell.autocall = self._magic_state.autocall_save except AttributeError: - rc.autocall = self._magic_state.autocall_save = 1 + self.shell.autocall = self._magic_state.autocall_save = 1 - print "Automatic calling is:",['OFF','Smart','Full'][rc.autocall] + print "Automatic calling is:",['OFF','Smart','Full'][self.shell.autocall] def magic_system_verbose(self, parameter_s = ''): """Set verbose printing of system calls. @@ -600,10 +598,13 @@ Currently the magic system has the following functions:\n""" val = bool(eval(parameter_s)) else: val = None - - self.shell.rc_set_toggle('system_verbose',val) + + if self.shell.system_verbose: + self.shell.system_verbose = False + else: + self.shell.system_verbose = True print "System verbose printing is:",\ - ['OFF','ON'][self.shell.rc.system_verbose] + ['OFF','ON'][self.shell.system_verbose] def magic_page(self, parameter_s=''): @@ -633,8 +634,8 @@ Currently the magic system has the following functions:\n""" def magic_profile(self, parameter_s=''): """Print your currently active IPyhton profile.""" - if self.shell.rc.profile: - printpl('Current IPython profile: $self.shell.rc.profile.') + if self.shell.profile: + printpl('Current IPython profile: $self.shell.profile.') else: print 'No profile active.' @@ -720,7 +721,7 @@ Currently the magic system has the following functions:\n""" try: IPython.utils.generics.inspect_object(info.obj) return - except ipapi.TryNext: + except TryNext: pass # Get the docstring of the class property if it exists. path = oname.split('.') @@ -848,7 +849,7 @@ Currently the magic system has the following functions:\n""" elif opts.has_key('c'): ignore_case = False else: - ignore_case = not shell.rc.wildcards_case_sensitive + ignore_case = not shell.wildcards_case_sensitive # Build list of namespaces to search from user options def_search.extend(opt('s',[])) @@ -1132,7 +1133,6 @@ Currently the magic system has the following functions:\n""" log_raw_input = 'r' in opts timestamp = 't' in opts - rc = self.shell.rc logger = self.shell.logger # if no args are given, the defaults set in the logger constructor by @@ -1149,11 +1149,14 @@ Currently the magic system has the following functions:\n""" # put logfname into rc struct as if it had been called on the command # line, so it ends up saved in the log header Save it in case we need # to restore it... - old_logfile = rc.opts.get('logfile','') + old_logfile = self.shell.logfile if logfname: logfname = os.path.expanduser(logfname) - rc.opts.logfile = logfname - loghead = self.shell.loghead_tpl % (rc.opts,rc.args) + self.shell.logfile = logfname + # TODO: we need to re-think how logs with args/opts are replayed + # and tracked. + # loghead = self.shell.loghead_tpl % (rc.opts,rc.args) + loghead = self.shell.loghead_tpl % ('','') try: started = logger.logstart(logfname,loghead,logmode, log_output,timestamp,log_raw_input) @@ -1421,7 +1424,7 @@ Currently the magic system has the following functions:\n""" output = stdout_trap.getvalue() output = output.rstrip() - page(output,screen_lines=self.shell.rc.screen_length) + page(output,screen_lines=self.shell.usable_screen_length) print sys_exit, dump_file = opts.D[0] @@ -1569,7 +1572,7 @@ Currently the magic system has the following functions:\n""" return if filename.lower().endswith('.ipy'): - self.api.runlines(open(filename).read()) + self.runlines(open(filename).read(), clean=True) return # Control the response to exit() calls made by the script being run @@ -1622,7 +1625,7 @@ Currently the magic system has the following functions:\n""" stats = self.magic_prun('',0,opts,arg_lst,prog_ns) else: if opts.has_key('d'): - deb = debugger.Pdb(self.shell.rc.colors) + deb = debugger.Pdb(self.shell.colors) # reset Breakpoint state, which is moronically kept # in a class bdb.Breakpoint.next = 1 @@ -2061,7 +2064,7 @@ Currently the magic system has the following functions:\n""" #print 'rng',ranges # dbg lines = self.extract_input_slices(ranges,opts.has_key('r')) macro = Macro(lines) - self.shell.user_ns.update({name:macro}) + self.shell.define_macro(name, macro) print 'Macro `%s` created. To execute, type its name (without quotes).' % name print 'Macro contents:' print macro, @@ -2391,7 +2394,7 @@ Currently the magic system has the following functions:\n""" sys.stdout.flush() try: self.shell.hooks.editor(filename,lineno) - except ipapi.TryNext: + except TryNext: warn('Could not open editor') return @@ -2492,7 +2495,7 @@ Defaulting color scheme to 'NoColor'""" except: color_switch_err('prompt') else: - shell.rc.colors = \ + shell.colors = \ shell.outputcache.color_table.active_scheme_name # Set exception colors try: @@ -2509,7 +2512,7 @@ Defaulting color scheme to 'NoColor'""" color_switch_err('system exception handler') # Set info (for 'object?') colors - if shell.rc.color_info: + if shell.color_info: try: shell.inspector.set_active_scheme(new_scheme) except: @@ -2528,17 +2531,17 @@ Defaulting color scheme to 'NoColor'""" than more) in your system, using colored object information displays will not work properly. Test it and see.""" - self.shell.rc.color_info = 1 - self.shell.rc.color_info - self.magic_colors(self.shell.rc.colors) + self.shell.color_info = not self.shell.color_info + self.magic_colors(self.shell.colors) print 'Object introspection functions have now coloring:', - print ['OFF','ON'][self.shell.rc.color_info] + print ['OFF','ON'][int(self.shell.color_info)] def magic_Pprint(self, parameter_s=''): """Toggle pretty printing on/off.""" - self.shell.rc.pprint = 1 - self.shell.rc.pprint + self.shell.pprint = 1 - self.shell.pprint print 'Pretty printing has been turned', \ - ['OFF','ON'][self.shell.rc.pprint] + ['OFF','ON'][self.shell.pprint] def magic_exit(self, parameter_s=''): """Exit IPython, confirming if configured to do so. @@ -2683,12 +2686,9 @@ Defaulting color scheme to 'NoColor'""" This function also resets the root module cache of module completer, used on slow filesystems. """ - - - ip = self.api # for the benefit of module completer in ipy_completers.py - del ip.db['rootmodules'] + del self.db['rootmodules'] path = [os.path.abspath(os.path.expanduser(p)) for p in os.environ.get('PATH','').split(os.pathsep)] @@ -2743,7 +2743,7 @@ Defaulting color scheme to 'NoColor'""" # no, we don't want them. if %rehashx clobbers them, good, # we'll probably get better versions # self.shell.init_auto_alias() - db = ip.db + db = self.db db['syscmdlist'] = syscmdlist finally: os.chdir(savedir) @@ -2853,9 +2853,8 @@ Defaulting color scheme to 'NoColor'""" if ps: try: os.chdir(os.path.expanduser(ps)) - if self.shell.rc.term_title: - #print 'set term title:',self.shell.rc.term_title # dbg - platutils.set_term_title('IPy ' + abbrev_cwd()) + if self.shell.term_title: + platutils.set_term_title('IPython: ' + abbrev_cwd()) except OSError: print sys.exc_info()[1] else: @@ -2867,8 +2866,8 @@ Defaulting color scheme to 'NoColor'""" else: os.chdir(self.shell.home_dir) - if self.shell.rc.term_title: - platutils.set_term_title("IPy ~") + if self.shell.term_title: + platutils.set_term_title('IPython: ' + '~') cwd = os.getcwd() dhist = self.shell.user_ns['_dh'] @@ -3171,7 +3170,7 @@ Defaulting color scheme to 'NoColor'""" esc_magic = self.shell.ESC_MAGIC # Identify magic commands even if automagic is on (which means # the in-memory version is different from that typed by the user). - if self.shell.rc.automagic: + if self.shell.automagic: start_magic = esc_magic+start else: start_magic = start @@ -3265,7 +3264,7 @@ Defaulting color scheme to 'NoColor'""" return page(self.shell.pycolorize(cont), - screen_lines=self.shell.rc.screen_length) + screen_lines=self.shell.usable_screen_length) def _rerun_pasted(self): """ Rerun a previously pasted command. @@ -3438,7 +3437,7 @@ Defaulting color scheme to 'NoColor'""" ipinstallation = path(IPython.__file__).dirname() upgrade_script = '%s "%s"' % (sys.executable,ipinstallation / 'utils' / 'upgradedir.py') src_config = ipinstallation / 'config' / 'userconfig' - userdir = path(ip.options.ipythondir) + userdir = path(ip.config.IPYTHONDIR) cmd = '%s "%s" "%s"' % (upgrade_script, src_config, userdir) print ">",cmd shell(cmd) @@ -3478,7 +3477,6 @@ Defaulting color scheme to 'NoColor'""" # Shorthands shell = self.shell oc = shell.outputcache - rc = shell.rc meta = shell.meta # dstore is a data store kept in the instance metadata bag to track any # changes we make, so we can undo them later. @@ -3487,12 +3485,12 @@ Defaulting color scheme to 'NoColor'""" # save a few values we'll need to recover later mode = save_dstore('mode',False) - save_dstore('rc_pprint',rc.pprint) + save_dstore('rc_pprint',shell.pprint) save_dstore('xmode',shell.InteractiveTB.mode) - save_dstore('rc_separate_out',rc.separate_out) - save_dstore('rc_separate_out2',rc.separate_out2) - save_dstore('rc_prompts_pad_left',rc.prompts_pad_left) - save_dstore('rc_separate_in',rc.separate_in) + save_dstore('rc_separate_out',shell.separate_out) + save_dstore('rc_separate_out2',shell.separate_out2) + save_dstore('rc_prompts_pad_left',shell.prompts_pad_left) + save_dstore('rc_separate_in',shell.separate_in) if mode == False: # turn on @@ -3510,7 +3508,7 @@ Defaulting color scheme to 'NoColor'""" oc.prompt1.pad_left = oc.prompt2.pad_left = \ oc.prompt_out.pad_left = False - rc.pprint = False + shell.pprint = False shell.magic_xmode('Plain') @@ -3518,9 +3516,9 @@ Defaulting color scheme to 'NoColor'""" # turn off ipaste.deactivate_prefilter() - oc.prompt1.p_template = rc.prompt_in1 - oc.prompt2.p_template = rc.prompt_in2 - oc.prompt_out.p_template = rc.prompt_out + oc.prompt1.p_template = shell.prompt_in1 + oc.prompt2.p_template = shell.prompt_in2 + oc.prompt_out.p_template = shell.prompt_out oc.input_sep = oc.prompt1.sep = dstore.rc_separate_in diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index b5661b3..a0cfb54 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -28,7 +28,8 @@ import types # IPython's own from IPython.utils import PyColorize -from IPython.utils.genutils import page,indent,Term +from IPython.utils.genutils import indent, Term +from IPython.core.page import page from IPython.external.Itpl import itpl from IPython.utils.wildcard import list_namespace from IPython.utils.coloransi import * diff --git a/IPython/core/oldusersetup.py b/IPython/core/oldusersetup.py new file mode 100644 index 0000000..b32ac45 --- /dev/null +++ b/IPython/core/oldusersetup.py @@ -0,0 +1,219 @@ +# -*- coding: utf-8 -*- +""" +Main IPython Component +""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2001 Janko Hauser +# Copyright (C) 2001-2007 Fernando Perez. +# Copyright (C) 2008-2009 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 glob +import os +import shutil +import sys + +from IPython.utils.genutils import * + +def user_setup(ipythondir,rc_suffix,mode='install',interactive=True): + """Install or upgrade the user configuration directory. + + Can be called when running for the first time or to upgrade the user's + .ipython/ directory. + + Parameters + ---------- + ipythondir : path + The directory to be used for installation/upgrade. In 'install' mode, + if this path already exists, the function exits immediately. + + rc_suffix : str + Extension for the config files. On *nix platforms it is typically the + empty string, while Windows normally uses '.ini'. + + mode : str, optional + Valid modes are 'install' and 'upgrade'. + + interactive : bool, optional + If False, do not wait for user input on any errors. Normally after + printing its status information, this function waits for the user to + hit Return before proceeding. This is because the default use case is + when first installing the IPython configuration, so we want the user to + acknowledge the initial message, which contains some useful + information. + """ + + # For automatic use, deactivate all i/o + if interactive: + def wait(): + try: + raw_input("Please press to start IPython.") + except EOFError: + print >> Term.cout + print '*'*70 + + def printf(s): + print s + else: + wait = lambda : None + printf = lambda s : None + + # Install mode should be re-entrant: if the install dir already exists, + # bail out cleanly. + # XXX. This is too hasty to return. We need to check to make sure that + # all the expected config files and directories are actually there. We + # currently have a failure mode if someone deletes a needed config file + # but still has the ipythondir. + if mode == 'install' and os.path.isdir(ipythondir): + return + + cwd = os.getcwd() # remember where we started + glb = glob.glob + + printf('*'*70) + if mode == 'install': + printf( +"""Welcome to IPython. I will try to create a personal configuration directory +where you can customize many aspects of IPython's functionality in:\n""") + else: + printf('I am going to upgrade your configuration in:') + + printf(ipythondir) + + rcdirend = os.path.join('IPython','config','userconfig') + cfg = lambda d: os.path.join(d,rcdirend) + try: + rcdir = filter(os.path.isdir,map(cfg,sys.path))[0] + printf("Initializing from configuration: %s" % rcdir) + except IndexError: + warning = """ +Installation error. IPython's directory was not found. + +Check the following: + +The ipython/IPython directory should be in a directory belonging to your +PYTHONPATH environment variable (that is, it should be in a directory +belonging to sys.path). You can copy it explicitly there or just link to it. + +IPython will create a minimal default configuration for you. + +""" + warn(warning) + wait() + + if sys.platform =='win32': + inif = 'ipythonrc.ini' + else: + inif = 'ipythonrc' + minimal_setup = {'ipy_user_conf.py' : 'import ipy_defaults', + inif : '# intentionally left blank' } + os.makedirs(ipythondir, mode = 0777) + for f, cont in minimal_setup.items(): + # In 2.5, this can be more cleanly done using 'with' + fobj = file(ipythondir + '/' + f,'w') + fobj.write(cont) + fobj.close() + + return + + if mode == 'install': + try: + shutil.copytree(rcdir,ipythondir) + os.chdir(ipythondir) + rc_files = glb("ipythonrc*") + for rc_file in rc_files: + os.rename(rc_file,rc_file+rc_suffix) + except: + warning = """ + +There was a problem with the installation: +%s +Try to correct it or contact the developers if you think it's a bug. +IPython will proceed with builtin defaults.""" % sys.exc_info()[1] + warn(warning) + wait() + return + + elif mode == 'upgrade': + try: + os.chdir(ipythondir) + except: + printf(""" +Can not upgrade: changing to directory %s failed. Details: +%s +""" % (ipythondir,sys.exc_info()[1]) ) + wait() + return + else: + sources = glb(os.path.join(rcdir,'[A-Za-z]*')) + for new_full_path in sources: + new_filename = os.path.basename(new_full_path) + if new_filename.startswith('ipythonrc'): + new_filename = new_filename + rc_suffix + # The config directory should only contain files, skip any + # directories which may be there (like CVS) + if os.path.isdir(new_full_path): + continue + if os.path.exists(new_filename): + old_file = new_filename+'.old' + if os.path.exists(old_file): + os.remove(old_file) + os.rename(new_filename,old_file) + shutil.copy(new_full_path,new_filename) + else: + raise ValueError('unrecognized mode for install: %r' % mode) + + # Fix line-endings to those native to each platform in the config + # directory. + try: + os.chdir(ipythondir) + except: + printf(""" +Problem: changing to directory %s failed. +Details: +%s + +Some configuration files may have incorrect line endings. This should not +cause any problems during execution. """ % (ipythondir,sys.exc_info()[1]) ) + wait() + else: + for fname in glb('ipythonrc*'): + try: + native_line_ends(fname,backup=0) + except IOError: + pass + + if mode == 'install': + printf(""" +Successful installation! + +Please read the sections 'Initial Configuration' and 'Quick Tips' in the +IPython manual (there are both HTML and PDF versions supplied with the +distribution) to make sure that your system environment is properly configured +to take advantage of IPython's features. + +Important note: the configuration system has changed! The old system is +still in place, but its setting may be partly overridden by the settings in +"~/.ipython/ipy_user_conf.py" config file. Please take a look at the file +if some of the new settings bother you. + +""") + else: + printf(""" +Successful upgrade! + +All files in your directory: +%(ipythondir)s +which would have been overwritten by the upgrade were backed up with a .old +extension. If you had made particular customizations in those files you may +want to merge them back into the new files.""" % locals() ) + wait() + os.chdir(cwd) \ No newline at end of file diff --git a/IPython/core/page.py b/IPython/core/page.py new file mode 100644 index 0000000..29f5bf2 --- /dev/null +++ b/IPython/core/page.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Paging capabilities for IPython.core + +Authors: + +* Brian Granger +* Fernando Perez + +Notes +----- + +For now this uses ipapi, so it can't be in IPython.utils. If we can get +rid of that dependency, we could move it there. +----- +""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2008-2009 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 os +import re +import sys + +from IPython.core import ipapi +from IPython.core.error import TryNext +from IPython.utils.genutils import ( + chop, Term +) + +if os.name == "nt": + from IPython.utils.winconsole import get_console_size + + +#----------------------------------------------------------------------------- +# Classes and functions +#----------------------------------------------------------------------------- + +esc_re = re.compile(r"(\x1b[^m]+m)") + +def page_dumb(strng,start=0,screen_lines=25): + """Very dumb 'pager' in Python, for when nothing else works. + + Only moves forward, same interface as page(), except for pager_cmd and + mode.""" + + out_ln = strng.splitlines()[start:] + screens = chop(out_ln,screen_lines-1) + if len(screens) == 1: + print >>Term.cout, os.linesep.join(screens[0]) + else: + last_escape = "" + for scr in screens[0:-1]: + hunk = os.linesep.join(scr) + print >>Term.cout, last_escape + hunk + if not page_more(): + return + esc_list = esc_re.findall(hunk) + if len(esc_list) > 0: + last_escape = esc_list[-1] + print >>Term.cout, last_escape + os.linesep.join(screens[-1]) + +#---------------------------------------------------------------------------- +def page(strng,start=0,screen_lines=0,pager_cmd = None): + """Print a string, piping through a pager after a certain length. + + The screen_lines parameter specifies the number of *usable* lines of your + terminal screen (total lines minus lines you need to reserve to show other + information). + + If you set screen_lines to a number <=0, page() will try to auto-determine + your screen size and will only use up to (screen_size+screen_lines) for + printing, paging after that. That is, if you want auto-detection but need + to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for + auto-detection without any lines reserved simply use screen_lines = 0. + + If a string won't fit in the allowed lines, it is sent through the + specified pager command. If none given, look for PAGER in the environment, + and ultimately default to less. + + If no system pager works, the string is sent through a 'dumb pager' + written in python, very simplistic. + """ + + # Some routines may auto-compute start offsets incorrectly and pass a + # negative value. Offset to 0 for robustness. + start = max(0,start) + + # first, try the hook + ip = ipapi.get() + if ip: + try: + ip.hooks.show_in_pager(strng) + return + except TryNext: + pass + + # Ugly kludge, but calling curses.initscr() flat out crashes in emacs + TERM = os.environ.get('TERM','dumb') + if TERM in ['dumb','emacs'] and os.name != 'nt': + print strng + return + # chop off the topmost part of the string we don't want to see + str_lines = strng.split(os.linesep)[start:] + str_toprint = os.linesep.join(str_lines) + num_newlines = len(str_lines) + len_str = len(str_toprint) + + # Dumb heuristics to guesstimate number of on-screen lines the string + # takes. Very basic, but good enough for docstrings in reasonable + # terminals. If someone later feels like refining it, it's not hard. + numlines = max(num_newlines,int(len_str/80)+1) + + if os.name == "nt": + screen_lines_def = get_console_size(defaulty=25)[1] + else: + screen_lines_def = 25 # default value if we can't auto-determine + + # auto-determine screen size + if screen_lines <= 0: + if TERM=='xterm': + use_curses = USE_CURSES + else: + # curses causes problems on many terminals other than xterm. + use_curses = False + if use_curses: + # There is a bug in curses, where *sometimes* it fails to properly + # initialize, and then after the endwin() call is made, the + # terminal is left in an unusable state. Rather than trying to + # check everytime for this (by requesting and comparing termios + # flags each time), we just save the initial terminal state and + # unconditionally reset it every time. It's cheaper than making + # the checks. + term_flags = termios.tcgetattr(sys.stdout) + scr = curses.initscr() + screen_lines_real,screen_cols = scr.getmaxyx() + curses.endwin() + # Restore terminal state in case endwin() didn't. + termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags) + # Now we have what we needed: the screen size in rows/columns + screen_lines += screen_lines_real + #print '***Screen size:',screen_lines_real,'lines x',\ + #screen_cols,'columns.' # dbg + else: + screen_lines += screen_lines_def + + #print 'numlines',numlines,'screenlines',screen_lines # dbg + if numlines <= screen_lines : + #print '*** normal print' # dbg + print >>Term.cout, str_toprint + else: + # Try to open pager and default to internal one if that fails. + # All failure modes are tagged as 'retval=1', to match the return + # value of a failed system command. If any intermediate attempt + # sets retval to 1, at the end we resort to our own page_dumb() pager. + pager_cmd = get_pager_cmd(pager_cmd) + pager_cmd += ' ' + get_pager_start(pager_cmd,start) + if os.name == 'nt': + if pager_cmd.startswith('type'): + # The default WinXP 'type' command is failing on complex strings. + retval = 1 + else: + tmpname = tempfile.mktemp('.txt') + tmpfile = file(tmpname,'wt') + tmpfile.write(strng) + tmpfile.close() + cmd = "%s < %s" % (pager_cmd,tmpname) + if os.system(cmd): + retval = 1 + else: + retval = None + os.remove(tmpname) + else: + try: + retval = None + # if I use popen4, things hang. No idea why. + #pager,shell_out = os.popen4(pager_cmd) + pager = os.popen(pager_cmd,'w') + pager.write(strng) + pager.close() + retval = pager.close() # success returns None + except IOError,msg: # broken pipe when user quits + if msg.args == (32,'Broken pipe'): + retval = None + else: + retval = 1 + except OSError: + # Other strange problems, sometimes seen in Win2k/cygwin + retval = 1 + if retval is not None: + page_dumb(strng,screen_lines=screen_lines) + +#---------------------------------------------------------------------------- +def page_file(fname,start = 0, pager_cmd = None): + """Page a file, using an optional pager command and starting line. + """ + + pager_cmd = get_pager_cmd(pager_cmd) + pager_cmd += ' ' + get_pager_start(pager_cmd,start) + + try: + if os.environ['TERM'] in ['emacs','dumb']: + raise EnvironmentError + xsys(pager_cmd + ' ' + fname) + except: + try: + if start > 0: + start -= 1 + page(open(fname).read(),start) + except: + print 'Unable to show file',`fname` + +#---------------------------------------------------------------------------- +def get_pager_cmd(pager_cmd = None): + """Return a pager command. + + Makes some attempts at finding an OS-correct one.""" + + if os.name == 'posix': + default_pager_cmd = 'less -r' # -r for color control sequences + elif os.name in ['nt','dos']: + default_pager_cmd = 'type' + + if pager_cmd is None: + try: + pager_cmd = os.environ['PAGER'] + except: + pager_cmd = default_pager_cmd + return pager_cmd + +#----------------------------------------------------------------------------- +def get_pager_start(pager,start): + """Return the string for paging files with an offset. + + This is the '+N' argument which less and more (under Unix) accept. + """ + + if pager in ['less','more']: + if start: + start_string = '+' + str(start) + else: + start_string = '' + else: + start_string = '' + return start_string + +#---------------------------------------------------------------------------- +# (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch() +if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs': + import msvcrt + def page_more(): + """ Smart pausing between pages + + @return: True if need print more lines, False if quit + """ + Term.cout.write('---Return to continue, q to quit--- ') + ans = msvcrt.getch() + if ans in ("q", "Q"): + result = False + else: + result = True + Term.cout.write("\b"*37 + " "*37 + "\b"*37) + return result +else: + def page_more(): + ans = raw_input('---Return to continue, q to quit--- ') + if ans.lower().startswith('q'): + return False + else: + return True + +#---------------------------------------------------------------------------- +def snip_print(str,width = 75,print_full = 0,header = ''): + """Print a string snipping the midsection to fit in width. + + print_full: mode control: + - 0: only snip long strings + - 1: send to page() directly. + - 2: snip long strings and ask for full length viewing with page() + Return 1 if snipping was necessary, 0 otherwise.""" + + if print_full == 1: + page(header+str) + return 0 + + print header, + if len(str) < width: + print str + snip = 0 + else: + whalf = int((width -5)/2) + print str[:whalf] + ' <...> ' + str[-whalf:] + snip = 1 + if snip and print_full == 2: + if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y': + page(str) + return snip \ No newline at end of file diff --git a/IPython/core/prefilter.py b/IPython/core/prefilter.py index 4bcadc8..0fb4524 100644 --- a/IPython/core/prefilter.py +++ b/IPython/core/prefilter.py @@ -8,7 +8,8 @@ transforming work. __docformat__ = "restructuredtext en" import re -from IPython.core import ipapi +from IPython.core.autocall import IPyAutocall + class LineInfo(object): """A single line of input and associated info. @@ -178,8 +179,8 @@ def checkEmacs(l_info,ip): def checkIPyAutocall(l_info,ip): "Instances of IPyAutocall in user_ns get autocalled immediately" obj = ip.user_ns.get(l_info.iFun, None) - if isinstance(obj, ipapi.IPyAutocall): - obj.set_ip(ip.api) + if isinstance(obj, IPyAutocall): + obj.set_ip(ip) return ip.handle_auto else: return None @@ -191,7 +192,7 @@ def checkMultiLineMagic(l_info,ip): # iFun and *not* the preChar. Also note that the below test matches # both ! and !!. if l_info.continue_prompt \ - and ip.rc.multi_line_specials: + and ip.multi_line_specials: if l_info.iFun.startswith(ip.ESC_MAGIC): return ip.handle_magic else: @@ -231,11 +232,11 @@ def checkAutomagic(l_info,ip): check_esc_chars. This just checks for automagic. Also, before triggering the magic handler, make sure that there is nothing in the user namespace which could shadow it.""" - if not ip.rc.automagic or not hasattr(ip,'magic_'+l_info.iFun): + if not ip.automagic or not hasattr(ip,'magic_'+l_info.iFun): return None # We have a likely magic method. Make sure we should actually call it. - if l_info.continue_prompt and not ip.rc.multi_line_specials: + if l_info.continue_prompt and not ip.multi_line_specials: return None head = l_info.iFun.split('.',1)[0] @@ -271,7 +272,7 @@ def checkPythonOps(l_info,ip): def checkAutocall(l_info,ip): "Check if the initial word/function is callable and autocall is on." - if not ip.rc.autocall: + if not ip.autocall: return None oinfo = l_info.ofind(ip) # This can mutate state via getattr diff --git a/IPython/core/prompts.py b/IPython/core/prompts.py index 1487d2d..5bb31bc 100644 --- a/IPython/core/prompts.py +++ b/IPython/core/prompts.py @@ -23,7 +23,7 @@ import time from IPython.utils import coloransi from IPython.core import release from IPython.external.Itpl import ItplNS -from IPython.core.ipapi import TryNext +from IPython.core.error import TryNext from IPython.utils.ipstruct import Struct from IPython.core.macro import Macro import IPython.utils.generics diff --git a/IPython/core/quitter.py b/IPython/core/quitter.py new file mode 100644 index 0000000..f7151f1 --- /dev/null +++ b/IPython/core/quitter.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +A simple class for quitting IPython. + +Authors: + +* Brian Granger +""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2008-2009 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 +#----------------------------------------------------------------------------- + + +class Quitter(object): + """Simple class to handle exit, similar to Python 2.5's. + + It handles exiting in an ipython-safe manner, which the one in Python 2.5 + doesn't do (obviously, since it doesn't know about ipython).""" + + def __init__(self, shell, name): + self.shell = shell + self.name = name + + def __repr__(self): + return 'Type %s() to exit.' % self.name + __str__ = __repr__ + + def __call__(self): + self.shell.exit() \ No newline at end of file diff --git a/IPython/core/shell.py b/IPython/core/shell.py deleted file mode 100644 index f2b2602..0000000 --- a/IPython/core/shell.py +++ /dev/null @@ -1,274 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 -"""IPython Shell classes. - -Originally, this module was horribly complicated because of the need to -use threads to integrate with GUI toolkit event loops. Now, we are using -the :mod:`IPython.lib.inputhook`, which is based on PyOS_InputHook. This -dramatically simplifies this logic and allow 3rd party packages (such as -matplotlib) to handle these things by themselves. - -This new approach also allows projects like matplotlib to work interactively -in the standard python shell. -""" - -#----------------------------------------------------------------------------- -# Copyright (C) 2008-2009 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 sys - -from IPython.core import ultratb -from IPython.core import ipapi -from IPython.utils.genutils import ask_yes_no -from IPython.core.iplib import InteractiveShell -from IPython.core.ipmaker import make_IPython - -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- - - -class IPShell: - """Create an IPython instance. - - This calls the factory :func:`make_IPython`, which creates a configured - :class:`InteractiveShell` object, and presents the result as a simple - class with a :meth:`mainloop` method. - """ - - def __init__(self, argv=None, user_ns=None, user_global_ns=None, - debug=1, shell_class=InteractiveShell): - self.IP = make_IPython(argv, user_ns=user_ns, - user_global_ns=user_global_ns, - debug=debug, shell_class=shell_class) - - def mainloop(self,sys_exit=0,banner=None): - self.IP.mainloop(banner) - if sys_exit: - sys.exit() - - -# This is an additional magic that is exposed in embedded shells. -def kill_embedded(self,parameter_s=''): - """%kill_embedded : deactivate for good the current embedded IPython. - - This function (after asking for confirmation) sets an internal flag so that - an embedded IPython will never activate again. This is useful to - permanently disable a shell that is being called inside a loop: once you've - figured out what you needed from it, you may then kill it and the program - will then continue to run without the interactive shell interfering again. - """ - - kill = ask_yes_no("Are you sure you want to kill this embedded instance " - "(y/n)? [y/N] ",'n') - if kill: - self.shell.embedded_active = False - print "This embedded IPython will not reactivate anymore once you exit." - - -class IPShellEmbed: - """Allow embedding an IPython shell into a running program. - - Instances of this class are callable, with the __call__ method being an - alias to the embed() method of an InteractiveShell instance. - - Usage (see also the example-embed.py file for a running example):: - - ipshell = IPShellEmbed([argv,banner,exit_msg,rc_override]) - - * argv: list containing valid command-line options for IPython, as they - would appear in sys.argv[1:]. - - For example, the following command-line options:: - - $ ipython -prompt_in1 'Input <\\#>' -colors LightBG - - would be passed in the argv list as:: - - ['-prompt_in1','Input <\\#>','-colors','LightBG'] - - * banner: string which gets printed every time the interpreter starts. - - * exit_msg: string which gets printed every time the interpreter exits. - - * rc_override: a dict or Struct of configuration options such as those - used by IPython. These options are read from your ~/.ipython/ipythonrc - file when the Shell object is created. Passing an explicit rc_override - dict with any options you want allows you to override those values at - creation time without having to modify the file. This way you can create - embeddable instances configured in any way you want without editing any - global files (thus keeping your interactive IPython configuration - unchanged). - - Then the ipshell instance can be called anywhere inside your code:: - - ipshell(header='') -> Opens up an IPython shell. - - * header: string printed by the IPython shell upon startup. This can let - you know where in your code you are when dropping into the shell. Note - that 'banner' gets prepended to all calls, so header is used for - location-specific information. - - For more details, see the __call__ method below. - - When the IPython shell is exited with Ctrl-D, normal program execution - resumes. - - This functionality was inspired by a posting on comp.lang.python by cmkl - on Dec. 06/01 concerning similar uses of pyrepl, and - by the IDL stop/continue commands. - """ - - def __init__(self, argv=None, banner='', exit_msg=None, - rc_override=None, user_ns=None): - """Note that argv here is a string, NOT a list.""" - - self.set_banner(banner) - self.set_exit_msg(exit_msg) - self.set_dummy_mode(0) - - # sys.displayhook is a global, we need to save the user's original - # Don't rely on __displayhook__, as the user may have changed that. - self.sys_displayhook_ori = sys.displayhook - - # save readline completer status - try: - #print 'Save completer',sys.ipcompleter # dbg - self.sys_ipcompleter_ori = sys.ipcompleter - except: - pass # not nested with IPython - - self.IP = make_IPython(argv,rc_override=rc_override, - embedded=True, - user_ns=user_ns) - - ip = ipapi.IPApi(self.IP) - ip.expose_magic("kill_embedded",kill_embedded) - - # copy our own displayhook also - self.sys_displayhook_embed = sys.displayhook - # and leave the system's display hook clean - sys.displayhook = self.sys_displayhook_ori - # don't use the ipython crash handler so that user exceptions aren't - # trapped - sys.excepthook = ultratb.FormattedTB(color_scheme = self.IP.rc.colors, - mode = self.IP.rc.xmode, - call_pdb = self.IP.rc.pdb) - self.restore_system_completer() - - def restore_system_completer(self): - """Restores the readline completer which was in place. - - This allows embedded IPython within IPython not to disrupt the - parent's completion. - """ - - try: - self.IP.readline.set_completer(self.sys_ipcompleter_ori) - sys.ipcompleter = self.sys_ipcompleter_ori - except: - pass - - def __call__(self, header='', local_ns=None, global_ns=None, dummy=None): - """Activate the interactive interpreter. - - __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start - the interpreter shell with the given local and global namespaces, and - optionally print a header string at startup. - - The shell can be globally activated/deactivated using the - set/get_dummy_mode methods. This allows you to turn off a shell used - for debugging globally. - - However, *each* time you call the shell you can override the current - state of dummy_mode with the optional keyword parameter 'dummy'. For - example, if you set dummy mode on with IPShell.set_dummy_mode(1), you - can still have a specific call work by making it as IPShell(dummy=0). - - The optional keyword parameter dummy controls whether the call - actually does anything. - """ - - # If the user has turned it off, go away - if not self.IP.embedded_active: - return - - # Normal exits from interactive mode set this flag, so the shell can't - # re-enter (it checks this variable at the start of interactive mode). - self.IP.exit_now = False - - # Allow the dummy parameter to override the global __dummy_mode - if dummy or (dummy != 0 and self.__dummy_mode): - return - - # Set global subsystems (display,completions) to our values - sys.displayhook = self.sys_displayhook_embed - if self.IP.has_readline: - self.IP.set_completer() - - if self.banner and header: - format = '%s\n%s\n' - else: - format = '%s%s\n' - banner = format % (self.banner,header) - - # Call the embedding code with a stack depth of 1 so it can skip over - # our call and get the original caller's namespaces. - self.IP.embed_mainloop(banner,local_ns,global_ns,stack_depth=1) - - if self.exit_msg: - print self.exit_msg - - # Restore global systems (display, completion) - sys.displayhook = self.sys_displayhook_ori - self.restore_system_completer() - - def set_dummy_mode(self, dummy): - """Sets the embeddable shell's dummy mode parameter. - - set_dummy_mode(dummy): dummy = 0 or 1. - - This parameter is persistent and makes calls to the embeddable shell - silently return without performing any action. This allows you to - globally activate or deactivate a shell you're using with a single call. - - If you need to manually""" - - if dummy not in [0,1,False,True]: - raise ValueError,'dummy parameter must be boolean' - self.__dummy_mode = dummy - - def get_dummy_mode(self): - """Return the current value of the dummy mode parameter. - """ - return self.__dummy_mode - - def set_banner(self, banner): - """Sets the global banner. - - This banner gets prepended to every header printed when the shell - instance is called.""" - - self.banner = banner - - def set_exit_msg(self, exit_msg): - """Sets the global exit_msg. - - This exit message gets printed upon exiting every time the embedded - shell is called. It is None by default. """ - - self.exit_msg = exit_msg - -# This is the one which should be called by external code. -def start(user_ns = None): - """Return a running shell instance of :class:`IPShell`.""" - return IPShell(user_ns = user_ns) - diff --git a/IPython/core/tests/obj_del.py b/IPython/core/tests/obj_del.py index 8ea9d18..56c8700 100644 --- a/IPython/core/tests/obj_del.py +++ b/IPython/core/tests/obj_del.py @@ -31,4 +31,4 @@ class A(object): a = A() # Now, we force an exit, the caller will check that the del printout was given -_ip.IP.ask_exit() +_ip.ask_exit() diff --git a/IPython/core/tests/test_imports.py b/IPython/core/tests/test_imports.py index 830ed52..7450104 100644 --- a/IPython/core/tests/test_imports.py +++ b/IPython/core/tests/test_imports.py @@ -28,9 +28,6 @@ def test_import_ipapi(): def test_import_iplib(): from IPython.core import iplib -def test_import_ipmaker(): - from IPython.core import ipmaker - def test_import_logger(): from IPython.core import logger diff --git a/IPython/core/tests/test_iplib.py b/IPython/core/tests/test_iplib.py index 798743e..c1b12c8 100644 --- a/IPython/core/tests/test_iplib.py +++ b/IPython/core/tests/test_iplib.py @@ -15,6 +15,7 @@ import nose.tools as nt # our own packages from IPython.core import iplib from IPython.core import ipapi +from IPython.core.oldusersetup import user_setup #----------------------------------------------------------------------------- # Globals @@ -37,8 +38,6 @@ if ip is None: # consistency when the test suite is being run via iptest from IPython.testing.plugin import ipdoctest ip = ipapi.get() - -IP = ip.IP # This is the actual IPython shell 'raw' object. #----------------------------------------------------------------------------- # Test functions @@ -46,10 +45,10 @@ IP = ip.IP # This is the actual IPython shell 'raw' object. def test_reset(): """reset must clear most namespaces.""" - IP.reset() # first, it should run without error + ip.reset() # first, it should run without error # Then, check that most namespaces end up empty - for ns in IP.ns_refs_table: - if ns is IP.user_ns: + for ns in ip.ns_refs_table: + if ns is ip.user_ns: # The user namespace is reset with some data, so we can't check for # it being empty continue @@ -59,12 +58,12 @@ def test_reset(): # make sure that user_setup can be run re-entrantly in 'install' mode. def test_user_setup(): # use a lambda to pass kwargs to the generator - user_setup = lambda a,k: iplib.user_setup(*a,**k) + user_setup = lambda a,k: user_setup(*a,**k) kw = dict(mode='install', interactive=False) # Call the user setup and verify that the directory exists - yield user_setup, (ip.options.ipythondir,''), kw - yield os.path.isdir, ip.options.ipythondir + yield user_setup, (ip.config.IPYTHONDIR,''), kw + yield os.path.isdir, ip.config.IPYTHONDIR # Now repeat the operation with a non-existent directory. Check both that # the call succeeds and that the directory is created. diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 87da106..f1f97a8 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -20,14 +20,14 @@ from IPython.testing import tools as tt def test_rehashx(): # clear up everything - _ip.IP.alias_table.clear() + _ip.alias_table.clear() del _ip.db['syscmdlist'] _ip.magic('rehashx') # Practically ALL ipython development systems will have more than 10 aliases - yield (nt.assert_true, len(_ip.IP.alias_table) > 10) - for key, val in _ip.IP.alias_table.items(): + yield (nt.assert_true, len(_ip.alias_table) > 10) + for key, val in _ip.alias_table.items(): # we must strip dots from alias names nt.assert_true('.' not in key) @@ -52,7 +52,7 @@ def doctest_hist_r(): XXX - This test is not recording the output correctly. Not sure why... - In [20]: 'hist' in _ip.IP.lsmagic() + In [20]: 'hist' in _ip.lsmagic() Out[20]: True In [6]: x=1 @@ -69,7 +69,7 @@ def test_obj_del(): test_dir = os.path.dirname(__file__) del_file = os.path.join(test_dir,'obj_del.py') ipython_cmd = find_cmd('ipython') - out = _ip.IP.getoutput('%s %s' % (ipython_cmd, del_file)) + out = _ip.getoutput('%s %s' % (ipython_cmd, del_file)) nt.assert_equals(out,'obj_del.py: object A deleted') @@ -124,7 +124,7 @@ def doctest_refbug(): """Very nasty problem with references held by multiple runs of a script. See: https://bugs.launchpad.net/ipython/+bug/269966 - In [1]: _ip.IP.clear_main_mod_cache() + In [1]: _ip.clear_main_mod_cache() In [2]: run refbug @@ -247,7 +247,7 @@ class TestMagicRun(object): def test_prompts(self): """Test that prompts correctly generate after %run""" self.run_tmpfile() - p2 = str(_ip.IP.outputcache.prompt2).strip() + p2 = str(_ip.outputcache.prompt2).strip() nt.assert_equals(p2[:3], '...') def teardown(self): @@ -268,7 +268,7 @@ def test_paste(): _ip.magic('paste '+flags) # Inject fake clipboard hook but save original so we can restore it later - hooks = _ip.IP.hooks + hooks = _ip.hooks user_ns = _ip.user_ns original_clip = hooks.clipboard_get @@ -305,8 +305,8 @@ def test_paste(): # Also test paste echoing, by temporarily faking the writer w = StringIO() - writer = _ip.IP.write - _ip.IP.write = w.write + writer = _ip.write + _ip.write = w.write code = """ a = 100 b = 200""" @@ -314,7 +314,7 @@ def test_paste(): paste(code,'') out = w.getvalue() finally: - _ip.IP.write = writer + _ip.write = writer yield (nt.assert_equal, user_ns['a'], 100) yield (nt.assert_equal, user_ns['b'], 200) yield (nt.assert_equal, out, code+"\n## -- End pasted text --\n") diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 4a22aa8..e79cae9 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -270,7 +270,7 @@ def _formatTracebackLines(lnum, index, lines, Colors, lvals=None,scheme=None): if scheme is None: ipinst = ipapi.get() if ipinst is not None: - scheme = ipinst.IP.rc.colors + scheme = ipinst.colors else: scheme = DEFAULT_SCHEME @@ -494,7 +494,7 @@ class ListTB(TBTools): if have_filedata: ipinst = ipapi.get() if ipinst is not None: - ipinst.IP.hooks.synchronize_with_editor(filename, lineno, 0) + ipinst.hooks.synchronize_with_editor(filename, lineno, 0) # vds:<< return list @@ -816,7 +816,7 @@ class VerboseTB(TBTools): filepath = os.path.abspath(filepath) ipinst = ipapi.get() if ipinst is not None: - ipinst.IP.hooks.synchronize_with_editor(filepath, lnum, 0) + ipinst.hooks.synchronize_with_editor(filepath, lnum, 0) # vds: << # return all our info assembled as a single string diff --git a/IPython/core/usage.py b/IPython/core/usage.py index 20cece8..62eb175 100644 --- a/IPython/core/usage.py +++ b/IPython/core/usage.py @@ -6,6 +6,9 @@ # the file COPYING, distributed as part of this software. #***************************************************************************** +import sys +from IPython.core import release + __doc__ = """ IPython -- An enhanced Interactive Python ========================================= @@ -504,6 +507,18 @@ MAIN FEATURES >>> x = ,my_function /home/me # syntax error """ +interactive_usage_min = """\ +An enhanced console for Python. +Some of its features are: +- Readline support if the readline library is present. +- Tab completion in the local namespace. +- Logging of input, see command-line options. +- System shell escape via ! , eg !ls. +- Magic commands, starting with a % (like %ls, %pwd, %cd, etc.) +- Keeps track of locally defined variables via %who, %whos. +- Show object information with a ? eg ?x or x? (use ?? for more info). +""" + quick_reference = r""" IPython -- An enhanced Interactive Python - Quick Reference Card ================================================================ @@ -556,3 +571,18 @@ or python names. The following magic functions are currently available: """ + +quick_guide = """\ +? -> Introduction and overview of IPython's features. +%quickref -> Quick reference. +help -> Python's own help system. +object? -> Details about 'object'. ?object also works, ?? prints more.""" + +default_banner_parts = [ + 'Python %s' % (sys.version.split('\n')[0],), + 'Type "copyright", "credits" or "license" for more information.\n', + 'IPython %s -- An enhanced Interactive Python.' % (release.version,), + quick_guide +] + +default_banner = '\n'.join(default_banner_parts) diff --git a/IPython/deathrow/GnuplotInteractive.py b/IPython/deathrow/GnuplotInteractive.py index cc9dd7b..ab837d7 100644 --- a/IPython/deathrow/GnuplotInteractive.py +++ b/IPython/deathrow/GnuplotInteractive.py @@ -16,7 +16,8 @@ __all__ = ['Gnuplot','gp','gp_new','plot','plot2','splot','replot', 'gphelp'] import IPython.GnuplotRuntime as GRun -from IPython.utils.genutils import page,warn +from IPython.utils.genutils import warn +from IPython.core.page import page # Set global names for interactive use Gnuplot = GRun.Gnuplot diff --git a/IPython/deathrow/dtutils.py b/IPython/deathrow/dtutils.py index 9bab867..41e377f 100644 --- a/IPython/deathrow/dtutils.py +++ b/IPython/deathrow/dtutils.py @@ -77,7 +77,7 @@ def idoctest(ns=None,eraise=False): if ns is None: ns = ip.user_ns - ip.IP.savehist() + ip.savehist() try: while True: line = raw_input() @@ -96,7 +96,7 @@ def idoctest(ns=None,eraise=False): print "KeyboardInterrupt - Discarding input." run_test = False - ip.IP.reloadhist() + ip.reloadhist() if run_test: # Extra blank line at the end to ensure that the final docstring has a diff --git a/IPython/extensions/clearcmd.py b/IPython/extensions/clearcmd.py index 8fbe4aa..a87edf7 100644 --- a/IPython/extensions/clearcmd.py +++ b/IPython/extensions/clearcmd.py @@ -81,7 +81,7 @@ def clear_f(self,arg): gc.collect() # Activate the extension -ip.expose_magic("clear",clear_f) +ip.define_magic("clear",clear_f) import ipy_completers ipy_completers.quick_completer( '%clear','in out shadow_nuke shadow_compress dhist') diff --git a/IPython/extensions/envpersist.py b/IPython/extensions/envpersist.py index 62a96b1..2144c78 100644 --- a/IPython/extensions/envpersist.py +++ b/IPython/extensions/envpersist.py @@ -3,6 +3,8 @@ """ from IPython.core import ipapi +from IPython.core.error import TryNext + ip = ipapi.get() import os,sys @@ -16,7 +18,7 @@ def restore_env(self): os.environ[k] = os.environ.get(k,"") + v for k,v in env['pre']: os.environ[k] = v + os.environ.get(k,"") - raise ipapi.TryNext + raise TryNext ip.set_hook('late_startup_hook', restore_env) @@ -85,6 +87,6 @@ def env_completer(self,event): """ Custom completer that lists all env vars """ return os.environ.keys() -ip.expose_magic('env', persist_env) +ip.define_magic('env', persist_env) ip.set_hook('complete_command',env_completer, str_key = '%env') diff --git a/IPython/extensions/ext_rescapture.py b/IPython/extensions/ext_rescapture.py index d3877c0..fdb7a4d 100644 --- a/IPython/extensions/ext_rescapture.py +++ b/IPython/extensions/ext_rescapture.py @@ -9,6 +9,7 @@ var = !ls """ from IPython.core import ipapi +from IPython.core.error import TryNext from IPython.utils.genutils import * ip = ipapi.get() @@ -17,9 +18,6 @@ import re def hnd_magic(line,mo): """ Handle a = %mymagic blah blah """ - #cmd = genutils.make_quoted_expr(mo.group('syscmd')) - #mag = 'ipmagic - #return "%s = %s" var = mo.group('varname') cmd = mo.group('cmd') expr = make_quoted_expr(cmd) @@ -27,9 +25,6 @@ def hnd_magic(line,mo): def hnd_syscmd(line,mo): """ Handle a = !ls """ - #cmd = genutils.make_quoted_expr(mo.group('syscmd')) - #mag = 'ipmagic - #return "%s = %s" var = mo.group('varname') cmd = mo.group('cmd') expr = make_quoted_expr(itpl("sc -l =$cmd")) @@ -58,6 +53,6 @@ def regex_prefilter_f(self,line): if mo: return handler(line,mo) - raise ipapi.TryNext + raise TryNext ip.set_hook('input_prefilter', regex_prefilter_f) diff --git a/IPython/extensions/ipipe.py b/IPython/extensions/ipipe.py index 2117c76..13b18ba 100644 --- a/IPython/extensions/ipipe.py +++ b/IPython/extensions/ipipe.py @@ -1612,10 +1612,10 @@ class ihist(Table): def __iter__(self): api = ipapi.get() if self.raw: - for line in api.IP.input_hist_raw: + for line in api.input_hist_raw: yield line.rstrip("\n") else: - for line in api.IP.input_hist: + for line in api.input_hist: yield line.rstrip("\n") @@ -1644,7 +1644,7 @@ class ialias(Table): def __iter__(self): api = ipapi.get() - for (name, (args, command)) in api.IP.alias_table.iteritems(): + for (name, (args, command)) in api.alias_table.iteritems(): yield Alias(name, args, command) diff --git a/IPython/extensions/ipy_autoreload.py b/IPython/extensions/ipy_autoreload.py index 98dd9db..3976551 100644 --- a/IPython/extensions/ipy_autoreload.py +++ b/IPython/extensions/ipy_autoreload.py @@ -225,6 +225,7 @@ reloader = ModuleReloader() # IPython connectivity #------------------------------------------------------------------------------ from IPython.core import ipapi +from IPython.core.error import TryNext ip = ipapi.get() @@ -232,7 +233,7 @@ autoreload_enabled = False def runcode_hook(self): if not autoreload_enabled: - raise ipapi.TryNext + raise TryNext try: reloader.check() except: @@ -339,11 +340,11 @@ def aimport_f(self, parameter_s=''): __import__(modname) basename = modname.split('.')[0] mod = sys.modules[basename] - ip.to_user_ns({basename: mod}) + ip.push({basename: mod}) def init(): - ip.expose_magic('autoreload', autoreload_f) - ip.expose_magic('aimport', aimport_f) + ip.define_magic('autoreload', autoreload_f) + ip.define_magic('aimport', aimport_f) ip.set_hook('pre_runcode_hook', runcode_hook) init() diff --git a/IPython/extensions/ipy_completers.py b/IPython/extensions/ipy_completers.py index 4403727..f4d9f6e 100644 --- a/IPython/extensions/ipy_completers.py +++ b/IPython/extensions/ipy_completers.py @@ -8,6 +8,8 @@ ip.set_hook('complete_command', svn_completer, str_key = 'svn') """ from IPython.core import ipapi +from IPython.core.error import TryNext + import glob,os,shlex,sys import inspect from time import time @@ -169,7 +171,7 @@ def vcs_completer(commands, event): if len(cmd_param) == 2 or 'help' in cmd_param: return commands.split() - return ip.IP.Completer.file_matches(event.symbol) + return ip.Completer.file_matches(event.symbol) pkg_cache = None @@ -245,7 +247,7 @@ def bzr_completer(self,event): return [] else: # the rest are probably file names - return ip.IP.Completer.file_matches(event.symbol) + return ip.Completer.file_matches(event.symbol) return bzr_commands() @@ -329,7 +331,7 @@ def cd_completer(self, event): if ' ' in d: # we don't want to deal with any of that, complex code # for this is elsewhere - raise ipapi.TryNext + raise TryNext found.append( d ) if not found: @@ -341,7 +343,7 @@ def cd_completer(self, event): if bkmatches: return bkmatches - raise ipapi.TryNext + raise TryNext def single_dir_expand(matches): diff --git a/IPython/extensions/ipy_editors.py b/IPython/extensions/ipy_editors.py index dc8f483..5ff34a2 100644 --- a/IPython/extensions/ipy_editors.py +++ b/IPython/extensions/ipy_editors.py @@ -6,6 +6,7 @@ Contributions are *very* welcome. """ from IPython.core import ipapi +from IPython.core.error import TryNext ip = ipapi.get() from IPython.external.Itpl import itplns @@ -29,7 +30,7 @@ def install_editor(run_template, wait = False): cmd = itplns(run_template, locals()) print ">",cmd if os.system(cmd) != 0: - raise ipapi.TryNext() + raise TryNext() if wait: raw_input("Press Enter when done editing:") diff --git a/IPython/extensions/ipy_exportdb.py b/IPython/extensions/ipy_exportdb.py index 9eff9ca..b6b3e6a 100644 --- a/IPython/extensions/ipy_exportdb.py +++ b/IPython/extensions/ipy_exportdb.py @@ -43,7 +43,7 @@ def export(filename = None): varstomove.append(k) lines.append('%s = %s' % (k,repr(v))) - lines.append('ip.to_user_ns("%s")' % (' '.join(varstomove))) + lines.append('ip.push("%s")' % (' '.join(varstomove))) bkms = ip.db.get('bookmarks',{}) @@ -57,7 +57,7 @@ def export(filename = None): lines.extend(['','# === Alias definitions ===','']) for k,v in aliases.items(): try: - lines.append("ip.defalias('%s', %s)" % (k, repr(v[1]))) + lines.append("ip.define_alias('%s', %s)" % (k, repr(v[1]))) except (AttributeError, TypeError): pass diff --git a/IPython/extensions/ipy_extutil.py b/IPython/extensions/ipy_extutil.py index 38f0d6c..e899e55 100644 --- a/IPython/extensions/ipy_extutil.py +++ b/IPython/extensions/ipy_extutil.py @@ -9,6 +9,7 @@ to. from IPython.core import ipapi ip = ipapi.get() +from IPython.core.iplib import InteractiveShell import sys,textwrap,inspect @@ -34,10 +35,10 @@ class ExtUtil: act = [] for mname,m in sys.modules.items(): o = getattr(m, 'ip', None) - if isinstance(o, ipapi.IPApi): + if isinstance(o, InteractiveShell): act.append((mname,m)) act.sort() return act extutil = ExtUtil() -ip.to_user_ns('extutil') +ip.push('extutil') diff --git a/IPython/extensions/ipy_fsops.py b/IPython/extensions/ipy_fsops.py index 5180bba..08282fd 100644 --- a/IPython/extensions/ipy_fsops.py +++ b/IPython/extensions/ipy_fsops.py @@ -16,12 +16,13 @@ Not to be confused with ipipe commands (ils etc.) that also start with i. """ from IPython.core import ipapi +from IPython.core.error import TryNext ip = ipapi.get() import shutil,os,shlex from IPython.external import mglob from IPython.external.path import path -from IPython.core.ipapi import UsageError +from IPython.core.error import UsageError import IPython.utils.generics def parse_args(args): @@ -59,7 +60,7 @@ def icp(ip,arg): else: shutil.copy2(f,targetdir) return fs -ip.defalias("icp",icp) +ip.define_alias("icp",icp) def imv(ip,arg): """ imv src tgt @@ -73,7 +74,7 @@ def imv(ip,arg): for f in fs: shutil.move(f, target) return fs -ip.defalias("imv",imv) +ip.define_alias("imv",imv) def irm(ip,arg): """ irm path[s]... @@ -92,7 +93,7 @@ def irm(ip,arg): else: os.remove(p) -ip.defalias("irm",irm) +ip.define_alias("irm",irm) def imkdir(ip,arg): """ imkdir path @@ -103,7 +104,7 @@ def imkdir(ip,arg): targetdir = arg.split(None,1)[1] distutils.dir_util.mkpath(targetdir,verbose =1) -ip.defalias("imkdir",imkdir) +ip.define_alias("imkdir",imkdir) def igrep(ip,arg): """ igrep PAT files... @@ -129,7 +130,7 @@ def igrep(ip,arg): print l.rstrip() return res -ip.defalias("igrep",igrep) +ip.define_alias("igrep",igrep) def collect(ip,arg): """ collect foo/a.txt rec:bar=*.py @@ -140,7 +141,7 @@ def collect(ip,arg): Without args, try to open ~/_ipython/collect dir (in win32 at least). """ from IPython.external.path import path - basedir = path(ip.options.ipythondir + '/collect') + basedir = path(ip.options.IPYTHONDIR + '/collect') try: fs = mglob.expand(arg.split(None,1)[1]) except IndexError: @@ -159,7 +160,7 @@ def collect(ip,arg): print f,"=>",trg shutil.copy2(f,trg) -ip.defalias("collect",collect) +ip.define_alias("collect",collect) def inote(ip,arg): """ inote Hello world @@ -169,15 +170,15 @@ def inote(ip,arg): Without args, opens notes.txt for editing. """ import time - fname = ip.options.ipythondir + '/notes.txt' + fname = ip.options.IPYTHONDIR + '/notes.txt' try: entry = " === " + time.asctime() + ': ===\n' + arg.split(None,1)[1] + '\n' f= open(fname, 'a').write(entry) except IndexError: - ip.IP.hooks.editor(fname) + ip.hooks.editor(fname) -ip.defalias("inote",inote) +ip.define_alias("inote",inote) def pathobj_mangle(p): return p.replace(' ', '__').replace('.','DOT') @@ -229,7 +230,7 @@ def complete_pathobj(obj, prev_completions): if res: return res # just return normal attributes of 'path' object if the dir is empty - raise ipapi.TryNext + raise TryNext complete_pathobj = IPython.utils.generics.complete_object.when_type(PathObj)(complete_pathobj) @@ -240,6 +241,6 @@ def test_pathobj(): rootdir = PathObj("/") startmenu = PathObj("d:/Documents and Settings/All Users/Start Menu/Programs") cwd = PathObj('.') - ip.to_user_ns("rootdir startmenu cwd") + ip.push("rootdir startmenu cwd") #test_pathobj() \ No newline at end of file diff --git a/IPython/extensions/ipy_gnuglobal.py b/IPython/extensions/ipy_gnuglobal.py index 32f5b7c..93e27bc 100644 --- a/IPython/extensions/ipy_gnuglobal.py +++ b/IPython/extensions/ipy_gnuglobal.py @@ -28,7 +28,7 @@ def global_f(self,cmdline): lines = ['%s [%s]\n%s' % (p[2].rjust(70),p[1],p[3].rstrip()) for p in parts] print "\n".join(lines) -ip.expose_magic('global', global_f) +ip.define_magic('global', global_f) def global_completer(self,event): compl = [l.rstrip() for l in os.popen(global_bin + ' -c ' + event.symbol).readlines()] diff --git a/IPython/extensions/ipy_greedycompleter.py b/IPython/extensions/ipy_greedycompleter.py index 17628f9..f928e45 100644 --- a/IPython/extensions/ipy_greedycompleter.py +++ b/IPython/extensions/ipy_greedycompleter.py @@ -10,6 +10,7 @@ do the same in default completer. """ from IPython.core import ipapi +from IPython.core.error import TryNext from IPython.utils import generics from IPython.utils.genutils import dir2 @@ -59,7 +60,7 @@ def attr_matches(self, text): try: words = generics.complete_object(obj, words) - except ipapi.TryNext: + except TryNext: pass # Build match list to return n = len(attr) diff --git a/IPython/extensions/ipy_jot.py b/IPython/extensions/ipy_jot.py index d813146..5b2e65e 100644 --- a/IPython/extensions/ipy_jot.py +++ b/IPython/extensions/ipy_jot.py @@ -116,14 +116,14 @@ def jot_obj(self, obj, name, comment=''): uname = 'jot/'+name+suffix # which one works better? - #all = ip.IP.shadowhist.all() - all = ip.IP.shell.input_hist + #all = ip.shadowhist.all() + all = ip.shell.input_hist # We may actually want to make snapshot of files that are run-ned. # get the comment try: - comment = ip.IP.magic_edit('-x').strip() + comment = ip.magic_edit('-x').strip() except: print "No comment is recorded." comment = '' @@ -307,5 +307,5 @@ def magic_read(self, parameter_s=''): return read_variables(ip, toret) -ip.expose_magic('jot',magic_jot) -ip.expose_magic('read',magic_read) +ip.define_magic('jot',magic_jot) +ip.define_magic('read',magic_read) diff --git a/IPython/extensions/ipy_kitcfg.py b/IPython/extensions/ipy_kitcfg.py index d77f672..57409c8 100644 --- a/IPython/extensions/ipy_kitcfg.py +++ b/IPython/extensions/ipy_kitcfg.py @@ -16,7 +16,7 @@ def pylaunchers(): for f in fs: l = PyLauncher(f) n = os.path.splitext(f)[0] - ip.defalias(n, l) + ip.define_alias(n, l) ip.magic('store '+n) @@ -39,7 +39,7 @@ def main(): return os.environ["PATH"] = os.environ["PATH"] + ";" + kitroot() + "\\bin;" - ip.to_user_ns("pylaunchers") + ip.push("pylaunchers") cmds = ip.db.get('syscmdlist', None) if cmds is None: ip.magic('rehashx') @@ -63,8 +63,8 @@ def ipython_firstrun(ip): print "First run of ipykit - configuring" - ip.defalias('py',selflaunch) - ip.defalias('d','dir /w /og /on') + ip.define_alias('py',selflaunch) + ip.define_alias('d','dir /w /og /on') ip.magic('store py') ip.magic('store d') diff --git a/IPython/extensions/ipy_legacy.py b/IPython/extensions/ipy_legacy.py index f3fdc26..aa7a148 100644 --- a/IPython/extensions/ipy_legacy.py +++ b/IPython/extensions/ipy_legacy.py @@ -43,7 +43,7 @@ def magic_rehash(self, parameter_s = ''): # aliases since %rehash will probably clobber them self.shell.init_auto_alias() -ip.expose_magic("rehash", magic_rehash) +ip.define_magic("rehash", magic_rehash) # Exit def magic_Quit(self, parameter_s=''): @@ -51,7 +51,7 @@ def magic_Quit(self, parameter_s=''): self.shell.ask_exit() -ip.expose_magic("Quit", magic_Quit) +ip.define_magic("Quit", magic_Quit) # make it autocallable fn if you really need it @@ -59,4 +59,4 @@ def magic_p(self, parameter_s=''): """Just a short alias for Python's 'print'.""" exec 'print ' + parameter_s in self.shell.user_ns -ip.expose_magic("p", magic_p) +ip.define_magic("p", magic_p) diff --git a/IPython/extensions/ipy_lookfor.py b/IPython/extensions/ipy_lookfor.py index 4c766db..98738c3 100644 --- a/IPython/extensions/ipy_lookfor.py +++ b/IPython/extensions/ipy_lookfor.py @@ -229,6 +229,6 @@ def lookfor_modules_f(self, arg=''): else: _lookfor_modules = arg.split() -ip.expose_magic('lookfor', lookfor_f) -ip.expose_magic('lookfor_modules', lookfor_modules_f) +ip.define_magic('lookfor', lookfor_f) +ip.define_magic('lookfor_modules', lookfor_modules_f) diff --git a/IPython/extensions/ipy_p4.py b/IPython/extensions/ipy_p4.py index 3c77e20..0bda2fe 100644 --- a/IPython/extensions/ipy_p4.py +++ b/IPython/extensions/ipy_p4.py @@ -25,9 +25,9 @@ def p4_f(self, parameter_s=''): def p4d(fname): return os.popen('p4 where ' + fname).read().split()[0] -ip.to_user_ns("p4d") +ip.push("p4d") -ip.expose_magic('p4', p4_f) +ip.define_magic('p4', p4_f) p4_commands = """\ add admin annotate branch branches change changes changelist diff --git a/IPython/extensions/ipy_pretty.py b/IPython/extensions/ipy_pretty.py index d2463e3..1c6c977 100644 --- a/IPython/extensions/ipy_pretty.py +++ b/IPython/extensions/ipy_pretty.py @@ -17,6 +17,7 @@ for numpy dtype objects, add the following to your ipy_user_conf.py:: """ from IPython.core import ipapi +from IPython.core.error import TryNext from IPython.utils.genutils import Term from IPython.external import pretty diff --git a/IPython/extensions/ipy_profile_doctest.py b/IPython/extensions/ipy_profile_doctest.py index 787131b..d1e4f75 100644 --- a/IPython/extensions/ipy_profile_doctest.py +++ b/IPython/extensions/ipy_profile_doctest.py @@ -41,6 +41,6 @@ def main(): o.xmode = 'plain' # Store the activity flag in the metadata bag from the running shell - ip.IP.meta.doctest_mode = True + ip.meta.doctest_mode = True main() diff --git a/IPython/extensions/ipy_profile_sh.py b/IPython/extensions/ipy_profile_sh.py index 19dd11b..d678e57 100644 --- a/IPython/extensions/ipy_profile_sh.py +++ b/IPython/extensions/ipy_profile_sh.py @@ -8,6 +8,7 @@ compatibility) """ from IPython.core import ipapi +from IPython.core.error import TryNext import os,re,textwrap # The import below effectively obsoletes your old-style ipythonrc[.ini], @@ -69,10 +70,10 @@ def main(): o.banner = "IPython %s [on Py %s]\n" % (release.version,sys.version.split(None,1)[0]) - ip.IP.default_option('cd','-q') - ip.IP.default_option('macro', '-r') + ip.default_option('cd','-q') + ip.default_option('macro', '-r') # If you only rarely want to execute the things you %edit... - #ip.IP.default_option('edit','-x') + #ip.default_option('edit','-x') o.prompts_pad_left="1" @@ -108,11 +109,11 @@ def main(): cmd = noext key = mapper(cmd) - if key not in ip.IP.alias_table: + if key not in ip.alias_table: # Dots will be removed from alias names, since ipython # assumes names with dots to be python code - ip.defalias(key.replace('.',''), cmd) + ip.define_alias(key.replace('.',''), cmd) # mglob combines 'find', recursion, exclusion... '%mglob?' to learn more ip.load("IPython.external.mglob") @@ -121,13 +122,13 @@ def main(): if sys.platform == 'win32': if 'cygwin' in os.environ['PATH'].lower(): # use the colors of cygwin ls (recommended) - ip.defalias('d', 'ls -F --color=auto') + ip.define_alias('d', 'ls -F --color=auto') else: # get icp, imv, imkdir, igrep, irm,... ip.load('ipy_fsops') # and the next best thing to real 'ls -F' - ip.defalias('d','dir /w /og /on') + ip.define_alias('d','dir /w /og /on') ip.set_hook('input_prefilter', slash_prefilter_f) extend_shell_behavior(ip) @@ -141,10 +142,10 @@ class LastArgFinder: ip = ipapi.get() if hist_idx is None: return str(self) - return ip.IP.input_hist_raw[hist_idx].strip().split()[-1] + return ip.input_hist_raw[hist_idx].strip().split()[-1] def __str__(self): ip = ipapi.get() - for cmd in reversed(ip.IP.input_hist_raw): + for cmd in reversed(ip.input_hist_raw): parts = cmd.strip().split() if len(parts) < 2 or parts[-1] in ['$LA', 'LA()']: continue @@ -159,7 +160,7 @@ def slash_prefilter_f(self,line): from IPython.utils import genutils if re.match('(?:[.~]|/[a-zA-Z_0-9]+)/', line): return "_ip.system(" + genutils.make_quoted_expr(line)+")" - raise ipapi.TryNext + raise TryNext # XXX You do not need to understand the next function! # This should probably be moved out of profile @@ -169,16 +170,16 @@ def extend_shell_behavior(ip): # Instead of making signature a global variable tie it to IPSHELL. # In future if it is required to distinguish between different # shells we can assign a signature per shell basis - ip.IP.__sig__ = 0xa005 + ip.__sig__ = 0xa005 # mark the IPSHELL with this signature - ip.IP.user_ns['__builtins__'].__dict__['__sig__'] = ip.IP.__sig__ + ip.user_ns['__builtins__'].__dict__['__sig__'] = ip.__sig__ from IPython.external.Itpl import ItplNS from IPython.utils.genutils import shell # utility to expand user variables via Itpl # xxx do something sensible with depth? - ip.IP.var_expand = lambda cmd, lvars=None, depth=2: \ - str(ItplNS(cmd, ip.IP.user_ns, get_locals())) + ip.var_expand = lambda cmd, lvars=None, depth=2: \ + str(ItplNS(cmd, ip.user_ns, get_locals())) def get_locals(): """ Substituting a variable through Itpl deep inside the IPSHELL stack @@ -194,7 +195,7 @@ def extend_shell_behavior(ip): getlvars = lambda fno: sys._getframe(fno+1).f_locals # trackback until we enter the IPSHELL frame_no = 1 - sig = ip.IP.__sig__ + sig = ip.__sig__ fsig = ~sig while fsig != sig : try: @@ -230,7 +231,7 @@ def extend_shell_behavior(ip): # We must start with a clean buffer, in case this is run from an # interactive IPython session (via a magic, for example). - ip.IP.resetbuffer() + ip.resetbuffer() lines = lines.split('\n') more = 0 command = '' @@ -251,9 +252,9 @@ def extend_shell_behavior(ip): command += line if command or more: # push to raw history, so hist line numbers stay in sync - ip.IP.input_hist_raw.append("# " + command + "\n") + ip.input_hist_raw.append("# " + command + "\n") - more = ip.IP.push(ip.IP.prefilter(command,more)) + more = ip.push_line(ip.prefilter(command,more)) command = '' # IPython's runsource returns None if there was an error # compiling the code. This allows us to stop processing right @@ -263,8 +264,8 @@ def extend_shell_behavior(ip): # final newline in case the input didn't have it, so that the code # actually does get executed if more: - ip.IP.push('\n') + ip.push_line('\n') - ip.IP.runlines = _runlines + ip.runlines = _runlines main() diff --git a/IPython/extensions/ipy_pydb.py b/IPython/extensions/ipy_pydb.py index 68fe930..278a336 100644 --- a/IPython/extensions/ipy_pydb.py +++ b/IPython/extensions/ipy_pydb.py @@ -18,13 +18,13 @@ def call_pydb(self, args): argl = arg_split(args) # print argl # dbg if len(inspect.getargspec(pydb.runv)[0]) == 2: - pdb = debugger.Pdb(color_scheme=self.rc.colors) - ip.IP.history_saving_wrapper( lambda : pydb.runv(argl, pdb) )() + pdb = debugger.Pdb(color_scheme=self.colors) + ip.history_saving_wrapper( lambda : pydb.runv(argl, pdb) )() else: - ip.IP.history_saving_wrapper( lambda : pydb.runv(argl) )() + ip.history_saving_wrapper( lambda : pydb.runv(argl) )() -ip.expose_magic("pydb",call_pydb) +ip.define_magic("pydb",call_pydb) diff --git a/IPython/extensions/ipy_rehashdir.py b/IPython/extensions/ipy_rehashdir.py index e3419ca..274c932 100644 --- a/IPython/extensions/ipy_rehashdir.py +++ b/IPython/extensions/ipy_rehashdir.py @@ -42,7 +42,7 @@ class PyLauncher: """ Invoke selflanucher on the specified script This is mostly useful for associating with scripts using:: - _ip.defalias('foo',PyLauncher('foo_script.py')) + _ip.define_alias('foo',PyLauncher('foo_script.py')) """ def __init__(self,script): @@ -137,4 +137,4 @@ def rehashdir_f(self,arg): os.chdir(savedir) return created -ip.expose_magic("rehashdir",rehashdir_f) +ip.define_magic("rehashdir",rehashdir_f) diff --git a/IPython/extensions/ipy_render.py b/IPython/extensions/ipy_render.py index 032d5ed..8aa1b72 100644 --- a/IPython/extensions/ipy_render.py +++ b/IPython/extensions/ipy_render.py @@ -64,5 +64,5 @@ def render(tmpl): toclip(res) return res -ip.to_user_ns('render') +ip.push('render') \ No newline at end of file diff --git a/IPython/extensions/ipy_signals.py b/IPython/extensions/ipy_signals.py index 8a152a3..3d7f072 100644 --- a/IPython/extensions/ipy_signals.py +++ b/IPython/extensions/ipy_signals.py @@ -55,7 +55,7 @@ def init(): o.allow_new_attr (True ) o.verbose = 0 - ip.IP.system = (sys.platform == 'win32' and new_ipsystem_win32 or + ip.system = (sys.platform == 'win32' and new_ipsystem_win32 or new_ipsystem_posix) init() diff --git a/IPython/extensions/ipy_traits_completer.py b/IPython/extensions/ipy_traits_completer.py index 80e1097..2dfe620 100644 --- a/IPython/extensions/ipy_traits_completer.py +++ b/IPython/extensions/ipy_traits_completer.py @@ -52,7 +52,8 @@ Notes from enthought.traits import api as T # IPython imports -from IPython.core.ipapi import TryNext, get as ipget +from IPython.core.error import TryNext +from IPython.core.ipapi import get as ipget from IPython.utils.genutils import dir2 try: set diff --git a/IPython/extensions/ipy_vimserver.py b/IPython/extensions/ipy_vimserver.py index bcb23ee..d055cd5 100644 --- a/IPython/extensions/ipy_vimserver.py +++ b/IPython/extensions/ipy_vimserver.py @@ -68,6 +68,7 @@ something. Instead of edit, use the vim magic. Thats it! """ from IPython.core import ipapi +from IPython.core.error import TryNext import socket, select import os, threading, subprocess @@ -161,7 +162,7 @@ def shutdown_server(self): if SERVER: SERVER.stop() SERVER.join(3) - raise ipapi.TryNext + raise TryNext ip.set_hook('shutdown_hook', shutdown_server, 10) @@ -235,5 +236,5 @@ def vim(self, argstr): argstr = 'edit -x ' + argstr ip.magic(argstr) -ip.expose_magic('vim', vim) +ip.define_magic('vim', vim) diff --git a/IPython/extensions/ipy_which.py b/IPython/extensions/ipy_which.py index e0380bd..efe7449 100644 --- a/IPython/extensions/ipy_which.py +++ b/IPython/extensions/ipy_which.py @@ -23,7 +23,7 @@ def which(fname): return def which_alias(fname): - for al, tgt in ip.IP.alias_table.items(): + for al, tgt in ip.alias_table.items(): if not (al == fname or fnmatch(al, fname)): continue if callable(tgt): @@ -72,5 +72,5 @@ def which_f(self, arg): for e in which(arg): print e -ip.expose_magic("which",which_f) +ip.define_magic("which",which_f) diff --git a/IPython/extensions/ipy_winpdb.py b/IPython/extensions/ipy_winpdb.py index 7c29af0..2150b17 100644 --- a/IPython/extensions/ipy_winpdb.py +++ b/IPython/extensions/ipy_winpdb.py @@ -22,6 +22,7 @@ For more details: https://bugs.launchpad.net/ipython/+bug/249036 import os from IPython.core import ipapi +from IPython.core.error import UsageError import rpdb2 ip = ipapi.get() @@ -58,7 +59,7 @@ def wdb_f(self, arg): path = os.path.abspath(arg) if not os.path.isfile(path): - raise ipapi.UsageError("%%wdb: file %s does not exist" % path) + raise UsageError("%%wdb: file %s does not exist" % path) if not rpdb_started: passwd = ip.db.get('winpdb_pass', None) if passwd is None: @@ -80,4 +81,4 @@ def wdb_f(self, arg): ip.magic('%run ' + arg) -ip.expose_magic('wdb', wdb_f) +ip.define_magic('wdb', wdb_f) diff --git a/IPython/extensions/ipy_workdir.py b/IPython/extensions/ipy_workdir.py index 852c33b..53d9105 100644 --- a/IPython/extensions/ipy_workdir.py +++ b/IPython/extensions/ipy_workdir.py @@ -40,4 +40,4 @@ def workdir_f(ip,line): finally: os.chdir(olddir) -ip.defalias("workdir",workdir_f) +ip.define_alias("workdir",workdir_f) diff --git a/IPython/extensions/jobctrl.py b/IPython/extensions/jobctrl.py index 2185bf4..8d1aa3a 100644 --- a/IPython/extensions/jobctrl.py +++ b/IPython/extensions/jobctrl.py @@ -48,6 +48,7 @@ import threading,Queue from IPython.utils import genutils from IPython.core import ipapi +from IPython.core.error import TryNext if os.name == 'nt': def kill_process(pid): @@ -123,12 +124,12 @@ def jobctrl_prefilter_f(self,line): if line.startswith('&'): pre,fn,rest = self.split_user_input(line[1:]) - line = ip.IP.expand_aliases(fn,rest) + line = ip.expand_aliases(fn,rest) if not _jobq: return '_ip.startjob(%s)' % genutils.make_quoted_expr(line) return '_ip.jobq(%s)' % genutils.make_quoted_expr(line) - raise ipapi.TryNext + raise TryNext def jobq_output_hook(self): if not _jobq: @@ -235,8 +236,8 @@ def install(): ip.startjob = startjob ip.set_hook('input_prefilter', jobctrl_prefilter_f) ip.set_hook('shell_hook', jobctrl_shellcmd) - ip.expose_magic('kill',magic_kill) - ip.expose_magic('tasks',magic_tasks) - ip.expose_magic('jobqueue',jobqueue_f) + ip.define_magic('kill',magic_kill) + ip.define_magic('tasks',magic_tasks) + ip.define_magic('jobqueue',jobqueue_f) ip.set_hook('pre_prompt_hook', jobq_output_hook) install() diff --git a/IPython/extensions/ledit.py b/IPython/extensions/ledit.py index a69acff..fa309b1 100644 --- a/IPython/extensions/ledit.py +++ b/IPython/extensions/ledit.py @@ -95,4 +95,4 @@ def line_edit_complete_f(self,event): ip.set_hook('complete_command', line_edit_complete_f , str_key = '%led') -ip.expose_magic('led', line_edit_f) \ No newline at end of file +ip.define_magic('led', line_edit_f) \ No newline at end of file diff --git a/IPython/extensions/pspersistence.py b/IPython/extensions/pspersistence.py index 5470750..c937b49 100644 --- a/IPython/extensions/pspersistence.py +++ b/IPython/extensions/pspersistence.py @@ -6,7 +6,7 @@ Stores variables, aliases etc. in PickleShare database. """ from IPython.core import ipapi -from IPython.core.ipapi import UsageError +from IPython.core.error import TryNext, UsageError ip = ipapi.get() import pickleshare @@ -20,7 +20,7 @@ def restore_aliases(self): for k,v in staliases.items(): #print "restore alias",k,v # dbg #self.alias_table[k] = v - ip.defalias(k,v) + ip.define_alias(k,v) def refresh_variables(ip): @@ -47,7 +47,7 @@ def restore_data(self): refresh_variables(ip) restore_aliases(self) restore_dhist(self) - raise ipapi.TryNext + raise TryNext ip.set_hook('late_startup_hook', restore_data) @@ -179,4 +179,4 @@ def magic_store(self, parameter_s=''): self.db[ 'autorestore/' + args[0] ] = obj print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__) -ip.expose_magic('store',magic_store) +ip.define_magic('store',magic_store) diff --git a/IPython/extensions/win32clip.py b/IPython/extensions/win32clip.py index bb5838e..8c836a0 100644 --- a/IPython/extensions/win32clip.py +++ b/IPython/extensions/win32clip.py @@ -42,4 +42,4 @@ def clip_f( self, parameter_s = '' ): print 'The following text was written to the clipboard' print val -ip.expose_magic( "clip", clip_f ) +ip.define_magic( "clip", clip_f ) diff --git a/IPython/external/mglob.py b/IPython/external/mglob.py index d2d81b1..1212c05 100755 --- a/IPython/external/mglob.py +++ b/IPython/external/mglob.py @@ -222,7 +222,7 @@ def mglob_f(self, arg): def init_ipython(ip): """ register %mglob for IPython """ mglob_f.__doc__ = globsyntax - ip.expose_magic("mglob",mglob_f) + ip.define_magic("mglob",mglob_f) # test() if __name__ == "__main__": diff --git a/IPython/frontend/prefilterfrontend.py b/IPython/frontend/prefilterfrontend.py index d7227cb..257669d 100644 --- a/IPython/frontend/prefilterfrontend.py +++ b/IPython/frontend/prefilterfrontend.py @@ -28,7 +28,6 @@ import re import __builtin__ from IPython.core.ipmaker import make_IPython -from IPython.core.ipapi import IPApi from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap @@ -112,7 +111,7 @@ class PrefilterFrontEnd(LineFrontEndBase): self.ipython0.set_hook('show_in_pager', lambda s, string: self.write("\n" + string)) self.ipython0.write = self.write - self._ip = _ip = IPApi(self.ipython0) + self._ip = _ip = self.ipython0 # Make sure the raw system call doesn't get called, as we don't # have a stdin accessible. self._ip.system = self.system_call diff --git a/IPython/frontend/tests/test_prefilterfrontend.py b/IPython/frontend/tests/test_prefilterfrontend.py index 4e1b05d..653b3e6 100644 --- a/IPython/frontend/tests/test_prefilterfrontend.py +++ b/IPython/frontend/tests/test_prefilterfrontend.py @@ -61,8 +61,8 @@ def isolate_ipython0(func): if ip0 is None: return func() # We have a real ipython running... - user_ns = ip0.IP.user_ns - user_global_ns = ip0.IP.user_global_ns + user_ns = ip0.user_ns + user_global_ns = ip0.user_global_ns # Previously the isolation was attempted with a deep copy of the user # dicts, but we found cases where this didn't work correctly. I'm not diff --git a/IPython/gui/wx/ipshell_nonblocking.py b/IPython/gui/wx/ipshell_nonblocking.py index 2fa6e6a..d4194d6 100644 --- a/IPython/gui/wx/ipshell_nonblocking.py +++ b/IPython/gui/wx/ipshell_nonblocking.py @@ -189,7 +189,7 @@ class NonBlockingIPShell(object): ip = ipapi.get() def bypass_magic(self, arg): print '%this magic is currently disabled.' - ip.expose_magic('cpaste', bypass_magic) + ip.define_magic('cpaste', bypass_magic) import __builtin__ __builtin__.raw_input = self._raw_input @@ -492,9 +492,9 @@ class NonBlockingIPShell(object): self._IP.showtraceback() else: self._IP.write(str(self._IP.outputcache.prompt_out).strip()) - self._iter_more = self._IP.push(line) + self._iter_more = self._IP.push_line(line) if (self._IP.SyntaxTB.last_syntax_error and \ - self._IP.rc.autoedit_syntax): + self._IP.autoedit_syntax): self._IP.edit_syntax_error() if self._iter_more: self._prompt = str(self._IP.outputcache.prompt2).strip() diff --git a/IPython/gui/wx/wxIPython.py b/IPython/gui/wx/wxIPython.py index f10d53a..9d70bd1 100644 --- a/IPython/gui/wx/wxIPython.py +++ b/IPython/gui/wx/wxIPython.py @@ -109,7 +109,7 @@ class MyFrame(wx.Frame): def optionSave(self, name, value): ip = get() - path = ip.IP.rc.ipythondir + path = ip.config.IPYTHONDIR opt = open(path + '/options.conf','w') try: @@ -126,7 +126,7 @@ class MyFrame(wx.Frame): def optionLoad(self): try: ip = get() - path = ip.IP.rc.ipythondir + path = ip.config.IPYTHONDIR opt = open(path + '/options.conf','r') lines = opt.readlines() opt.close() diff --git a/IPython/ipapi.py b/IPython/ipapi.py index 39c3427..8a4dd65 100644 --- a/IPython/ipapi.py +++ b/IPython/ipapi.py @@ -25,5 +25,5 @@ to use the new IPython.core.ipapi module""" warn(msg, category=DeprecationWarning, stacklevel=1) -from IPython.core.ipapi import * +from IPython.core.ipapi import get, launch_new_instance diff --git a/IPython/kernel/contexts.py b/IPython/kernel/contexts.py index 45eeb2b..2e9daa3 100644 --- a/IPython/kernel/contexts.py +++ b/IPython/kernel/contexts.py @@ -110,7 +110,7 @@ class RemoteContextBase(object): def _findsource_ipython(self,f): from IPython.core import ipapi self.ip = ipapi.get() - buf = self.ip.IP.input_hist_raw[-1].splitlines()[1:] + buf = self.ip.input_hist_raw[-1].splitlines()[1:] wsource = [l+'\n' for l in buf ] return strip_whitespace(wsource) diff --git a/IPython/kernel/core/prompts.py b/IPython/kernel/core/prompts.py index efd6aec..1759df7 100644 --- a/IPython/kernel/core/prompts.py +++ b/IPython/kernel/core/prompts.py @@ -29,7 +29,7 @@ from IPython.external.Itpl import ItplNS from IPython.utils import coloransi from IPython.core import release -from IPython.core.ipapi import TryNext +from IPython.core.error import TryNext from IPython.utils.genutils import * import IPython.utils.generics diff --git a/IPython/kernel/multiengineclient.py b/IPython/kernel/multiengineclient.py index 5058165..0f3b406 100644 --- a/IPython/kernel/multiengineclient.py +++ b/IPython/kernel/multiengineclient.py @@ -314,7 +314,7 @@ class InteractiveMultiEngineClient(object): from IPython.core import ipapi self.ip = ipapi.get() wsource = [l+'\n' for l in - self.ip.IP.input_hist_raw[-1].splitlines()[1:]] + self.ip.input_hist_raw[-1].splitlines()[1:]] return strip_whitespace(wsource) def __enter__(self): diff --git a/IPython/kernel/scripts/ipcluster.py b/IPython/kernel/scripts/ipcluster.py index e668519..6ffa396 100644 --- a/IPython/kernel/scripts/ipcluster.py +++ b/IPython/kernel/scripts/ipcluster.py @@ -39,7 +39,7 @@ from IPython.kernel.fcutil import have_crypto # Create various ipython directories if they don't exist. # This must be done before IPython.kernel.config is imported. -from IPython.core.iplib import user_setup +from IPython.core.oldusersetup import user_setup if os.name == 'posix': rc_suffix = '' else: diff --git a/IPython/kernel/scripts/ipcontroller.py b/IPython/kernel/scripts/ipcontroller.py index aa87cc0..3ab6175 100755 --- a/IPython/kernel/scripts/ipcontroller.py +++ b/IPython/kernel/scripts/ipcontroller.py @@ -41,7 +41,7 @@ from IPython.kernel.fcutil import check_furl_file_security # Create various ipython directories if they don't exist. # This must be done before IPython.kernel.config is imported. -from IPython.core.iplib import user_setup +from IPython.core.oldusersetup import user_setup from IPython.utils.genutils import get_ipython_dir, get_log_dir, get_security_dir if os.name == 'posix': rc_suffix = '' diff --git a/IPython/kernel/scripts/ipengine.py b/IPython/kernel/scripts/ipengine.py index 2210b11..9a41047 100755 --- a/IPython/kernel/scripts/ipengine.py +++ b/IPython/kernel/scripts/ipengine.py @@ -36,7 +36,7 @@ from IPython.kernel.engineservice import EngineService # Create various ipython directories if they don't exist. # This must be done before IPython.kernel.config is imported. -from IPython.core.iplib import user_setup +from IPython.core.oldusersetup import user_setup from IPython.utils.genutils import get_ipython_dir, get_log_dir, get_security_dir if os.name == 'posix': rc_suffix = '' diff --git a/IPython/lib/clipboard.py b/IPython/lib/clipboard.py index 89bf456..f42b93b 100644 --- a/IPython/lib/clipboard.py +++ b/IPython/lib/clipboard.py @@ -4,7 +4,7 @@ import subprocess import sys -from IPython.core.ipapi import TryNext +from IPython.core.error import TryNext def win32_clipboard_get(): diff --git a/IPython/scripts/ipython b/IPython/scripts/ipython index 0accfd4..a93e1de 100755 --- a/IPython/scripts/ipython +++ b/IPython/scripts/ipython @@ -23,6 +23,6 @@ this mode, there is no way to pass IPython any command-line options, as those are trapped first by Python itself. """ -import IPython.core.shell +import IPython.core.ipapi import launch_new_instance -IPython.core.shell.start().mainloop() +launch_new_instance() diff --git a/IPython/testing/plugin/ipdoctest.py b/IPython/testing/plugin/ipdoctest.py index 47ccb77..fb6394d 100644 --- a/IPython/testing/plugin/ipdoctest.py +++ b/IPython/testing/plugin/ipdoctest.py @@ -105,7 +105,7 @@ def _run_ns_sync(self,arg_s,runner=None): fname = arg_s finder = py_file_finder(fname) - out = _ip.IP.magic_run_ori(arg_s,runner,finder) + out = _ip.magic_run_ori(arg_s,runner,finder) # Simliarly, there is no test_globs when a test is NOT a doctest if hasattr(_run_ns_sync,'test_globs'): @@ -172,7 +172,7 @@ def start_ipython(): This is just a convenience function to replace the IPython system call with one that is more doctest-friendly. """ - cmd = _ip.IP.var_expand(cmd,depth=1) + cmd = _ip.var_expand(cmd,depth=1) sys.stdout.write(commands.getoutput(cmd)) sys.stdout.flush() @@ -184,8 +184,7 @@ def start_ipython(): argv = default_argv() # Start IPython instance. We customize it to start with minimal frills. - user_ns,global_ns = ipapi.make_user_namespaces(ipnsdict(),dict()) - IPython.shell.IPShell(argv,user_ns,global_ns) + IPython.shell.IPShell(argv,ipnsdict(),global_ns) # Deactivate the various python system hooks added by ipython for # interactive convenience so we don't confuse the doctest system @@ -204,16 +203,16 @@ def start_ipython(): _ip.system = xsys # Also patch our %run function in. - im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__) - _ip.IP.magic_run_ori = _ip.IP.magic_run - _ip.IP.magic_run = im + im = new.instancemethod(_run_ns_sync,_ip, _ip.__class__) + _ip.magic_run_ori = _ip.magic_run + _ip.magic_run = im # XXX - For some very bizarre reason, the loading of %history by default is # failing. This needs to be fixed later, but for now at least this ensures # that tests that use %hist run to completion. from IPython.core import history history.init_ipython(_ip) - if not hasattr(_ip.IP,'magic_history'): + if not hasattr(_ip,'magic_history'): raise RuntimeError("Can't load magics, aborting") @@ -437,8 +436,8 @@ class DocTestCase(doctests.DocTestCase): # for IPython examples *only*, we swap the globals with the ipython # namespace, after updating it with the globals (which doctest # fills with the necessary info from the module being tested). - _ip.IP.user_ns.update(self._dt_test.globs) - self._dt_test.globs = _ip.IP.user_ns + _ip.user_ns.update(self._dt_test.globs) + self._dt_test.globs = _ip.user_ns super(DocTestCase, self).setUp() @@ -539,7 +538,7 @@ class IPDocTestParser(doctest.DocTestParser): # and turned into lines, so it looks to the parser like regular user # input for lnum,line in enumerate(source.strip().splitlines()): - newline(_ip.IP.prefilter(line,lnum>0)) + newline(_ip.prefilter(line,lnum>0)) newline('') # ensure a closing newline, needed by doctest #print "PYSRC:", '\n'.join(out) # dbg return '\n'.join(out) diff --git a/IPython/utils/generics.py b/IPython/utils/generics.py index 38a592d..8ca605f 100644 --- a/IPython/utils/generics.py +++ b/IPython/utils/generics.py @@ -1,8 +1,8 @@ -''' 'Generic' functions for extending IPython. +"""Generic functions for extending IPython. See http://cheeseshop.python.org/pypi/simplegeneric. -Here is an example from genutils.py: +Here is an example from genutils.py:: def print_lsstring(arg): "Prettier (non-repr-like) and more informative printer for LSString" @@ -10,45 +10,34 @@ Here is an example from genutils.py: print arg print_lsstring = result_display.when_type(LSString)(print_lsstring) +""" -(Yes, the nasty syntax is for python 2.3 compatibility. Your own extensions -can use the niftier decorator syntax introduced in Python 2.4). -''' - -from IPython.core.ipapi import TryNext +from IPython.core.error import TryNext from IPython.external.simplegeneric import generic +@generic def result_display(result): - """ print the result of computation """ + """Print the result of computation.""" raise TryNext -result_display = generic(result_display) - +@generic def inspect_object(obj): - """ Called when you do obj? """ + """Called when you do obj?""" raise TryNext -inspect_object = generic(inspect_object) +@generic def complete_object(obj, prev_completions): - """ Custom completer dispatching for python objects - - obj is the object itself. - prev_completions is the list of attributes discovered so far. - + """Custom completer dispatching for python objects. + + Parameters + ---------- + obj : object + The object to complete. + prev_completions : list + List of attributes discovered so far. + This should return the list of attributes in obj. If you only wish to - add to the attributes already discovered normally, return + add to the attributes already discovered normally, return own_attrs + prev_completions. """ - raise TryNext -complete_object = generic(complete_object) - -#import os -#def my_demo_complete_object(obj, prev_completions): -# """ Demo completer that adds 'foobar' to the completions suggested -# for any object that has attribute (path), e.g. 'os'""" -# if hasattr(obj,'path'): -# return prev_completions + ['foobar'] -# raise TryNext -# -#my_demo_complete_object = complete_object.when_type(type(os))(my_demo_complete_object) diff --git a/IPython/utils/genutils.py b/IPython/utils/genutils.py index 28dcce9..9bf9d56 100644 --- a/IPython/utils/genutils.py +++ b/IPython/utils/genutils.py @@ -15,11 +15,7 @@ these things are also convenient when working at the command line. #**************************************************************************** # required modules from the Python standard library import __main__ -import commands -try: - import doctest -except ImportError: - pass + import os import platform import re @@ -27,7 +23,6 @@ import shlex import shutil import subprocess import sys -import tempfile import time import types import warnings @@ -46,14 +41,10 @@ else: # Other IPython utilities import IPython -from IPython.external.Itpl import Itpl,itpl,printpl +from IPython.external.Itpl import itpl,printpl from IPython.utils import platutils -from IPython.utils import DPyGetOpt from IPython.utils.generics import result_display -from IPython.core import ipapi from IPython.external.path import path -if os.name == "nt": - from IPython.utils.winconsole import get_console_size try: set @@ -642,215 +633,6 @@ def unquote_ends(istr): return istr #---------------------------------------------------------------------------- -def process_cmdline(argv,names=[],defaults={},usage=''): - """ Process command-line options and arguments. - - Arguments: - - - argv: list of arguments, typically sys.argv. - - - names: list of option names. See DPyGetOpt docs for details on options - syntax. - - - defaults: dict of default values. - - - usage: optional usage notice to print if a wrong argument is passed. - - Return a dict of options and a list of free arguments.""" - - getopt = DPyGetOpt.DPyGetOpt() - getopt.setIgnoreCase(0) - getopt.parseConfiguration(names) - - try: - getopt.processArguments(argv) - except DPyGetOpt.ArgumentError, exc: - print usage - warn('"%s"' % exc,level=4) - - defaults.update(getopt.optionValues) - args = getopt.freeValues - - return defaults,args - -#---------------------------------------------------------------------------- -def optstr2types(ostr): - """Convert a string of option names to a dict of type mappings. - - optstr2types(str) -> {None:'string_opts',int:'int_opts',float:'float_opts'} - - This is used to get the types of all the options in a string formatted - with the conventions of DPyGetOpt. The 'type' None is used for options - which are strings (they need no further conversion). This function's main - use is to get a typemap for use with read_dict(). - """ - - typeconv = {None:'',int:'',float:''} - typemap = {'s':None,'i':int,'f':float} - opt_re = re.compile(r'([\w]*)([^:=]*:?=?)([sif]?)') - - for w in ostr.split(): - oname,alias,otype = opt_re.match(w).groups() - if otype == '' or alias == '!': # simple switches are integers too - otype = 'i' - typeconv[typemap[otype]] += oname + ' ' - return typeconv - -#---------------------------------------------------------------------------- -def read_dict(filename,type_conv=None,**opt): - r"""Read a dictionary of key=value pairs from an input file, optionally - performing conversions on the resulting values. - - read_dict(filename,type_conv,**opt) -> dict - - Only one value per line is accepted, the format should be - # optional comments are ignored - key value\n - - Args: - - - type_conv: A dictionary specifying which keys need to be converted to - which types. By default all keys are read as strings. This dictionary - should have as its keys valid conversion functions for strings - (int,long,float,complex, or your own). The value for each key - (converter) should be a whitespace separated string containing the names - of all the entries in the file to be converted using that function. For - keys to be left alone, use None as the conversion function (only needed - with purge=1, see below). - - - opt: dictionary with extra options as below (default in parens) - - purge(0): if set to 1, all keys *not* listed in type_conv are purged out - of the dictionary to be returned. If purge is going to be used, the - set of keys to be left as strings also has to be explicitly specified - using the (non-existent) conversion function None. - - fs(None): field separator. This is the key/value separator to be used - when parsing the file. The None default means any whitespace [behavior - of string.split()]. - - strip(0): if 1, strip string values of leading/trailinig whitespace. - - warn(1): warning level if requested keys are not found in file. - - 0: silently ignore. - - 1: inform but proceed. - - 2: raise KeyError exception. - - no_empty(0): if 1, remove keys with whitespace strings as a value. - - unique([]): list of keys (or space separated string) which can't be - repeated. If one such key is found in the file, each new instance - overwrites the previous one. For keys not listed here, the behavior is - to make a list of all appearances. - - Example: - - If the input file test.ini contains (we put it in a string to keep the test - self-contained): - - >>> test_ini = '''\ - ... i 3 - ... x 4.5 - ... y 5.5 - ... s hi ho''' - - Then we can use it as follows: - >>> type_conv={int:'i',float:'x',None:'s'} - - >>> d = read_dict(test_ini) - - >>> sorted(d.items()) - [('i', '3'), ('s', 'hi ho'), ('x', '4.5'), ('y', '5.5')] - - >>> d = read_dict(test_ini,type_conv) - - >>> sorted(d.items()) - [('i', 3), ('s', 'hi ho'), ('x', 4.5), ('y', '5.5')] - - >>> d = read_dict(test_ini,type_conv,purge=True) - - >>> sorted(d.items()) - [('i', 3), ('s', 'hi ho'), ('x', 4.5)] - """ - - # starting config - opt.setdefault('purge',0) - opt.setdefault('fs',None) # field sep defaults to any whitespace - opt.setdefault('strip',0) - opt.setdefault('warn',1) - opt.setdefault('no_empty',0) - opt.setdefault('unique','') - if type(opt['unique']) in StringTypes: - unique_keys = qw(opt['unique']) - elif type(opt['unique']) in (types.TupleType,types.ListType): - unique_keys = opt['unique'] - else: - raise ValueError, 'Unique keys must be given as a string, List or Tuple' - - dict = {} - - # first read in table of values as strings - if '\n' in filename: - lines = filename.splitlines() - file = None - else: - file = open(filename,'r') - lines = file.readlines() - for line in lines: - line = line.strip() - if len(line) and line[0]=='#': continue - if len(line)>0: - lsplit = line.split(opt['fs'],1) - try: - key,val = lsplit - except ValueError: - key,val = lsplit[0],'' - key = key.strip() - if opt['strip']: val = val.strip() - if val == "''" or val == '""': val = '' - if opt['no_empty'] and (val=='' or val.isspace()): - continue - # if a key is found more than once in the file, build a list - # unless it's in the 'unique' list. In that case, last found in file - # takes precedence. User beware. - try: - if dict[key] and key in unique_keys: - dict[key] = val - elif type(dict[key]) is types.ListType: - dict[key].append(val) - else: - dict[key] = [dict[key],val] - except KeyError: - dict[key] = val - # purge if requested - if opt['purge']: - accepted_keys = qwflat(type_conv.values()) - for key in dict.keys(): - if key in accepted_keys: continue - del(dict[key]) - # now convert if requested - if type_conv==None: return dict - conversions = type_conv.keys() - try: conversions.remove(None) - except: pass - for convert in conversions: - for val in qw(type_conv[convert]): - try: - dict[val] = convert(dict[val]) - except KeyError,e: - if opt['warn'] == 0: - pass - elif opt['warn'] == 1: - print >>sys.stderr, 'Warning: key',val,\ - 'not found in file',filename - elif opt['warn'] == 2: - raise KeyError,e - else: - raise ValueError,'Warning level must be 0,1 or 2' - - return dict - -#---------------------------------------------------------------------------- def flag_calls(func): """Wrap a function to detect and flag when it gets called. @@ -1368,16 +1150,6 @@ def ask_yes_no(prompt,default=None): return answers[ans] #---------------------------------------------------------------------------- -def marquee(txt='',width=78,mark='*'): - """Return the input string centered in a 'marquee'.""" - if not txt: - return (mark*width)[:width] - nmark = (width-len(txt)-2)/len(mark)/2 - if nmark < 0: nmark =0 - marks = mark*nmark - return '%s %s %s' % (marks,txt,marks) - -#---------------------------------------------------------------------------- class EvalDict: """ Emulate a dict which evaluates its contents in the caller's frame. @@ -1530,267 +1302,6 @@ def native_line_ends(filename,backup=1): except: pass -#---------------------------------------------------------------------------- -def get_pager_cmd(pager_cmd = None): - """Return a pager command. - - Makes some attempts at finding an OS-correct one.""" - - if os.name == 'posix': - default_pager_cmd = 'less -r' # -r for color control sequences - elif os.name in ['nt','dos']: - default_pager_cmd = 'type' - - if pager_cmd is None: - try: - pager_cmd = os.environ['PAGER'] - except: - pager_cmd = default_pager_cmd - return pager_cmd - -#----------------------------------------------------------------------------- -def get_pager_start(pager,start): - """Return the string for paging files with an offset. - - This is the '+N' argument which less and more (under Unix) accept. - """ - - if pager in ['less','more']: - if start: - start_string = '+' + str(start) - else: - start_string = '' - else: - start_string = '' - return start_string - -#---------------------------------------------------------------------------- -# (X)emacs on W32 doesn't like to be bypassed with msvcrt.getch() -if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs': - import msvcrt - def page_more(): - """ Smart pausing between pages - - @return: True if need print more lines, False if quit - """ - Term.cout.write('---Return to continue, q to quit--- ') - ans = msvcrt.getch() - if ans in ("q", "Q"): - result = False - else: - result = True - Term.cout.write("\b"*37 + " "*37 + "\b"*37) - return result -else: - def page_more(): - ans = raw_input('---Return to continue, q to quit--- ') - if ans.lower().startswith('q'): - return False - else: - return True - -esc_re = re.compile(r"(\x1b[^m]+m)") - -def page_dumb(strng,start=0,screen_lines=25): - """Very dumb 'pager' in Python, for when nothing else works. - - Only moves forward, same interface as page(), except for pager_cmd and - mode.""" - - out_ln = strng.splitlines()[start:] - screens = chop(out_ln,screen_lines-1) - if len(screens) == 1: - print >>Term.cout, os.linesep.join(screens[0]) - else: - last_escape = "" - for scr in screens[0:-1]: - hunk = os.linesep.join(scr) - print >>Term.cout, last_escape + hunk - if not page_more(): - return - esc_list = esc_re.findall(hunk) - if len(esc_list) > 0: - last_escape = esc_list[-1] - print >>Term.cout, last_escape + os.linesep.join(screens[-1]) - -#---------------------------------------------------------------------------- -def page(strng,start=0,screen_lines=0,pager_cmd = None): - """Print a string, piping through a pager after a certain length. - - The screen_lines parameter specifies the number of *usable* lines of your - terminal screen (total lines minus lines you need to reserve to show other - information). - - If you set screen_lines to a number <=0, page() will try to auto-determine - your screen size and will only use up to (screen_size+screen_lines) for - printing, paging after that. That is, if you want auto-detection but need - to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for - auto-detection without any lines reserved simply use screen_lines = 0. - - If a string won't fit in the allowed lines, it is sent through the - specified pager command. If none given, look for PAGER in the environment, - and ultimately default to less. - - If no system pager works, the string is sent through a 'dumb pager' - written in python, very simplistic. - """ - - # Some routines may auto-compute start offsets incorrectly and pass a - # negative value. Offset to 0 for robustness. - start = max(0,start) - - # first, try the hook - ip = ipapi.get() - if ip: - try: - ip.IP.hooks.show_in_pager(strng) - return - except ipapi.TryNext: - pass - - # Ugly kludge, but calling curses.initscr() flat out crashes in emacs - TERM = os.environ.get('TERM','dumb') - if TERM in ['dumb','emacs'] and os.name != 'nt': - print strng - return - # chop off the topmost part of the string we don't want to see - str_lines = strng.split(os.linesep)[start:] - str_toprint = os.linesep.join(str_lines) - num_newlines = len(str_lines) - len_str = len(str_toprint) - - # Dumb heuristics to guesstimate number of on-screen lines the string - # takes. Very basic, but good enough for docstrings in reasonable - # terminals. If someone later feels like refining it, it's not hard. - numlines = max(num_newlines,int(len_str/80)+1) - - if os.name == "nt": - screen_lines_def = get_console_size(defaulty=25)[1] - else: - screen_lines_def = 25 # default value if we can't auto-determine - - # auto-determine screen size - if screen_lines <= 0: - if TERM=='xterm': - use_curses = USE_CURSES - else: - # curses causes problems on many terminals other than xterm. - use_curses = False - if use_curses: - # There is a bug in curses, where *sometimes* it fails to properly - # initialize, and then after the endwin() call is made, the - # terminal is left in an unusable state. Rather than trying to - # check everytime for this (by requesting and comparing termios - # flags each time), we just save the initial terminal state and - # unconditionally reset it every time. It's cheaper than making - # the checks. - term_flags = termios.tcgetattr(sys.stdout) - scr = curses.initscr() - screen_lines_real,screen_cols = scr.getmaxyx() - curses.endwin() - # Restore terminal state in case endwin() didn't. - termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags) - # Now we have what we needed: the screen size in rows/columns - screen_lines += screen_lines_real - #print '***Screen size:',screen_lines_real,'lines x',\ - #screen_cols,'columns.' # dbg - else: - screen_lines += screen_lines_def - - #print 'numlines',numlines,'screenlines',screen_lines # dbg - if numlines <= screen_lines : - #print '*** normal print' # dbg - print >>Term.cout, str_toprint - else: - # Try to open pager and default to internal one if that fails. - # All failure modes are tagged as 'retval=1', to match the return - # value of a failed system command. If any intermediate attempt - # sets retval to 1, at the end we resort to our own page_dumb() pager. - pager_cmd = get_pager_cmd(pager_cmd) - pager_cmd += ' ' + get_pager_start(pager_cmd,start) - if os.name == 'nt': - if pager_cmd.startswith('type'): - # The default WinXP 'type' command is failing on complex strings. - retval = 1 - else: - tmpname = tempfile.mktemp('.txt') - tmpfile = file(tmpname,'wt') - tmpfile.write(strng) - tmpfile.close() - cmd = "%s < %s" % (pager_cmd,tmpname) - if os.system(cmd): - retval = 1 - else: - retval = None - os.remove(tmpname) - else: - try: - retval = None - # if I use popen4, things hang. No idea why. - #pager,shell_out = os.popen4(pager_cmd) - pager = os.popen(pager_cmd,'w') - pager.write(strng) - pager.close() - retval = pager.close() # success returns None - except IOError,msg: # broken pipe when user quits - if msg.args == (32,'Broken pipe'): - retval = None - else: - retval = 1 - except OSError: - # Other strange problems, sometimes seen in Win2k/cygwin - retval = 1 - if retval is not None: - page_dumb(strng,screen_lines=screen_lines) - -#---------------------------------------------------------------------------- -def page_file(fname,start = 0, pager_cmd = None): - """Page a file, using an optional pager command and starting line. - """ - - pager_cmd = get_pager_cmd(pager_cmd) - pager_cmd += ' ' + get_pager_start(pager_cmd,start) - - try: - if os.environ['TERM'] in ['emacs','dumb']: - raise EnvironmentError - xsys(pager_cmd + ' ' + fname) - except: - try: - if start > 0: - start -= 1 - page(open(fname).read(),start) - except: - print 'Unable to show file',`fname` - - -#---------------------------------------------------------------------------- -def snip_print(str,width = 75,print_full = 0,header = ''): - """Print a string snipping the midsection to fit in width. - - print_full: mode control: - - 0: only snip long strings - - 1: send to page() directly. - - 2: snip long strings and ask for full length viewing with page() - Return 1 if snipping was necessary, 0 otherwise.""" - - if print_full == 1: - page(header+str) - return 0 - - print header, - if len(str) < width: - print str - snip = 0 - else: - whalf = int((width -5)/2) - print str[:whalf] + ' <...> ' + str[-whalf:] - snip = 1 - if snip and print_full == 2: - if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y': - page(str) - return snip - #**************************************************************************** # lists, dicts and structures @@ -2259,6 +1770,8 @@ def list_strings(arg): if isinstance(arg,basestring): return [arg] else: return arg + +#---------------------------------------------------------------------------- def marquee(txt='',width=78,mark='*'): """Return the input string centered in a 'marquee'. diff --git a/IPython/utils/platutils.py b/IPython/utils/platutils.py index ab5c2a7..2c3e52a 100644 --- a/IPython/utils/platutils.py +++ b/IPython/utils/platutils.py @@ -54,7 +54,6 @@ def toggle_set_term_title(val): def set_term_title(title): """Set terminal title using the necessary platform-dependent calls.""" - if _platutils.ignore_termtitle: return _platutils.set_term_title(title) diff --git a/IPython/utils/platutils_posix.py b/IPython/utils/platutils_posix.py index 3c38dba..a618d15 100644 --- a/IPython/utils/platutils_posix.py +++ b/IPython/utils/platutils_posix.py @@ -17,17 +17,18 @@ import os ignore_termtitle = True + def _dummy_op(*a, **b): """ A no-op function """ def _set_term_title_xterm(title): """ Change virtual terminal title in xterm-workalikes """ - sys.stdout.write('\033]0;%s\007' % title) +TERM = os.environ.get('TERM','') -if os.environ.get('TERM','') == 'xterm': +if (TERM == 'xterm') or (TERM == 'xterm-color'): set_term_title = _set_term_title_xterm else: set_term_title = _dummy_op diff --git a/IPython/utils/platutils_win32.py b/IPython/utils/platutils_win32.py index 9afc060..68e5017 100644 --- a/IPython/utils/platutils_win32.py +++ b/IPython/utils/platutils_win32.py @@ -26,6 +26,7 @@ try: """Set terminal title using ctypes to access the Win32 APIs.""" SetConsoleTitleW(title) + except ImportError: def set_term_title(title): """Set terminal title using the 'title' command.""" diff --git a/IPython/utils/traitlets.py b/IPython/utils/traitlets.py index 0b25b76..216df41 100644 --- a/IPython/utils/traitlets.py +++ b/IPython/utils/traitlets.py @@ -52,10 +52,15 @@ Authors: import inspect import sys import types -from types import InstanceType, ClassType, FunctionType +from types import ( + InstanceType, ClassType, FunctionType, + ListType, TupleType +) ClassTypes = (ClassType, type) +SequenceTypes = (ListType, TupleType) + #----------------------------------------------------------------------------- # Basic classes #----------------------------------------------------------------------------- @@ -858,4 +863,63 @@ class CBool(Bool): try: return bool(value) except: - self.error(obj, value) \ No newline at end of file + self.error(obj, value) + + +class Enum(TraitletType): + """An enum that whose value must be in a given sequence.""" + + def __init__(self, values, default_value=None, allow_none=True, **metadata): + self.values = values + self._allow_none = allow_none + super(Enum, self).__init__(default_value, **metadata) + + def validate(self, obj, value): + if value is None: + if self._allow_none: + return value + + if value in self.values: + return value + self.error(obj, value) + + def info(self): + """ Returns a description of the trait.""" + result = 'any of ' + repr(self.values) + if self._allow_none: + return result + ' or None' + return result + +class CaselessStrEnum(Enum): + """An enum of strings that are caseless in validate.""" + + def validate(self, obj, value): + if value is None: + if self._allow_none: + return value + + if not isinstance(value, str): + self.error(obj, value) + + for v in self.values: + if v.lower() == value.lower(): + return v + self.error(obj, value) + + +class List(Instance): + """An instance of a Python list.""" + + def __init__(self, default_value=None, allow_none=True, **metadata): + """Create a list traitlet type from a list or tuple. + + The default value is created by doing ``list(default_value)``, + which creates a copy of the ``default_value``. + """ + if default_value is None: + args = ((),) + elif isinstance(default_value, SequenceTypes): + args = (default_value,) + + super(List,self).__init__(klass=list, args=args, + allow_none=allow_none, **metadata)