#!/usr/bin/env python """ ipython -- An enhanced interactive Python Execution with automatic history (input and output), easier configuration, command completion, access to the shell and more. USAGE ipython [options] files If invoked with no options, it executes all the files listed in sequence and drops you into the interpreter. This behavior is different from standard Python, which when called as python -i only will execute one file and will ignore your configuration setup. OPTIONS All options can be abbreviated to their shortest non-ambiguous form and are case-sensitive. One or two dashes can be used. -help: print this help and exit. -config : load as your ipython config file. Normally ipython loads .ipythonrc (from current directory) or $HOME/.ipythonrc. If the loading of your config file fails, ipython starts with a bare bones configuration (no modules loaded at all). -profile : assume that your config file is .ipythonrc- (looks in current dir first, then in $HOME). This is a quick way to keep and load multiple config files for different tasks, especially if you use the include option of config files. You can keep a basic $HOME/.ipythonrc file and then have other 'profiles' which include this one and load extra things for particular tasks. You can turn ipython into an efficient interactive environment for a multitude of problems. For example: 1) ~/.ipythonrc : load basic things you always want. 2) ~.ipythonrc-calc : include (1) and load basic math-related modules. 3) ~.ipythonrc-math : include (2) and load Numeric and plotting modules. 4) ~.ipythonrc-text : include (1) and load re, string, other text modules. -log: generate a log file of all input. Defaults to .ipython.log You can use this to later restore a session by simply loading your logfile as a file to be executed. -Logfile : specify the name of your logfile. -session : you can restore a previous session by giving the name of a logfile as a parameter. In fact, if the logfile was created by ipython, just calling ipython should work, because ipython tags its logfiles so it can later recognize them and load them properly. But if you have a logfile which you've edited and ipython is having difficulty loading, using the -session switch will force ipython to try to load it 'safely'. -quick: start in bare bones mode (no config file loaded). -nonumbers: don't use numbered prompts but the regular '>>>' Python prompt instead. This also stops the dynamic cache with _p variables. Only _p, _pp and _ppp remain available. -nopprint: don't use the pprint pretty-printer module for displaying results, but instead use the regular 'print' builtin. pprint gives a nicer display of nested data structures. -Classic: same as -nonumbers -nopprint -quick. Gives ipython a similar feel to the classic Python prompt. Good for slow machines with very little memory. -debug: Show information about the loading process. Very useful to pin down problems with your configuration files. -exit: execute given files and exit (don't go to interactive prompt). This may be useful to run programs under a given configuration. -version: print version information and exit. """ # STATUS # ------ # This is an EARLY work in progress. I've brought code from Janko's ipp and # Nathan's pythonstartup into my ipython system. # IPP: 100% worked, I think, though no Class integration has been done. # Pythonstartup: only history and deep_reload so far. The fancy command-line # handling (LazyPython) seems to collide with IPP. Once the whole thing is # integrated we'll have a fabulous system! # Credits / Copyright: # Note that I (fperez) have used Janko's and Nathan's code *very* # liberally. This file is almost 100% my code, but I've messed quite a bit # with ipplib. Hopefully this is ok, I didn't find any licensing in their code # files. As long as we can keep this moving, I don't care about single/joint # copyrights, and I'm happy to oblige other's requests. # Fernando Pérez. # Janko Hauser # Nathan Gray # credits and copyright (preliminary, fix later) credits._Printer__data = '\nPython: '+credits._Printer__data+\ '\n\nipython: Fernando Pérez, Janko Hauser, Nathan Graham.' copyright._Printer__data += '\n\nCopyright (c) 2001 Fernando Pérez, Janko Hauser, Nathan Graham.\nAll Rights Reserved.' # This is what I put in all my files, change it later: #**************************************************************************** # Copyright (C) 2001 Fernando Pérez. # # Distributed under the terms of the GNU General Public License. # # The full text of the GPL is available at: # # http://www.gnu.org/copyleft/gpl.html #**************************************************************************** __author__ = 'Fernando Pérez. ' __version__= '0.4' #**************************************************************************** # Modules # Standard ones import __main__,sys,os from pprint import pprint # Homebrewed modules import ipythonlib,ipplib,DPyGetOpt from genutils import qw,qwflat,exc_info,Struct,list_strings,exclusive_opts # Recursive reload try: import __builtin__, deep_reload __builtin__.reload = deep_reload.reload del __builtin__, deep_reload except ImportError: pass #***************************************************************************** # Defaults and initialization # _ip is the main global that lives throughout and represents the whole # application. If the user rediefines it, all bets are off as to what happens. _ip = ipplib.InteractiveShell('_ip') _ip.BANNER = """ Python %s Type "copyright", "credits" or "license" for more information. ipython -- An enhanced interactive Python. Some useful commands: ? -> Quick help on the system. ? -> Help on a topic. help() -> Open Python's own built-in help system. @magic -> Information about ipython's 'magic' @ functions.""" % \ (sys.version.split('\n')[0],) _ip.usage = """\ ipython -- An enhanced interactive Python ----------------------------------------- ipython offers a combination of convenient shell features, special commands and a history mechanism for both input (command history) and output (results caching, similar to Mathematica). Warning: ipython relies on the existence of a global variable called _ip which controls the shell itself. If you redefine _ip to anything, bizarre behavior will quickly occur. Main features: - Readline support if present. - Completion in the local namespace, by typing TAB at the prompt. - Logging of input, see command-line options (use ipython -help) with the ability to fully save and later restore a working session. - Systemshell escape by the ! , eg !ls - Expansion of history lines by a starting '.' - Persistent command history across sessions. - deep_reload: a reload that works (just use the reload command, it's been replaced) - Magic commands: type @magic for information on the magic subsystem. - Numbered prompts (In/Out) with output caching similar to Mathematica. Only actions that produce a result (NOT assingments, for example) affect the counter and cache. - The following GLOBAL variables always exist (so don't overwrite them!): _p: stores previous result which generated printable output. _pp: next previous _ppp: next-next previous _ip.outcache: cache of all previous output. The data is stored in the member array entries[], indexed by prompt counter. - Additionally, global variables named _p are dynamically created ( being the prompt counter), such that the following is always true: _p == _outcache.entries[] E.g. the 4th result is available as _p4 or as _ip.outcache.entries[4]""" # Set these to the directory and the index file of the Python html docs. try: _ip.help_docpath = os.path.join(os.environ['PYTHONDOCS'],'lib') _ip.help_docindex = 'genindex.html' except: print 'You should set your environment variable PYTHONDOCS properly.' # make namespace cleanup easier later (just delete the temp _t) _t = Struct(home = os.environ['HOME'], # command history between sessions histfile = os.path.join(os.environ['HOME'],'.ipython-history'), # user config file rcfile = '.ipythonrc', # conversion functions to use when reading the config file typeconv = {int:'prompt_ini prompt_max pretty_print', qwflat:'modules modules_all functions execfiles include', ipythonlib.qw_lol:'modules_some', list_strings:'pycode' }) # build conflict resolver for recursive loading of config files: # I don't do it with lambdas b/c I need keys I can refer to later. def __keep_old(old,new): return old def __add(old,new): return old+new _t.conflict = {__keep_old:'prompt_ini prompt_max pretty_print', __add:'modules modules_all functions ' 'execfiles include modules_some pycode'} #----------------------------------------------------------------------------- # Command history completion/saving/reloading try: import readline, atexit readline.set_completer(_ip.Completer.complete) readline.parse_and_bind('tab: complete') # otherwise newbies will end up with a 10MB history after a while: readline.set_history_length(1000) _ip.histfile = _t.histfile # work with _ip b/c _t gets deleted try: readline.read_history_file(_ip.histfile) except IOError: pass # It doesn't exist yet. def savehist(): try: global _ip readline.write_history_file(_ip.histfile) except: print exc_info() print 'Unable to save Python command history to file:',_ip.histfile atexit.register(savehist) del atexit except ImportError: pass #----------------------------------------------------------------------------- # Command line handling # valid command line options (uses DPyGetOpt syntax, like Perl's GetOpt::Long) _t.opt_names = 'help exit log Logfile|L=s config_file=s profile=s '\ 'session=s debug quick nonumbers nopprint Classic version' # TODO: write an Options class to wrap all this into a clean interface. _t.getopt = DPyGetOpt.DPyGetOpt() _t.getopt.setIgnoreCase(0) _t.getopt.parseConfiguration(qw(_t.opt_names)) # Set default values for options _t.rcfile = ipythonlib.file_cwd_home(_t.rcfile) _t.opt_def = Struct(config_file = _t.rcfile) try: _t.getopt.processArguments(sys.argv) except: print __doc__ print '\n*** ERROR in Arguments *** ',sys.exc_value sys.exit() # convert the options dict to a struct for much lighter syntax later _t.opt = Struct(_t.getopt.optionValues) _t.args = _t.getopt.freeValues # exit options: if 'help' in _t.opt: print __doc__ sys.exit() if 'version' in _t.opt: print 'ipython version',__version__+'. An enhanced interactive Python.\n' sys.exit() # check mutually exclusive options: exclusive_opts(_t.opt,[qw('log Logfile'),qw('config_file profile')]) # merge defaults (merge does a safe update -- no key overwriting) _t.opt.merge(_t.opt_def) # this could be a bit less clumsy _ip.LOGDEF = '.ipython.log' _t.logfile = _t.opt.get('Logfile',_ip.LOGDEF) if 'log' in _t.opt or 'Logfile' in _t.opt: # Overwrite what's set in the rc file. _ip.LOG = _t.logfile _ip.logon(_ip.LOGHEAD) if 'profile' in _t.opt: _t.opt.config_file = ipythonlib.file_cwd_home('.ipythonrc-'+_t.opt.profile) #----------------------------------------------------------------------------- # Process user config files # this will be the main configuration structure (stays alive later) # initialize with defaults: _ip.rc = Struct(prompt_ini = 1, prompt_max = 300, pretty_print = 1, modules = [], modules_all = [], modules_some = [[]], functions = [], pycode = [], execfiles = [], config_file = _t.opt.config_file, log_file = _ip.LOG, include = [], histfile = _ip.histfile ) # load the config file if 'quick' in _t.opt: print 'Launching ipython in quick mode. No config file read.' elif 'Classic' in _t.opt: print 'Launching ipython in classic mode. No config file read.' _ip.rc.prompt_ini = _ip.rc.prompt_max = -1 _ip.rc.pretty_print = 0 else: try: _ip.rc.update(ipythonlib.load_config(_ip.rc.config_file,_t.typeconv, __conflict_solve=_t.conflict)) except: print exc_info() print 'Warning: Problems loading configuration file',_ip.rc.config_file print 'Starting with default -bare bones- configuration.' # reverse the loading lists so that things specified in outer files in an # include hierarchy are loaded later. This may be important in some cases # (Numeric must come after math, for example). for _t.key in qw(_t.conflict[__add]): _ip.rc[_t.key].reverse() if 'nonumbers' in _t.opt or _ip.rc.prompt_ini >= _ip.rc.prompt_max: _ip.rc.prompt_ini = _ip.rc.prompt_max = -1 if 'nopprint' in _t.opt: _ip.rc.pretty_print = 0 if 'debug' in _t.opt: 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__) #----------------------------------------------------------------------------- # Execute user config # cleanup global namespace a bit before loading user stuff. del DPyGetOpt,os,qw,qwflat,Struct,list_strings,exclusive_opts del __keep_old,__add # now run through the different sections of the users's config for _t.mod in _ip.rc.modules: try: exec 'import '+_t.mod except ImportError: print exc_info() ipythonlib.import_fail_info(_t.mod) for _t.mod_fn in _ip.rc.modules_some: if _t.mod_fn == []: break _t.mod,_t.fn = _t.mod_fn[0],' '.join(_t.mod_fn[1:]) try: exec 'from '+_t.mod+' import '+_t.fn except ImportError: print exc_info() ipythonlib.import_fail_info(_t.mod,_t.fn) for _t.mod in _ip.rc.modules_all: try: exec 'from '+_t.mod+' import *' except ImportError: print exc_info() ipythonlib.import_fail_info(_t.mod) for _t.fn in _ip.rc.functions: try: exec _t.fn+'()' except: print exc_info() print 'Failure executing function ',_t.fn for _t.code in _ip.rc.pycode: try: exec _t.code except: print exc_info() print 'Failure executing code: ',_t.code # 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! locals_ini = __main__.__dict__.copy() # trick to propagate this name through so it doesn't show up in @who locals_ini['locals_ini'] = 1 # key MUST be equal to the var. name # Execute the files the user wants in ipythonrc for _t.file in _ip.rc.execfiles: _ip.safe_execfile(_t.file,__main__.__dict__) #---------------------------------------------------------------------------- # 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. # Force reading a file as if it were a session log. Slower but safer. if 'session' in _t.opt: _ip.safe_execfile(_t.opt.session,__main__.__dict__,islog=1) # Load remaining files in command line if _t.args: for _t.run in _t.args: _ip.safe_execfile(_t.run,__main__.__dict__) if 'exit' in _t.opt: # No interactive session, just run the scripts given and leave. sys.exit() # Initialize cache, set in/out prompts and printing system _ip.outcache = ipythonlib.CachedOutput(_ip.rc.prompt_ini, _ip.rc.prompt_max, _ip.rc.pretty_print) sys.displayhook = _ip.outcache sys.ps1 = _ip.outcache.prompt1 sys.ps2 = _ip.outcache.prompt2 # more namespace cleanup del sys,ipythonlib,ipplib,_t # And finally, launch the interpreter. Tada!!! _ip.mainloop(local_1=locals_ini,local_2=__main__.__dict__) #--------------------------------------------------------------------------- # DON'T REMOVE foo(): # Xemacs goes crazy if there's not at least one def. Stupid, I know. # It seems to be a bug in the functions auto-parser. def _foo():pass ; del _foo #************************* end of file ***********************