Skip to content

Python2 end of life

Boris Staletic edited this page Jan 24, 2020 · 4 revisions

Dropping support for Python 2 in 2020

In early 2020, ycmd has dropped support for Python 2. But we will maintain critical fixes on a branch legacy-py2 for a period of 1 year.

Why?

Over the past decade, ycm has had an at times fractious, but ultimately very successful relationship with Python 2. However, more recently it has been carrying on a simultaneous relationship with Python 3. Indeed all of YCM and ycmd code is Python 3 code, with a lot of gubbins to make it work also on Python 2. This makes the code more complex, requires double testing of everything, and restricts the developers from using certain new language features, ultimately restricting the features we can deliver to users.

On 1st January 2020, Python 2 will be officially end of life. And therefore, so will its relationship with YouCompleteMe and ycmd.

Dropped modules

Besides the dropped python-future, some additional modules have been dropped as they are not needed any more.

ycmd.bottle_utils

It's unlikely that this was useful for end-users, but on the off-chance that you needed SetResponseHeader() from ycmd.bottle_utils, the equivalent python3 implementation of SetResponseHeader() is:

import bottle
from ycmd.utils import ToUnicode
def SetResponseHeader( name, value ):
  bottle.response.set_header( ToUnicode( name ), ToUnicode( value ) )

Obviously, if name and value are already of type str (python3 str), there's no need for ToUnicode() calls.

Misc utilities

ycmd.hmac_utils.SecureBytesEqual()

This was always just a backport of a standard python 3.4 utility. Can be replaced with hmac.compare_digest().

ycmd.server_utils.GetStandardLibraryIndexInSysPath() and friends

The "and friends" part is referring to IsVirtualEnvLibraryFolder() and IsStandardLibraryFolder() from the same module. YCMD used these to know exactly how to insert python-future into the sys.path. Since python-future was dropped, there was no need to keep these utilities around. Their implementation is below:

PYTHON_STDLIB_ZIP_REGEX = re.compile( 'python[23][0-9]\\.zip' )


def IsStandardLibraryFolder( path ):
  return ( ( p.isfile( path ) and
             PYTHON_STDLIB_ZIP_REGEX.match( p.basename( path ) ) )
           or p.isfile( p.join( path, 'os.py' ) ) )


def IsVirtualEnvLibraryFolder( path ):
  return p.isfile( p.join( path, 'orig-prefix.txt' ) )


def GetStandardLibraryIndexInSysPath():
  for index, path in enumerate( sys.path ):
    if ( IsStandardLibraryFolder( path ) and not IsVirtualEnvLibraryFolder( path ) ):
      return index
  raise RuntimeError( 'Could not find standard library path in Python path.' )

ycmd.utils.ToCppStringCompatible

Technically, this isn't related to dropping python2. It wasn't needed ever since ycmd switched to pybind11. After dropping future and python2, this utility becomes the same thing as ycmd.utils.ToBytes.

Tips and tricks

  1. If your default python is python2, when rebuilding ycmd, remember to use python3 build.py.
  2. If you wish to stay on python2 and switch to the legacy-py2 branch do the following (assuming you already have cloned ycmd):
git fetch origin
git checkout legacy-py2
python2 build.py