Bug 1390968: python-3 compatibility for python/**/*.py; r?gps r?Alex_Gaynor draft
authorDustin J. Mitchell <dustin@mozilla.com>
Mon, 28 Aug 2017 21:31:30 +0000
changeset 654965 8c239cd1a46714c719fa2acc922901c310789178
parent 654435 643442bb78bd5fd97d5e227278f5202ecd07f7a7
child 654966 eeeee3a11448f9d9572f6e023191cd206acec3d8
push id76735
push userdmitchell@mozilla.com
push dateTue, 29 Aug 2017 13:48:25 +0000
reviewersgps, Alex_Gaynor
bugs1390968
milestone57.0a1
Bug 1390968: python-3 compatibility for python/**/*.py; r?gps r?Alex_Gaynor This passes `python3 -mcompileall`. Changes: * use `0o` prefix for octal literals * print as a function * except .. as * use six.reraise to replace a multi-argument raise statement * use six.string_types and six.moves.configparser * remove uses of `L` suffix for long integers MozReview-Commit-ID: KLaYRNHGpay
python/mach/mach/config.py
python/mach/setup.py
python/mozboot/mozboot/archlinux.py
python/mozboot/mozboot/windows.py
python/mozbuild/mozbuild/action/exe_7z_archive.py
python/mozbuild/mozbuild/action/explode_aar.py
python/mozbuild/mozbuild/action/output_searchplugins_list.py
python/mozbuild/mozbuild/action/tooltool.py
python/mozbuild/mozbuild/configure/check_debug_ranges.py
python/mozbuild/mozbuild/configure/libstdcxx.py
python/mozbuild/mozbuild/configure/lint_util.py
python/mozbuild/mozbuild/doctor.py
python/mozbuild/mozbuild/jar.py
python/mozbuild/mozbuild/preprocessor.py
python/mozbuild/mozbuild/test/test_util.py
python/mozbuild/mozbuild/util.py
python/mozbuild/mozpack/archive.py
python/mozbuild/mozpack/files.py
python/mozbuild/mozpack/mozjar.py
--- a/python/mach/mach/config.py
+++ b/python/mach/mach/config.py
@@ -14,24 +14,20 @@ ConfigProvider classes are associated wi
 settings are available.
 """
 
 from __future__ import absolute_import, unicode_literals
 
 import collections
 import os
 import sys
+import six
 from functools import wraps
-
-if sys.version_info[0] == 3:
-    from configparser import RawConfigParser, NoSectionError
-    str_type = str
-else:
-    from ConfigParser import RawConfigParser, NoSectionError
-    str_type = basestring
+from six.moves.configparser import RawConfigParser, NoSectionError
+from six import string_types as str_type
 
 
 class ConfigException(Exception):
     pass
 
 
 class ConfigType(object):
     """Abstract base class for config values."""
@@ -139,17 +135,17 @@ def reraise_attribute_error(func):
     raise AttributeError instead of KeyError.
     """
     @wraps(func)
     def _(*args, **kwargs):
         try:
             return func(*args, **kwargs)
         except KeyError:
             exc_class, exc, tb = sys.exc_info()
