Repository: ycm-core/ycmd

Issue:
replace `builtins` with `future.builtins`, see Valloric/YouCompleteMe/issues/2024
Basically, I just run:
`find . -type f -iname '*.py' -print0 | xargs -0 -P 2 -n 1 sed -i '' -e 's/from builtins/from future.builtins/g'`
This patch fixed YouCompleteMe on my machine (Mac OS 10.11.3).

> VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Mar 30 2016 11:47:02)
> MacOS X (unix) version
> Included patches: 1-1655
> Compiled by Homebrew
> Huge version without GUI.  Features included (+) or not (-):
> +acl             +farsi           +mouse_netterm   +tag_binary
> +arabic          +file_in_path    +mouse_sgr       +tag_old_static
> +autocmd         +find_in_path    -mouse_sysmouse  -tag_any_white
> -balloon_eval    +float           +mouse_urxvt     -tcl
> -browse          +folding         +mouse_xterm     +terminfo
> ++builtin_terms  -footer          +multi_byte      +termresponse
> +byte_offset     +fork()          +multi_lang      +textobjects
> +channel         -gettext         -mzscheme        +timers
> +cindent         -hangul_input    +netbeans_intg   +title
> -clientserver    +iconv           +packages        -toolbar
> +clipboard       +insert_expand   +path_extra      +user_commands
> +cmdline_compl   +job             +perl            +vertsplit
> +cmdline_hist    +jumplist        +persistent_undo +virtualedit
> +cmdline_info    +keymap          +postscript      +visual
> +comments        +langmap         +printer         +visualextra
> +conceal         +libcall         +profile         +viminfo
> +cryptv          +linebreak       +python          +vreplace
> +cscope          +lispindent      -python3         +wildignore
> +cursorbind      +listcmds        +quickfix        +wildmenu
> +cursorshape     +localmap        +reltime         +windows
> +dialog_con      -lua             +rightleft       +writebackup
> +diff            +menu            +ruby            -X11
> +digraphs        +mksession       +scrollbind      -xfontset
> -dnd             +modify_fname    +signs           -xim
> -ebcdic          +mouse           +smartindent     -xsmp
> +emacs_tags      -mouseshape      +startuptime     -xterm_clipboard
> +eval            +mouse_dec       +statusline      -xterm_save
> +ex_extra        -mouse_gpm       -sun_workshop    -xpm
> +extra_search    -mouse_jsbterm   +syntax  
>    system vimrc file: "$VIM/vimrc"
>      user vimrc file: "$HOME/.vimrc"
>  2nd user vimrc file: "~/.vim/vimrc"
>       user exrc file: "$HOME/.exrc"
>   fall-back for $VIM: "/usr/local/share/vim"
> Compilation: /usr/bin/clang -c -I. -Iproto -DHAVE_CONFIG_H   -F/usr/local/Frameworks -DMACOS_X_UNIX  -Os -w -pipe -march=native -mmacosx-version-min=10.11 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1  
> Linking: /usr/bin/clang   -L. -fstack-protector -L/usr/local/lib -L/usr/local/opt/libyaml/lib -L/usr/local/opt/openssl/lib -L/usr/local/opt/readline/lib -L/usr/local/lib -F/usr/local/Frameworks -Wl,-headerpad_max_install_names -o vim        -lm  -lncurses -liconv -framework Cocoa   -fstack-protector  -L/System/Library/Perl/5.18/darwin-thread-multi-2level/CORE -lperl -F/usr/local/Cellar/python/2.7.11/Frameworks -framework Python   -lruby.2.3.0 -lobjc -L/usr/local/Cellar/ruby/2.3.0/lib

<!-- Reviewable:start -->

---

This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/ycmd/446)

<!-- Reviewable:end -->



Discussion:

Resolving patch:
diff --git a/ycmd/server_utils.py b/ycmd/server_utils.py
--- a/ycmd/server_utils.py
+++ b/ycmd/server_utils.py
@@ -25,6 +25,7 @@
 import sys
 import os
 import io
+import re
 
 VERSION_FILENAME = 'CORE_VERSION'
 CORE_NOT_COMPATIBLE_MESSAGE = (
@@ -32,6 +33,7 @@
 )
 
 DIR_OF_CURRENT_SCRIPT = os.path.dirname( os.path.abspath( __file__ ) )
+DIR_PACKAGES_REGEX = re.compile( '(site|dist)-packages$' )
 
 
 def SetUpPythonPath():
@@ -86,11 +88,19 @@ def AddNearestThirdPartyFoldersToSysPath( filepath ):
     # under its 'src' folder, but SOME of its modules are only meant to be
     # accessible under py2, not py3. This is because these modules (like
     # `queue`) are implementations of modules present in the py3 standard
-    # library. So to work around issues, we place the python-future last on
-    # sys.path so that they can be overriden by the standard library.
+    # library. Furthermore, we need to be sure that they are not overriden by
+    # already installed packages (for example, the 'builtins' module from
+    # 'pies2overrides' or a different version of 'python-future'). To work
+    # around these issues, we place the python-future just before the first
+    # path ending with 'site-packages' (or 'dist-packages' for Debian-like
+    # distributions) so that its modules can be overridden by the standard
+    # library but not by installed packages.
     if folder == 'python-future':
       folder = os.path.join( folder, 'src' )
