From c7e32b3600020c65b39a0aba517a229609bcf23e Mon Sep 17 00:00:00 2001 From: micbou Date: Mon, 11 Jan 2016 13:33:43 +0100 Subject: [PATCH 01/10] Implement new strategy to find Python path --- python/ycm/paths.py | 50 +++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/python/ycm/paths.py b/python/ycm/paths.py index b5e1373d..fcd78572 100644 --- a/python/ycm/paths.py +++ b/python/ycm/paths.py @@ -18,14 +18,14 @@ # along with YouCompleteMe. If not, see . import os +import sys import vim import functools from ycmd import utils DIR_OF_CURRENT_SCRIPT = os.path.dirname( os.path.abspath( __file__ ) ) -WIN_PYTHON27_PATH = 'C:\python27\python.exe' -WIN_PYTHON26_PATH = 'C:\python26\python.exe' +WIN_PYTHON_PATH = os.path.join( sys.exec_prefix, 'python.exe' ) def Memoize( obj ): @@ -42,29 +42,39 @@ def Memoize( obj ): @Memoize def PathToPythonInterpreter(): - user_path_to_python = vim.eval( 'g:ycm_path_to_python_interpreter' ) + python_interpreter = vim.eval( 'g:ycm_path_to_python_interpreter' ) - if user_path_to_python: - return user_path_to_python + if python_interpreter: + if not CheckPythonVersion( python_interpreter ): + raise RuntimeError( "Path in 'g:ycm_path_to_python_interpreter' option " + "does not point to a valid Python 2.6 or 2.7." ) - # We check for 'python2' before 'python' because some OS's (I'm looking at - # you Arch Linux) have made the... interesting decision to point - # /usr/bin/python to python3. - python_names = [ 'python2', 'python' ] + return python_interpreter - path_to_python = utils.PathToFirstExistingExecutable( python_names ) - if path_to_python: - return path_to_python + # On UNIX platforms, we use sys.executable as the Python interpreter path. + # We cannot use sys.executable on Windows because for unknown reasons, it + # returns the Vim executable. Instead, we use sys.exec_prefix to deduce the + # interpreter path. + python_interpreter = ( WIN_PYTHON_PATH if utils.OnWindows() else + sys.executable ) - # On Windows, Python may not be on the PATH at all, so we check some common - # install locations. - if utils.OnWindows(): - if os.path.exists( WIN_PYTHON27_PATH ): - return WIN_PYTHON27_PATH - elif os.path.exists( WIN_PYTHON26_PATH ): - return WIN_PYTHON26_PATH + if not CheckPythonVersion( python_interpreter ): + raise RuntimeError( "Cannot find Python 2.6 or 2.7. You can set its path " + "using the 'g:ycm_path_to_python_interpreter' " + "option." ) - raise RuntimeError( 'Python 2.7/2.6 not installed!' ) + return python_interpreter + + +def CheckPythonVersion( python_interpreter ): + """Check if given path is the Python interpreter version 2.6 or 2.7.""" + command = [ python_interpreter, + '-c', + "import sys;" + "major, minor = sys.version_info[ :2 ];" + "sys.exit( major != 2 or minor < 6)" ] + + return utils.SafePopen( command ).wait() == 0 def PathToServerScript(): From a80846e35dd733f094f8ced9daeacba58eeb4316 Mon Sep 17 00:00:00 2001 From: micbou Date: Tue, 12 Jan 2016 21:24:23 +0100 Subject: [PATCH 02/10] Check Python interpreter pathname Rename CheckPythonVersion to IsPythonVersionCorrect. In embedders, sys.executable may contain a Vim path instead of a Python one. To avoid starting a Vim instance in this case, we check that given path ends with a Python 2.6 or 2.7 name using a regex. Add tests for this regex. --- python/ycm/paths.py | 18 +++++++++++--- python/ycm/tests/paths_test.py | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 python/ycm/tests/paths_test.py diff --git a/python/ycm/paths.py b/python/ycm/paths.py index fcd78572..15f82e81 100644 --- a/python/ycm/paths.py +++ b/python/ycm/paths.py @@ -21,11 +21,13 @@ import os import sys import vim import functools +import re from ycmd import utils DIR_OF_CURRENT_SCRIPT = os.path.dirname( os.path.abspath( __file__ ) ) WIN_PYTHON_PATH = os.path.join( sys.exec_prefix, 'python.exe' ) +PYTHON_BINARY_REGEX = re.compile( r'python(2(\.[67])?)?(.exe)?$' ) def Memoize( obj ): @@ -45,7 +47,7 @@ def PathToPythonInterpreter(): python_interpreter = vim.eval( 'g:ycm_path_to_python_interpreter' ) if python_interpreter: - if not CheckPythonVersion( python_interpreter ): + if not IsPythonVersionCorrect( python_interpreter ): raise RuntimeError( "Path in 'g:ycm_path_to_python_interpreter' option " "does not point to a valid Python 2.6 or 2.7." ) @@ -58,7 +60,7 @@ def PathToPythonInterpreter(): python_interpreter = ( WIN_PYTHON_PATH if utils.OnWindows() else sys.executable ) - if not CheckPythonVersion( python_interpreter ): + if not IsPythonVersionCorrect( python_interpreter ): raise RuntimeError( "Cannot find Python 2.6 or 2.7. You can set its path " "using the 'g:ycm_path_to_python_interpreter' " "option." ) @@ -66,9 +68,17 @@ def PathToPythonInterpreter(): return python_interpreter -def CheckPythonVersion( python_interpreter ): +def EndsWithPython( path ): + """Check if given path ends with a python 2.6 or 2.7 name.""" + return PYTHON_BINARY_REGEX.search( path ) is not None + + +def IsPythonVersionCorrect( path ): """Check if given path is the Python interpreter version 2.6 or 2.7.""" - command = [ python_interpreter, + if not EndsWithPython( path ): + return False + + command = [ path, '-c', "import sys;" "major, minor = sys.version_info[ :2 ];" diff --git a/python/ycm/tests/paths_test.py b/python/ycm/tests/paths_test.py new file mode 100644 index 00000000..b7a43702 --- /dev/null +++ b/python/ycm/tests/paths_test.py @@ -0,0 +1,45 @@ +# +# Copyright (C) 2016 YouCompleteMe contributors +# +# This file is part of YouCompleteMe. +# +# YouCompleteMe is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# YouCompleteMe is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with YouCompleteMe. If not, see . + +from ycm.test_utils import MockVimModule +MockVimModule() + +from nose.tools import ok_ +from ycm.paths import EndsWithPython + + +def EndsWithPython_PythonPaths_test(): + python_paths = [ + 'python', + '/usr/bin/python2.6', + '/home/user/.pyenv/shims/python2.7', + r'C:\aPython26\python.exe' + ] + + for path in python_paths: + ok_( EndsWithPython( path ) ) + + +def EndsWithPython_NotPythonPaths_test(): + not_python_paths = [ + '/opt/local/bin/vim', + r'C:\Program Files\Vim\vim74\gvim.exe' + ] + + for path in not_python_paths: + ok_( not EndsWithPython( path ) ) From 1cdbe4a770c6b721b819b1ed6fde99068416a614 Mon Sep 17 00:00:00 2001 From: micbou Date: Tue, 12 Jan 2016 22:48:48 +0100 Subject: [PATCH 03/10] Add python3 failing tests --- python/ycm/tests/paths_test.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/python/ycm/tests/paths_test.py b/python/ycm/tests/paths_test.py index b7a43702..13c75dcc 100644 --- a/python/ycm/tests/paths_test.py +++ b/python/ycm/tests/paths_test.py @@ -23,7 +23,7 @@ from nose.tools import ok_ from ycm.paths import EndsWithPython -def EndsWithPython_PythonPaths_test(): +def EndsWithPython_Python2Paths_test(): python_paths = [ 'python', '/usr/bin/python2.6', @@ -35,10 +35,12 @@ def EndsWithPython_PythonPaths_test(): ok_( EndsWithPython( path ) ) -def EndsWithPython_NotPythonPaths_test(): +def EndsWithPython_NotPython2Paths_test(): not_python_paths = [ '/opt/local/bin/vim', - r'C:\Program Files\Vim\vim74\gvim.exe' + r'C:\Program Files\Vim\vim74\gvim.exe', + '/usr/bin/python3', + '/home/user/.pyenv/shims/python3', ] for path in not_python_paths: From 9a27c990db65650cc8505b40e485078e64747ec5 Mon Sep 17 00:00:00 2001 From: micbou Date: Tue, 12 Jan 2016 22:51:15 +0100 Subject: [PATCH 04/10] Fix typo in test --- python/ycm/tests/paths_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ycm/tests/paths_test.py b/python/ycm/tests/paths_test.py index 13c75dcc..d8e5ca7f 100644 --- a/python/ycm/tests/paths_test.py +++ b/python/ycm/tests/paths_test.py @@ -28,7 +28,7 @@ def EndsWithPython_Python2Paths_test(): 'python', '/usr/bin/python2.6', '/home/user/.pyenv/shims/python2.7', - r'C:\aPython26\python.exe' + r'C:\Python26\python.exe' ] for path in python_paths: From c2d473c4ba5755ce081ff5188ffedb36b4224b7e Mon Sep 17 00:00:00 2001 From: "Spencer G. Jones" Date: Thu, 31 Dec 2015 16:14:26 -0700 Subject: [PATCH 05/10] Add missing implementation on OmniCompletionRequest OmniCompletionRequest is missing the RawResponse method, so any attempt to call it calls the base class method instead. However, since the data structures of this class and base class are different, this causes an error. --- python/ycm/client/omni_completion_request.py | 28 +++++++ .../tests/omni_completion_request_tests.py | 76 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 python/ycm/tests/omni_completion_request_tests.py diff --git a/python/ycm/client/omni_completion_request.py b/python/ycm/client/omni_completion_request.py index ddf9d0b6..209eead3 100644 --- a/python/ycm/client/omni_completion_request.py +++ b/python/ycm/client/omni_completion_request.py @@ -17,6 +17,7 @@ # You should have received a copy of the GNU General Public License # along with YouCompleteMe. If not, see . +from ycmd.utils import ToUtf8IfNeeded from ycm.client.completion_request import CompletionRequest @@ -34,5 +35,32 @@ class OmniCompletionRequest( CompletionRequest ): return True + def RawResponse( self ): + return _ConvertVimDatasToCompletionDatas( self._results ) + + def Response( self ): return self._results + + +def ConvertVimDataToCompletionData( vim_data ): + # see :h complete-items for a description of the dictionary fields + completion_data = {} + + if 'word' in vim_data: + completion_data[ 'insertion_text' ] = ToUtf8IfNeeded( vim_data[ 'word' ] ) + if 'abbr' in vim_data: + completion_data[ 'menu_text' ] = ToUtf8IfNeeded( vim_data[ 'abbr' ] ) + if 'menu' in vim_data: + completion_data[ 'extra_menu_info' ] = ToUtf8IfNeeded( vim_data[ 'menu' ] ) + if 'kind' in vim_data: + completion_data[ 'kind' ] = [ ToUtf8IfNeeded( vim_data[ 'kind' ] ) ] + if 'info' in vim_data: + completion_data[ 'detailed_info' ] = ToUtf8IfNeeded( vim_data[ 'info' ] ) + + return completion_data + + +def _ConvertVimDatasToCompletionDatas( response_data ): + return [ ConvertVimDataToCompletionData( x ) + for x in response_data ] diff --git a/python/ycm/tests/omni_completion_request_tests.py b/python/ycm/tests/omni_completion_request_tests.py new file mode 100644 index 00000000..8d17e07e --- /dev/null +++ b/python/ycm/tests/omni_completion_request_tests.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# +# Copyright (C) 2016 YouCompleteMe contributors +# +# This file is part of YouCompleteMe. +# +# YouCompleteMe is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# YouCompleteMe is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with YouCompleteMe. If not, see . + + +from mock import MagicMock +from nose.tools import eq_ +from hamcrest import assert_that, has_entries + +from ycm.client.omni_completion_request import OmniCompletionRequest + + +def BuildOmnicompletionRequest( results ): + omni_completer = MagicMock() + omni_completer.ComputeCandidates = MagicMock( return_value = results ) + + request = OmniCompletionRequest( omni_completer, None ) + request.Start() + + return request; + + +def Done_AlwaysTrue_test(): + request = BuildOmnicompletionRequest( [] ) + + eq_( request.Done(), True ) + + +def Response_FromOmniCompleter_test(): + results = [ { "word": "test" } ] + request = BuildOmnicompletionRequest( results ) + + eq_( request.Response(), results ) + + +def RawResponse_ConvertedFromOmniCompleter_test(): + vim_results = [ + { "word": "WORD", "abbr": "ABBR", "menu": "MENU", + "kind": "KIND", "info": "INFO" }, + { "word": "WORD2", "abbr": "ABBR2", "menu": "MENU2", + "kind": "KIND2", "info": "INFO" }, + { "word": "WORD", "abbr": "ABBR", }, + { }, + ] + expected_results = [ + has_entries( { "insertion_text": "WORD", "menu_text": "ABBR", + "extra_menu_info": "MENU", "kind": [ "KIND" ], + "detailed_info": "INFO" } ), + 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( { } ), + ] + request = BuildOmnicompletionRequest( vim_results ) + + results = request.RawResponse() + + eq_( len( results ), len( expected_results ) ) + for result, expected_result in zip( results, expected_results ): + assert_that( result, expected_result ) From bdf09a75379e2ff7fe21e0537c99a7d62a85ca03 Mon Sep 17 00:00:00 2001 From: micbou Date: Wed, 20 Jan 2016 21:47:36 +0100 Subject: [PATCH 06/10] Update get-pip.py script URL on AppVeyor Update also the way get-pip.py script is downloaded. --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 88817a87..3a5aba4a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,9 +6,9 @@ environment: install: - git submodule update --init --recursive - ps: $env:python = if ($env:arch -eq 32) { 'C:\Python27' } else { 'C:\Python27-x64' } - - ps: (new-object net.webclient).DownloadFile('https://raw.github.com/pypa/pip/master/contrib/get-pip.py', 'C:\get-pip.py') + - appveyor DownloadFile https://bootstrap.pypa.io/get-pip.py - set PATH=%python%;%python%\Scripts;%PATH% - - python C:\get-pip.py + - python get-pip.py - pip install -r python\test_requirements.txt build_script: - python run_tests.py From c92b4ac0ff0fa3eb75ebc42099a296aa7e384dde Mon Sep 17 00:00:00 2001 From: micbou Date: Wed, 20 Jan 2016 20:09:11 +0100 Subject: [PATCH 07/10] Fix issue in EventNotification tests assert_has_calls is not enough to check if a call didn't raise a warning. We also need to check the number of calls. This is done by creating a subclass of MagicMock implementing the assert_has_exact_calls method. --- python/ycm/test_utils.py | 8 +++ python/ycm/tests/event_notification_test.py | 54 ++++++++++++--------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/python/ycm/test_utils.py b/python/ycm/test_utils.py index 4f9da546..20f1b88a 100644 --- a/python/ycm/test_utils.py +++ b/python/ycm/test_utils.py @@ -18,6 +18,7 @@ # along with YouCompleteMe. If not, see . from mock import MagicMock +from hamcrest import assert_that, equal_to import re import sys @@ -116,3 +117,10 @@ def MockVimModule(): sys.modules[ 'vim' ] = VIM_MOCK return VIM_MOCK + + +class ExtendedMock( MagicMock ): + + def assert_has_exact_calls( self, calls, any_order = False ): + self.assert_has_calls( calls, any_order ) + assert_that( self.call_count, equal_to( len( calls ) ) ) diff --git a/python/ycm/tests/event_notification_test.py b/python/ycm/tests/event_notification_test.py index f7ee868f..68585f63 100644 --- a/python/ycm/tests/event_notification_test.py +++ b/python/ycm/tests/event_notification_test.py @@ -16,10 +16,11 @@ # You should have received a copy of the GNU General Public License # along with YouCompleteMe. If not, see . -from ycm.test_utils import MockVimModule +from ycm.test_utils import MockVimModule, ExtendedMock MockVimModule() -import contextlib, os +import contextlib +import os from ycm.youcompleteme import YouCompleteMe from ycmd import user_options_store @@ -36,6 +37,7 @@ DEFAULT_CLIENT_OPTIONS = { 'extra_conf_vim_data': [], } + def PostVimMessage_Call( message ): """Return a mock.call object for a call to vimsupport.PostVimMesasge with the supplied message""" @@ -74,7 +76,7 @@ def MockArbitraryBuffer( filetype, native_available = True ): raise ValueError( 'Unexpected evaluation' ) # Arbitrary, but valid, cursor position - vim_current.window.cursor = (1,2) + vim_current.window.cursor = ( 1, 2 ) # Arbitrary, but valid, single buffer open current_buffer = MagicMock() @@ -129,7 +131,7 @@ class EventNotification_test( object ): def setUp( self ): options = dict( user_options_store.DefaultOptions() ) - options.update ( DEFAULT_CLIENT_OPTIONS ) + options.update( DEFAULT_CLIENT_OPTIONS ) user_options_store.SetAll( options ) self.server_state = YouCompleteMe( user_options_store.GetAll() ) @@ -141,7 +143,7 @@ class EventNotification_test( object ): self.server_state.OnVimLeave() - @patch( 'vim.command' ) + @patch( 'vim.command', new_callable = ExtendedMock ) def FileReadyToParse_NonDiagnostic_Error_test( self, vim_command ): # This test validates the behaviour of YouCompleteMe.ValidateParseRequest in # combination with YouCompleteMe.OnFileReadyToParse when the completer @@ -158,13 +160,13 @@ class EventNotification_test( object ): self.server_state.ValidateParseRequest() # The first call raises a warning - vim_command.assert_has_calls( [ + vim_command.assert_has_exact_calls( [ PostVimMessage_Call( ERROR_TEXT ), ] ) # Subsequent calls don't re-raise the warning self.server_state.ValidateParseRequest() - vim_command.assert_has_calls( [ + vim_command.assert_has_exact_calls( [ PostVimMessage_Call( ERROR_TEXT ), ] ) @@ -172,7 +174,7 @@ class EventNotification_test( object ): self.server_state.OnFileReadyToParse() assert self.server_state.DiagnosticsForCurrentFileReady() self.server_state.ValidateParseRequest() - vim_command.assert_has_calls( [ + vim_command.assert_has_exact_calls( [ PostVimMessage_Call( ERROR_TEXT ), PostVimMessage_Call( ERROR_TEXT ), ] ) @@ -187,8 +189,10 @@ class EventNotification_test( object ): vim_command.assert_not_called() - @patch( 'ycm.client.event_notification._LoadExtraConfFile' ) - @patch( 'ycm.client.event_notification._IgnoreExtraConfFile' ) + @patch( 'ycm.client.event_notification._LoadExtraConfFile', + new_callable = ExtendedMock ) + @patch( 'ycm.client.event_notification._IgnoreExtraConfFile', + new_callable = ExtendedMock ) def FileReadyToParse_NonDiagnostic_ConfirmExtraConf_test( self, ignore_extra_conf, @@ -211,25 +215,26 @@ class EventNotification_test( object ): # When the user accepts the extra conf, we load it with patch( 'ycm.vimsupport.PresentDialog', - return_value = 0 ) as present_dialog: + return_value = 0, + new_callable = ExtendedMock ) as present_dialog: self.server_state.OnFileReadyToParse() assert self.server_state.DiagnosticsForCurrentFileReady() self.server_state.ValidateParseRequest() - present_dialog.assert_has_calls( [ + present_dialog.assert_has_exact_calls( [ PresentDialog_Confirm_Call( MESSAGE ), ] ) - load_extra_conf.assert_has_calls( [ + load_extra_conf.assert_has_exact_calls( [ call( FILE_NAME ), ] ) # Subsequent calls don't re-raise the warning self.server_state.ValidateParseRequest() - present_dialog.assert_has_calls( [ + present_dialog.assert_has_exact_calls( [ PresentDialog_Confirm_Call( MESSAGE ) ] ) - load_extra_conf.assert_has_calls( [ + load_extra_conf.assert_has_exact_calls( [ call( FILE_NAME ), ] ) @@ -238,36 +243,37 @@ class EventNotification_test( object ): assert self.server_state.DiagnosticsForCurrentFileReady() self.server_state.ValidateParseRequest() - present_dialog.assert_has_calls( [ + present_dialog.assert_has_exact_calls( [ PresentDialog_Confirm_Call( MESSAGE ), PresentDialog_Confirm_Call( MESSAGE ), ] ) - load_extra_conf.assert_has_calls( [ + load_extra_conf.assert_has_exact_calls( [ call( FILE_NAME ), call( FILE_NAME ), ] ) # When the user rejects the extra conf, we reject it with patch( 'ycm.vimsupport.PresentDialog', - return_value = 1 ) as present_dialog: + return_value = 1, + new_callable = ExtendedMock ) as present_dialog: self.server_state.OnFileReadyToParse() assert self.server_state.DiagnosticsForCurrentFileReady() self.server_state.ValidateParseRequest() - present_dialog.assert_has_calls( [ + present_dialog.assert_has_exact_calls( [ PresentDialog_Confirm_Call( MESSAGE ), ] ) - ignore_extra_conf.assert_has_calls( [ + ignore_extra_conf.assert_has_exact_calls( [ call( FILE_NAME ), ] ) # Subsequent calls don't re-raise the warning self.server_state.ValidateParseRequest() - present_dialog.assert_has_calls( [ + present_dialog.assert_has_exact_calls( [ PresentDialog_Confirm_Call( MESSAGE ) ] ) - ignore_extra_conf.assert_has_calls( [ + ignore_extra_conf.assert_has_exact_calls( [ call( FILE_NAME ), ] ) @@ -276,11 +282,11 @@ class EventNotification_test( object ): assert self.server_state.DiagnosticsForCurrentFileReady() self.server_state.ValidateParseRequest() - present_dialog.assert_has_calls( [ + present_dialog.assert_has_exact_calls( [ PresentDialog_Confirm_Call( MESSAGE ), PresentDialog_Confirm_Call( MESSAGE ), ] ) - ignore_extra_conf.assert_has_calls( [ + ignore_extra_conf.assert_has_exact_calls( [ call( FILE_NAME ), call( FILE_NAME ), ] ) From a0943d5d31a7b80b22588bd0d30bbca6cd0798fc Mon Sep 17 00:00:00 2001 From: micbou Date: Sat, 23 Jan 2016 16:58:24 +0100 Subject: [PATCH 08/10] Fall back to Python search in PATH --- python/ycm/paths.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/python/ycm/paths.py b/python/ycm/paths.py index 15f82e81..e103778c 100644 --- a/python/ycm/paths.py +++ b/python/ycm/paths.py @@ -47,11 +47,11 @@ def PathToPythonInterpreter(): python_interpreter = vim.eval( 'g:ycm_path_to_python_interpreter' ) if python_interpreter: - if not IsPythonVersionCorrect( python_interpreter ): - raise RuntimeError( "Path in 'g:ycm_path_to_python_interpreter' option " - "does not point to a valid Python 2.6 or 2.7." ) + if IsPythonVersionCorrect( python_interpreter ): + return python_interpreter - return python_interpreter + raise RuntimeError( "Path in 'g:ycm_path_to_python_interpreter' option " + "does not point to a valid Python 2.6 or 2.7." ) # On UNIX platforms, we use sys.executable as the Python interpreter path. # We cannot use sys.executable on Windows because for unknown reasons, it @@ -60,12 +60,21 @@ def PathToPythonInterpreter(): python_interpreter = ( WIN_PYTHON_PATH if utils.OnWindows() else sys.executable ) - if not IsPythonVersionCorrect( python_interpreter ): - raise RuntimeError( "Cannot find Python 2.6 or 2.7. You can set its path " - "using the 'g:ycm_path_to_python_interpreter' " - "option." ) + if IsPythonVersionCorrect( python_interpreter ): + return python_interpreter - return python_interpreter + # As a last resort, we search python in the PATH. We check 'python2' before + # 'python' because on some distributions (Arch Linux for example), python + # refers to python3. + python_interpreter = utils.PathToFirstExistingExecutable( [ 'python2', + 'python' ] ) + + if IsPythonVersionCorrect( python_interpreter ): + return python_interpreter + + raise RuntimeError( "Cannot find Python 2.6 or 2.7. You can set its path " + "using the 'g:ycm_path_to_python_interpreter' " + "option." ) def EndsWithPython( path ): From 0efa66893128dafe48caaa806455704e197efbe0 Mon Sep 17 00:00:00 2001 From: Strahinja Val Markovic Date: Tue, 26 Jan 2016 15:49:58 -0800 Subject: [PATCH 09/10] Adding an explicit Contributor Code of Conduct Everything in the CoC was true since the beginning of the project, it was just implicit and not written down. Now we're making it explicit. --- CODE_OF_CONDUCT.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++ README.md | 9 +++++++++ 2 files changed, 59 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..e39575fb --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,50 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of +fostering an open and welcoming community, we pledge to respect all people who +contribute through reporting issues, posting feature requests, updating +documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free +experience for everyone, regardless of level of experience, gender, gender +identity and expression, sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, such as physical or electronic + addresses, without explicit permission +* Other unethical or unprofessional conduct + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +By adopting this Code of Conduct, project maintainers commit themselves to +fairly and consistently applying these principles to every aspect of managing +this project. Project maintainers who do not follow or enforce the Code of +Conduct may be permanently removed from the project team. + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting a project maintainer at val@markovic.io. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. Maintainers are +obligated to maintain confidentiality with regard to the reporter of an +incident. + + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.3.0, available at +[http://contributor-covenant.org/version/1/3/0/][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/3/0/ diff --git a/README.md b/README.md index acb77bca..14cc3864 100644 --- a/README.md +++ b/README.md @@ -2579,6 +2579,13 @@ If this is still really annoying, and you have a good reason not to have a and YCM will stop complaining. +Contributor Code of Conduct +--------------------------- + +Please note that this project is released with a [Contributor Code of +Conduct][ccoc]. By participating in this project you agree to abide by its +terms. + Contact ------- @@ -2594,6 +2601,7 @@ The latest version of the plugin is available at The author's homepage is . + License ------- @@ -2653,3 +2661,4 @@ This software is licensed under the [GPL v3 license][gpl]. [racer]: https://github.com/phildawes/racer [rust-install]: https://www.rust-lang.org/ [rust-src]: https://www.rust-lang.org/downloads.html +[ccoc]: https://github.com/Valloric/YouCompleteMe/blob/master/CODE_OF_CONDUCT.md From 5ee7bd2c807384ac51074f8212a4aec5364627b9 Mon Sep 17 00:00:00 2001 From: Strahinja Val Markovic Date: Tue, 26 Jan 2016 15:54:44 -0800 Subject: [PATCH 10/10] Updating TOC in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 14cc3864..8ec31c2c 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ YouCompleteMe: a code-completion engine for Vim - [YcmCompleter subcommands](#ycmcompleter-subcommands) - [Options](#options) - [FAQ](#faq) +- [Contributor Code of Conduct](#contributor-code-of-conduct) - [Contact](#contact) - [License](#license)