Tests for various python features. vim: set ft=vim : NOTE: This will cause errors when run under valgrind. This would require recompiling Python with: ./configure --without-pymalloc See http://svn.python.org/view/python/trunk/Misc/README.valgrind?view=markup STARTTEST :so small.vim :if !has('python') | e! test.ok | wq! test.out | endif :lang C :py import vim :fun Test() :let l = [] :py l=vim.bindeval('l') :py f=vim.bindeval('function("strlen")') :" Extending List directly with different types :py l.extend([1, "as'd", [1, 2, f, {'a': 1}]]) :$put =string(l) :$put =string(l[-1]) :try : $put =string(l[-4]) :catch : $put =v:exception[:13] :endtry :" List assignment :py l[0]=0 :$put =string(l) :py l[-2]=f :$put =string(l) :" :" Extending Dictionary directly with different types :let d = {} py << EOF d=vim.bindeval('d') d['1']='asd' d.update(b=[1, 2, f]) d.update((('-1', {'a': 1}),)) d.update({'0': -1}) dk = d.keys() dv = d.values() di = d.items() dk.sort(key=repr) dv.sort(key=repr) di.sort(key=repr) EOF :$put =pyeval('repr(dk)') :$put =substitute(pyeval('repr(dv)'),'0x\x\+','','g') :$put =substitute(pyeval('repr(di)'),'0x\x\+','','g') :for [key, val] in sort(items(d)) : $put =string(key) . ' : ' . string(val) : unlet key val :endfor :" :" removing items with del :py del l[2] :$put =string(l) :let l = range(8) :py l=vim.bindeval('l') :try : py del l[:3] : py del l[1:] :catch : $put =v:exception :endtry :$put =string(l) :" :py del d['-1'] :$put =string(pyeval('d.get(''b'', 1)')) :$put =string(pyeval('d.pop(''b'')')) :$put =string(pyeval('d.get(''b'', 1)')) :$put =string(pyeval('d.pop(''1'', 2)')) :$put =string(pyeval('d.pop(''1'', 2)')) :$put =pyeval('repr(d.has_key(''0''))') :$put =pyeval('repr(d.has_key(''1''))') :$put =pyeval('repr(''0'' in d)') :$put =pyeval('repr(''1'' in d)') :$put =pyeval('repr(list(iter(d)))') :$put =string(d) :$put =pyeval('repr(d.popitem(''0''))') :$put =pyeval('repr(d.get(''0''))') :$put =pyeval('repr(list(iter(d)))') :" :" removing items out of range: silently skip items that don't exist :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :" The following two ranges delete nothing as they match empty list: :py del l[2:1] :$put =string(l) :py del l[2:2] :$put =string(l) :py del l[2:3] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py del l[2:4] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py del l[2:5] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py del l[2:6] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :" The following two ranges delete nothing as they match empty list: :py del l[-1:2] :$put =string(l) :py del l[-2:2] :$put =string(l) :py del l[-3:2] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py del l[-4:2] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py del l[-5:2] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py del l[-6:2] :$put =string(l) :" :" Slice assignment to a list :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py l[0:0]=['a'] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py l[1:2]=['b'] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py l[2:4]=['c'] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py l[4:4]=['d'] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py l[-1:2]=['e'] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py l[-10:2]=['f'] :$put =string(l) :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :py l[2:-10]=['g'] :$put =string(l) :let l = [] :py l=vim.bindeval('l') :py l[0:0]=['h'] :$put =string(l) :" :" Locked variables :let l = [0, 1, 2, 3] :py l=vim.bindeval('l') :lockvar! l :py l[2]='i' :$put =string(l) :unlockvar! l :" :" Function calls :function New(...) :return ['NewStart']+a:000+['NewEnd'] :endfunction :function DictNew(...) dict :return ['DictNewStart']+a:000+['DictNewEnd', self] :endfunction :let l=[function('New'), function('DictNew')] :py l=vim.bindeval('l') :py l.extend(list(l[0](1, 2, 3))) :$put =string(l) :py l.extend(list(l[1](1, 2, 3, self={'a': 'b'}))) :$put =string(l) :py l.extend([l[0].name]) :$put =string(l) :try : py l[1](1, 2, 3) :catch : $put =v:exception[:16] :endtry :delfunction New :try : py l[0](1, 2, 3) :catch : $put =v:exception[:16] :endtry :if has('float') : let l=[0.0] : py l=vim.bindeval('l') : py l.extend([0.0]) : $put =string(l) :else : $put ='[0.0, 0.0]' :endif :let messages=[] py < 8 # check if the background thread is working :$put =string(l) :" :" settrace :let l = [] :py l=vim.bindeval('l') :py <")') + ':BufFilePost:' + vim.eval('bufnr("%")')) : autocmd BufFilePre * python cb.append(vim.eval('expand("")') + ':BufFilePre:' + vim.eval('bufnr("%")')) :augroup END py << EOF cb = vim.current.buffer # Tests BufferAppend and BufferItem cb.append(b[0]) # Tests BufferSlice and BufferAssSlice cb.append('abc') # Will be overwritten cb[-1:] = b[:-2] # Test BufferLength and BufferAssSlice cb.append('def') # Will not be overwritten cb[len(cb):] = b[:] # Test BufferAssItem and BufferMark cb.append('ghi') # Will be overwritten cb[-1] = repr((len(cb) - cb.mark('a')[0], cb.mark('a')[1])) # Test BufferRepr cb.append(repr(cb) + repr(b)) # Modify foreign buffer b.append('foo') b[0]='bar' b[0:0]=['baz'] vim.command('call append("$", getbufline(%i, 1, "$"))' % b.number) # Test assigning to name property old_name = cb.name cb.name = 'foo' cb.append(cb.name[-11:]) b.name = 'bar' cb.append(b.name[-11:]) cb.name = old_name cb.append(cb.name[-17:]) # Test CheckBuffer for _b in vim.buffers: if _b is not cb: vim.command('bwipeout! ' + str(_b.number)) del _b cb.append('valid: b:%s, cb:%s' % (repr(b.valid), repr(cb.valid))) for expr in ('b[1]','b[:] = ["A", "B"]','b[:]','b.append("abc")', 'b.name = "!"'): try: exec(expr) except vim.error: pass else: # Usually a SEGV here # Should not happen in any case cb.append('No exception for ' + expr) vim.command('cd .') EOF :augroup BUFS : autocmd! :augroup END :augroup! BUFS :" :" Test vim.buffers object :set hidden :edit a :buffer # :edit b :buffer # :edit c :buffer # py << EOF try: from __builtin__ import next except ImportError: next = lambda o: o.next() # Check GCing iterator that was not fully exhausted i = iter(vim.buffers) cb.append('i:' + str(next(i))) # and also check creating more then one iterator at a time i2 = iter(vim.buffers) cb.append('i2:' + str(next(i2))) cb.append('i:' + str(next(i))) # The following should trigger GC and not cause any problems del i del i2 i3 = iter(vim.buffers) cb.append('i3:' + str(next(i3))) del i3 prevnum = 0 for b in vim.buffers: # Check buffer order if prevnum >= b.number: cb.append('!!! Buffer numbers not in strictly ascending order') # Check indexing: vim.buffers[number].number == number cb.append(str(b.number) + ':' + repr(vim.buffers[b.number]) + '=' + repr(b)) prevnum = b.number cb.append(str(len(vim.buffers))) bnums = list(map(lambda b: b.number, vim.buffers))[1:] # Test wiping out buffer with existing iterator i4 = iter(vim.buffers) cb.append('i4:' + str(next(i4))) vim.command('bwipeout! ' + str(bnums.pop(0))) try: next(i4) except vim.error: pass else: cb.append('!!!! No vim.error') i4 = iter(vim.buffers) vim.command('bwipeout! ' + str(bnums.pop(-1))) vim.command('bwipeout! ' + str(bnums.pop(-1))) cb.append('i4:' + str(next(i4))) try: next(i4) except StopIteration: cb.append('StopIteration') EOF :" :" Test vim.{tabpage,window}list and vim.{tabpage,window} objects :tabnew 0 :tabnew 1 :vnew a.1 :tabnew 2 :vnew a.2 :vnew b.2 :vnew c.2 py << EOF cb.append('Number of tabs: ' + str(len(vim.tabpages))) cb.append('Current tab pages:') def W(w): if repr(w).find('(unknown)') != -1: return '' else: return repr(w) start = len(cb) def Cursor(w): if w.buffer is cb: return repr((start - w.cursor[0], w.cursor[1])) else: return repr(w.cursor) for t in vim.tabpages: cb.append(' ' + repr(t) + '(' + str(t.number) + ')' + ': ' + str(len(t.windows)) + ' windows, current is ' + W(t.window)) cb.append(' Windows:') for w in t.windows: cb.append(' ' + W(w) + '(' + str(w.number) + ')' + ': displays buffer ' + repr(w.buffer) + '; cursor is at ' + Cursor(w)) # Other values depend on the size of the terminal, so they are checked partly: for attr in ('height', 'row', 'width', 'col'): try: aval = getattr(w, attr) if type(aval) is not long: raise TypeError if aval < 0: raise ValueError except Exception: cb.append('!!!!!! Error while getting attribute ' + attr + ': ' + sys.exc_type.__name__) w.cursor = (len(w.buffer), 0) cb.append('Number of windows in current tab page: ' + str(len(vim.windows))) if list(vim.windows) != list(vim.current.tabpage.windows): cb.append('!!!!!! Windows differ') EOF :" :" Test vim.current py << EOF def H(o): return repr(o) cb.append('Current tab page: ' + repr(vim.current.tabpage)) cb.append('Current window: ' + repr(vim.current.window) + ': ' + H(vim.current.window) + ' is ' + H(vim.current.tabpage.window)) cb.append('Current buffer: ' + repr(vim.current.buffer) + ': ' + H(vim.current.buffer) + ' is ' + H(vim.current.window.buffer)+ ' is ' + H(vim.current.tabpage.window.buffer)) # Assigning: fails try: vim.current.window = vim.tabpages[0].window except ValueError: cb.append('ValueError at assigning foreign tab window') for attr in ('window', 'tabpage', 'buffer'): try: setattr(vim.current, attr, None) except TypeError: cb.append('Type error at assigning None to vim.current.' + attr) # Assigning: success vim.current.tabpage = vim.tabpages[-2] vim.current.buffer = cb vim.current.window = vim.windows[0] vim.current.window.cursor = (len(vim.current.buffer), 0) cb.append('Current tab page: ' + repr(vim.current.tabpage)) cb.append('Current window: ' + repr(vim.current.window)) cb.append('Current buffer: ' + repr(vim.current.buffer)) cb.append('Current line: ' + repr(vim.current.line)) ws = list(vim.windows) ts = list(vim.tabpages) for b in vim.buffers: if b is not cb: vim.command('bwipeout! ' + str(b.number)) cb.append('w.valid: ' + repr([w.valid for w in ws])) cb.append('t.valid: ' + repr([t.valid for t in ts])) EOF :tabonly! :only! :" :" Test types py << EOF for expr, attr in ( ('vim.vars', 'Dictionary'), ('vim.options', 'Options'), ('vim.bindeval("{}")', 'Dictionary'), ('vim.bindeval("[]")', 'List'), ('vim.bindeval("function(\'tr\')")', 'Function'), ('vim.current.buffer', 'Buffer'), ('vim.current.range', 'Range'), ('vim.current.window', 'Window'), ('vim.current.tabpage', 'TabPage'), ): cb.append(expr + ':' + attr + ':' + repr(type(eval(expr)) is getattr(vim, attr))) EOF :" :" Test __dir__() method py << EOF for name, o in ( ('current', vim.current), ('buffer', vim.current.buffer), ('window', vim.current.window), ('tabpage', vim.current.tabpage), ('range', vim.current.range), ('dictionary', vim.bindeval('{}')), ('list', vim.bindeval('[]')), ('function', vim.bindeval('function("tr")')), ('output', sys.stdout), ): cb.append(name + ':' + ','.join(dir(o))) del name del o EOF :" :" Test vim.*.__new__ :$put =string(pyeval('vim.Dictionary({})')) :$put =string(pyeval('vim.Dictionary(a=1)')) :$put =string(pyeval('vim.Dictionary(((''a'', 1),))')) :$put =string(pyeval('vim.List()')) :$put =string(pyeval('vim.List(iter(''abc''))')) :" :" Test stdout/stderr :redir => messages :py sys.stdout.write('abc') ; sys.stdout.write('def') :py sys.stderr.write('abc') ; sys.stderr.write('def') :py sys.stdout.writelines(iter('abc')) :py sys.stderr.writelines(iter('abc')) :redir END :$put =string(substitute(messages, '\d\+', '', 'g')) :" Test subclassing py << EOF class DupDict(vim.Dictionary): def __setitem__(self, key, value): super(DupDict, self).__setitem__(key, value) super(DupDict, self).__setitem__('dup_' + key, value) dd = DupDict() dd['a'] = 'b' class DupList(vim.List): def __getitem__(self, idx): return [super(DupList, self).__getitem__(idx)] * 2 dl = DupList() dl2 = DupList(iter('abc')) dl.extend(dl2[0]) EOF :$put =string(sort(keys(pyeval('dd')))) :$put =string(pyeval('dl')) :$put =string(pyeval('dl2')) :" :" Test exceptions :fun Exe(e) : execute a:e :endfun py << EOF def ee(expr, g=globals(), l=locals()): try: exec(expr, g, l) except: cb.append(repr(sys.exc_info()[:2])) Exe = vim.bindeval('function("Exe")') ee('vim.command("throw \'abc\'")') ee('Exe("throw \'def\'")') ee('vim.eval("Exe(\'throw \'\'ghi\'\'\')")') ee('vim.eval("Exe(\'echoerr \'\'jkl\'\'\')")') ee('vim.eval("Exe(\'xxx_non_existent_command_xxx\')")') ee('vim.bindeval("Exe(\'xxx_non_existent_command_xxx\')")') EOF :endfun :" :call Test() :" :delfunc Test :call garbagecollect(1) :" :/^start:/,$wq! test.out :call getchar() ENDTEST start: