From 8ce576641c4d1d244944fcb4c6b244efde4aa1df 2009-08-19 21:56:41 From: Brian Granger Date: 2009-08-19 21:56:41 Subject: [PATCH] Continuing a massive refactor of everything. --- diff --git a/IPython/__init__.py b/IPython/__init__.py index d44f528..f04897e 100644 --- a/IPython/__init__.py +++ b/IPython/__init__.py @@ -1,76 +1,50 @@ - # -*- 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,[]) -from IPython.core import shell -Shell = shell -from IPython.core import ipapi +# from IPython.core import shell +# Shell = shell from IPython.core import iplib + # 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/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/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/completer.py b/IPython/core/completer.py index 4b499b2..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) @@ -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 9cf898a..c0fc202 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 @@ -122,6 +123,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. @@ -170,6 +172,8 @@ class Component(HasTraitlets): 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/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/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 7c90676..199e36d 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,13 +41,13 @@ 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: >> @@ -83,7 +83,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): @@ -105,7 +105,7 @@ def fix_error_editor(self,filename,linenum,column,msg): 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() @@ -140,12 +140,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) @@ -214,14 +214,12 @@ def late_startup_hook(self): 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() """ @@ -231,7 +229,7 @@ def shell_hook(self,cmd): 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 diff --git a/IPython/core/ipapi.py b/IPython/core/ipapi.py index 0538056..739ee14 100644 --- a/IPython/core/ipapi.py +++ b/IPython/core/ipapi.py @@ -1,684 +1,61 @@ -"""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. - - return self.IP - - 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 +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- +from IPython.core.error import TryNext, UsageError +from IPython.core.component import Component +from warnings import warn -def make_user_namespaces(user_ns = None, user_global_ns = None): - """Return a valid local and global user interactive namespaces. +#----------------------------------------------------------------------------- +# Classes and functions +#----------------------------------------------------------------------------- - 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. +msg = """ +This module (IPython.core.ipapi) is being deprecated. For now, all we +offer here is the ``get`` function for getting the most recently created +InteractiveShell instance.""" - Raises TypeError if the provided globals namespace is not a true dict. +warn(msg, category=DeprecationWarning, stacklevel=1) - :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. - """ +def get(): + """Get the most recently created InteractiveShell instance.""" + insts = Component.get_instances(name='__IP') + most_recent = insts[0] + for inst in insts[1:]: + if inst.created > most_recent.created: + most_recent = inst + return most_recent.getapi() - 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/iplib.py b/IPython/core/iplib.py index 34c5742..b3b1712 100644 --- a/IPython/core/iplib.py +++ b/IPython/core/iplib.py @@ -34,17 +34,19 @@ import tempfile from IPython.core import ultratb from IPython.core import debugger, oinspect -from IPython.core import ipapi 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.fakemodule import FakeModule, init_fakemod_dict from IPython.core.logger import Logger from IPython.core.magic import Magic from IPython.core.prompts import CachedOutput +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 @@ -319,10 +321,6 @@ class InteractiveShell(Component, Magic): self.init_hooks() self.init_pushd_popd_magic() self.init_traceback_handlers(custom_exceptions) - - # Produce a public API instance - self.api = ipapi.IPApi(self) - self.init_namespaces() self.init_logger() self.init_aliases() @@ -343,7 +341,6 @@ class InteractiveShell(Component, Magic): self.init_magics() self.init_pdb() self.hooks.late_startup_hook() - self.init_exec_commands() #------------------------------------------------------------------------- # Traitlet changed handlers @@ -485,7 +482,7 @@ class InteractiveShell(Component, 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 @@ -576,6 +573,55 @@ class InteractiveShell(Component, Magic): 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() @@ -933,23 +979,55 @@ class InteractiveShell(Component, Magic): # 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 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_namespaces(self): """Initialize all user-visible namespaces to their minimum defaults. @@ -966,8 +1044,8 @@ class InteractiveShell(Component, 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 @@ -1015,10 +1093,9 @@ class InteractiveShell(Component, Magic): builtins_new = dict(__IPYTHON__ = self, ip_set_hook = self.set_hook, jobs = self.jobs, - ipmagic = wrap_deprecated(self.ipmagic,'_ip.magic()'), + # magic = self.magic, ipalias = wrap_deprecated(self.ipalias), - ipsystem = wrap_deprecated(self.ipsystem,'_ip.system()'), - #_ip = self.api + # ipsystem = wrap_deprecated(self.ipsystem,'_ip.system()'), ) for biname,bival in builtins_new.items(): try: @@ -1184,33 +1261,24 @@ class InteractiveShell(Component, 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] @@ -1227,6 +1295,44 @@ class InteractiveShell(Component, Magic): magic_args = self.var_expand(magic_args,1) return fn(magic_args) + 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.""" @@ -1280,7 +1386,16 @@ class InteractiveShell(Component, Magic): """Make a system call, using IPython.""" return self.hooks.shell_hook(self.var_expand(cmd, depth=2)) - ipsystem = system + 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 getoutput(self, cmd): return getoutput(self.var_expand(cmd,depth=2), @@ -1314,7 +1429,7 @@ class InteractiveShell(Component, 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'] """ @@ -1350,8 +1465,7 @@ class InteractiveShell(Component, 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. @@ -1365,7 +1479,20 @@ class InteractiveShell(Component, 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. @@ -1518,9 +1645,9 @@ class InteractiveShell(Component, 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() @@ -1535,14 +1662,14 @@ class InteractiveShell(Component, 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() @@ -1572,7 +1699,7 @@ class InteractiveShell(Component, 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 @@ -1686,7 +1813,7 @@ class InteractiveShell(Component, 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 @@ -1743,7 +1870,7 @@ class InteractiveShell(Component, Magic): This emulates Python's -c option.""" #sys.argv = ['-c'] - self.push(self.prefilter(self.c, False)) + self.push_line(self.prefilter(self.c, False)) if not self.interactive: self.ask_exit() @@ -1856,7 +1983,7 @@ class InteractiveShell(Component, 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.autoedit_syntax): self.edit_syntax_error() @@ -1951,7 +2078,7 @@ class InteractiveShell(Component, 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.autoedit_syntax): self.edit_syntax_error() @@ -1983,8 +2110,22 @@ class InteractiveShell(Component, 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: @@ -2091,18 +2232,114 @@ class InteractiveShell(Component, 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: @@ -2113,7 +2350,7 @@ class InteractiveShell(Component, Magic): 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)) + 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. @@ -2124,7 +2361,7 @@ class InteractiveShell(Component, Magic): # final newline in case the input didn't have it, so that the code # actually does get executed if more: - self.push('\n') + self.push_line('\n') def runsource(self, source, filename='', symbol='single'): """Compile and run some source in the interpreter. @@ -2232,7 +2469,7 @@ class InteractiveShell(Component, 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 @@ -2442,7 +2679,7 @@ class InteractiveShell(Component, 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, @@ -2510,7 +2747,7 @@ class InteractiveShell(Component, 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: @@ -2593,18 +2830,6 @@ class InteractiveShell(Component, 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.""" diff --git a/IPython/core/ipmaker.py b/IPython/core/ipmaker.py deleted file mode 100644 index 41af205..0000000 --- a/IPython/core/ipmaker.py +++ /dev/null @@ -1,793 +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.core.oldusersetup import user_setup -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): - user_setup(opts_all.ipythondir,rc_suffix,'install') - - # upgrade user config files while preserving a copy of the originals - if opts_all.upgrade: - 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 4500f4b..96634dc 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 #*************************************************************************** @@ -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?'. @@ -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('.') @@ -1571,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 @@ -2063,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, @@ -2393,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 @@ -2685,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)] @@ -2745,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) @@ -3439,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) 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/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 3735253..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 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/shell.py b/IPython/core/shell.py index 9507a12..8483199 100644 --- a/IPython/core/shell.py +++ b/IPython/core/shell.py @@ -150,8 +150,8 @@ class IPShellEmbed: embedded=True, user_ns=user_ns) - ip = ipapi.IPApi(self.IP) - ip.expose_magic("kill_embedded",kill_embedded) + ip = self.IP + ip.define_magic("kill_embedded",kill_embedded) # copy our own displayhook also self.sys_displayhook_embed = sys.displayhook 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 03173eb..c1b12c8 100644 --- a/IPython/core/tests/test_iplib.py +++ b/IPython/core/tests/test_iplib.py @@ -38,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 @@ -47,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 @@ -64,8 +62,8 @@ def test_user_setup(): 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 bbe324c..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.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/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 9a0f42b..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 @@ -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 @@ -175,9 +176,9 @@ def inote(ip,arg): 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 0d5fca9..278a336 100644 --- a/IPython/extensions/ipy_pydb.py +++ b/IPython/extensions/ipy_pydb.py @@ -19,12 +19,12 @@ def call_pydb(self, args): # print argl # dbg if len(inspect.getargspec(pydb.runv)[0]) == 2: pdb = debugger.Pdb(color_scheme=self.colors) - ip.IP.history_saving_wrapper( lambda : pydb.runv(argl, pdb) )() + 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 aeed11a..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,7 +492,7 @@ 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.autoedit_syntax): self._IP.edit_syntax_error() diff --git a/IPython/gui/wx/wxIPython.py b/IPython/gui/wx/wxIPython.py index 63c0e71..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.config.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.config.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..bfdbfdf 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 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/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..2b1083f 100755 --- a/IPython/scripts/ipython +++ b/IPython/scripts/ipython @@ -23,6 +23,7 @@ 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.ipapp import IPythonApp -IPython.core.shell.start().mainloop() +app = IPythonApp() +app.start() 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'.