diff --git a/python/test_requirements.txt b/python/test_requirements.txt index 9cc2eef4..266aad2e 100644 --- a/python/test_requirements.txt +++ b/python/test_requirements.txt @@ -1,5 +1,6 @@ flake8 >= 3.0.0 flake8-comprehensions >= 1.4.1 +flake8-ycm >= 0.1.0 mock >= 1.0.1 nose >= 1.3.7 PyHamcrest >= 1.8.0 diff --git a/python/ycm/client/base_request.py b/python/ycm/client/base_request.py index 10fb7992..3c1f2ff3 100644 --- a/python/ycm/client/base_request.py +++ b/python/ycm/client/base_request.py @@ -32,7 +32,7 @@ from ycmd.utils import ToBytes, urljoin, urlparse, GetCurrentDirectory from ycmd.hmac_utils import CreateRequestHmac, CreateHmac, SecureBytesEqual from ycmd.responses import ServerError, UnknownExtraConf -_HEADERS = {'content-type': 'application/json'} +_HEADERS = { 'content-type': 'application/json' } _CONNECT_TIMEOUT_SEC = 0.01 # Setting this to None seems to screw up the Requests/urllib3 libs. _READ_TIMEOUT_SEC = 30 diff --git a/python/ycm/client/debug_info_request.py b/python/ycm/client/debug_info_request.py index ef1d8688..32d7bd3d 100644 --- a/python/ycm/client/debug_info_request.py +++ b/python/ycm/client/debug_info_request.py @@ -94,7 +94,7 @@ def _FormatCompleterDebugInfo( completer ): message += ' {0} process ID: {1}\n'.format( name, server[ 'pid' ] ) else: message += ' {0} not running\n'.format( name ) - message += ' {0} executable: {1}\n'.format( name, server[ 'executable'] ) + message += ' {0} executable: {1}\n'.format( name, server[ 'executable' ] ) logfiles = server[ 'logfiles' ] if logfiles: message += ' {0} logfiles:\n'.format( name ) diff --git a/python/ycm/syntax_parse.py b/python/ycm/syntax_parse.py index 375cf244..0fbdad9d 100644 --- a/python/ycm/syntax_parse.py +++ b/python/ycm/syntax_parse.py @@ -42,7 +42,7 @@ SYNTAX_ARGUMENT_REGEX = re.compile( r"^\w+=.*$" ) SYNTAX_REGION_ARGUMENT_REGEX = re.compile( - r"^(?:matchgroup|start)=.*$") + r"^(?:matchgroup|start)=.*$" ) # See ":h syn-nextgroup". SYNTAX_NEXTGROUP_ARGUMENTS = { @@ -106,7 +106,7 @@ def _SyntaxGroupsFromOutput( syntax_output ): group_name_to_group[ current_group.name ] = current_group current_group = SyntaxGroup( match.group( 'group_name' ), - [ match.group( 'content').strip() ] ) + [ match.group( 'content' ).strip() ] ) else: if looking_for_group: continue diff --git a/python/ycm/tests/base_test.py b/python/ycm/tests/base_test.py index b4a775e9..9f7516d1 100644 --- a/python/ycm/tests/base_test.py +++ b/python/ycm/tests/base_test.py @@ -35,7 +35,7 @@ from ycm import base @contextlib.contextmanager -def MockCurrentFiletypes( filetypes = [''] ): +def MockCurrentFiletypes( filetypes = [ '' ] ): with patch( 'ycm.vimsupport.CurrentFiletypes', return_value = filetypes ): yield @@ -180,7 +180,7 @@ def LastEnteredCharIsIdentifierChar_Basic_test(): def LastEnteredCharIsIdentifierChar_FiletypeHtml_test(): - with MockCurrentFiletypes( ['html'] ): + with MockCurrentFiletypes( [ 'html' ] ): with MockCurrentColumnAndLineContents( 3, 'ab-' ): ok_( base.LastEnteredCharIsIdentifierChar() ) @@ -272,7 +272,7 @@ def CurrentIdentifierFinished_InMiddleOfLine_test(): def CurrentIdentifierFinished_Html_test(): - with MockCurrentFiletypes( ['html'] ): + with MockCurrentFiletypes( [ 'html' ] ): with MockCurrentColumnAndLineContents( 4, 'bar-zoo' ): ok_( not base.CurrentIdentifierFinished() ) diff --git a/python/ycm/tests/client/command_request_test.py b/python/ycm/tests/client/command_request_test.py index 1397e71e..46f66723 100644 --- a/python/ycm/tests/client/command_request_test.py +++ b/python/ycm/tests/client/command_request_test.py @@ -203,7 +203,7 @@ class Response_Detection_test( object ): [ 'and8434fd andy garbag!', basic_fixit, basic_fixit_chunks, 0, False ], [ 'Format', - basic_fixit, basic_fixit_chunks, 0, True ], + basic_fixit, basic_fixit_chunks, 0, True ], [ 'select from multiple 1', multi_fixit, multi_fixit_first_chunks, 0, False ], [ 'select from multiple 2', @@ -293,7 +293,7 @@ class Response_Detection_test( object ): [ GoToTest, 'FindAThing', basic_goto ], [ GoToTest, 'FixItGoto', basic_goto ], [ GoToListTest, 'AnythingYouLike', [ basic_goto ] ], - [ GoToListTest, 'GoTo', [] ], + [ GoToListTest, 'GoTo', [] ], [ GoToListTest, 'FixItGoto', [ basic_goto, basic_goto ] ], ] diff --git a/python/ycm/tests/client/omni_completion_request_tests.py b/python/ycm/tests/client/omni_completion_request_tests.py index db2cf498..aba42412 100644 --- a/python/ycm/tests/client/omni_completion_request_tests.py +++ b/python/ycm/tests/client/omni_completion_request_tests.py @@ -64,8 +64,8 @@ def RawResponse_ConvertedFromOmniCompleter_test(): "kind": "KIND", "info": "INFO" }, { "word": "WORD2", "abbr": "ABBR2", "menu": "MENU2", "kind": "KIND2", "info": "INFO" }, - { "word": "WORD", "abbr": "ABBR", }, - { }, + { "word": "WORD", "abbr": "ABBR", }, + {}, ] expected_results = [ has_entries( { "insertion_text": "WORD", "menu_text": "ABBR", @@ -74,8 +74,8 @@ def RawResponse_ConvertedFromOmniCompleter_test(): has_entries( { "insertion_text": "WORD2", "menu_text": "ABBR2", "extra_menu_info": "MENU2", "kind": [ "KIND2" ], "detailed_info": "INFO" } ), - has_entries( { "insertion_text": "WORD", "menu_text": "ABBR", } ), - has_entries( { } ), + has_entries( { "insertion_text": "WORD", "menu_text": "ABBR", } ), + has_entries( {} ), ] request = BuildOmnicompletionRequest( vim_results ) diff --git a/python/ycm/tests/diagnostic_filter_test.py b/python/ycm/tests/diagnostic_filter_test.py index 9ecff64b..e4a74b22 100644 --- a/python/ycm/tests/diagnostic_filter_test.py +++ b/python/ycm/tests/diagnostic_filter_test.py @@ -61,7 +61,7 @@ def RegexFilter_test(): def RegexSingleList_test(): - opts = _JavaFilter( { 'regex' : [ 'taco' ] } ) + opts = _JavaFilter( { 'regex' : [ 'taco' ] } ) f = _CreateFilterForTypes( opts, [ 'java' ] ) _assert_rejects( f, 'This is a Taco' ) diff --git a/python/ycm/tests/postcomplete_test.py b/python/ycm/tests/postcomplete_test.py index d026781d..515bea2e 100644 --- a/python/ycm/tests/postcomplete_test.py +++ b/python/ycm/tests/postcomplete_test.py @@ -389,7 +389,7 @@ def PostCompleteFixIt_ApplyFixIt_EmptyFixIt_test( replace_chunks, *args ): @patch( 'ycm.vimsupport.ReplaceChunks' ) def PostCompleteFixIt_ApplyFixIt_NoFixIt_test( replace_chunks, *args ): completions = [ - BuildCompletion( ) + BuildCompletion() ] with _SetUpCompleteDone( completions ) as request: request._OnCompleteDone_FixIt() diff --git a/python/ycm/tests/test_utils.py b/python/ycm/tests/test_utils.py index 67d01cd5..b9c4e515 100644 --- a/python/ycm/tests/test_utils.py +++ b/python/ycm/tests/test_utils.py @@ -530,11 +530,11 @@ def MockVimModule(): class VimError( Exception ): def __init__( self, code ): - self.code = code + self.code = code def __str__( self ): - return repr( self.code ) + return repr( self.code ) class ExtendedMock( MagicMock ): diff --git a/python/ycm/tests/vimsupport_test.py b/python/ycm/tests/vimsupport_test.py index 660b7031..5973f4be 100644 --- a/python/ycm/tests/vimsupport_test.py +++ b/python/ycm/tests/vimsupport_test.py @@ -1114,17 +1114,17 @@ def ReplaceChunks_User_Aborts_Opening_File_test( False, # second_file (apply) True, # side_effect (check after open) ], - new_callable = ExtendedMock) + new_callable = ExtendedMock ) @patch( 'ycm.vimsupport.OpenFilename', - new_callable = ExtendedMock) + new_callable = ExtendedMock ) @patch( 'ycm.vimsupport.PostVimMessage', - new_callable = ExtendedMock) + new_callable = ExtendedMock ) @patch( 'ycm.vimsupport.Confirm', return_value = True, - new_callable = ExtendedMock) + new_callable = ExtendedMock ) @patch( 'vim.eval', return_value = 10, - new_callable = ExtendedMock) + new_callable = ExtendedMock ) @patch( 'vim.command', - new_callable = ExtendedMock) + new_callable = ExtendedMock ) def ReplaceChunks_MultiFile_Open_test( vim_command, vim_eval, confirm, @@ -1295,7 +1295,7 @@ def AddDiagnosticSyntaxMatch_UnicodeAtEndOfLine_test(): @patch( 'vim.command', new_callable=ExtendedMock ) -@patch( 'vim.current', new_callable=ExtendedMock) +@patch( 'vim.current', new_callable=ExtendedMock ) def WriteToPreviewWindow_test( vim_current, vim_command ): vim_current.window.options.__getitem__ = MagicMock( return_value = True ) @@ -1534,8 +1534,8 @@ def SelectFromList_FirstItem_test( vim_eval ): @patch( 'vim.eval', side_effect = [ None, 3, None ] ) def SelectFromList_OutOfRange_test( vim_eval ): - assert_that( calling( vimsupport.SelectFromList).with_args( 'test', - [ 'a', 'b' ] ), + assert_that( calling( vimsupport.SelectFromList ).with_args( 'test', + [ 'a', 'b' ] ), raises( RuntimeError, vimsupport.NO_SELECTION_MADE_MSG ) ) diff --git a/python/ycm/tests/youcompleteme_test.py b/python/ycm/tests/youcompleteme_test.py index c08c9ded..efdcac3e 100644 --- a/python/ycm/tests/youcompleteme_test.py +++ b/python/ycm/tests/youcompleteme_test.py @@ -240,22 +240,22 @@ def YouCompleteMe_DebugInfo_ServerNotRunning_test( ycm ): @YouCompleteMeInstance() def YouCompleteMe_OnVimLeave_RemoveClientLogfileByDefault_test( ycm ): - client_logfile = ycm._client_logfile - assert_that( os.path.isfile( client_logfile ), - 'Logfile {0} does not exist.'.format( client_logfile ) ) - ycm.OnVimLeave() - assert_that( not os.path.isfile( client_logfile ), - 'Logfile {0} was not removed.'.format( client_logfile ) ) + client_logfile = ycm._client_logfile + assert_that( os.path.isfile( client_logfile ), + 'Logfile {0} does not exist.'.format( client_logfile ) ) + ycm.OnVimLeave() + assert_that( not os.path.isfile( client_logfile ), + 'Logfile {0} was not removed.'.format( client_logfile ) ) @YouCompleteMeInstance( { 'g:ycm_keep_logfiles': 1 } ) def YouCompleteMe_OnVimLeave_KeepClientLogfile_test( ycm ): - client_logfile = ycm._client_logfile - assert_that( os.path.isfile( client_logfile ), - 'Logfile {0} does not exist.'.format( client_logfile ) ) - ycm.OnVimLeave() - assert_that( os.path.isfile( client_logfile ), - 'Logfile {0} was removed.'.format( client_logfile ) ) + client_logfile = ycm._client_logfile + assert_that( os.path.isfile( client_logfile ), + 'Logfile {0} does not exist.'.format( client_logfile ) ) + ycm.OnVimLeave() + assert_that( os.path.isfile( client_logfile ), + 'Logfile {0} was removed.'.format( client_logfile ) ) @YouCompleteMeInstance() @@ -696,7 +696,7 @@ def YouCompleteMe_UpdateMatches_ClearDiagnosticMatchesInNewBuffer_test( ycm ): @patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock ) def YouCompleteMe_AsyncDiagnosticUpdate_SingleFile_test( ycm, post_vim_message, - *args ): + *args ): # This test simulates asynchronous diagnostic updates associated with a single # file (e.g. Translation Unit), but where the actual errors refer to other @@ -811,7 +811,7 @@ def YouCompleteMe_AsyncDiagnosticUpdate_SingleFile_test( ycm, @patch( 'ycm.vimsupport.PostVimMessage', new_callable = ExtendedMock ) def YouCompleteMe_AsyncDiagnosticUpdate_PerFile_test( ycm, post_vim_message, - *args ): + *args ): # This test simulates asynchronous diagnostic updates which are delivered per # file, including files which are open and files which are not. @@ -903,7 +903,7 @@ def YouCompleteMe_AsyncDiagnosticUpdate_PerFile_test( ycm, @YouCompleteMeInstance() -def YouCompleteMe_OnPeriodicTick_ServerNotRunning_test( ycm, *args ): +def YouCompleteMe_OnPeriodicTick_ServerNotRunning_test( ycm, *args ): with patch.object( ycm, 'IsServerAlive', return_value = False ): assert_that( ycm.OnPeriodicTick(), equal_to( False ) ) @@ -935,8 +935,8 @@ def YouCompleteMe_OnPeriodicTick_DontRetry_test( ycm, # Create the request and make the first poll; we expect no response with MockVimBuffers( buffers, current_buffer, ( 1, 1 ) ): - assert_that( ycm.OnPeriodicTick(), equal_to( True ) ) - post_data_to_handler_async.assert_called() + assert_that( ycm.OnPeriodicTick(), equal_to( True ) ) + post_data_to_handler_async.assert_called() assert ycm._message_poll_request is not None post_data_to_handler_async.reset_mock() diff --git a/python/ycm/unsafe_thread_pool_executor.py b/python/ycm/unsafe_thread_pool_executor.py index 666aebcf..e55dc018 100644 --- a/python/ycm/unsafe_thread_pool_executor.py +++ b/python/ycm/unsafe_thread_pool_executor.py @@ -14,9 +14,9 @@ import sys from concurrent.futures import _base try: - import queue + import queue except ImportError: - import Queue as queue + import Queue as queue # This file provides an UnsafeThreadPoolExecutor, which operates exactly like @@ -28,93 +28,93 @@ except ImportError: # only send network requests). The YCM workload is one of those workloads where # it's safe (the aforementioned network requests case). -class _WorkItem(object): - def __init__(self, future, fn, args, kwargs): - self.future = future - self.fn = fn - self.args = args - self.kwargs = kwargs +class _WorkItem( object ): + def __init__( self, future, fn, args, kwargs ): + self.future = future + self.fn = fn + self.args = args + self.kwargs = kwargs - def run(self): - if not self.future.set_running_or_notify_cancel(): - return + def run( self ): + if not self.future.set_running_or_notify_cancel(): + return - try: - result = self.fn(*self.args, **self.kwargs) - except BaseException: - e = sys.exc_info()[1] - self.future.set_exception(e) - else: - self.future.set_result(result) - - -def _worker(executor_reference, work_queue): try: - while True: - work_item = work_queue.get(block=True) - if work_item is not None: - work_item.run() - continue - executor = executor_reference() - # Exit if: - # - The executor that owns the worker has been collected OR - # - The executor that owns the worker has been shutdown. - if executor is None or executor._shutdown: - # Notice other workers - work_queue.put(None) - return - del executor + result = self.fn( *self.args, **self.kwargs ) except BaseException: - _base.LOGGER.critical('Exception in worker', exc_info=True) + e = sys.exc_info()[ 1 ] + self.future.set_exception( e ) + else: + self.future.set_result( result ) -class UnsafeThreadPoolExecutor(_base.Executor): - def __init__(self, max_workers): - """Initializes a new ThreadPoolExecutor instance. +def _worker( executor_reference, work_queue ): + try: + while True: + work_item = work_queue.get( block=True ) + if work_item is not None: + work_item.run() + continue + executor = executor_reference() + # Exit if: + # - The executor that owns the worker has been collected OR + # - The executor that owns the worker has been shutdown. + if executor is None or executor._shutdown: + # Notice other workers + work_queue.put( None ) + return + del executor + except BaseException: + _base.LOGGER.critical( 'Exception in worker', exc_info=True ) - Args: - max_workers: The maximum number of threads that can be used to - execute the given calls. - """ - self._max_workers = max_workers - self._work_queue = queue.Queue() - self._threads = set() - self._shutdown = False - self._shutdown_lock = threading.Lock() - def submit(self, fn, *args, **kwargs): - with self._shutdown_lock: - if self._shutdown: - raise RuntimeError('cannot schedule new futures after shutdown') +class UnsafeThreadPoolExecutor( _base.Executor ): + def __init__( self, max_workers ): + """Initializes a new ThreadPoolExecutor instance. - f = _base.Future() - w = _WorkItem(f, fn, args, kwargs) + Args: + max_workers: The maximum number of threads that can be used to + execute the given calls. + """ + self._max_workers = max_workers + self._work_queue = queue.Queue() + self._threads = set() + self._shutdown = False + self._shutdown_lock = threading.Lock() - self._work_queue.put(w) - self._adjust_thread_count() - return f - submit.__doc__ = _base.Executor.submit.__doc__ + def submit( self, fn, *args, **kwargs ): + with self._shutdown_lock: + if self._shutdown: + raise RuntimeError( 'cannot schedule new futures after shutdown' ) - def _adjust_thread_count(self): - # When the executor gets lost, the weakref callback will wake up - # the worker threads. - def weakref_cb(_, q=self._work_queue): - q.put(None) - # TODO(bquinlan): Should avoid creating new threads if there are more - # idle threads than items in the work queue. - if len(self._threads) < self._max_workers: - t = threading.Thread(target=_worker, - args=(weakref.ref(self, weakref_cb), - self._work_queue)) - t.daemon = True - t.start() - self._threads.add(t) + f = _base.Future() + w = _WorkItem( f, fn, args, kwargs ) - def shutdown(self, wait=True): - with self._shutdown_lock: - self._shutdown = True - self._work_queue.put(None) - if wait: - for t in self._threads: - t.join() - shutdown.__doc__ = _base.Executor.shutdown.__doc__ + self._work_queue.put( w ) + self._adjust_thread_count() + return f + submit.__doc__ = _base.Executor.submit.__doc__ + + def _adjust_thread_count( self ): + # When the executor gets lost, the weakref callback will wake up + # the worker threads. + def weakref_cb( _, q=self._work_queue ): + q.put( None ) + # TODO(bquinlan): Should avoid creating new threads if there are more + # idle threads than items in the work queue. + if len( self._threads ) < self._max_workers: + t = threading.Thread( target=_worker, + args=( weakref.ref( self, weakref_cb ), + self._work_queue ) ) + t.daemon = True + t.start() + self._threads.add( t ) + + def shutdown( self, wait=True ): + with self._shutdown_lock: + self._shutdown = True + self._work_queue.put( None ) + if wait: + for t in self._threads: + t.join() + shutdown.__doc__ = _base.Executor.shutdown.__doc__ diff --git a/python/ycm/vimsupport.py b/python/ycm/vimsupport.py index e658683d..e7cc81fe 100644 --- a/python/ycm/vimsupport.py +++ b/python/ycm/vimsupport.py @@ -941,7 +941,7 @@ def ReplaceChunk( start, end, replacement_text, vim_buffer ): replacement_lines[ 0 ] = start_existing_text + replacement_lines[ 0 ] replacement_lines[ -1 ] = replacement_lines[ -1 ] + end_existing_text - vim_buffer[ start_line : end_line + 1 ] = replacement_lines[:] + vim_buffer[ start_line : end_line + 1 ] = replacement_lines[ : ] return { 'bufnr': vim_buffer.number, @@ -977,7 +977,8 @@ def InsertNamespace( namespace ): def SearchInCurrentBuffer( pattern ): """ Returns the 1-indexed line on which the pattern matches (going UP from the current position) or 0 if not found """ - return GetIntValue( "search('{0}', 'Wcnb')".format( EscapeForVim( pattern ))) + return GetIntValue( + "search('{0}', 'Wcnb')".format( EscapeForVim( pattern ) ) ) def LineTextInCurrentBuffer( line_number ): @@ -1033,7 +1034,7 @@ def WriteToPreviewWindow( message ): vim.current.buffer.options[ 'modifiable' ] = True vim.current.buffer.options[ 'readonly' ] = False - vim.current.buffer[:] = message.splitlines() + vim.current.buffer[ : ] = message.splitlines() vim.current.buffer.options[ 'buftype' ] = 'nofile' vim.current.buffer.options[ 'bufhidden' ] = 'wipe' diff --git a/python/ycm/youcompleteme.py b/python/ycm/youcompleteme.py index 142f191e..a49a6749 100644 --- a/python/ycm/youcompleteme.py +++ b/python/ycm/youcompleteme.py @@ -53,10 +53,10 @@ from ycm.client.messages_request import MessagesPoll def PatchNoProxy(): - current_value = os.environ.get('no_proxy', '') + current_value = os.environ.get( 'no_proxy', '' ) additions = '127.0.0.1,localhost' - os.environ['no_proxy'] = ( additions if not current_value - else current_value + ',' + additions ) + os.environ[ 'no_proxy' ] = ( additions if not current_value + else current_value + ',' + additions ) # We need this so that Requests doesn't end up using the local HTTP proxy when