# To use this add: # import LazyPython # sys.excepthook = LazyPython.LazyPython() # # to your $PYTHONSTARTUP file import re, exceptions, traceback, sys, os # There's no version_info in 1.5.2. Use sys.version instead if sys.version[0:3] < '2.1': raise ImportError, 'Python Version 2.1 or above is required.' __author__ = "Nathaniel Gray " __version__ = '0.5.5' __date__ = "Sun Sep 30 15:38:50 PDT 2001" # This is deep, deep evil! I love it! _auto_quote_funcs_=['cd', 'cp', 'cpr', 'delete', 'll', 'ln', 'lnh', 'lr', 'ls', 'mkdir', 'mv', 'popd', 'pushd', 'rm', 'rmdir', 'who', 'whos', 'execfile'] _auto_paren_funcs_=[] _PAREN_ESCAPE = '/' _QUOTE_ESCAPE = ',' _SHELL_ESCAPE = '!' ##################################################################### ### You probably don't want to change things below here ##################################################################### _first_word_re_=re.compile(r'^[ \t]*[^ \t\n]+[ \t\n]') # All commands are evaluated in the interpreter's namespace _ns_ = sys.modules['__main__'].__dict__ class LazyPython: """ Lazy Python is an attempt to make interactive python less painful for lazy, lazy programmers. There are five ways (three, sir), ah yes, three ways that LazyPython does this: 1. Auto-Quoting Certain functions, methods, and other callables can be invoked with: >>> func arg1 arg2 arg3 and the input will be translated to this: --> func("arg1", "arg2", "arg3") The list of auto-quoted functions is in LazyPython and can be extended or altered. You can force auto-quoting by using ',' as the first character of a line. For example: >>> ,my_function /home/me # becomes my_function("/home/me") Note that the ',' MUST be the first character on the line! This won't work: >>> x = ,my_function /home/me # syntax error 2. Auto-Parenning Callable objects (i.e. functions, methods, etc) can be invoked like this (notice the commas between the arguments, unlike auto-quoting): >>> callable_ob arg1, arg2, arg3 and the input will be translated to this: --> callable_ob(arg1, arg2, arg3) You can force auto-parenning by using '/' as the first character of a line. For example: >>> /popd # becomes 'popd()' Note that the '/' MUST be the first character on the line! This won't work: >>> print /globals # syntax error 5. Shell-Escapes Any line that starts with '!' is treated as a shell escape. So if you want to copy a file you can type: >>> !cp file1.py file2.py Note that !cd /some/dir won't change the working directory of the Python interpreter. All shell escapes take place in a subshell that is immediately discarded. You have to use os.chdir or the cd convenience function to change the interpreter's directory. IMPORTANT NOTES ON USAGE: 1. The intent of this work is to make little functions like dir, pprint, and reload easier to use interactively. By design, these tricks only work in the interactive shell and only at the __main__ scope. DON'T USE THEM WHEN YOU WRITE SCRIPTS! 2. LazyPython tells you that it's altered your command line by displaying the new command line preceded by -->. e.g.: >>> ls research/results --> ls("research/results") The only exception is shell escapes. They are simply executed without printing anything. 5. LazyPython isn't triggered at all unless the command you enter would normally cause a SyntaxError. Here are some examples of commands that don't work because they aren't syntax errors: >>> ls /usr/local/lib # Looks like division >>> len [1,2,3,4] # Looks like indexing >>> zip (1,2,3), (4,5,6) # Looks like call + tuple construct In these cases you must force auto-quoting or auto-parenning with the appropriate escape character. 4. Whitespace is more important than usual (even for Python ;^)! The function name must have some trailing whitespace and arguments to auto-quote functions cannot have embedded whitespace. >>> ls pathname/with whitespace becomes --> ls("pathname/with", "whitespace") and >>> len"something" causes a SyntaxError. >>> /zip (1,2,3), (4,5,6) # Works But >>> /zip(1,2,3), (4,5,6) # Fails --> zip(1,2,3),((4,5,6)) Just remember to always put a space after your function name and you'll be fine. If you need whitespace in an auto-quote function's argument I'm afraid you're just going to have to write your function call out the old-fashioned way, ya lazy bum. Current Auto-Quote Functions: cd, cp, cpr, delete, execfile, ll, ln, lnh, lr, ls, mkdir, mv, popd, pushd, rm, rmdir, who, whos To extend this list for the current session, type: >>> LazyPython._auto_quote_funcs_.append('funcname') To permanently alter this list, edit LazyPython.py Note that the characters used as escapes (!,/,,) can be changed by editing LazyPython.py """ def __init__(self): # Save the original excepthook for use when there *is* an error self._orig_ehook = sys.excepthook def uninstall(self): sys.excepthook = self._orig_ehook print "LazyPython uninstalled" def __call__(self, tp, val, argin3): global _auto_quote_funcs_ # We only handle SyntaxErrors if not isinstance(val, exceptions.SyntaxError): self._orig_ehook(tp,val,argin3) return # Complain if we're not at the top level if (val.text[0]).isspace(): raise RuntimeError, \ "LazyPython shortcuts do not work in loops or functions." # Test for shell escape if val.text[0] == _SHELL_ESCAPE: os.system(val.text[1:]) return # 0 -> normal exception, 1 -> auto-quote, 2 -> auto-paren lp_mode = 0 iFun = _first_word_re_.match(val.text) if iFun is None: #Hard to see how this could happen, but just in case self._orig_ehook(tp,val,argin3) return iFun = iFun.group(0)[:-1] if val.text[0] == _PAREN_ESCAPE: # Check for the auto-paren escape lp_mode = 2 iFun = iFun[1:] text = val.text[1:] elif val.text[0] == _QUOTE_ESCAPE: # Check for the auto-quote escape lp_mode = 1 iFun = iFun[1:] text = val.text[1:] else: # See if it's an auto-quote/paren function or a callable text = val.text if iFun in _auto_quote_funcs_: lp_mode = 1 elif iFun in _auto_paren_funcs_: lp_mode = 2 else: try: if callable( eval(iFun, _ns_) ): lp_mode = 2 except: lp_mode = 0 # Now decide what to do based on lp_mode if lp_mode == 0: # Normal Exception self._orig_ehook(tp,val,argin3) return if lp_mode == 1: theRest = text[len(iFun):].strip() # Auto-quote newcmd = iFun + '("' + '", "'.join(theRest.split()) + '")\n' elif lp_mode == 2: # Auto-paren #newcmd = iFun + '(' + ','.join(theRest.split()) + ')\n' theRest = text[len(iFun):].strip() newcmd = iFun + '(' + theRest + ')\n' elif lp_mode == 3: pass # newcmd has already been set else: raise RuntimeError, 'Error in LazyPython.py! Illegal lp_mode.' # Try to execute the new command try: print '-->', newcmd sys.displayhook( eval( newcmd, _ns_ ) ) #exec newcmd in _ns_ except: traceback.print_exc() print 'Welcome to Lazy Python. Type "help LazyPython" for help.'