Auto merge of #2899 - micbou:catch-extra-conf-data-exception, r=bstaletic
[READY] Avoid traceback when computing extra conf data Evaluating the values of [the `g:ycm_extra_conf_vim_data` option](https://github.com/Valloric/YouCompleteMe#the-gycm_extra_conf_vim_data-option) may raise a Python exception (e.g. one of the values is not defined). Since that option is evaluated each time a request is sent, such exception can render the editor almost unusable as each key press will print a Python traceback to the user. A simple way to reproduce the issue is to add the following line in vimrc: ```viml let g:ycm_extra_conf_vim_data = [ 'undefined_value' ] ``` We fix that by catching and logging the exception. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/youcompleteme/2899) <!-- Reviewable:end -->
This commit is contained in:
commit
26a5e3cbc4
@ -22,7 +22,7 @@ from __future__ import absolute_import
|
|||||||
# Not installing aliases from python-future; it's unreliable and slow.
|
# Not installing aliases from python-future; it's unreliable and slow.
|
||||||
from builtins import * # noqa
|
from builtins import * # noqa
|
||||||
|
|
||||||
from ycm.tests.test_utils import ( MockVimModule, MockVimBuffers, VimBuffer )
|
from ycm.tests.test_utils import MockVimModule, MockVimBuffers, VimBuffer
|
||||||
MockVimModule()
|
MockVimModule()
|
||||||
|
|
||||||
from hamcrest import assert_that, equal_to
|
from hamcrest import assert_that, equal_to
|
||||||
@ -32,7 +32,7 @@ from ycm.tests import YouCompleteMeInstance
|
|||||||
|
|
||||||
|
|
||||||
@YouCompleteMeInstance( { 'extra_conf_vim_data': [ 'tempname()' ] } )
|
@YouCompleteMeInstance( { 'extra_conf_vim_data': [ 'tempname()' ] } )
|
||||||
def SendCommandRequest_test( ycm ):
|
def SendCommandRequest_ExtraConfData_Works_test( ycm ):
|
||||||
current_buffer = VimBuffer( 'buffer' )
|
current_buffer = VimBuffer( 'buffer' )
|
||||||
with MockVimBuffers( [ current_buffer ], current_buffer ):
|
with MockVimBuffers( [ current_buffer ], current_buffer ):
|
||||||
with patch( 'ycm.youcompleteme.SendCommandRequest' ) as send_request:
|
with patch( 'ycm.youcompleteme.SendCommandRequest' ) as send_request:
|
||||||
@ -47,3 +47,20 @@ def SendCommandRequest_test( ycm ):
|
|||||||
ycm.SendCommandRequest( [ 'GoTo' ], 'python' ),
|
ycm.SendCommandRequest( [ 'GoTo' ], 'python' ),
|
||||||
equal_to( 'Some response' )
|
equal_to( 'Some response' )
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@YouCompleteMeInstance( { 'extra_conf_vim_data': [ 'undefined_value' ] } )
|
||||||
|
def SendCommandRequest_ExtraConfData_UndefinedValue_test( ycm ):
|
||||||
|
current_buffer = VimBuffer( 'buffer' )
|
||||||
|
with MockVimBuffers( [ current_buffer ], current_buffer ):
|
||||||
|
with patch( 'ycm.youcompleteme.SendCommandRequest' ) as send_request:
|
||||||
|
ycm.SendCommandRequest( [ 'GoTo' ], 'python' )
|
||||||
|
send_request.assert_called_once_with(
|
||||||
|
[ 'GoTo' ], 'python', { 'extra_conf_data': {} }
|
||||||
|
)
|
||||||
|
with patch( 'ycm.client.base_request.JsonFromFuture',
|
||||||
|
return_value = 'Some response' ):
|
||||||
|
assert_that(
|
||||||
|
ycm.SendCommandRequest( [ 'GoTo' ], 'python' ),
|
||||||
|
equal_to( 'Some response' )
|
||||||
|
)
|
||||||
|
@ -215,7 +215,7 @@ def _MockVimEval( value ):
|
|||||||
if match:
|
if match:
|
||||||
return match.group( 'filepath' )
|
return match.group( 'filepath' )
|
||||||
|
|
||||||
raise ValueError( 'Unexpected evaluation: {0}'.format( value ) )
|
raise VimError( 'Unexpected evaluation: {0}'.format( value ) )
|
||||||
|
|
||||||
|
|
||||||
def _MockWipeoutBuffer( buffer_number ):
|
def _MockWipeoutBuffer( buffer_number ):
|
||||||
@ -381,6 +381,7 @@ def MockVimModule():
|
|||||||
|
|
||||||
VIM_MOCK.buffers = {}
|
VIM_MOCK.buffers = {}
|
||||||
VIM_MOCK.eval = MagicMock( side_effect = _MockVimEval )
|
VIM_MOCK.eval = MagicMock( side_effect = _MockVimEval )
|
||||||
|
VIM_MOCK.error = VimError
|
||||||
sys.modules[ 'vim' ] = VIM_MOCK
|
sys.modules[ 'vim' ] = VIM_MOCK
|
||||||
|
|
||||||
return VIM_MOCK
|
return VIM_MOCK
|
||||||
|
@ -1684,7 +1684,6 @@ def JumpToLocation_DifferentFile_SameBuffer_Modified_CanHide_test(
|
|||||||
|
|
||||||
@patch( 'ycmd.user_options_store._USER_OPTIONS',
|
@patch( 'ycmd.user_options_store._USER_OPTIONS',
|
||||||
{ 'goto_buffer_command': 'same-buffer' } )
|
{ 'goto_buffer_command': 'same-buffer' } )
|
||||||
@patch( 'vim.error', VimError )
|
|
||||||
@patch( 'vim.command',
|
@patch( 'vim.command',
|
||||||
side_effect = [ None, VimError( 'Unknown code' ), None ] )
|
side_effect = [ None, VimError( 'Unknown code' ), None ] )
|
||||||
def JumpToLocation_DifferentFile_SameBuffer_SwapFile_Unexpected_test(
|
def JumpToLocation_DifferentFile_SameBuffer_SwapFile_Unexpected_test(
|
||||||
@ -1701,7 +1700,6 @@ def JumpToLocation_DifferentFile_SameBuffer_SwapFile_Unexpected_test(
|
|||||||
|
|
||||||
@patch( 'ycmd.user_options_store._USER_OPTIONS',
|
@patch( 'ycmd.user_options_store._USER_OPTIONS',
|
||||||
{ 'goto_buffer_command': 'same-buffer' } )
|
{ 'goto_buffer_command': 'same-buffer' } )
|
||||||
@patch( 'vim.error', VimError )
|
|
||||||
@patch( 'vim.command',
|
@patch( 'vim.command',
|
||||||
new_callable = ExtendedMock,
|
new_callable = ExtendedMock,
|
||||||
side_effect = [ None, VimError( 'E325' ), None ] )
|
side_effect = [ None, VimError( 'E325' ), None ] )
|
||||||
@ -1720,7 +1718,6 @@ def JumpToLocation_DifferentFile_SameBuffer_SwapFile_Quit_test( vim_command ):
|
|||||||
|
|
||||||
@patch( 'ycmd.user_options_store._USER_OPTIONS',
|
@patch( 'ycmd.user_options_store._USER_OPTIONS',
|
||||||
{ 'goto_buffer_command': 'same-buffer' } )
|
{ 'goto_buffer_command': 'same-buffer' } )
|
||||||
@patch( 'vim.error', VimError )
|
|
||||||
@patch( 'vim.command',
|
@patch( 'vim.command',
|
||||||
new_callable = ExtendedMock,
|
new_callable = ExtendedMock,
|
||||||
side_effect = [ None, KeyboardInterrupt, None ] )
|
side_effect = [ None, KeyboardInterrupt, None ] )
|
||||||
|
@ -750,8 +750,17 @@ class YouCompleteMe( object ):
|
|||||||
|
|
||||||
def _AddExtraConfDataIfNeeded( self, extra_data ):
|
def _AddExtraConfDataIfNeeded( self, extra_data ):
|
||||||
def BuildExtraConfData( extra_conf_vim_data ):
|
def BuildExtraConfData( extra_conf_vim_data ):
|
||||||
return dict( ( expr, vimsupport.VimExpressionToPythonType( expr ) )
|
extra_conf_data = {}
|
||||||
for expr in extra_conf_vim_data )
|
for expr in extra_conf_vim_data:
|
||||||
|
try:
|
||||||
|
extra_conf_data[ expr ] = vimsupport.VimExpressionToPythonType( expr )
|
||||||
|
except vim.error:
|
||||||
|
message = (
|
||||||
|
"Error evaluating '{expr}' in the 'g:ycm_extra_conf_vim_data' "
|
||||||
|
"option.".format( expr = expr ) )
|
||||||
|
vimsupport.PostVimMessage( message, truncate = True )
|
||||||
|
self._logger.exception( message )
|
||||||
|
return extra_conf_data
|
||||||
|
|
||||||
extra_conf_vim_data = self._user_options[ 'extra_conf_vim_data' ]
|
extra_conf_vim_data = self._user_options[ 'extra_conf_vim_data' ]
|
||||||
if extra_conf_vim_data:
|
if extra_conf_vim_data:
|
||||||
|
Loading…
Reference in New Issue
Block a user