To: vim_dev@googlegroups.com Subject: Patch 7.3.997 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.3.997 Problem: Vim and Python exceptions are different. Solution: Make Vim exceptions be Python exceptions. (ZyX) Files: src/if_py_both.h, src/testdir/test86.in, src/testdir/test86.ok, src/testdir/test87.in, src/testdir/test87.ok *** ../vim-7.3.996/src/if_py_both.h 2013-05-21 19:49:58.000000000 +0200 --- src/if_py_both.h 2013-05-21 20:35:07.000000000 +0200 *************** *** 272,291 **** /* Check to see whether a Vim error has been reported, or a keyboard * interrupt has been detected. */ static int ! VimErrorCheck(void) { if (got_int) { PyErr_SetNone(PyExc_KeyboardInterrupt); return 1; } ! else if (did_emsg && !PyErr_Occurred()) { ! PyErr_SetNone(VimError); return 1; } return 0; } --- 272,313 ---- /* Check to see whether a Vim error has been reported, or a keyboard * interrupt has been detected. */ + + static void + VimTryStart(void) + { + ++trylevel; + } + static int ! 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; + } return 0; } *************** *** 306,322 **** Py_BEGIN_ALLOW_THREADS Python_Lock_Vim(); do_cmdline_cmd((char_u *)cmd); update_screen(VALID); Python_Release_Vim(); Py_END_ALLOW_THREADS ! if (VimErrorCheck()) result = NULL; else result = Py_None; Py_XINCREF(result); return result; } --- 328,346 ---- 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 (VimTryEnd()) result = NULL; else result = Py_None; + Py_XINCREF(result); return result; } *************** *** 449,459 **** Py_BEGIN_ALLOW_THREADS Python_Lock_Vim(); our_tv = eval_expr((char_u *)expr, NULL); - Python_Release_Vim(); Py_END_ALLOW_THREADS if (our_tv == NULL) { PyErr_SetVim(_("invalid expression")); --- 473,486 ---- 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,500 **** Py_BEGIN_ALLOW_THREADS Python_Lock_Vim(); our_tv = eval_expr((char_u *)expr, NULL); - Python_Release_Vim(); Py_END_ALLOW_THREADS if (our_tv == NULL) { PyErr_SetVim(_("invalid expression")); --- 517,530 ---- 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,1335 **** Py_BEGIN_ALLOW_THREADS Python_Lock_Vim(); error = func_call(name, &args, selfdict, &rettv); Python_Release_Vim(); Py_END_ALLOW_THREADS ! if (error != OK) { result = NULL; PyErr_SetVim(_("failed to run function")); --- 1354,1368 ---- Py_BEGIN_ALLOW_THREADS Python_Lock_Vim(); + VimTryStart(); error = func_call(name, &args, selfdict, &rettv); Python_Release_Vim(); Py_END_ALLOW_THREADS ! if (VimTryEnd()) ! result = NULL; ! else if (error != OK) { result = NULL; PyErr_SetVim(_("failed to run function")); *************** *** 1486,1499 **** win_T *save_curwin; tabpage_T *save_curtab; buf_T *save_curbuf; - int r = 0; switch (opt_type) { case SREQ_WIN: if (switch_win(&save_curwin, &save_curtab, (win_T *)from, win_find_tabpage((win_T *)from)) == FAIL) { PyErr_SetVim("Problem while switching windows."); return -1; } --- 1519,1534 ---- win_T *save_curwin; tabpage_T *save_curtab; buf_T *save_curbuf; + 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,1515 **** set_option_value(key, numval, stringval, opt_flags); break; } ! return r; } static int --- 1544,1550 ---- set_option_value(key, numval, stringval, opt_flags); break; } ! return VimTryEnd(); } static int *************** *** 1961,1967 **** } /* Check for keyboard interrupts */ ! if (VimErrorCheck()) return -1; self->win->w_cursor.lnum = lnum; --- 1996,2002 ---- } /* Check for keyboard interrupts */ ! if (VimCheckInterrupt()) return -1; self->win->w_cursor.lnum = lnum; *************** *** 1988,1998 **** #endif savewin = curwin; curwin = self->win; win_setheight(height); curwin = savewin; ! ! /* Check for keyboard interrupts */ ! if (VimErrorCheck()) return -1; return 0; --- 2023,2033 ---- #endif savewin = curwin; curwin = self->win; + + VimTryStart(); win_setheight(height); curwin = savewin; ! if (VimTryEnd()) return -1; return 0; *************** *** 2011,2021 **** #endif savewin = curwin; curwin = self->win; win_setwidth(width); curwin = savewin; ! ! /* Check for keyboard interrupts */ ! if (VimErrorCheck()) return -1; return 0; --- 2046,2056 ---- #endif savewin = curwin; curwin = self->win; + + VimTryStart(); win_setwidth(width); curwin = savewin; ! if (VimTryEnd()) return -1; return 0; *************** *** 2304,2309 **** --- 2339,2346 ---- 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,2323 **** restore_buffer(savebuf); ! if (PyErr_Occurred() || VimErrorCheck()) return FAIL; if (len_change) --- 2354,2360 ---- restore_buffer(savebuf); ! if (VimTryEnd()) return FAIL; if (len_change) *************** *** 2333,2338 **** --- 2370,2377 ---- 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,2362 **** if (buf == savebuf) check_cursor_col(); ! if (PyErr_Occurred() || VimErrorCheck()) return FAIL; if (len_change) --- 2395,2401 ---- if (buf == savebuf) check_cursor_col(); ! if (VimTryEnd()) return FAIL; if (len_change) *************** *** 2395,2400 **** --- 2434,2440 ---- buf_T *savebuf; PyErr_Clear(); + VimTryStart(); switch_buffer(&savebuf, buf); if (u_savedel((linenr_T)lo, (long)n) == FAIL) *************** *** 2416,2422 **** restore_buffer(savebuf); ! if (PyErr_Occurred() || VimErrorCheck()) return FAIL; if (len_change) --- 2456,2462 ---- restore_buffer(savebuf); ! if (VimTryEnd()) return FAIL; if (len_change) *************** *** 2459,2464 **** --- 2499,2505 ---- } } + VimTryStart(); PyErr_Clear(); // START of region without "return". Must call restore_buffer()! *************** *** 2545,2551 **** // END of region without "return". restore_buffer(savebuf); ! if (PyErr_Occurred() || VimErrorCheck()) return FAIL; if (len_change) --- 2586,2592 ---- // END of region without "return". restore_buffer(savebuf); ! if (VimTryEnd()) return FAIL; if (len_change) *************** *** 2583,2588 **** --- 2624,2630 ---- return FAIL; PyErr_Clear(); + VimTryStart(); switch_buffer(&savebuf, buf); if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL) *************** *** 2596,2602 **** restore_buffer(savebuf); update_screen(VALID); ! if (PyErr_Occurred() || VimErrorCheck()) return FAIL; if (len_change) --- 2638,2644 ---- restore_buffer(savebuf); update_screen(VALID); ! if (VimTryEnd()) return FAIL; if (len_change) *************** *** 2633,2638 **** --- 2675,2681 ---- } PyErr_Clear(); + VimTryStart(); switch_buffer(&savebuf, buf); if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL) *************** *** 2666,2672 **** restore_buffer(savebuf); update_screen(VALID); ! if (PyErr_Occurred() || VimErrorCheck()) return FAIL; if (len_change) --- 2709,2715 ---- restore_buffer(savebuf); update_screen(VALID); ! if (VimTryEnd()) return FAIL; if (len_change) *************** *** 2896,2902 **** static void RangeDestructor(RangeObject *self) { ! Py_DECREF(self->buf); DESTRUCTOR_FINISH(self); } --- 2939,2945 ---- static void RangeDestructor(RangeObject *self) { ! Py_XDECREF(self->buf); DESTRUCTOR_FINISH(self); } *************** *** 3078,3086 **** --- 3121,3132 ---- 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,3097 **** return NULL; } - /* Check for keyboard interrupt */ - if (VimErrorCheck()) - return NULL; - if (posp->lnum <= 0) { /* Or raise an error? */ --- 3134,3139 ---- *************** *** 3330,3342 **** return -1; count = ((BufferObject *)(value))->buf->b_fnum; if (do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, count, 0) == FAIL) { PyErr_SetVim(_("failed to switch to given buffer")); return -1; } ! return 0; } else if (strcmp(name, "window") == 0) { --- 3372,3387 ---- 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 VimTryEnd(); } else if (strcmp(name, "window") == 0) { *************** *** 3359,3373 **** return -1; } win_goto(((WindowObject *)(value))->win); if (((WindowObject *)(value))->win != curwin) { PyErr_SetString(PyExc_RuntimeError, _("did not switch to the specified window")); return -1; } ! return 0; } else if (strcmp(name, "tabpage") == 0) { --- 3404,3421 ---- 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 VimTryEnd(); } else if (strcmp(name, "tabpage") == 0) { *************** *** 3380,3394 **** if (CheckTabPage((TabPageObject *)(value))) return -1; goto_tabpage_tp(((TabPageObject *)(value))->tab, TRUE, TRUE); if (((TabPageObject *)(value))->tab != curtab) { PyErr_SetString(PyExc_RuntimeError, _("did not switch to the specified tab page")); return -1; } ! return 0; } else { --- 3428,3445 ---- 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 VimTryEnd(); } else { *** ../vim-7.3.996/src/testdir/test86.in 2013-05-21 19:49:58.000000000 +0200 --- src/testdir/test86.in 2013-05-21 20:34:32.000000000 +0200 *************** *** 380,399 **** try: exec(s, g, l) except: ! vim.command('throw ' + 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__)) return 0 EOF :function E(s) : python e(vim.eval('a:s')) :endfunction :function Ev(s) ! : return pyeval('ev(vim.eval("a:s"))') :endfunction :py gopts1=vim.options :py wopts1=vim.windows[2].options --- 380,403 ---- try: exec(s, g, l) except: ! vim.command('return ' + repr(sys.exc_type.__name__)) def ev(s, g=globals(), l=locals()): try: return eval(s, g, l) except: ! 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) ! : 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,463 **** : catch : put =' p/'.v.'! '.v:exception : endtry ! : try ! : call E(v.'["'.oname.'"]=invval') ! : catch ! : put =' inv: '.string(invval).'! '.v:exception ! : endtry : 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 : endfor : endfor : call RecVars(oname) : for v in ['wopts3', 'bopts3'] ! : try ! : call E('del '.v.'["'.oname.'"]') ! : catch ! : put =' del '.v.'! '.v:exception ! : endtry : endfor : call RecVars(oname) :endfor --- 441,464 ---- : catch : put =' p/'.v.'! '.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', '') ! : let r=E(vv.'['''.oname.''']='.val) ! : if r isnot 0 ! : put =' '.vv.'! '.r ! : endif : endfor : endfor : call RecVars(oname) : for v in ['wopts3', 'bopts3'] ! : let r=E('del '.v.'["'.oname.'"]') ! : if r isnot 0 ! : put =' del '.v.'! '.r ! : endif : endfor : call RecVars(oname) :endfor *************** *** 651,656 **** --- 652,676 ---- ): 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() *** ../vim-7.3.996/src/testdir/test86.ok 2013-05-21 19:49:58.000000000 +0200 --- src/testdir/test86.ok 2013-05-21 20:38:29.000000000 +0200 *************** *** 333,339 **** Current tab pages: (1): 1 windows, current is Windows: ! (1): displays buffer ; cursor is at (970, 0) (2): 1 windows, current is Windows: (1): displays buffer ; cursor is at (1, 0) --- 333,339 ---- Current tab pages: (1): 1 windows, current is Windows: ! (1): displays buffer ; cursor is at (990, 0) (2): 1 windows, current is Windows: (1): displays buffer ; cursor is at (1, 0) *************** *** 368,370 **** --- 368,376 ---- 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',)) *** ../vim-7.3.996/src/testdir/test87.in 2013-05-21 19:49:58.000000000 +0200 --- src/testdir/test87.in 2013-05-21 20:34:32.000000000 +0200 *************** *** 367,386 **** try: exec(s, g, l) except Exception as e: ! vim.command('throw ' + 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__)) return 0 EOF :function E(s) : python3 e(vim.eval('a:s')) :endfunction :function Ev(s) ! : return py3eval('ev(vim.eval("a:s"))') :endfunction :py3 gopts1=vim.options :py3 wopts1=vim.windows[2].options --- 367,390 ---- try: exec(s, g, l) except Exception as e: ! 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('let exc=' + repr(e.__class__.__name__)) return 0 EOF :function E(s) : python3 e(vim.eval('a:s')) :endfunction :function Ev(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,450 **** : catch : put =' p/'.v.'! '.v:exception : endtry ! : try ! : call E(v.'["'.oname.'"]=invval') ! : catch ! : put =' inv: '.string(invval).'! '.v:exception ! : endtry : 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 : endfor : endfor : call RecVars(oname) : for v in ['wopts3', 'bopts3'] ! : try ! : call E('del '.v.'["'.oname.'"]') ! : catch ! : put =' del '.v.'! '.v:exception ! : endtry : endfor : call RecVars(oname) :endfor --- 428,451 ---- : catch : put =' p/'.v.'! '.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', '') ! : let r=E(vv.'['''.oname.''']='.val) ! : if r isnot 0 ! : put =' '.vv.'! '.r ! : endif : endfor : endfor : call RecVars(oname) : for v in ['wopts3', 'bopts3'] ! : let r=E('del '.v.'["'.oname.'"]') ! : if r isnot 0 ! : put =' del '.v.'! '.r ! : endif : endfor : call RecVars(oname) :endfor *************** *** 638,643 **** --- 639,663 ---- ): 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() *** ../vim-7.3.996/src/testdir/test87.ok 2013-05-21 19:49:58.000000000 +0200 --- src/testdir/test87.ok 2013-05-21 20:38:46.000000000 +0200 *************** *** 322,328 **** Current tab pages: (1): 1 windows, current is Windows: ! (1): displays buffer ; cursor is at (946, 0) (2): 1 windows, current is Windows: (1): displays buffer ; cursor is at (1, 0) --- 322,328 ---- Current tab pages: (1): 1 windows, current is Windows: ! (1): displays buffer ; cursor is at (966, 0) (2): 1 windows, current is Windows: (1): displays buffer ; cursor is at (1, 0) *************** *** 357,359 **** --- 357,365 ---- 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',)) *** ../vim-7.3.996/src/version.c 2013-05-21 19:49:58.000000000 +0200 --- src/version.c 2013-05-21 20:32:46.000000000 +0200 *************** *** 730,731 **** --- 730,733 ---- { /* Add new patch number below this line */ + /**/ + 997, /**/ -- ARTHUR: It is I, Arthur, son of Uther Pendragon, from the castle of Camelot. King of all Britons, defeator of the Saxons, sovereign of all England! [Pause] SOLDIER: Get away! "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///