# HG changeset patch # User Bram Moolenaar # Date 1369161640 -7200 # Node ID ef02f32d8e53a7b3d7327ac79359a18070e4a101 # Parent 51bae43f1787ec0ce18a5b53240d70ea92f149f8 updated for version 7.3.997 Problem: Vim and Python exceptions are different. Solution: Make Vim exceptions be Python exceptions. (ZyX) diff --git a/src/if_py_both.h b/src/if_py_both.h --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -272,20 +272,42 @@ static PyObject *VimError; /* Check to see whether a Vim error has been reported, or a keyboard * interrupt has been detected. */ + + static void +VimTryStart(void) +{ + ++trylevel; +} + static int -VimErrorCheck(void) +VimTryEnd(void) +{ + --trylevel; + if (got_int) + { + PyErr_SetNone(PyExc_KeyboardInterrupt); + return 1; + } + else if (!did_throw) + return 0; + else if (PyErr_Occurred()) + return 1; + else + { + PyErr_SetVim((char *) current_exception->value); + discard_current_exception(); + return 1; + } +} + + static int +VimCheckInterrupt(void) { if (got_int) { PyErr_SetNone(PyExc_KeyboardInterrupt); return 1; } - else if (did_emsg && !PyErr_Occurred()) - { - PyErr_SetNone(VimError); - return 1; - } - return 0; } @@ -306,17 +328,19 @@ VimCommand(PyObject *self UNUSED, PyObje Py_BEGIN_ALLOW_THREADS Python_Lock_Vim(); + VimTryStart(); do_cmdline_cmd((char_u *)cmd); update_screen(VALID); Python_Release_Vim(); Py_END_ALLOW_THREADS - if (VimErrorCheck()) + if (VimTryEnd()) result = NULL; else result = Py_None; + Py_XINCREF(result); return result; } @@ -449,11 +473,14 @@ VimEval(PyObject *self UNUSED, PyObject Py_BEGIN_ALLOW_THREADS Python_Lock_Vim(); + VimTryStart(); our_tv = eval_expr((char_u *)expr, NULL); - Python_Release_Vim(); Py_END_ALLOW_THREADS + if (VimTryEnd()) + return NULL; + if (our_tv == NULL) { PyErr_SetVim(_("invalid expression")); @@ -490,11 +517,14 @@ VimEvalPy(PyObject *self UNUSED, PyObjec Py_BEGIN_ALLOW_THREADS Python_Lock_Vim(); + VimTryStart(); our_tv = eval_expr((char_u *)expr, NULL); - Python_Release_Vim(); Py_END_ALLOW_THREADS + if (VimTryEnd()) + return NULL; + if (our_tv == NULL) { PyErr_SetVim(_("invalid expression")); @@ -1324,12 +1354,15 @@ FunctionCall(FunctionObject *self, PyObj Py_BEGIN_ALLOW_THREADS Python_Lock_Vim(); + VimTryStart(); error = func_call(name, &args, selfdict, &rettv); Python_Release_Vim(); Py_END_ALLOW_THREADS - if (error != OK) + if (VimTryEnd()) + result = NULL; + else if (error != OK) { result = NULL; PyErr_SetVim(_("failed to run function")); @@ -1486,14 +1519,16 @@ set_option_value_for(key, numval, string win_T *save_curwin; tabpage_T *save_curtab; buf_T *save_curbuf; - int r = 0; - + + VimTryStart(); switch (opt_type) { case SREQ_WIN: if (switch_win(&save_curwin, &save_curtab, (win_T *)from, win_find_tabpage((win_T *)from)) == FAIL) { + if (VimTryEnd()) + return -1; PyErr_SetVim("Problem while switching windows."); return -1; } @@ -1509,7 +1544,7 @@ set_option_value_for(key, numval, string set_option_value(key, numval, stringval, opt_flags); break; } - return r; + return VimTryEnd(); } static int @@ -1961,7 +1996,7 @@ WindowSetattr(WindowObject *self, char * } /* Check for keyboard interrupts */ - if (VimErrorCheck()) + if (VimCheckInterrupt()) return -1; self->win->w_cursor.lnum = lnum; @@ -1988,11 +2023,11 @@ WindowSetattr(WindowObject *self, char * #endif savewin = curwin; curwin = self->win; + + VimTryStart(); win_setheight(height); curwin = savewin; - - /* Check for keyboard interrupts */ - if (VimErrorCheck()) + if (VimTryEnd()) return -1; return 0; @@ -2011,11 +2046,11 @@ WindowSetattr(WindowObject *self, char * #endif savewin = curwin; curwin = self->win; + + VimTryStart(); win_setwidth(width); curwin = savewin; - - /* Check for keyboard interrupts */ - if (VimErrorCheck()) + if (VimTryEnd()) return -1; return 0; @@ -2304,6 +2339,8 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj PyErr_Clear(); switch_buffer(&savebuf, buf); + VimTryStart(); + if (u_savedel((linenr_T)n, 1L) == FAIL) PyErr_SetVim(_("cannot save undo information")); else if (ml_delete((linenr_T)n, FALSE) == FAIL) @@ -2317,7 +2354,7 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj restore_buffer(savebuf); - if (PyErr_Occurred() || VimErrorCheck()) + if (VimTryEnd()) return FAIL; if (len_change) @@ -2333,6 +2370,8 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj if (save == NULL) return FAIL; + VimTryStart(); + /* We do not need to free "save" if ml_replace() consumes it. */ PyErr_Clear(); switch_buffer(&savebuf, buf); @@ -2356,7 +2395,7 @@ SetBufferLine(buf_T *buf, PyInt n, PyObj if (buf == savebuf) check_cursor_col(); - if (PyErr_Occurred() || VimErrorCheck()) + if (VimTryEnd()) return FAIL; if (len_change) @@ -2395,6 +2434,7 @@ SetBufferLineList(buf_T *buf, PyInt lo, buf_T *savebuf; PyErr_Clear(); + VimTryStart(); switch_buffer(&savebuf, buf); if (u_savedel((linenr_T)lo, (long)n) == FAIL) @@ -2416,7 +2456,7 @@ SetBufferLineList(buf_T *buf, PyInt lo, restore_buffer(savebuf); - if (PyErr_Occurred() || VimErrorCheck()) + if (VimTryEnd()) return FAIL; if (len_change) @@ -2459,6 +2499,7 @@ SetBufferLineList(buf_T *buf, PyInt lo, } } + VimTryStart(); PyErr_Clear(); // START of region without "return". Must call restore_buffer()! @@ -2545,7 +2586,7 @@ SetBufferLineList(buf_T *buf, PyInt lo, // END of region without "return". restore_buffer(savebuf); - if (PyErr_Occurred() || VimErrorCheck()) + if (VimTryEnd()) return FAIL; if (len_change) @@ -2583,6 +2624,7 @@ InsertBufferLines(buf_T *buf, PyInt n, P return FAIL; PyErr_Clear(); + VimTryStart(); switch_buffer(&savebuf, buf); if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL) @@ -2596,7 +2638,7 @@ InsertBufferLines(buf_T *buf, PyInt n, P restore_buffer(savebuf); update_screen(VALID); - if (PyErr_Occurred() || VimErrorCheck()) + if (VimTryEnd()) return FAIL; if (len_change) @@ -2633,6 +2675,7 @@ InsertBufferLines(buf_T *buf, PyInt n, P } PyErr_Clear(); + VimTryStart(); switch_buffer(&savebuf, buf); if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL) @@ -2666,7 +2709,7 @@ InsertBufferLines(buf_T *buf, PyInt n, P restore_buffer(savebuf); update_screen(VALID); - if (PyErr_Occurred() || VimErrorCheck()) + if (VimTryEnd()) return FAIL; if (len_change) @@ -2896,7 +2939,7 @@ RangeNew(buf_T *buf, PyInt start, PyInt static void RangeDestructor(RangeObject *self) { - Py_DECREF(self->buf); + Py_XDECREF(self->buf); DESTRUCTOR_FINISH(self); } @@ -3078,9 +3121,12 @@ BufferMark(BufferObject *self, PyObject return NULL; mark = *pmark; + VimTryStart(); switch_buffer(&savebuf, self->buf); posp = getmark(mark, FALSE); restore_buffer(savebuf); + if (VimTryEnd()) + return NULL; if (posp == NULL) { @@ -3088,10 +3134,6 @@ BufferMark(BufferObject *self, PyObject return NULL; } - /* Check for keyboard interrupt */ - if (VimErrorCheck()) - return NULL; - if (posp->lnum <= 0) { /* Or raise an error? */ @@ -3330,13 +3372,16 @@ CurrentSetattr(PyObject *self UNUSED, ch return -1; count = ((BufferObject *)(value))->buf->b_fnum; + VimTryStart(); if (do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, count, 0) == FAIL) { + if (VimTryEnd()) + return -1; PyErr_SetVim(_("failed to switch to given buffer")); return -1; } - return 0; + return VimTryEnd(); } else if (strcmp(name, "window") == 0) { @@ -3359,15 +3404,18 @@ CurrentSetattr(PyObject *self UNUSED, ch return -1; } + VimTryStart(); win_goto(((WindowObject *)(value))->win); if (((WindowObject *)(value))->win != curwin) { + if (VimTryEnd()) + return -1; PyErr_SetString(PyExc_RuntimeError, _("did not switch to the specified window")); return -1; } - return 0; + return VimTryEnd(); } else if (strcmp(name, "tabpage") == 0) { @@ -3380,15 +3428,18 @@ CurrentSetattr(PyObject *self UNUSED, ch if (CheckTabPage((TabPageObject *)(value))) return -1; + VimTryStart(); goto_tabpage_tp(((TabPageObject *)(value))->tab, TRUE, TRUE); if (((TabPageObject *)(value))->tab != curtab) { + if (VimTryEnd()) + return -1; PyErr_SetString(PyExc_RuntimeError, _("did not switch to the specified tab page")); return -1; } - return 0; + return VimTryEnd(); } else { diff --git a/src/testdir/test86.in b/src/testdir/test86.in --- a/src/testdir/test86.in +++ b/src/testdir/test86.in @@ -380,20 +380,24 @@ def e(s, g=globals(), l=locals()): try: exec(s, g, l) except: - vim.command('throw ' + repr(sys.exc_type.__name__)) + vim.command('return ' + repr(sys.exc_type.__name__)) def ev(s, g=globals(), l=locals()): try: return eval(s, g, l) except: - vim.command('throw ' + repr(sys.exc_type.__name__)) + vim.command('let exc=' + repr(sys.exc_type.__name__)) return 0 EOF :function E(s) : python e(vim.eval('a:s')) :endfunction :function Ev(s) -: return pyeval('ev(vim.eval("a:s"))') +: let r=pyeval('ev(vim.eval("a:s"))') +: if exists('exc') +: throw exc +: endif +: return r :endfunction :py gopts1=vim.options :py wopts1=vim.windows[2].options @@ -437,27 +441,24 @@ EOF : catch : put =' p/'.v.'! '.v:exception : endtry -: try -: call E(v.'["'.oname.'"]=invval') -: catch -: put =' inv: '.string(invval).'! '.v:exception -: endtry +: let r=E(v.'['''.oname.''']=invval') +: if r isnot 0 +: put =' inv: '.string(invval).'! '.r +: endif : for vv in (v is# 'gopts1' ? [v] : [v, v[:-2].'2', v[:-2].'3']) : let val=substitute(vv, '^.opts', 'oval', '') -: try -: call E(vv.'["'.oname.'"]='.val) -: catch -: put =' '.vv.'! '.v:exception -: endtry +: let r=E(vv.'['''.oname.''']='.val) +: if r isnot 0 +: put =' '.vv.'! '.r +: endif : endfor : endfor : call RecVars(oname) : for v in ['wopts3', 'bopts3'] -: try -: call E('del '.v.'["'.oname.'"]') -: catch -: put =' del '.v.'! '.v:exception -: endtry +: let r=E('del '.v.'["'.oname.'"]') +: if r isnot 0 +: put =' del '.v.'! '.r +: endif : endfor : call RecVars(oname) :endfor @@ -651,6 +652,25 @@ for expr, attr in ( ): cb.append(expr + ':' + attr + ':' + repr(type(eval(expr)) is getattr(vim, attr))) EOF +:" +:" 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() diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok --- a/src/testdir/test86.ok +++ b/src/testdir/test86.ok @@ -333,7 +333,7 @@ Number of tabs: 4 Current tab pages: (1): 1 windows, current is Windows: - (1): displays buffer ; cursor is at (970, 0) + (1): displays buffer ; cursor is at (990, 0) (2): 1 windows, current is Windows: (1): displays buffer ; cursor is at (1, 0) @@ -368,3 +368,9 @@ vim.current.buffer:Buffer:True vim.current.range:Range:True vim.current.window:Window:True vim.current.tabpage:TabPage:True +(, error('abc',)) +(, error('def',)) +(, error('ghi',)) +(, error('Vim(echoerr):jkl',)) +(, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)) +(, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)) diff --git a/src/testdir/test87.in b/src/testdir/test87.in --- a/src/testdir/test87.in +++ b/src/testdir/test87.in @@ -367,20 +367,24 @@ def e(s, g=globals(), l=locals()): try: exec(s, g, l) except Exception as e: - vim.command('throw ' + repr(e.__class__.__name__)) + vim.command('return ' + repr(e.__class__.__name__)) def ev(s, g=globals(), l=locals()): try: return eval(s, g, l) except Exception as e: - vim.command('throw ' + repr(e.__class__.__name__)) + vim.command('let exc=' + repr(e.__class__.__name__)) return 0 EOF :function E(s) : python3 e(vim.eval('a:s')) :endfunction :function Ev(s) -: return py3eval('ev(vim.eval("a:s"))') +: let r=py3eval('ev(vim.eval("a:s"))') +: if exists('exc') +: throw exc +: endif +: return r :endfunction :py3 gopts1=vim.options :py3 wopts1=vim.windows[2].options @@ -424,27 +428,24 @@ EOF : catch : put =' p/'.v.'! '.v:exception : endtry -: try -: call E(v.'["'.oname.'"]=invval') -: catch -: put =' inv: '.string(invval).'! '.v:exception -: endtry +: let r=E(v.'['''.oname.''']=invval') +: if r isnot 0 +: put =' inv: '.string(invval).'! '.r +: endif : for vv in (v is# 'gopts1' ? [v] : [v, v[:-2].'2', v[:-2].'3']) : let val=substitute(vv, '^.opts', 'oval', '') -: try -: call E(vv.'["'.oname.'"]='.val) -: catch -: put =' '.vv.'! '.v:exception -: endtry +: let r=E(vv.'['''.oname.''']='.val) +: if r isnot 0 +: put =' '.vv.'! '.r +: endif : endfor : endfor : call RecVars(oname) : for v in ['wopts3', 'bopts3'] -: try -: call E('del '.v.'["'.oname.'"]') -: catch -: put =' del '.v.'! '.v:exception -: endtry +: let r=E('del '.v.'["'.oname.'"]') +: if r isnot 0 +: put =' del '.v.'! '.r +: endif : endfor : call RecVars(oname) :endfor @@ -638,6 +639,25 @@ for expr, attr in ( ): cb.append(expr + ':' + attr + ':' + repr(type(eval(expr)) is getattr(vim, attr))) EOF +:" +:" Test exceptions +:fun Exe(e) +: execute a:e +:endfun +py3 << EOF +def ee(expr, g=globals(), l=locals()): + try: + exec(expr, g, l) + except Exception as e: + cb.append(repr((e.__class__, e))) +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() diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok --- a/src/testdir/test87.ok +++ b/src/testdir/test87.ok @@ -322,7 +322,7 @@ Number of tabs: 4 Current tab pages: (1): 1 windows, current is Windows: - (1): displays buffer ; cursor is at (946, 0) + (1): displays buffer ; cursor is at (966, 0) (2): 1 windows, current is Windows: (1): displays buffer ; cursor is at (1, 0) @@ -357,3 +357,9 @@ vim.current.buffer:Buffer:True vim.current.range:Range:True vim.current.window:Window:True vim.current.tabpage:TabPage:True +(, error('abc',)) +(, error('def',)) +(, error('ghi',)) +(, error('Vim(echoerr):jkl',)) +(, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)) +(, error('Vim:E492: Not an editor command: xxx_non_existent_command_xxx',)) diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 997, +/**/ 996, /**/ 995,