-            raise AttributeError().__class__, exc, tb
+            six.reraise(AttributeError().__class__, exc, tb)
     return _
 
 
 class ConfigSettings(collections.Mapping):
     """Interface for configuration settings.
 
     This is the main interface to the configuration.
 
--- a/python/mach/setup.py
+++ b/python/mach/setup.py
@@ -27,12 +27,13 @@ setup(
         'Development Status :: 3 - Alpha',
         'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
         'Natural Language :: English',
     ],
     install_requires=[
         'blessings',
         'mozfile',
         'mozprocess',
+        'six',
     ],
     tests_require=['mock'],
 )
 
--- a/python/mozboot/mozboot/archlinux.py
+++ b/python/mozboot/mozboot/archlinux.py
@@ -70,17 +70,17 @@ class ArchlinuxBootstrapper(StyloInstall
         # See comment about 32 bit binaries and multilib below.
         'multilib/lib32-libstdc++5',
         'multilib/lib32-ncurses',
         'multilib/lib32-readline',
         'multilib/lib32-zlib',
     ]
 
     def __init__(self, version, dist_id, **kwargs):
-        print 'Using an experimental bootstrapper for Archlinux.'
+        print('Using an experimental bootstrapper for Archlinux.')
         BaseBootstrapper.__init__(self, **kwargs)
 
     def install_system_packages(self):
         self.pacman_install(*self.SYSTEM_PACKAGES)
 
     def install_browser_packages(self):
         self.ensure_browser_packages()
 
--- a/python/mozboot/mozboot/windows.py
+++ b/python/mozboot/mozboot/windows.py
@@ -40,17 +40,17 @@ class WindowsBootstrapper(BaseBootstrapp
         if 'MOZ_WINDOWS_BOOTSTRAP' not in os.environ or os.environ['MOZ_WINDOWS_BOOTSTRAP'] != '1':
             raise NotImplementedError('Bootstrap support for Windows is under development. For now, use MozillaBuild '
                                       'to set up a build environment on Windows. If you are testing Windows Bootstrap support, '
                                       'try `export MOZ_WINDOWS_BOOTSTRAP=1`')
         BaseBootstrapper.__init__(self, **kwargs)
         if not self.which('pacman'):
             raise NotImplementedError('The Windows bootstrapper only works with msys2 with pacman. Get msys2 at '
                                       'http://msys2.github.io/')
-        print 'Using an experimental bootstrapper for Windows.'
+        print('Using an experimental bootstrapper for Windows.')
 
     def which(self, name):
         return BaseBootstrapper.which(self, name + '.exe')
 
     def install_system_packages(self):
         self.pacman_install(*self.SYSTEM_PACKAGES)
 
     def upgrade_mercurial(self, current):
--- a/python/mozbuild/mozbuild/action/exe_7z_archive.py
+++ b/python/mozbuild/mozbuild/action/exe_7z_archive.py
@@ -18,17 +18,17 @@ def archive_exe(pkg_dir, tagfile, sfx_pa
             shutil.move(pkg_dir, 'core')
         subprocess.check_call(['upx', '--best', '-o', mozpath.join(tmpdir, '7zSD.sfx'), sfx_package])
 
         subprocess.check_call(['7z', 'a', '-r', '-t7z', mozpath.join(tmpdir, 'app.7z'), '-mx', '-m0=BCJ2', '-m1=LZMA:d25', '-m2=LZMA:d19', '-m3=LZMA:d19', '-mb0:1', '-mb0s1:2', '-mb0s2:3'])
 
         with open(package, 'wb') as o:
             for i in [mozpath.join(tmpdir, '7zSD.sfx'), tagfile, mozpath.join(tmpdir, 'app.7z')]:
                 shutil.copyfileobj(open(i, 'rb'), o)
-        os.chmod(package, 0755)
+        os.chmod(package, 0o0755)
     finally:
         if pkg_dir:
             shutil.move('core', pkg_dir)
         shutil.rmtree(tmpdir)
 
 def main(args):
     if len(args) != 4:
         print('Usage: exe_7z_archive.py <pkg_dir> <tagfile> <sfx_package> <package>',
--- a/python/mozbuild/mozbuild/action/explode_aar.py
+++ b/python/mozbuild/mozbuild/action/explode_aar.py
@@ -39,17 +39,17 @@ def explode(aar, destdir):
         jar = mozpath.join(finder.base, name + '-' + p)
         os.rename(mozpath.join(finder.base, p), jar)
 
     # Frequently assets/ is present but empty.  Protect against meaningless
     # changes to the AAR files by deleting empty assets/ directories.
     assets = mozpath.join(destdir, 'assets')
     try:
         os.rmdir(assets)
-    except OSError, e:
+    except OSError as e:
         if e.errno in (errno.ENOTEMPTY, errno.ENOENT):
             pass
         else:
             raise
 
     return True
 
 
--- a/python/mozbuild/mozbuild/action/output_searchplugins_list.py
+++ b/python/mozbuild/mozbuild/action/output_searchplugins_list.py
@@ -23,9 +23,9 @@ else:
 # Get additional engines from regionOverrides
 for region, overrides in searchinfo["regionOverrides"].iteritems():
   for originalengine, replacement in overrides.iteritems():
     if originalengine in engines:
       # We add the engine because we still need the original
       engines.add(replacement)
 
 # join() will take an iterable, not just a list.
-print '\n'.join(engines)
+print('\n'.join(engines))
--- a/python/mozbuild/mozbuild/action/tooltool.py
+++ b/python/mozbuild/mozbuild/action/tooltool.py
@@ -367,19 +367,19 @@ def list_manifest(manifest_file):
         manifest = open_manifest(manifest_file)
     except InvalidManifest as e:
         log.error("failed to load manifest file at '%s': %s" % (
             manifest_file,
             str(e),
         ))
         return False
     for f in manifest.file_records:
-        print "%s\t%s\t%s" % ("P" if f.present() else "-",
+        print("%s\t%s\t%s" % ("P" if f.present() else "-",
                               "V" if f.present() and f.validate() else "-",
-                              f.filename)
+                              f.filename))
     return True
 
 
 def validate_manifest(manifest_file):
     """I validate that all files in a manifest are present and valid but
     don't fetch or delete them if they aren't"""
     try:
         manifest = open_manifest(manifest_file)
@@ -669,17 +669,17 @@ def fetch_files(manifest_file, base_urls
 
             # if I am using a cache and a new file has just been retrieved from a
             # remote location, I need to update the cache as well
             if cache_folder:
                 log.info("Updating local cache %s..." % cache_folder)
                 try:
                     if not os.path.exists(cache_folder):
                         log.info("Creating cache in %s..." % cache_folder)
-                        os.makedirs(cache_folder, 0700)
+                        os.makedirs(cache_folder, 0o0700)
                     shutil.copy(os.path.join(os.getcwd(), localfile.filename),
                                 os.path.join(cache_folder, localfile.digest))
                     log.info("Local cache %s updated with %s" % (cache_folder,
                                                                  localfile.filename))
                     touch(os.path.join(cache_folder, localfile.digest))
                 except (OSError, IOError):
                     log.warning('Impossible to add file %s to cache folder %s' %
                                 (localfile.filename, cache_folder), exc_info=True)
--- a/python/mozbuild/mozbuild/configure/check_debug_ranges.py
+++ b/python/mozbuild/mozbuild/configure/check_debug_ranges.py
@@ -54,9 +54,9 @@ def main(bin, compilation_unit):
     range = get_range_for(compilation_unit, debug_info[0])
     if range is not None:
         return get_range_length(range, debug_ranges[0])
 
     return -1
 
 
 if __name__ == '__main__':
-    print main(*sys.argv[1:])
+    print(main(*sys.argv[1:]))
--- a/python/mozbuild/mozbuild/configure/libstdcxx.py
+++ b/python/mozbuild/mozbuild/configure/libstdcxx.py
@@ -71,11 +71,11 @@ def find_version(e):
     p = subprocess.Popen(['readelf', '-V', libstdcxx], stdout=subprocess.PIPE)
     versions = [parse_readelf_line(x)
                 for x in p.stdout.readlines() if 'Name: GLIBCXX' in x]
     last_version = sorted(versions, cmp = cmp_ver)[-1]
     return encode_ver(last_version)
 
 if __name__ == '__main__':
     cxx_env = os.environ['CXX']
-    print 'MOZ_LIBSTDCXX_TARGET_VERSION=%s' % find_version(cxx_env)
+    print('MOZ_LIBSTDCXX_TARGET_VERSION=%s' % find_version(cxx_env))
     host_cxx_env = os.environ.get('HOST_CXX', cxx_env)
-    print 'MOZ_LIBSTDCXX_HOST_VERSION=%s' % find_version(host_cxx_env)
+    print('MOZ_LIBSTDCXX_HOST_VERSION=%s' % find_version(host_cxx_env))
--- a/python/mozbuild/mozbuild/configure/lint_util.py
+++ b/python/mozbuild/mozbuild/configure/lint_util.py
@@ -25,17 +25,17 @@ def disassemble_as_iter(co):
         op = ord(c)
         opname = dis.opname[op]
         i += 1;
         if op >= dis.HAVE_ARGUMENT:
             arg = ord(code[i]) + ord(code[i + 1]) * 256 + extended_arg
             extended_arg = 0
             i += 2
             if op == dis.EXTENDED_ARG:
-                extended_arg = arg * 65536L
+                extended_arg = arg * 65536
                 continue
             if op in dis.hasconst:
                 yield opname, co.co_consts[arg]
             elif op in dis.hasname:
                 yield opname, co.co_names[arg]
             elif op in dis.hasjrel:
                 yield opname, i + arg
             elif op in dis.haslocal:
--- a/python/mozbuild/mozbuild/doctor.py
+++ b/python/mozbuild/mozbuild/doctor.py
@@ -207,17 +207,17 @@ class Doctor(object):
                     if not choice:
                         return {'status': 'BAD, NOT FIXED',
                                 'desc': 'lastaccess enabled systemwide'}
                     try:
                         command = 'fsutil behavior set disablelastaccess 1'.split(' ')
                         fsutil_output = subprocess.check_output(command)
                         status = 'GOOD, FIXED'
                         desc = 'lastaccess disabled systemwide'
-                    except subprocess.CalledProcessError, e:
+                    except subprocess.CalledProcessError as e:
                         desc = 'lastaccess enabled systemwide'
                         if e.output.find('denied') != -1:
                             status = 'BAD, FIX DENIED'
                             denied = True
                         else:
                             status = 'BAD, NOT FIXED'
                 else:
                     status = 'BAD, FIXABLE'
--- a/python/mozbuild/mozbuild/jar.py
+++ b/python/mozbuild/mozbuild/jar.py
@@ -367,17 +367,17 @@ class JarMaker(object):
 
         jarfile = os.path.join(jardir, jarinfo.base, jarinfo.name)
         jf = None
         if self.outputFormat == 'jar':
             # jar
             jarfilepath = jarfile + '.jar'
             try:
                 os.makedirs(os.path.dirname(jarfilepath))
-            except OSError, error:
+            except OSError as error:
                 if error.errno != errno.EEXIST:
                     raise
             jf = ZipFile(jarfilepath, 'a', lock=True)
             outHelper = self.OutputHelper_jar(jf)
         else:
             outHelper = getattr(self, 'OutputHelper_'
                                 + self.outputFormat)(jarfile)
 
@@ -509,44 +509,44 @@ class JarMaker(object):
             return getModTime(os.path.join(self.basepath, aPath))
 
         def getOutput(self, name):
             out = self.ensureDirFor(name)
 
             # remove previous link or file
             try:
                 os.remove(out)
-            except OSError, e:
+            except OSError as e:
                 if e.errno != errno.ENOENT:
                     raise
             return open(out, 'wb')
 
         def ensureDirFor(self, name):
             out = os.path.join(self.basepath, name)
             outdir = os.path.dirname(out)
             if not os.path.isdir(outdir):
                 try:
                     os.makedirs(outdir)
-                except OSError, error:
+                except OSError as error:
                     if error.errno != errno.EEXIST:
                         raise
             return out
 
     class OutputHelper_symlink(OutputHelper_flat):
         '''Subclass of OutputHelper_flat that provides a helper for
         creating a symlink including creating the parent directories.
         '''
 
         def symlink(self, src, dest):
             out = self.ensureDirFor(dest)
 
             # remove previous link or file
             try:
                 os.remove(out)
-            except OSError, e:
+            except OSError as e:
                 if e.errno != errno.ENOENT:
                     raise
             if sys.platform != 'win32':
                 os.symlink(src, out)
             else:
                 # On Win32, use ctypes to create a hardlink
                 rv = CreateHardLink(out, src, None)
                 if rv == 0:
--- a/python/mozbuild/mozbuild/preprocessor.py
+++ b/python/mozbuild/mozbuild/preprocessor.py
@@ -51,17 +51,17 @@ class Expression:
         Create a new expression with this string.
         The expression will already be parsed into an Abstract Syntax Tree.
         """
         self.content = expression_string
         self.offset = 0
         self.__ignore_whitespace()
         self.e = self.__get_logical_or()
         if self.content:
-            raise Expression.ParseError, self
+            raise Expression.ParseError(self)
 
     def __get_logical_or(self):
         """
         Production: and_cond ( '||' expression ) ?
         """
         if not len(self.content):
             return None
         rv = Expression.__AST("logical_op")
@@ -152,17 +152,17 @@ class Expression:
             if word_len:
                 value = int(self.content[:word_len])
                 rv = Expression.__ASTLeaf('int', value)
             else:
                 word_len = re.match('\w*', self.content).end()
                 if word_len:
                     rv = Expression.__ASTLeaf('string', self.content[:word_len])
                 else:
-                    raise Expression.ParseError, self
+                    raise Expression.ParseError(self)
         self.__strip(word_len)
         self.__ignore_whitespace()
         return rv
 
     def __ignore_whitespace(self):
         ws_len = re.match('\s*', self.content).end()
         self.__strip(ws_len)
         return
@@ -191,17 +191,17 @@ class Expression:
         # Helper function to evaluate __get_logical_and and __get_logical_or results
         def eval_logical_op(tok):
             left = opmap[tok[0].type](tok[0])
             right = opmap[tok[2].type](tok[2])
             if tok[1].value == '&&':
                 return left and right
             elif tok[1].value == '||':
                 return left or right
-            raise Expression.ParseError, self
+            raise Expression.ParseError(self)
 
         # Mapping from token types to evaluator functions
         # Apart from (non-)equality, all these can be simple lambda forms.
         opmap = {
           'logical_op': eval_logical_op,
           'equality': eval_equality,
           'not': lambda tok: not opmap[tok[0].type](tok[0]),
           'string': lambda tok: context[tok.value],
--- a/python/mozbuild/mozbuild/test/test_util.py
+++ b/python/mozbuild/mozbuild/test/test_util.py
@@ -105,17 +105,17 @@ class TestFileAvoidWrite(unittest.TestCa
             self.assertEqual(open('file', 'r').read(), 'foobar')
 
         class MyMockedOpen(MockedOpen):
             '''MockedOpen extension to raise an exception if something
             attempts to write in an opened file.
             '''
             def __call__(self, name, mode):
                 if 'w' in mode:
-                    raise Exception, 'Unexpected open with write mode'
+                    raise Exception('Unexpected open with write mode')
                 return MockedOpen.__call__(self, name, mode)
 
         with MyMockedOpen({'file': 'content'}):
             # Validate that MyMockedOpen works as intended
             file = FileAvoidWrite('file')
             file.write('foobar')
             self.assertRaises(Exception, file.close)
 
--- a/python/mozbuild/mozbuild/util.py
+++ b/python/mozbuild/mozbuild/util.py
@@ -147,17 +147,17 @@ class ReadOnlyDefaultDict(ReadOnlyDict):
 
 
 def ensureParentDir(path):
     """Ensures the directory parent to the given file exists."""
     d = os.path.dirname(path)
     if d and not os.path.exists(path):
         try:
             os.makedirs(d)
-        except OSError, error:
+        except OSError as error:
             if error.errno != errno.EEXIST:
                 raise
 
 
 def mkdir(path, not_indexed=False):
     """Ensure a directory exists.
 
     If ``not_indexed`` is True, an attribute is set that disables content
--- a/python/mozbuild/mozpack/archive.py
+++ b/python/mozbuild/mozpack/archive.py
@@ -1,17 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import
 
 import bz2
 import gzip
-import io
 import stat
 import tarfile
 
 from .files import (
     BaseFile, File,
 )
 
 # 2016-01-01T00:00:00+0000
@@ -32,17 +31,17 @@ def create_tar_from_files(fp, files):
     FUTURE accept a filename argument (or create APIs to write files)
     """
     with tarfile.open(name='', mode='w', fileobj=fp, dereference=True) as tf:
         for archive_path, f in sorted(files.items()):
             if not isinstance(f, BaseFile):
                 f = File(f)
 
             ti = tarfile.TarInfo(archive_path)
-            ti.mode = f.mode or 0644
+            ti.mode = f.mode or 0o0644
             ti.type = tarfile.REGTYPE
 
             if not ti.isreg():
                 raise ValueError('not a regular file: %s' % f)
 
             # Disallow setuid and setgid bits. This is an arbitrary restriction.
             # However, since we set uid/gid to root:root, setuid and setgid
             # would be a glaring security hole if the archive were
--- a/python/mozbuild/mozpack/files.py
+++ b/python/mozbuild/mozpack/files.py
@@ -140,23 +140,23 @@ class BaseFile(object):
         return False
 
     @staticmethod
     def normalize_mode(mode):
         # Normalize file mode:
         # - keep file type (e.g. S_IFREG)
         ret = stat.S_IFMT(mode)
         # - expand user read and execute permissions to everyone
-        if mode & 0400:
-            ret |= 0444
-        if mode & 0100:
-            ret |= 0111
-        # - keep user write permissions
-        if mode & 0200:
-            ret |= 0200
+        if mode & 0o0400:
+            ret |= 0o0444
+        if mode & 0o0100:
+            ret |= 0o0111
+         # - keep user write permissions
+        if mode & 0o0200:
+            ret |= 0o0200
         # - leave away sticky bit, setuid, setgid
         return ret
 
     def copy(self, dest, skip_if_older=True):
         '''
         Copy the BaseFile content to the destination given as a string or a
         Dest instance. Avoids replacing existing files if the BaseFile content
         matches that of the destination, or in case of plain files, if the
--- a/python/mozbuild/mozpack/mozjar.py
+++ b/python/mozbuild/mozpack/mozjar.py
@@ -380,17 +380,17 @@ class JarReader(object):
             # Creator host system. 0 is MSDOS, 3 is Unix
             host = entry['creator_version'] >> 8
             # External attributes values depend on host above. On Unix the
             # higher bits are the stat.st_mode value. On MSDOS, the lower bits
             # are the FAT attributes.
             xattr = entry['external_attr']
             # Skip directories
             if (host == 0 and xattr & 0x10) or (host == 3 and
-                                                xattr & (040000 << 16)):
+                                                xattr & (0o040000 << 16)):
                 continue
             entries[entry['filename']] = entry
             if entry['offset'] < preload:
                 self._last_preloaded = entry['filename']
         self._entries = entries
         return entries
 
     @property
@@ -610,17 +610,17 @@ class JarWriter(object):
                                      type(data))
         # Fill a central directory entry for this new member.
         entry = JarCdirEntry()
         entry['creator_version'] = 20
         if mode is not None:
             # Set creator host system (upper byte of creator_version)
             # to 3 (Unix) so mode is honored when there is one.
             entry['creator_version'] |= 3 << 8
-            entry['external_attr'] = (mode & 0xFFFF) << 16L
+            entry['external_attr'] = (mode & 0xFFFF) << 16
         if deflater.compressed:
             entry['min_version'] = 20  # Version 2.0 supports deflated streams
             entry['general_flag'] = 2  # Max compression
             entry['compression'] = JAR_DEFLATED
         else:
             entry['min_version'] = 10  # Version 1.0 for stored streams
             entry['general_flag'] = 0
             entry['compression'] = JAR_STORED