-      sys.path.append( os.path.realpath( os.path.join( path_to_third_party,
+      packages_indices = ( sys.path.index( path ) for path in sys.path
+                           if DIR_PACKAGES_REGEX.search( path ) )
+      sys.path.insert( next( packages_indices, len( sys.path ) ),
+                       os.path.realpath( os.path.join( path_to_third_party,
                                                        folder ) ) )
       continue
     sys.path.insert( 0, os.path.realpath( os.path.join( path_to_third_party,


Test patch:
diff --git a/ycmd/tests/server_utils_test.py b/ycmd/tests/server_utils_test.py
--- a/ycmd/tests/server_utils_test.py
+++ b/ycmd/tests/server_utils_test.py
@@ -23,11 +23,31 @@
 standard_library.install_aliases()
 from builtins import *  # noqa
 
-from hamcrest import raises, assert_that, calling
+from hamcrest import ( assert_that, calling, contains, contains_inanyorder,
+                       raises )
+from mock import patch
 from nose.tools import ok_
-from ycmd.server_utils import ( PathToNearestThirdPartyFolder,
-                                AddNearestThirdPartyFoldersToSysPath )
 import os.path
+import sys
+
+from ycmd.server_utils import ( AddNearestThirdPartyFoldersToSysPath,
+                                PathToNearestThirdPartyFolder )
+
+DIR_OF_THIRD_PARTY = os.path.abspath(
+  os.path.join( os.path.dirname( __file__ ), '..', '..', 'third_party' ) )
+THIRD_PARTY_FOLDERS = (
+  os.path.join( DIR_OF_THIRD_PARTY, 'argparse' ),
+  os.path.join( DIR_OF_THIRD_PARTY, 'bottle' ),
+  os.path.join( DIR_OF_THIRD_PARTY, 'frozendict' ),
+  os.path.join( DIR_OF_THIRD_PARTY, 'godef' ),
+  os.path.join( DIR_OF_THIRD_PARTY, 'gocode' ),
+  os.path.join( DIR_OF_THIRD_PARTY, 'JediHTTP' ),
+  os.path.join( DIR_OF_THIRD_PARTY, 'OmniSharpServer' ),
+  os.path.join( DIR_OF_THIRD_PARTY, 'racerd' ),
+  os.path.join( DIR_OF_THIRD_PARTY, 'requests' ),
+  os.path.join( DIR_OF_THIRD_PARTY, 'tern_runtime' ),
+  os.path.join( DIR_OF_THIRD_PARTY, 'waitress' )
+)
 
 
 def PathToNearestThirdPartyFolder_Success_test():
@@ -43,3 +63,53 @@ def AddNearestThirdPartyFoldersToSysPath_Failure_test():
     calling( AddNearestThirdPartyFoldersToSysPath ).with_args(
       os.path.expanduser( '~' ) ),
     raises( RuntimeError, '.*third_party folder.*' ) )
+
+
+@patch( 'sys.path', [ '/some/path',
+                      '/first/path/to/site-packages',
+                      '/another/path',
+                      '/second/path/to/site-packages' ] )
+def AddNearestThirdPartyFoldersToSysPath_FutureBeforeSitePackages_test():
+  AddNearestThirdPartyFoldersToSysPath( __file__ )
+  assert_that( sys.path[ : len( THIRD_PARTY_FOLDERS ) ], contains_inanyorder(
+    *THIRD_PARTY_FOLDERS
+  ) )
+  assert_that( sys.path[ len( THIRD_PARTY_FOLDERS ) : ], contains(
+    '/some/path',
+    os.path.join( DIR_OF_THIRD_PARTY, 'python-future', 'src' ),
+    '/first/path/to/site-packages',
+    '/another/path',
+    '/second/path/to/site-packages',
+  ) )
+
+
+@patch( 'sys.path', [ '/some/path',
+                      '/first/path/to/dist-packages',
+                      '/another/path',
+                      '/second/path/to/dist-packages' ] )
+def AddNearestThirdPartyFoldersToSysPath_FutureBeforeDistPackages_test():
+  AddNearestThirdPartyFoldersToSysPath( __file__ )
+  assert_that( sys.path[ : len( THIRD_PARTY_FOLDERS ) ], contains_inanyorder(
+    *THIRD_PARTY_FOLDERS
+  ) )
+  assert_that( sys.path[ len( THIRD_PARTY_FOLDERS ) : ], contains(
+    '/some/path',
+    os.path.join( DIR_OF_THIRD_PARTY, 'python-future', 'src' ),
+    '/first/path/to/dist-packages',
+    '/another/path',
+    '/second/path/to/dist-packages',
+  ) )
+
+
+@patch( 'sys.path', [ '/some/path',
+                      '/another/path' ] )
+def AddNearestThirdPartyFoldersToSysPath_FutureLastIfNoPackages_test():
+  AddNearestThirdPartyFoldersToSysPath( __file__ )
+  assert_that( sys.path[ : len( THIRD_PARTY_FOLDERS ) ], contains_inanyorder(
+    *THIRD_PARTY_FOLDERS
+  ) )
+  assert_that( sys.path[ len( THIRD_PARTY_FOLDERS ) : ], contains(
+    '/some/path',
+    '/another/path',
+    os.path.join( DIR_OF_THIRD_PARTY, 'python-future', 'src' ),
+  ) )