# python-startup.py # Author: Nathan Gray, based on interactive.py by Robin Friedrich and an # evil innate desire to customize things. # E-Mail: n8gray@caltech.edu # # Version: 0.6 # These modules are always nice to have in the namespace import sys, os ##### Some settings you may want to change ##### # Define the editor used by the edit() function. Try to use the editor # defined in the Unix environment, or default to vi if not set. # (patch due to Stephan Fiedler) # # %(lineno)s gets replaced by the line number. Ditto %(fname)s the filename EDITOR = os.environ.get('EDITOR', 'emacs') editorbase = EDITOR.split()[0] if editorbase in ['nedit', 'nc', 'ncl', 'emacs', 'emacsclient', 'xemacs'] : # We know these editors supoprt a linenumber argument EDITOR = EDITOR + ' +%(lineno)s %(fname)s &' elif editorbase in ['vi', 'vim', 'jed']: # Don't want to run vi in the background! # If your editor requires a terminal (e.g. joe) use this as a template EDITOR = 'xterm -e ' + EDITOR + ' +%(lineno)s %(fname)s &' else: # Guess that the editor only supports the filename EDITOR = EDITOR + ' %(fname)s &' del editorbase # The place to store your command history between sessions histfile=os.environ["HOME"] + "/python/.python-history" # Functions automatically added to the builtins namespace so that you can # use them in the debugger and other unusual environments autobuiltins = ['edit', 'which', 'ls', 'cd', 'mv', 'cp', 'rm', 'help', 'rmdir', 'ln', 'pwd', 'pushd', 'popd', 'env', 'mkdir'] ##### Now set up the interactive features that I like ##### # Colorize the prompts if possible (This is probably non-portable muck) # Thanks to Stephan Fiedler for the fix! if os.environ[ 'TERM' ] in [ 'xterm', 'vt100' ]: pre = chr(1) + "\033[1;32m" + chr(2) # Turn the text green suf = chr(1) + "\033[0m" + chr(2) # Reset to normal sys.ps1 = pre + ">>>" + suf + " " sys.ps2 = pre + "..." + suf + " " del pre, suf try: # Set up colorized tracebacks # Make sure to do this *before* installing LazyPython import ultraTB sys.excepthook = ultraTB.ColorTB() except ImportError: pass # LazyPython only works for Python versions 2.1 and above try: # Try to use LazyPython from LazyPython import LazyPython sys.excepthook = LazyPython() except ImportError: pass # Pretty-print at the command prompt for more readable dicts and lists. from pprint import pprint import __builtin__ def myhook(value, show=pprint, bltin=__builtin__): if value is not None: bltin._ = value show(value) sys.displayhook = myhook del __builtin__ try: # Try to set up command history completion/saving/reloading import readline, atexit, rlcompleter readline.parse_and_bind('tab: complete') try: readline.read_history_file(histfile) except IOError: pass # It doesn't exist yet. def savehist(): try: global histfile readline.write_history_file(histfile) except: print 'Unable to save Python command history' atexit.register(savehist) del atexit except ImportError: pass ##### Make reload work recursively ##### try: import __builtin__, deep_reload __builtin__.reload = deep_reload.reload del __builtin__, deep_reload except ImportError: pass # Make an "edit" command that sends you to the right file *and line number* # to edit a module, class, method, or function! # Note that this relies on my enhanced version of which(). def edit(object, editor=EDITOR): """Edit the source file from which a module, class, method, or function was imported. Usage: >>> edit(mysteryObject) """ if type(object) is type(""): fname = object; lineno = 1 print editor % locals() os.system( editor % locals() ) return ret = which(object) if not ret: print "Can't edit that!" return fname, lineno = ret if fname[-4:] == '.pyc' or fname[-4:] == '.pyo': fname = fname[:-1] print editor % locals() os.system( editor % locals() ) ############################################################################ # Below this is Robin Friedrich's interactive.py with some edits to decrease # namespace pollution and change the help functionality # NG # # Also enhanced 'which' to return filename/lineno # Patch from Stephan Fiedler to allow multiple args to ls variants # NG 10/21/01 -- Corrected a bug in _glob # ########################### interactive.py ########################### # """Functions for doing shellish things in Python interactive mode. # # Meant to be imported at startup via environment: # setenv PYTHONSTARTUP $HOME/easy.py # or # export PYTHONSTARTUP=$HOME/easy.py # # - Robin Friedrich # """ import shutil import glob import os import types try: from pydoc import help except ImportError: def help(*objects): """Print doc strings for object(s). Usage: >>> help(object, [obj2, objN]) (brackets mean [optional] argument) """ if len(objects) == 0: help(help) return for obj in objects: try: print '****', obj.__name__ , '****' print obj.__doc__ except AttributeError: print `obj`, 'has no __doc__ attribute' print home = os.path.expandvars('$HOME') def _glob(filenames): """Expand a filename or sequence of filenames with possible shell metacharacters to a list of valid filenames. Ex: _glob(('*.py*',)) == ['able.py','baker.py','charlie.py'] """ if type(filenames) is types.StringType: return glob.glob(filenames) flist = [] for filename in filenames: globbed = glob.glob(filename) if globbed: for file in globbed: flist.append(file) else: flist.append(filename) return flist def _expandpath(d): """Convert a relative path to an absolute path. """ return os.path.join(os.getcwd(), os.path.expandvars(d)) def _ls(options, *files): """ _ls(options, ['fname', ...']) Lists the given filenames, or the current directory if none are given, with the given options, which should be a string like '-lF'. """ if len(files) == 0 : args = os.curdir else : args = ' '.join(files) os.system('ls %s %s' % (options, args)) def ls(*files): """Same as 'ls -aF' Usage: >>> ls(['dirname', ...]) (brackets mean [optional] argument) """ _ls('-aF', *files) def ll(*files): """Same as 'ls -alF' Usage: >>> ll(['dirname', ...]) (brackets mean [optional] argument) """ _ls('-alF', *files) def lr(*files): """Recursive listing. same as 'ls -aRF' Usage: >>> lr(['dirname', ...]) (brackets mean [optional] argument) """ _ls('-aRF', *files) mkdir = os.mkdir def rm(*args): """Delete a file or files. Usage: >>> rm('file.c' [, 'file.h']) (brackets mean [optional] argument) Alias: delete """ filenames = _glob(args) for item in filenames: try: os.remove(item) except os.error, detail: print "%s: %s" % (detail[1], item) delete = rm def rmdir(directory): """Remove a directory. Usage: >>> rmdir('dirname') If the directory isn't empty, can recursively delete all sub-files. """ try: os.rmdir(directory) except os.error: #directory wasn't empty answer = raw_input(directory+" isn't empty. Delete anyway?[n] ") if answer and answer[0] in 'Yy': os.system('rm -rf %s' % directory) print directory + ' Deleted.' else: print directory + ' Unharmed.' def mv(*args): """Move files within a filesystem. Usage: >>> mv('file1', ['fileN',] 'fileordir') If two arguments - both must be files If more arguments - last argument must be a directory """ filenames = _glob(args) nfilenames = len(filenames) if nfilenames < 2: print 'Need at least two arguments' elif nfilenames == 2: try: os.rename(filenames[0], filenames[1]) except os.error, detail: print "%s: %s" % (detail[1], filenames[1]) else: for filename in filenames[:-1]: try: dest = filenames[-1]+'/'+filename if not os.path.isdir(filenames[-1]): print 'Last argument needs to be a directory' return os.rename(filename, dest) except os.error, detail: print "%s: %s" % (detail[1], filename) def cp(*args): """Copy files along with their mode bits. Usage: >>> cp('file1', ['fileN',] 'fileordir') If two arguments - both must be files If more arguments - last argument must be a directory """ filenames = _glob(args) nfilenames = len(filenames) if nfilenames < 2: print 'Need at least two arguments' elif nfilenames == 2: try: shutil.copy(filenames[0], filenames[1]) except os.error, detail: print "%s: %s" % (detail[1], filenames[1]) else: for filename in filenames[:-1]: try: dest = filenames[-1]+'/'+filename if not os.path.isdir(filenames[-1]): print 'Last argument needs to be a directory' return shutil.copy(filename, dest) except os.error, detail: print "%s: %s" % (detail[1], filename) def cpr(src, dst): """Recursively copy a directory tree to a new location Usage: >>> cpr('directory0', 'newdirectory') Symbolic links are copied as links not source files. """ shutil.copytree(src, dst) def ln(src, dst): """Create a symbolic link. Usage: >>> ln('existingfile', 'newlink') """ os.symlink(src, dst) def lnh(src, dst): """Create a hard file system link. Usage: >>> ln('existingfile', 'newlink') """ os.link(src, dst) def pwd(): """Print current working directory path. Usage: >>> pwd() """ print os.getcwd() cdlist = [home] def cd(directory = -1): """Change directory. Environment variables are expanded. Usage: cd('rel/$work/dir') change to a directory relative to your own cd('/abs/path') change to an absolute directory path cd() list directories you've been in cd(int) integer from cd() listing, jump to that directory """ global cdlist if type(directory) is types.IntType: if directory in range(len(cdlist)): cd(cdlist[directory]) return else: pprint(cdlist) return directory = _glob(directory)[0] if not os.path.isdir(directory): print `directory`+' is not a directory' return directory = _expandpath(directory) if directory not in cdlist: cdlist.append(directory) os.chdir(directory) def env(): """List environment variables. Usage: >>> env() """ #unfortunately environ is an instance not a dictionary envdict = {} for key, value in os.environ.items(): envdict[key] = value pprint(envdict) interactive_dir_stack = [] def pushd(directory=home): """Place the current dir on stack and change directory. Usage: >>> pushd(['dirname']) (brackets mean [optional] argument) pushd() goes home. """ global interactive_dir_stack interactive_dir_stack.append(os.getcwd()) cd(directory) def popd(): """Change to directory popped off the top of the stack. Usage: >>> popd() """ global interactive_dir_stack try: cd(interactive_dir_stack[-1]) print interactive_dir_stack[-1] del interactive_dir_stack[-1] except IndexError: print 'Stack is empty' def syspath(): """Print the Python path. Usage: >>> syspath() """ import sys pprint(sys.path) def which(object): """Print the source file from which a module, class, function, or method was imported. Usage: >>> which(mysteryObject) Returns: Tuple with (file_name, line_number) of source file, or None if no source file exists Alias: whence """ object_type = type(object) if object_type is types.ModuleType: if hasattr(object, '__file__'): print 'Module from', object.__file__ return (object.__file__, 1) else: print 'Built-in module.' elif object_type is types.ClassType: if object.__module__ == '__main__': print 'Built-in class or class loaded from $PYTHONSTARTUP' else: print 'Class', object.__name__, 'from', \ sys.modules[object.__module__].__file__ # Send you to the first line of the __init__ method return (sys.modules[object.__module__].__file__, object.__init__.im_func.func_code.co_firstlineno) elif object_type in (types.BuiltinFunctionType, types.BuiltinMethodType): print "Built-in or extension function/method." elif object_type is types.FunctionType: print 'Function from', object.func_code.co_filename return (object.func_code.co_filename, object.func_code.co_firstlineno) elif object_type is types.MethodType: print 'Method of class', object.im_class.__name__, 'from', fname = sys.modules[object.im_class.__module__].__file__ print fname return (fname, object.im_func.func_code.co_firstlineno) else: print "argument is not a module or function." return None whence = which # Automatically add some convenience functions to __builtin__ import __builtin__ for n in autobuiltins: exec '__builtin__.__dict__["%s"] = %s' % (n,n) in globals()