diff --git a/IPython/Extensions/ipy_completers.py b/IPython/Extensions/ipy_completers.py index e5644cb..10ed5dc 100644 --- a/IPython/Extensions/ipy_completers.py +++ b/IPython/Extensions/ipy_completers.py @@ -211,10 +211,15 @@ def hg_completer(self,event): +__bzr_commands = None + def bzr_commands(): + global __bzr_commands + if __bzr_commands is not None: + return __bzr_commands out = os.popen('bzr help commands') - return [l.split()[0] for l in out] - + __bzr_commands = [l.split()[0] for l in out] + return __bzr_commands def bzr_completer(self,event): """ Completer for bazaar commands """ diff --git a/IPython/Extensions/ipy_leo.py b/IPython/Extensions/ipy_leo.py index 0380427..38cec27 100644 --- a/IPython/Extensions/ipy_leo.py +++ b/IPython/Extensions/ipy_leo.py @@ -10,6 +10,7 @@ import re import UserDict from IPython.ipapi import TryNext import IPython.macro +import IPython.Shell def init_ipython(ipy): """ This will be run by _ip.load('ipy_leo') @@ -19,6 +20,7 @@ def init_ipython(ipy): """ global ip ip = ipy + IPython.Shell.hijack_tk() ip.set_hook('complete_command', mb_completer, str_key = '%mb') ip.expose_magic('mb',mb_f) ip.expose_magic('lee',lee_f) diff --git a/IPython/Extensions/ipy_vimserver.py b/IPython/Extensions/ipy_vimserver.py new file mode 100644 index 0000000..f23b712 --- /dev/null +++ b/IPython/Extensions/ipy_vimserver.py @@ -0,0 +1,239 @@ +""" Integration with gvim, by Erich Heine + +Provides a %vim magic command, and reuses the same vim session. Uses +unix domain sockets for communication between vim and IPython. ipy.vim is +available in doc/examples of the IPython distribution. + +Slightly touched up email announcement (and description how to use it) by +Erich Heine is here: + +Ive recently been playing with ipython, and like it quite a bit. I did +however discover a bit of frustration, namely with editor interaction. +I am a gvim user, and using the command edit on a new file causes +ipython to try and run that file as soon as the text editor opens +up. The -x command of course fixes this, but its still a bit annoying, +switching windows to do a run file, then back to the text +editor. Being a heavy tab user in gvim, another annoyance is not being +able to specify weather a new tab is how I choose to open the file. + +Not being one to shirk my open source duties (and seeing this as a +good excuse to poke around ipython internals), Ive created a script +for having gvim and ipython work very nicely together. Ive attached +both to this email (hoping of course that the mailing list allows such +things). + +There are 2 files: + +ipy_vimserver.py -- this file contains the ipython stuff +ipy.vim -- this file contains the gvim stuff + +In combination they allow for a few functionalities: + +#1. the vim magic command. This is a fancy wrapper around the edit +magic, that allows for a new option, -t, which opens the text in a new +gvim tab. Otherwise it works the same as edit -x. (it internally +calls edit -x). This magic command also juggles vim server management, +so when it is called when there is not a gvim running, it creates a +new gvim instance, named after the ipython session name. Once such a +gvim instance is running, it will be used for subsequent uses of the +vim command. + +#2. ipython - gvim interaction. Once a file has been opened with the +vim magic (and a session set up, see below), pressing the F5 key in +vim will cause the calling ipython instance to execute run +filename.py. (if you typo like I do, this is very useful) + +#3. ipython server - this is a thread wich listens on a unix domain +socket, and runs commands sent to that socket. + +Note, this only works on POSIX systems, that allow for AF_UNIX type +sockets. It has only been tested on linux (a fairly recent debian +testing distro). + +To install it put, the ipserver.py in your favorite locaion for +sourcing ipython scripts. I put the ipy.vim in +~/.vim/after/ftplugin/python/. + +To use (this can be scripted im sure, but i usually have 2 or 3 +ipythons and corresponding gvims open): + +import ipy_vimserver +ipy_vimserver.setup('sessionname') + +(Editors note - you can probably add these to your ipy_user_conf.py) + +Then use ipython as you normally would, until you need to edit +something. Instead of edit, use the vim magic. Thats it! + +""" + +import IPython.ipapi +#import ipythonhooks +import socket, select +import os, threading, subprocess +import re + +ERRCONDS = select.POLLHUP|select.POLLERR +SERVER = None +ip = IPython.ipapi.get() + +# this listens to a unix domain socket in a separate thread, so that comms +# between a vim instance and ipython can happen in a fun and productive way +class IpyServer(threading.Thread): + def __init__(self, sname): + super(IpyServer, self).__init__() + self.keep_running = True + self.__sname = sname + self.socket = socket.socket(socket.AF_UNIX) + self.poller = select.poll() + self.current_conns = dict() + self.setDaemon(True) + + def listen(self): + self.socket.bind(self.__sname) + self.socket.listen(1) + + def __handle_error(self, socket): + if socket == self.socket.fileno(): + self.keep_running = False + for a in self.current_conns.values(): + a.close() + return False + else: + y = self.current_conns[socket] + del self.current_conns[socket] + y.close() + self.poller.unregister(socket) + + def serve_me(self): + self.listen() + self.poller.register(self.socket,select.POLLIN|ERRCONDS) + + while self.keep_running: + try: + avail = self.poller.poll(1) + except: + continue + + if not avail: continue + + for sock, conds in avail: + if conds & (ERRCONDS): + if self.__handle_error(sock): continue + else: break + + if sock == self.socket.fileno(): + y = self.socket.accept()[0] + self.poller.register(y, select.POLLIN|ERRCONDS) + self.current_conns[y.fileno()] = y + else: y = self.current_conns.get(sock) + + self.handle_request(y) + + os.remove(self.__sname) + + run = serve_me + + def stop(self): + self.keep_running = False + + def handle_request(self,sock): + sock.settimeout(1) + while self.keep_running: + try: + x = sock.recv(4096) + except socket.timeout: + pass + else: + break + self.do_it(x) + + def do_it(self, data): + data = data.split('\n') + cmds = list() + for line in data: + cmds.append(line) + ip.runlines(cmds) + + +# try to help ensure that the unix domain socket is cleaned up proper +def shutdown_server(self): + if SERVER: + SERVER.stop() + SERVER.join(3) + raise IPython.ipapi.TryNext + +ip.set_hook('shutdown_hook', shutdown_server, 10) + +# this fun function exists to make setup easier for all, and makes the +# vimhook function ready for instance specific communication +def setup(sessionname='',socketdir=os.path.expanduser('~/.ipython/')): + global SERVER + + if sessionname: + session = sessionname + elif os.environ.get('IPY_SESSION'): + session = os.environ.get('IPY_SESSION') + else: + session = 'IPYS' + vimhook.vimserver=session + vimhook.ipyserver = os.path.join(socketdir, session) + if not SERVER: + SERVER = IpyServer(vimhook.ipyserver) + SERVER.start() + + + +# calls gvim, with all ops happening on the correct gvim instance for this +# ipython instance. it then calls edit -x (since gvim will return right away) +# things of note: it sets up a special environment, so that the ipy.vim script +# can connect back to the ipython instance and do fun things, like run the file +def vimhook(self, fname, line): + env = os.environ.copy() + vserver = vimhook.vimserver.upper() + check = subprocess.Popen('gvim --serverlist', stdout = subprocess.PIPE, + shell=True) + check.wait() + cval = [l for l in check.stdout.readlines() if vserver in l] + + if cval: + vimargs = '--remote%s' % (vimhook.extras,) + else: + vimargs = '' + vimhook.extras = '' + + env['IPY_SESSION'] = vimhook.vimserver + env['IPY_SERVER'] = vimhook.ipyserver + + if line is None: line = '' + else: line = '+' + line + vim_cmd = 'gvim --servername %s %s %s %s' % (vimhook.vimserver, vimargs, + line, fname) + subprocess.call(vim_cmd, env=env, shell=True) + + +#default values to keep it sane... +vimhook.vimserver = '' +vimhook.ipyserver = '' + +ip.set_hook('editor',vimhook) + +# this is set up so more vim specific commands can be added, instead of just +# the current -t. all thats required is a compiled regex, a call to do_arg(pat) +# and the logic to deal with the new feature +newtab = re.compile(r'-t(?:\s|$)') +def vim(self, argstr): + def do_arg(pat, rarg): + x = len(pat.findall(argstr)) + if x: + a = pat.sub('',argstr) + return rarg, a + else: return '', argstr + + t, argstr = do_arg(newtab, '-tab') + vimhook.extras = t + argstr = 'edit -x ' + argstr + ip.magic(argstr) + +ip.expose_magic('vim', vim) + diff --git a/IPython/Release.py b/IPython/Release.py index 45b29ee..50094ad 100644 --- a/IPython/Release.py +++ b/IPython/Release.py @@ -22,9 +22,13 @@ name = 'ipython' # because bdist_rpm does not accept dashes (an RPM) convention, and # bdist_deb does not accept underscores (a Debian convention). -revision = '46' +revision = '57' +branch = 'ipython' -version = '0.8.3.bzr.r' + revision +if branch == 'ipython': + version = '0.8.3.bzr.r' + revision +else: + version = '0.8.3.bzr.r%s.%s' % (revision,branch) description = "An enhanced interactive Python shell." diff --git a/IPython/ipapi.py b/IPython/ipapi.py index 99f2fc1..307fe8c 100644 --- a/IPython/ipapi.py +++ b/IPython/ipapi.py @@ -275,11 +275,12 @@ class IPApi: lines = script.splitlines() level = 0 for l in lines: - stripped = l.lstrip() - if not l.strip(): + lstripped = l.lstrip() + stripped = l.strip() + if not stripped: continue - newlevel = len(l) - len(stripped) - if level > 0 and newlevel == 0: + newlevel = len(l) - len(lstripped) + if level > 0 and newlevel == 0 and not stripped.endswith(':'): # add empty line res.append('') res.append(l) diff --git a/doc/examples/ipy.vim b/doc/examples/ipy.vim new file mode 100644 index 0000000..cb05cf5 --- /dev/null +++ b/doc/examples/ipy.vim @@ -0,0 +1,67 @@ +if !exists("$IPY_SESSION") + finish +endif + +" set up the python interpreter within vim, to have all the right modules +" imported, as well as certain useful globals set +python import socket +python import os +python import vim +python IPYSERVER = None + +python << EOF +# do we have a connection to the ipython instance? +def check_server(): + global IPYSERVER + if IPYSERVER: + return True + else: + return False + +# connect to the ipython server, if we need to +def connect(): + global IPYSERVER + if check_server(): + return + try: + IPYSERVER = socket.socket(socket.AF_UNIX) + IPYSERVER.connect(os.environ.get('IPY_SERVER')) + except: + IPYSERVER = None + +def disconnect(): + if IPYSERVER: + IPYSERVER.close() + +def send(cmd): + x = 0 + while True: + x += IPYSERVER.send(cmd) + if x < len(cmd): + cmd = cmd[x:] + else: + break + +def run_this_file(): + if check_server(): + send('run %s' % (vim.current.buffer.name,)) + else: + raise Exception, "Not connected to an IPython server" +EOF + +fun! toggle_send_on_save() + if exists("s:ssos") && s:ssos == 1 + let s:ssos = 0 + au! BufWritePost *.py :py run_this_file() + echo "Autosend Off" + else + let s:ssos = 1 + au BufWritePost *.py :py run_this_file() + echo "Autowsend On" + endif +endfun + +map :python run_this_file() +imap a +map :call toggle_send_on_save() +py connect() diff --git a/doc/examples/leo_bridge_demo.leo b/doc/examples/leo_bridge_demo.leo index 8fbbb25..ca4aa17 100644 --- a/doc/examples/leo_bridge_demo.leo +++ b/doc/examples/leo_bridge_demo.leo @@ -3,7 +3,7 @@ - + @@ -25,7 +25,8 @@ @chapters -@settings +@settings +@@string ipython_argv = ipython -pylab @enabled-plugins @ipy-startup @@ -47,11 +48,16 @@ NewHeadline bar +pylab tests +Generate testarr +testarr +Call plotter on testarr + test stuff -@ipy-results +@ipy-results foo -spam +spam ? @@ -129,7 +135,14 @@ print "hello" def f(x): return x.upper() -f('hello world') +f('hello world') + +if 0: + print "foo" +else: + print "bar" + + @cl rfile hello @@ -495,5 +508,21 @@ Create 10 child nodes for baz, where i is headline and 'Hello ' + i is body: 12 +array([[ 0, 1, 2], + [ 3, 4, 5], + [ 6, 7, 8], + [ 9, 10, 11]]) +# press alt+i here to plot testarr + +plot(wb.testarr.v) + +Quickstart: + easy_install numpy + easy_install matplotlib + +Make sure you have '@string ipython-argv = ipython -pylab' in @settings. We currently recommend using TkAgg as the backend (it's also the default) +#press alt+i here to generate an array for plotter + +wb.testarr.v = arange(12).reshape(4,3) diff --git a/test/test_embed.py b/test/test_embed.py index 727a925..ad88343 100644 --- a/test/test_embed.py +++ b/test/test_embed.py @@ -15,7 +15,7 @@ import IPython.ipapi def test_session(shellclass): print "*****************\nLaunch shell for",shellclass my_ns = dict(a=10) - ses = IPython.ipapi.make_session(my_ns) + ses = IPython.ipapi.make_session(my_ns, shellclass=shellclass) # Now get the ipapi instance, to be stored somewhere in your program for manipulation of the running # IPython session. See http://ipython.scipy.org/moin/IpythonExtensionApi @@ -38,5 +38,11 @@ def test_session(shellclass): import IPython.Shell -test_session(shellclass = None) -test_session(IPython.Shell._select_shell(['ipython', '-q4thread'])) +def do_test(arg_line): + test_session(IPython.Shell._select_shell(arg_line.split())) + +do_test('') +do_test('ipython -gthread') +do_test('ipython -q4thread') +do_test('ipython -pylab') +do_test('ipython -pylab -gthread') \ No newline at end of file diff --git a/tools/make_tarball.py b/tools/make_tarball.py index 80bd309..7768bcd 100755 --- a/tools/make_tarball.py +++ b/tools/make_tarball.py @@ -1,12 +1,7 @@ import os,sys,shutil -repo = "http://ipython.scipy.org/svn/ipython/ipython/branches/0.7.3" -basename = 'ipython' -workdir = './mkdist' - -workdir = os.path.abspath(workdir) +basever = '0.8.3' -print "working at",workdir def oscmd(c): print ">",c s = os.system(c) @@ -14,15 +9,24 @@ def oscmd(c): print "Error",s sys.exit(s) +def verinfo(): + + out = os.popen('bzr version-info') + pairs = (l.split(':',1) for l in out) + d = dict(((k,v.strip()) for (k,v) in pairs)) + return d + +basename = 'ipython' + +#tarname = '%s.r%s.tgz' % (basename, ver) +oscmd('update_revnum.py') + +ver = verinfo() -assert not os.path.isdir(workdir) -os.mkdir(workdir) -os.chdir(workdir) +if ver['branch-nick'] == 'ipython': + tarname = 'ipython-%s.bzr.r%s.tgz' % (basever, ver['revno']) +else: + tarname = 'ipython-%s.bzr.r%s.%s.tgz' % (basever, ver['revno'], ver['branch-nick']) + +oscmd('bzr export ' + tarname) -oscmd('svn export %s %s' % (repo,basename)) -ver = os.popen('svnversion ../..').read().strip() -tarname = '%s.r%s.tgz' % (basename, ver) -oscmd('tar czvf ../%s %s' % (tarname, basename)) -print "Produced: ",os.path.abspath('../' + tarname) -os.chdir('/') -shutil.rmtree(workdir) diff --git a/tools/update_revnum.py b/tools/update_revnum.py index 87e4f0b..f97b933 100755 --- a/tools/update_revnum.py +++ b/tools/update_revnum.py @@ -2,13 +2,22 @@ """ Change the revision number in Release.py """ import os -import re +import re,pprint -rev = os.popen('bzr revno').read().strip() +def verinfo(): + + out = os.popen('bzr version-info') + pairs = (l.split(':',1) for l in out) + d = dict(((k,v.strip()) for (k,v) in pairs)) + return d -print "current rev is",rev -assert ':' not in rev +ver = verinfo() + +pprint.pprint(ver) rfile = open('../IPython/Release.py','rb').read() -newcont = re.sub(r'revision\s*=.*', "revision = '%s'" % rev, rfile) +newcont = re.sub(r'revision\s*=.*', "revision = '%s'" % ver['revno'], rfile) + +newcont = re.sub(r'^branch\s*=[^=].*', "branch = '%s'" % ver['branch-nick'], newcont ) + open('../IPython/Release.py','wb').write(newcont)