From e188ded31f23d13a5d376ae3c7f7db5dffd93de8 Mon Sep 17 00:00:00 2001 From: Robin Ramael Date: Fri, 7 Jan 2011 15:03:14 +0100 Subject: [PATCH] Added a python plugin, which adds, among others, command completion and editing commands in a texteditor to the python prompt the plugin sets a provided pythonrc file as the startupscript for the python cli. --- plugins/python/python.plugin.zsh | 17 +++ plugins/python/pythonrc.py | 196 +++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 plugins/python/python.plugin.zsh create mode 100644 plugins/python/pythonrc.py diff --git a/plugins/python/python.plugin.zsh b/plugins/python/python.plugin.zsh new file mode 100644 index 000000000..51c2fb466 --- /dev/null +++ b/plugins/python/python.plugin.zsh @@ -0,0 +1,17 @@ +# use the ./pythonrc.py file as the rc for the python +# this enables among other things: +# - command completion on , +# - prettyprinting of long variables +# - a colored prompt +# - editing commands in an editor with '\e' +# to change the editor: set the EDITOR env variable. + +PYTHONSTARTUP=$ZSH/plugins/python/pythonrc.py +export PYTHONSTARTUP + +#aliases +alias py=python +alias pytohn=python +alias pyton=python +alias py=python +alias py=python diff --git a/plugins/python/pythonrc.py b/plugins/python/pythonrc.py new file mode 100644 index 000000000..78badd9d7 --- /dev/null +++ b/plugins/python/pythonrc.py @@ -0,0 +1,196 @@ +# This is the python resource file used in the python-plugin for oh-my-zsh. +# It is executed when the Python interactive shell is started +# This file is is heavily based on the sontek's dotfiles, which can be found at https://github.com/sontek/dotfiles +# any files generated by this plugin should be contained within oh-my-zsh + +import sys +import os +import atexit +import pprint +from tempfile import mkstemp +from code import InteractiveConsole + +try: + import readline +except ImportError: + print("Module readline not available.") +else: + import rlcompleter + readline.parse_and_bind("tab: complete") + +ZSH_ROOT = os.environ.get("ZSH") +if not ZSH_ROOT: + sys.stderr.write("""Either oh-my-zsh is not installed, or the $ZSH variable was never set. + Check your zsh resource file or reinstall oh-my-zsh + If you want the features implented in this python resource without + oh-my-zsh, use the script this one was based off. It can be found at: + https://github.com/sontek/dotfiles/blob/master/_pythonrc.py + + exiting. """) + sys.exit() + + + +# Color Support +class TermColors(dict): + """Gives easy access to ANSI color codes. Attempts to fall back to no color + for certain TERM values. (Mostly stolen from IPython.)""" + # Todo: Make these compatible or at least the same as the ones in oh-my-zsh + + COLOR_TEMPLATES = ( + ("Black" , "0;30"), + ("Red" , "0;31"), + ("Green" , "0;32"), + ("Brown" , "0;33"), + ("Blue" , "0;34"), + ("Purple" , "0;35"), + ("Cyan" , "0;36"), + ("LightGray" , "0;37"), + ("DarkGray" , "1;30"), + ("LightRed" , "1;31"), + ("LightGreen" , "1;32"), + ("Yellow" , "1;33"), + ("LightBlue" , "1;34"), + ("LightPurple" , "1;35"), + ("LightCyan" , "1;36"), + ("White" , "1;37"), + ("Normal" , "0"), + ) + + NoColor = '' + _base = '\001\033[%sm\002' + + def __init__(self): + if os.environ.get('TERM') in ('xterm-color', 'xterm-256color', 'linux', + 'screenecho $TER', 'screen-256color', 'screen-bce'): + self.update(dict([(k, self._base % v) for k,v in self.COLOR_TEMPLATES])) + else: + self.update(dict([(k, self.NoColor) for k,v in self.COLOR_TEMPLATES])) +_c = TermColors() + +# Set a welcome message +WELCOME='%s(Tricked out by the python plugin for oh-my-zsh)%s' % (_c['LightBlue'], _c['Normal']) + + +# Enable a History +HISTFILE="%s/custom/.pyhistory.zsh" % ZSH_ROOT +# this has a .zsh extension so it will be ignored by git (only files with zsh are in the .gitignore) + +# Read the existing history if there is one +if os.path.exists(HISTFILE): + readline.read_history_file(HISTFILE) + +# Set maximum number of items that will be written to the history file +readline.set_history_length(300) + +def savehist(): + readline.write_history_file(HISTFILE) + +atexit.register(savehist) # save history at exit + +# Enable Color Prompts +sys.ps1 = '%s>>> %s' % (_c['Green'], _c['Normal']) +sys.ps2 = '%s... %s' % (_c['Red'], _c['Normal']) + + +def my_displayhook(value): + """Enable Pretty Printing for stdout: + this will hijack the way the python interpreter prints out long variables + >>> s = ["this is a very long element of a list", "and this is another one, which makes the list quite long"] + >>> s + ['this is a very long element of a list', + 'and this is another one, which makes the list quite long'] + """ + if value is not None: + try: + import __builtin__ + __builtin__._ = value + except ImportError: + __builtins__._ = value + + pprint.pprint(value) + +sys.displayhook = my_displayhook + +# TODO: move django functions to a separate plugin. + +# Django Helpers +def SECRET_KEY(): + "Generates a new SECRET_KEY that can be used in a project settings file." + + from random import choice + return ''.join( + [choice('abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)') + for i in range(50)]) + +# If we're working with a Django project, set up the environment +if 'DJANGO_SETTINGS_MODULE' in os.environ: + from django.db.models.loading import get_models + from django.test.client import Client + from django.test.utils import setup_test_environment, teardown_test_environment + from django.conf import settings as S + + class DjangoModels(object): + """Loop through all the models in INSTALLED_APPS and import them.""" + def __init__(self): + for m in get_models(): + setattr(self, m.__name__, m) + + A = DjangoModels() + C = Client() + + WELCOME += """%(Green)s + Django environment detected. +* Your INSTALLED_APPS models are available as `A`. +* Your project settings are available as `S`. +* The Django test client is available as `C`. +%(Normal)s""" % _c + + setup_test_environment() + S.DEBUG_PROPAGATE_EXCEPTIONS = True + + WELCOME += """%(LightPurple)s +Warning: the Django test environment has been set up; to restore the +normal environment call `teardown_test_environment()`. + +Warning: DEBUG_PROPAGATE_EXCEPTIONS has been set to True. +%(Normal)s""" % _c + +# Start an external editor with \e +# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/438813/ + +EDITOR = os.environ.get('EDITOR', failobj='vi') #get the editor, fail to vi +EDIT_CMD = '\e' +CD_COMMAND = "cd " + +class EditableBufferInteractiveConsole(InteractiveConsole): + def __init__(self, *args, **kwargs): + self.last_buffer = [] # This holds the last executed statement + InteractiveConsole.__init__(self, *args, **kwargs) + + def runsource(self, source, *args): + self.last_buffer = [ source.encode('latin-1') ] + return InteractiveConsole.runsource(self, source, *args) + + def raw_input(self, *args): + line = InteractiveConsole.raw_input(self, *args) + if line == EDIT_CMD: + fd, tmpfl = mkstemp('.py') + os.write(fd, b'\n'.join(self.last_buffer)) + os.close(fd) + os.system('%s %s' % (EDITOR, tmpfl)) + line = open(tmpfl).read() + os.unlink(tmpfl) + tmpfl = '' + lines = line.split( '\n' ) + for i in range(len(lines) - 1): self.push( lines[i] ) + line = lines[-1] + if line.startswith(CD_COMMAND): + return "os.chdir('%s')" % line.split()[1] + return line + +c = EditableBufferInteractiveConsole(locals=locals()) +c.interact(banner=WELCOME) + +# Exit the Python shell on exiting the InteractiveConsole +sys.exit()